separate users' configurations from wide.json

This commit is contained in:
Liang Ding 2014-12-19 15:43:59 +08:00
parent 24c29e176e
commit 3b359d92d8
13 changed files with 302 additions and 227 deletions

112
conf/user.go Normal file
View File

@ -0,0 +1,112 @@
// Copyright (c) 2014, B3log
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package conf
import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
// LatestSessionContent represents the latest session content.
type LatestSessionContent struct {
FileTree []string // paths of expanding nodes of file tree
Files []string // paths of files of opening editor tabs
CurrentFile string // path of file of the current focused editor tab
}
// User configuration.
type User struct {
Name string
Password string
Email string
Gravatar string // see http://gravatar.com
Workspace string // the GOPATH of this user
Locale string
GoFormat string
FontFamily string
FontSize string
Theme string
Editor *editor
LatestSessionContent *LatestSessionContent
}
// Editor configuration of a user.
type editor struct {
FontFamily string
FontSize string
LineHeight string
Theme string
TabSize string
}
// NewUser creates a user with the specified username, password, email and workspace.
func NewUser(username, password, email, workspace string) *User {
hash := md5.New()
hash.Write([]byte(email))
gravatar := hex.EncodeToString(hash.Sum(nil))
return &User{Name: username, Password: password, Email: email, Gravatar: gravatar, Workspace: workspace,
Locale: Wide.Locale, GoFormat: "gofmt", FontFamily: "Helvetica", FontSize: "13px", Theme: "default",
Editor: &editor{FontFamily: "Consolas, 'Courier New', monospace", FontSize: "inherit", LineHeight: "17px",
Theme: "wide", TabSize: "4"}}
}
// Save saves the user's configurations in conf/users/{username}.json.
func (u *User) Save() bool {
bytes, err := json.MarshalIndent(u, "", " ")
if nil != err {
logger.Error(err)
return false
}
if err = ioutil.WriteFile("conf/users/"+u.Name+".json", bytes, 0644); nil != err {
logger.Error(err)
return false
}
return true
}
// GetWorkspace gets workspace path of the user.
//
// Compared to the use of Wide.Workspace, this function will be processed as follows:
// 1. Replace {WD} variable with the actual directory path
// 2. Replace ${GOPATH} with enviorment variable GOPATH
// 3. Replace "/" with "\\" (Windows)
func (u *User) GetWorkspace() string {
w := strings.Replace(u.Workspace, "{WD}", Wide.WD, 1)
w = strings.Replace(w, "${GOPATH}", os.Getenv("GOPATH"), 1)
return filepath.FromSlash(w)
}
// GetOwner gets the user the specified path belongs to. Returns "" if not found.
func GetOwner(path string) string {
for _, user := range Users {
if strings.HasPrefix(path, user.GetWorkspace()) {
return user.Name
}
}
return ""
}

26
conf/users/admin.json Normal file
View File

@ -0,0 +1,26 @@
{
"Name": "admin",
"Password": "admin",
"Email": "",
"Gravatar": "d41d8cd98f00b204e9800998ecf8427e",
"Workspace": "${GOPATH}",
"Locale": "en_US",
"GoFormat": "gofmt",
"FontFamily": "Helvetica",
"FontSize": "13px",
"Theme": "black",
"Editor": {
"FontFamily": "Consolas, 'Courier New', monospace",
"FontSize": "13px",
"LineHeight": "17px",
"Theme": "wide",
"TabSize": "4"
},
"LatestSessionContent": {
"FileTree": [
"D:\\GoGoGo\\src"
],
"Files": [],
"CurrentFile": ""
}
}

View File

