2017-03-14 17:40:45 +03:00
|
|
|
// Copyright (c) 2014-2017, b3log.org & hacpai.com
|
2014-12-19 10:43:59 +03:00
|
|
|
//
|
|
|
|
// 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"
|
2014-12-23 19:14:03 +03:00
|
|
|
"crypto/sha1"
|
2014-12-19 10:43:59 +03:00
|
|
|
"encoding/hex"
|
|
|
|
"encoding/json"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
2014-12-23 19:14:03 +03:00
|
|
|
"time"
|
2017-03-27 05:22:22 +03:00
|
|
|
"regexp"
|
2014-12-23 19:14:03 +03:00
|
|
|
"github.com/b3log/wide/util"
|
2014-12-19 10:43:59 +03:00
|
|
|
)
|
|
|
|
|
2015-12-08 18:48:16 +03:00
|
|
|
// Panel represents a UI panel.
|
|
|
|
type Panel struct {
|
|
|
|
State string `json:"state"` // panel state, "min"/"max"/"normal"
|
|
|
|
Size uint16 `json:"size"` // panel size
|
|
|
|
}
|
|
|
|
|
|
|
|
// Layout represents the UI layout.
|
2015-01-19 05:19:38 +03:00
|
|
|
type Layout struct {
|
2015-12-08 18:48:16 +03:00
|
|
|
Side *Panel `json:"side"` // Side panel
|
|
|
|
SideRight *Panel `json:"sideRight"` // Right-Side panel
|
|
|
|
Bottom *Panel `json:"bottom"` // Bottom panel
|
2015-01-19 05:19:38 +03:00
|
|
|
}
|
|
|
|
|
2014-12-19 10:43:59 +03:00
|
|
|
// LatestSessionContent represents the latest session content.
|
|
|
|
type LatestSessionContent struct {
|
2015-12-08 18:48:16 +03:00
|
|
|
FileTree []string `json:"fileTree"` // paths of expanding nodes of file tree
|
|
|
|
Files []string `json:"files"` // paths of files of opening editor tabs
|
|
|
|
CurrentFile string `json:"currentFile"` // path of file of the current focused editor tab
|
|
|
|
Layout *Layout `json:"layout"` // UI Layout
|
2014-12-19 10:43:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// User configuration.
|
|
|
|
type User struct {
|
|
|
|
Name string
|
|
|
|
Password string
|
2014-12-23 19:14:03 +03:00
|
|
|
Salt string
|
2014-12-19 10:43:59 +03:00
|
|
|
Email string
|
|
|
|
Gravatar string // see http://gravatar.com
|
2015-03-11 05:22:35 +03:00
|
|
|
Workspace string // the GOPATH of this user (maybe contain several paths splitted by os.PathListSeparator)
|
2014-12-19 10:43:59 +03:00
|
|
|
Locale string
|
|
|
|
GoFormat string
|
2017-03-27 04:59:35 +03:00
|
|
|
GoBuildArgsforLinux string
|
|
|
|
GoBuildArgsforWindows string
|
|
|
|
GoBuildArgsforDarwin string
|
2014-12-19 10:43:59 +03:00
|
|
|
FontFamily string
|
|
|
|
FontSize string
|
|
|
|
Theme string
|
2015-05-11 10:46:17 +03:00
|
|
|
Keymap string // wide/vim
|
|
|
|
Created int64 // user create time in unix nano
|
|
|
|
Updated int64 // preference update time in unix nano
|
|
|
|
Lived int64 // the latest session activity in unix nano
|
2014-12-19 10:43:59 +03:00
|
|
|
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 {
|
2014-12-23 19:14:03 +03:00
|
|
|
md5hash := md5.New()
|
|
|
|
md5hash.Write([]byte(email))
|
|
|
|
gravatar := hex.EncodeToString(md5hash.Sum(nil))
|
|
|
|
|
|
|
|
salt := util.Rand.String(16)
|
|
|
|
password = Salt(password, salt)
|
|
|
|
|
|
|
|
now := time.Now().UnixNano()
|
2014-12-19 10:43:59 +03:00
|
|
|
|
2014-12-23 19:14:03 +03:00
|
|
|
return &User{Name: username, Password: password, Salt: salt, Email: email, Gravatar: gravatar, Workspace: workspace,
|
2017-03-27 04:59:35 +03:00
|
|
|
Locale: Wide.Locale, GoFormat: "gofmt", GoBuildArgsforLinux: "-i", GoBuildArgsforWindows: "-i", GoBuildArgsforDarwin: "-i", FontFamily: "Helvetica", FontSize: "13px", Theme: "default",
|
2015-05-11 10:46:17 +03:00
|
|
|
Keymap: "wide",
|
2014-12-23 19:14:03 +03:00
|
|
|
Created: now, Updated: now, Lived: now,
|
2014-12-19 10:43:59 +03:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2016-01-14 10:45:52 +03:00
|
|
|
if "" == string(bytes) {
|
|
|
|
logger.Error("Truncated user [" + u.Name + "]")
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2014-12-19 10:43:59 +03:00
|
|
|
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 ""
|
|
|
|
}
|
2014-12-23 19:14:03 +03:00
|
|
|
|
|
|
|
// Salt salts the specified password with the specified salt.
|
|
|
|
func Salt(password, salt string) string {
|
|
|
|
sha1hash := sha1.New()
|
|
|
|
sha1hash.Write([]byte(password + salt))
|
|
|
|
|
|
|
|
return hex.EncodeToString(sha1hash.Sum(nil))
|
|
|
|
}
|
2017-03-27 04:59:35 +03:00
|
|
|
|
|
|
|
func (u *User) GetBuildArgs(os string) []string {
|
|
|
|
var tmp string
|
|
|
|
if os == "windows" {
|
|
|
|
tmp = u.GoBuildArgsforWindows
|
|
|
|
}
|
|
|
|
if os == "linux" {
|
|
|
|
tmp = u.GoBuildArgsforLinux
|
|
|
|
}
|
|
|
|
if os == "darwin" {
|
|
|
|
tmp = u.GoBuildArgsforDarwin
|
|
|
|
}
|
|
|
|
exp := regexp.MustCompile(`[^\s"']+|"([^"]*)"|'([^']*)'`)
|
|
|
|
words := exp.FindAllString(tmp, -1)
|
|
|
|
for idx := range words {
|
|
|
|
words[idx] = strings.Replace(words[idx], "\"", "", -1)
|
|
|
|
}
|
|
|
|
return words
|
|
|
|
}
|
|
|
|
|