@ -12,13 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package conf includes configurations related manipulations, all configurations (including user configurations) are
// stored in wide.json.
// Package conf includes configurations related manipulations.
package conf
import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"io/ioutil"
"os"
@ -40,108 +37,102 @@ const (
PathSeparator = string(os.PathSeparator)
// PathListSeparator holds the OS-specific path list separator.
PathListSeparator = string(os.PathListSeparator)
)
const (
// WideVersion holds the current wide version.
WideVersion = "1.1.0"
// CodeMirrorVer holds the current editor version.
CodeMirrorVer = "4.8"
)
// LatestSessionContent represents the latest session content.
type LatestSessionContent struct {
FileTree []string // paths of expanding nodes of file tree
Files []string // paths of files of opening editor tabs
CurrentFile string // path of file of the current focused editor tab
}
// User configuration.
type User struct {
Name string
Password string
Email string
Gravatar string // see http://gravatar.com
Workspace string // the GOPATH of this user
Locale string
GoFormat string
FontFamily string
FontSize string
Theme string
Editor *Editor
LatestSessionContent *LatestSessionContent
}
// Editor configuration of a user.
type Editor struct {
FontFamily string
FontSize string
LineHeight string
Theme string
TabSize string
}
// Configuration.
type conf struct {
IP string // server ip, ${ip}
Port string // server port
Context string // server context
Server string // server host and port ({IP}:{Port})
StaticServer string // static resources server scheme, host and port (http://{IP}:{Port})
LogLevel string // logging level
Channel string // channel (ws://{IP}:{Port})
HTTPSessionMaxAge int // HTTP session max age (in seciond)
StaticResourceVersion string // version of static resources
MaxProcs int // Go max procs
RuntimeMode string // runtime mode (dev/prod)
WD string // current working direcitory, ${pwd}
Locale string // default locale
Users []*User // configurations of users
IP string // server ip, ${ip}
Port string // server port
Context string // server context
Server string // server host and port ({IP}:{Port})
StaticServer string // static resources server scheme, host and port (http://{IP}:{Port})
LogLevel string // logging level: trace/debug/info/warn/error
Channel string // channel (ws://{IP}:{Port})
HTTPSessionMaxAge int // HTTP session max age (in seciond)
StaticResourceVersion string // version of static resources
MaxProcs int // Go max procs
RuntimeMode string // runtime mode (dev/prod)
WD string // current working direcitory, ${pwd}
Locale string // default locale
}
// Configuration variable.
var Wide conf
// A raw copy of configuration variable.
//
// Save function will use this variable to persist.
var rawWide conf
// Logger.
var logger = log.NewLogger(os.Stdout)
// Wide configurations.
var Wide *conf
// configurations of users.
var Users []*User
// Indicates whether runs via Docker.
var Docker bool
// NewUser creates a user with the specified username, password, email and workspace.
func NewUser(username, password, email, workspace string) *User {
hash := md5.New()
hash.Write([]byte(email))
gravatar := hex.EncodeToString(hash.Sum(nil))
return &User{Name: username, Password: password, Email: email, Gravatar: gravatar, Workspace: workspace,
Locale: Wide.Locale, GoFormat: "gofmt", FontFamily: "Helvetica", FontSize: "13px", Theme: "default",
Editor: &Editor{FontFamily: "Consolas, 'Courier New', monospace", FontSize: "inherit", LineHeight: "17px",
Theme: "wide", TabSize: "4"}}
// Load loads the Wide configurations from wide.json and users' configurations from users/{username}.json.
func Load(confPath, confIP, confPort, confServer, confLogLevel, confStaticServer, confContext, confChannel string, confDocker bool) {
initWide(confPath, confIP, confPort, confServer, confLogLevel, confStaticServer, confContext, confChannel, confDocker)
initUsers()
}
// Load loads the configurations from wide.json.
func Load(confPath, confIP, confPort, confServer, confLogLevel, confStaticServer, confContext, confChannel string,
confDocker bool) {
bytes, _ := ioutil.ReadFile(confPath)
func initUsers() {
f, err := os.Open("conf/users")
if nil != err {
logger.Error(err)
err := json.Unmarshal(bytes, &Wide)
os.Exit(-1)
}
names, err := f.Readdirnames(-1)
if nil != err {
logger.Error(err)
os.Exit(-1)
}
f.Close()
for _, name := range names {
user := &User{}
bytes, _ := ioutil.ReadFile("conf/users/" + name)
err := json.Unmarshal(bytes, user)
if err != nil {
logger.Errorf("Parses [%s] error: %v", name, err)
os.Exit(-1)
}
Users = append(Users, user)
}
initWorkspaceDirs()
initCustomizedConfs()
}
func initWide(confPath, confIP, confPort, confServer, confLogLevel, confStaticServer, confContext, confChannel string, confDocker bool) {
bytes, err := ioutil.ReadFile(confPath)
if nil != err {
logger.Error(err)
os.Exit(-1)
}
Wide = &conf{}
err = json.Unmarshal(bytes, Wide)
if err != nil {
logger.Error("Parses wide.json error: ", err)
logger.Error("Parses [wide.json] error: ", err)
os.Exit(-1)
}
log.SetLevel(Wide.LogLevel)
// keep the raw content
json.Unmarshal(bytes, &rawWide)
logger.Debug("Conf: \n" + string(bytes))
// Working Driectory
@ -204,12 +195,6 @@ func Load(confPath, confIP, confPort, confServer, confLogLevel, confStaticServer
Wide.Server = strings.Replace(Wide.Server, "{Port}", Wide.Port, 1)
Wide.StaticServer = strings.Replace(Wide.StaticServer, "{Port}", Wide.Port, 1)
// upgrade if need
upgrade()
initWorkspaceDirs()
initCustomizedConfs()
}
// FixedTimeCheckEnv checks Wide runtime enviorment periodically (7 minutes).
@ -261,20 +246,9 @@ func checkEnv() {
}
}
// FixedTimeSave saves configurations (wide.json) periodically (1 minute).
//
// Main goal of this function is to save user session content, for restoring session content while user open Wide next time.
func FixedTimeSave() {
go func() {
for _ = range time.Tick(time.Minute) {
Save()
}
}()
}
// GetUserWorkspace gets workspace path with the specified username, returns "" if not found.
func (c *conf) GetUserWorkspace(username string) string {
for _, user := range c.Users {
func GetUserWorkspace(username string) string {
for _, user := range Users {
if user.Name == username {
return user.GetWorkspace()
}
@ -284,8 +258,8 @@ func (c *conf) GetUserWorkspace(username string) string {
}
// GetGoFmt gets the path of Go format tool, returns "gofmt" if not found "goimports".
func (c *conf) GetGoFmt(username string) string {
for _, user := range c.Users {
func GetGoFmt(username string) string {
for _, user := range Users {
if user.Name == username {
switch user.GoFormat {
case "gofmt":
@ -302,22 +276,9 @@ func (c *conf) GetGoFmt(username string) string {
return "gofmt"
}
// GetWorkspace gets workspace path of the user.
//
// Compared to the use of Wide.Workspace, this function will be processed as follows:
// 1. Replace {WD} variable with the actual directory path
// 2. Replace ${GOPATH} with enviorment variable GOPATH
// 3. Replace "/" with "\\" (Windows)
func (u *User) GetWorkspace() string {
w := strings.Replace(u.Workspace, "{WD}", Wide.WD, 1)
w = strings.Replace(w, "${GOPATH}", os.Getenv("GOPATH"), 1)
return filepath.FromSlash(w)
}
// GetUser gets configuration of the user specified by the given username, returns nil if not found.
func (*conf) GetUser(username string) *User {
for _, user := range Wide.Users {
func GetUser(username string) *User {
for _, user := range Users {
if user.Name == username {
return user
}
@ -326,13 +287,10 @@ func (*conf) GetUser(username string) *User {
return nil
}
// Save saves Wide configurations.
// Save saves Wide and all users' configurations.
func Save() bool {
// just the Users field are volatile
rawWide.Users = Wide.Users
// format
bytes, err := json.MarshalIndent(rawWide, "", " ")
// Wide, XXX: does we need to save wide.json?
bytes, err := json.MarshalIndent(Wide, "", " ")
if nil != err {
logger.Error(err)
@ -346,40 +304,17 @@ func Save() bool {
return false
}
return true
}
// upgrade upgrades the wide.json.
func upgrade() {
// Users
for _, user := range Wide.Users {
if "" == user.Theme {
user.Theme = "default" // since 1.1.0
}
if "" == user.Editor.Theme {
user.Editor.Theme = "wide" // since 1.1.0
}
if "" == user.Editor.TabSize {
user.Editor.TabSize = "4" // since 1.1.0
}
if "" != user.Email && "" == user.Gravatar {
hash := md5.New()
hash.Write([]byte(user.Email))
gravatar := hex.EncodeToString(hash.Sum(nil))
user.Gravatar = gravatar
}
for _, user := range Users {
user.Save()
}
Save()
return true
}
// initCustomizedConfs initializes the user customized configurations.
func initCustomizedConfs() {
for _, user := range Wide.Users {
for _, user := range Users {
UpdateCustomizedConf(user.Name)
}
}
@ -389,7 +324,7 @@ func initCustomizedConfs() {
// 1. /static/user/{username}/style.css
func UpdateCustomizedConf(username string) {
var u *User
for _, user := range Wide.Users { // maybe it is a beauty of the trade-off of the another world between design and implementation
for _, user := range Users { // maybe it is a beauty of the trade-off of the another world between design and implementation
if user.Name == username {
u = user
}
@ -438,7 +373,7 @@ func UpdateCustomizedConf(username string) {
func initWorkspaceDirs() {
paths := []string{}
for _, user := range Wide.Users {
for _, user := range Users {
paths = append(paths, filepath.SplitList(user.GetWorkspace())...)
}

View File

@ -11,35 +11,5 @@
"MaxProcs": 4,
"RuntimeMode": "dev",
"WD": "${pwd}",
"Locale": "en_US",
"Users": [
{
"Name": "admin",
"Password": "admin",
"Email": "",
"Gravatar": "",
"Workspace": "${GOPATH}",
"Locale": "en_US",
"GoFormat": "gofmt",
"FontFamily": "Helvetica",
"FontSize": "13px",
"Theme": "default",
"Editor": {
"FontFamily": "Consolas, 'Courier New', monospace",
"FontSize": "13px",
"LineHeight": "17px",
"Theme": "wide",
"TabSize": "4"
},
"LatestSessionContent": {
"FileTree": [
"D:\\GoGoGo\\src",
"D:\\GoGoGo\\src\\demo",
"D:\\GoGoGo\\src\\hello"
],
"Files": [],
"CurrentFile": ""
}
}
]
"Locale": "en_US"
}

View File

@ -147,7 +147,7 @@ func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
// logger.Infof("offset: %d", offset)
userWorkspace := conf.Wide.GetUserWorkspace(username)
userWorkspace := conf.GetUserWorkspace(username)
workspaces := filepath.SplitList(userWorkspace)
libPath := ""
for _, workspace := range workspaces {
@ -455,7 +455,7 @@ func getCursorOffset(code string, line, ch int) (offset int) {
}
func setCmdEnv(cmd *exec.Cmd, username string) {
userWorkspace := conf.Wide.GetUserWorkspace(username)
userWorkspace := conf.GetUserWorkspace(username)
cmd.Env = append(cmd.Env,
"GOPATH="+userWorkspace,

View File

@ -77,7 +77,7 @@ func GoFmtHandler(w http.ResponseWriter, r *http.Request) {
return
}
fmt := conf.Wide.GetGoFmt(username)
fmt := conf.GetGoFmt(username)
argv := []string{filePath}
cmd := exec.Command(fmt, argv...)

View File

@ -82,7 +82,7 @@ func GetFiles(w http.ResponseWriter, r *http.Request) {
}
username := session.Values["username"].(string)
userWorkspace := conf.Wide.GetUserWorkspace(username)
userWorkspace := conf.GetUserWorkspace(username)
workspaces := filepath.SplitList(userWorkspace)
root := Node{Name: "root", Path: "", IconSkin: "ico-ztree-dir ", Type: "d", Children: []*Node{}}
@ -163,14 +163,16 @@ func GetFile(w http.ResponseWriter, r *http.Request) {
data["mode"] = "img"
user := GetUsre(path)
if nil == user {
username := conf.GetOwner(path)
if "" == username {
logger.Warnf("The path [%s] has no owner")
data["path"] = ""
return
}
user := conf.GetUser(username)
data["path"] = "/workspace/" + user.Name + "/" + strings.Replace(path, user.GetWorkspace(), "", 1)
return
@ -356,7 +358,7 @@ func Find(w http.ResponseWriter, r *http.Request) {
}
username := session.Values["username"].(string)
userWorkspace := conf.Wide.GetUserWorkspace(username)
userWorkspace := conf.GetUserWorkspace(username)
workspaces := filepath.SplitList(userWorkspace)
if "" != path && !util.File.IsDir(path) {
@ -406,7 +408,7 @@ func SearchText(w http.ResponseWriter, r *http.Request) {
dir := args["dir"].(string)
if "" == dir {
userWorkspace := conf.Wide.GetUserWorkspace(wSession.Username)
userWorkspace := conf.GetUserWorkspace(wSession.Username)
workspaces := filepath.SplitList(userWorkspace)
dir = workspaces[0]
}
@ -736,14 +738,3 @@ func searchInFile(path string, text string) []*Snippet {
return ret
}
// GetUsre gets the user the specified path belongs to. Returns nil if not found.
func GetUsre(path string) *conf.User {
for _, user := range conf.Wide.Users {
if strings.HasPrefix(path, user.GetWorkspace()) {
return user
}
}
return nil
}

22
main.go
View File

@ -47,13 +47,13 @@ var logger *log.Logger
// The only one init function in Wide.
func init() {
confPath := flag.String("conf", "conf/wide.json", "path of wide.json")
confIP := flag.String("ip", "", "ip to visit")
confPort := flag.String("port", "", "port to visit")
confIP := flag.String("ip", "", "this will overwrite Wide.IP if specified")
confPort := flag.String("port", "", "this will overwrite Wide.Port if specified")
confServer := flag.String("server", "", "this will overwrite Wide.Server if specified")
confLogLevel := flag.String("log_level", "info", "logging level: trace/debug/info/warn/error")
confLogLevel := flag.String("log_level", "info", "this will overwrite Wide.LogLevel if specified")
confStaticServer := flag.String("static_server", "", "this will overwrite Wide.StaticServer if specified")
confContext := flag.String("context", "", "this will overwrite Wide.Context if specified")
confChannel := flag.String("channel", "", "this will overwrite Wide.XXXChannel if specified")
confChannel := flag.String("channel", "", "this will overwrite Wide.Channel if specified")
confStat := flag.Bool("stat", false, "whether report statistics periodically")
confDocker := flag.Bool("docker", false, "whether run in a docker container")
@ -77,8 +77,8 @@ func init() {
*confDocker)
conf.FixedTimeCheckEnv()
conf.FixedTimeSave()
session.FixedTimeSave()
session.FixedTimeRelease()
if *confStat {
@ -103,7 +103,7 @@ func main() {
serveSingle("/favicon.ico", "./static/favicon.ico")
// workspaces
for _, user := range conf.Wide.Users {
for _, user := range conf.Users {
http.Handle(conf.Wide.Context+"/workspace/"+user.Name+"/",
http.StripPrefix(conf.Wide.Context+"/workspace/"+user.Name+"/", http.FileServer(http.Dir(user.GetWorkspace()))))
}
@ -193,7 +193,7 @@ func indexHandler(w http.ResponseWriter, r *http.Request) {
wideSession := session.WideSessions.New(httpSession, sid)
username := httpSession.Values["username"].(string)
user := conf.Wide.GetUser(username)
user := conf.GetUser(username)
if nil == user {
logger.Warnf("Not found user [%s]", username)
@ -248,8 +248,8 @@ func startHandler(w http.ResponseWriter, r *http.Request) {
httpSession.Save(r, w)
username := httpSession.Values["username"].(string)
locale := conf.Wide.GetUser(username).Locale
userWorkspace := conf.Wide.GetUserWorkspace(username)
locale := conf.GetUser(username).Locale
userWorkspace := conf.GetUserWorkspace(username)
sid := r.URL.Query()["sid"][0]
wSession := session.WideSessions.Get(sid)
@ -288,7 +288,7 @@ func keyboardShortcutsHandler(w http.ResponseWriter, r *http.Request) {
httpSession.Save(r, w)
username := httpSession.Values["username"].(string)
locale := conf.Wide.GetUser(username).Locale
locale := conf.GetUser(username).Locale
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(locale), "locale": locale}
@ -320,7 +320,7 @@ func aboutHandler(w http.ResponseWriter, r *http.Request) {
httpSession.Save(r, w)
username := httpSession.Values["username"].(string)
locale := conf.Wide.GetUser(username).Locale
locale := conf.GetUser(username).Locale
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(locale), "locale": locale,
"ver": conf.WideVersion, "goos": runtime.GOOS, "goarch": runtime.GOARCH, "gover": runtime.Version()}

View File

@ -64,7 +64,7 @@ func event2Notification(e *event.Event) {
httpSession, _ := session.HTTPSession.Get(wsChannel.Request, "wide-session")
username := httpSession.Values["username"].(string)
locale := conf.Wide.GetUser(username).Locale
locale := conf.GetUser(username).Locale
var notification *Notification

View File

@ -263,7 +263,7 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) {
return
}
username := httpSession.Values["username"].(string)
locale := conf.Wide.GetUser(username).Locale
locale := conf.GetUser(username).Locale
var args map[string]interface{}
@ -522,7 +522,7 @@ func GoTestHandler(w http.ResponseWriter, r *http.Request) {
return
}
username := httpSession.Values["username"].(string)
locale := conf.Wide.GetUser(username).Locale
locale := conf.GetUser(username).Locale
var args map[string]interface{}
@ -640,7 +640,7 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) {
return
}
username := httpSession.Values["username"].(string)
locale := conf.Wide.GetUser(username).Locale
locale := conf.GetUser(username).Locale
var args map[string]interface{}
@ -805,7 +805,7 @@ func GoGetHandler(w http.ResponseWriter, r *http.Request) {
return
}
username := httpSession.Values["username"].(string)
locale := conf.Wide.GetUser(username).Locale
locale := conf.GetUser(username).Locale
var args map[string]interface{}
@ -937,7 +937,7 @@ func StopHandler(w http.ResponseWriter, r *http.Request) {
}
func setCmdEnv(cmd *exec.Cmd, username string) {
userWorkspace := conf.Wide.GetUserWorkspace(username)
userWorkspace := conf.GetUserWorkspace(username)
cmd.Env = append(cmd.Env,
"GOPATH="+userWorkspace,

View File

@ -242,7 +242,7 @@ func SaveContent(w http.ResponseWriter, r *http.Request) {
wSession.Content = args.LatestSessionContent
for _, user := range conf.Wide.Users {
for _, user := range conf.Users {
if user.Name == wSession.Username {
// update the variable in-memory, conf.FixedTimeSave() function will persist it periodically
user.LatestSessionContent = wSession.Content

View File

@ -26,6 +26,7 @@ import (
"strconv"
"sync"
"text/template"
"time"
"github.com/b3log/wide/conf"
"github.com/b3log/wide/i18n"
@ -61,7 +62,7 @@ func PreferenceHandler(w http.ResponseWriter, r *http.Request) {
httpSession.Save(r, w)
username := httpSession.Values["username"].(string)
user := conf.Wide.GetUser(username)
user := conf.GetUser(username)
if "GET" == r.Method {
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(user.Locale), "user": user,
@ -134,7 +135,7 @@ func PreferenceHandler(w http.ResponseWriter, r *http.Request) {
conf.UpdateCustomizedConf(username)
succ = conf.Save()
succ = user.Save()
}
// LoginHandler handles request of user login.
@ -178,7 +179,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
}
succ = false
for _, user := range conf.Wide.Users {
for _, user := range conf.Users {
if user.Name == args.Username && user.Password == args.Password {
succ = true
@ -219,7 +220,7 @@ func SignUpUser(w http.ResponseWriter, r *http.Request) {
if "GET" == r.Method {
// show the user sign up page
firstUserWorkspace := conf.Wide.GetUserWorkspace(conf.Wide.Users[0].Name)
firstUserWorkspace := conf.GetUserWorkspace(conf.Users[0].Name)
dir := filepath.Dir(firstUserWorkspace)
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(conf.Wide.Locale),
@ -266,6 +267,46 @@ func SignUpUser(w http.ResponseWriter, r *http.Request) {
}
}
// FixedTimeSave saves online users' configurations periodically (1 minute).
//
// Main goal of this function is to save user session content, for restoring session content while user open Wide next time.
func FixedTimeSave() {
go func() {
for _ = range time.Tick(time.Minute) {
users := getOnlineUsers()
for _, u := range users {
if u.Save() {
logger.Tracef("Saved online user [%s]'s configurations")
}
}
}
}()
}
func getOnlineUsers() []*conf.User {
ret := []*conf.User{}
usernames := map[string]string{} // distinct username
for _, s := range WideSessions {
usernames[s.Username] = ""
}
for _, username := range usernames {
u := conf.GetUser(username)
if nil == u {
logger.Warnf("Not found user [%s]", username)
continue
}
ret = append(ret, u)
}
return ret
}
// addUser add a user with the specified username, password and email.
//
// 1. create the user's workspace
@ -276,7 +317,7 @@ func addUser(username, password, email string) string {
addUserMutex.Lock()
defer addUserMutex.Unlock()
for _, user := range conf.Wide.Users {
for _, user := range conf.Users {
if user.Name == username {
return userExists
}
@ -286,12 +327,12 @@ func addUser(username, password, email string) string {
}
}
firstUserWorkspace := conf.Wide.GetUserWorkspace(conf.Wide.Users[0].Name)
firstUserWorkspace := conf.GetUserWorkspace(conf.Users[0].Name)
dir := filepath.Dir(firstUserWorkspace)
workspace := filepath.Join(dir, username)
newUser := conf.NewUser(username, password, email, workspace)
conf.Wide.Users = append(conf.Wide.Users, newUser)
conf.Users = append(conf.Users, newUser)
if !conf.Save() {
return userCreateError

View File

@ -63,7 +63,7 @@ func IndexHandler(w http.ResponseWriter, r *http.Request) {
wideSession := session.WideSessions.New(httpSession, sid)
username := httpSession.Values["username"].(string)
locale := conf.Wide.GetUser(username).Locale
locale := conf.GetUser(username).Locale
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(locale), "locale": locale,
"session": wideSession}
@ -182,7 +182,7 @@ func pipeCommands(username string, commands ...*exec.Cmd) string {
}
func setCmdEnv(cmd *exec.Cmd, username string) {
userWorkspace := conf.Wide.GetUserWorkspace(username)
userWorkspace := conf.GetUserWorkspace(username)
cmd.Env = append(cmd.Env,
"TERM="+os.Getenv("TERM"),