From 7f5d5e17d673397f86522292929582a1cf994845 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Wed, 20 Jan 2021 14:47:48 -0800 Subject: [PATCH 01/20] ubuntu: apt-get update --- .github/workflows/build-ubuntu.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml index b8086b34b..da62aee30 100644 --- a/.github/workflows/build-ubuntu.yml +++ b/.github/workflows/build-ubuntu.yml @@ -25,10 +25,13 @@ jobs: with: go-version: 1.15 - - name: apt-get libgtk-3-dev + - name: apt-get update + run: sudo apt-get update + + - name: apt-get install libgtk-3-dev run: sudo apt-get install libgtk-3-dev - - name: apt-get libwebkit2gtk-4.0-dev + - name: apt-get install libwebkit2gtk-4.0-dev run: sudo apt-get install libwebkit2gtk-4.0-dev - name: Build Linux server and app From 2ea8022bae91ffddc5b078d3c933a852c15df750 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Wed, 20 Jan 2021 14:53:45 -0800 Subject: [PATCH 02/20] windows app path slash --- win/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/win/main.go b/win/main.go index 43c72b311..f6914047b 100644 --- a/win/main.go +++ b/win/main.go @@ -11,8 +11,8 @@ import ( ) func runOctoTasks(ctx context.Context) *exec.Cmd { - // cmd := exec.CommandContext(ctx, "bin/octoserver.exe", "--monitorpid", strconv.FormatInt(int64(os.Getpid()), 10)) - cmd := exec.CommandContext(ctx, "bin/octoserver.exe --single-user") + // cmd := exec.CommandContext(ctx, "bin\\octoserver.exe", "--monitorpid", strconv.FormatInt(int64(os.Getpid()), 10)) + cmd := exec.CommandContext(ctx, "bin\\octoserver.exe --single-user") // cmd := exec.CommandContext(ctx, "cmd.exe", "/C", "start", "./bin/octoserver.exe", "--monitorpid", strconv.FormatInt(int64(os.Getpid()), 10)) // cmd := exec.CommandContext(ctx, "cmd.exe", "/C", "start", "./bin/octoserver.exe") From 268250b7ea10fc7903d9d54ba89f15dbc440ad83 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Wed, 20 Jan 2021 14:55:40 -0800 Subject: [PATCH 03/20] Fix linux-app make --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index e8c5179f2..84071f1d8 100644 --- a/Makefile +++ b/Makefile @@ -130,6 +130,7 @@ win-app: server-win webapp linux-app: server-linux webapp rm -rf linux/temp mkdir -p linux/dist + mkdir -p linux/temp/tasks-app cp -R bin/linux/octoserver linux/temp/tasks-app/ cp -R app-config.json linux/temp/tasks-app/config.json cp -R webapp/pack linux/temp/tasks-app/pack From c614e727c26b8186a54a582f8ced2e070605d801 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Wed, 20 Jan 2021 15:03:29 -0800 Subject: [PATCH 04/20] Fix win-app commandline args --- win/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/win/main.go b/win/main.go index f6914047b..eaba07e00 100644 --- a/win/main.go +++ b/win/main.go @@ -11,8 +11,8 @@ import ( ) func runOctoTasks(ctx context.Context) *exec.Cmd { - // cmd := exec.CommandContext(ctx, "bin\\octoserver.exe", "--monitorpid", strconv.FormatInt(int64(os.Getpid()), 10)) - cmd := exec.CommandContext(ctx, "bin\\octoserver.exe --single-user") + // cmd := exec.CommandContext(ctx, "bin/octoserver.exe", "--monitorpid", strconv.FormatInt(int64(os.Getpid()), 10)) + cmd := exec.CommandContext(ctx, "bin/octoserver.exe", "--single-user") // cmd := exec.CommandContext(ctx, "cmd.exe", "/C", "start", "./bin/octoserver.exe", "--monitorpid", strconv.FormatInt(int64(os.Getpid()), 10)) // cmd := exec.CommandContext(ctx, "cmd.exe", "/C", "start", "./bin/octoserver.exe") From 12f5321107b3e280e107edaeeca9a4d89a0b4f06 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Wed, 20 Jan 2021 15:23:33 -0800 Subject: [PATCH 05/20] windows octoserver.exe path --- Makefile | 4 ++-- win/main.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 84071f1d8..029f472f5 100644 --- a/Makefile +++ b/Makefile @@ -119,8 +119,8 @@ mac-app: server-mac webapp win-app: server-win webapp cd win; make build - mkdir -p win/temp/bin - cp -R bin/win/octoserver.exe win/temp/bin + mkdir -p win/temp + cp -R bin/win/octoserver.exe win/temp cp -R app-config.json win/temp/config.json cp -R webapp/pack win/temp/pack mkdir -p win/dist diff --git a/win/main.go b/win/main.go index eaba07e00..742ad8ce3 100644 --- a/win/main.go +++ b/win/main.go @@ -11,8 +11,8 @@ import ( ) func runOctoTasks(ctx context.Context) *exec.Cmd { - // cmd := exec.CommandContext(ctx, "bin/octoserver.exe", "--monitorpid", strconv.FormatInt(int64(os.Getpid()), 10)) - cmd := exec.CommandContext(ctx, "bin/octoserver.exe", "--single-user") + // cmd := exec.CommandContext(ctx, "octoserver.exe", "--monitorpid", strconv.FormatInt(int64(os.Getpid()), 10), "--single-user") + cmd := exec.CommandContext(ctx, "octoserver.exe", "--single-user") // cmd := exec.CommandContext(ctx, "cmd.exe", "/C", "start", "./bin/octoserver.exe", "--monitorpid", strconv.FormatInt(int64(os.Getpid()), 10)) // cmd := exec.CommandContext(ctx, "cmd.exe", "/C", "start", "./bin/octoserver.exe") From a88f9592d89c7702ed45ca43a6d974619706a418 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Wed, 20 Jan 2021 18:59:59 -0800 Subject: [PATCH 06/20] Use Edge on Windows if Chrome not installed --- win/main.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/win/main.go b/win/main.go index 742ad8ce3..87a2cb136 100644 --- a/win/main.go +++ b/win/main.go @@ -5,6 +5,7 @@ import ( "log" "os" "os/exec" + "runtime" "github.com/gonutz/w32" "github.com/zserge/lorca" @@ -36,6 +37,11 @@ func main() { ctx, cancel := context.WithCancel(context.Background()) cmd := runOctoTasks(ctx) + chromePath := locateChrome() + if len(chromePath) > 0 { + os.Setenv("LORCACHROME", chromePath) + } + ui, err := lorca.New("http://localhost:8088", "", 1024, 768) if err != nil { log.Fatal(err) @@ -61,3 +67,54 @@ func hideConsole() { } } } + +// This duplicates the logic in Lorca, but adds Edge as an option for Windows, fallback to standard logic for other OSes +func locateChrome() string { + // If env variable "LORCACHROME" specified and it exists + if path, ok := os.LookupEnv("LORCACHROME"); ok { + if _, err := os.Stat(path); err == nil { + return path + } + } + + var paths []string + switch runtime.GOOS { + // case "darwin": + // paths = []string{ + // "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", + // "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary", + // "/Applications/Chromium.app/Contents/MacOS/Chromium", + // "/usr/bin/google-chrome-stable", + // "/usr/bin/google-chrome", + // "/usr/bin/chromium", + // "/usr/bin/chromium-browser", + // } + case "windows": + paths = []string{ + os.Getenv("LocalAppData") + "/Google/Chrome/Application/chrome.exe", + os.Getenv("ProgramFiles") + "/Google/Chrome/Application/chrome.exe", + os.Getenv("ProgramFiles(x86)") + "/Google/Chrome/Application/chrome.exe", + os.Getenv("LocalAppData") + "/Chromium/Application/chrome.exe", + os.Getenv("ProgramFiles") + "/Chromium/Application/chrome.exe", + os.Getenv("ProgramFiles(x86)") + "/Chromium/Application/chrome.exe", + os.Getenv("ProgramFiles(x86)") + "/Microsoft/Edge/Application/msedge.exe", + } + // default: + // paths = []string{ + // "/usr/bin/google-chrome-stable", + // "/usr/bin/google-chrome", + // "/usr/bin/chromium", + // "/usr/bin/chromium-browser", + // "/snap/bin/chromium", + // } + } + + for _, path := range paths { + if _, err := os.Stat(path); os.IsNotExist(err) { + continue + } + return path + } + + return "" +} From 1db75f114228445017df9300913003dd27a70981 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Wed, 20 Jan 2021 19:49:35 -0800 Subject: [PATCH 07/20] Win: Prompt download Chrome if not installed --- win/main.go | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/win/main.go b/win/main.go index 87a2cb136..f9a590870 100644 --- a/win/main.go +++ b/win/main.go @@ -34,14 +34,14 @@ func main() { // log.Printf("PID: %s", strconv.FormatInt(int64(os.Getpid()), 10)) hideConsole() + if len(lorca.ChromeExecutable) == 0 { + lorca.PromptDownload() + log.Fatal("Chrome not installed") + } + ctx, cancel := context.WithCancel(context.Background()) cmd := runOctoTasks(ctx) - chromePath := locateChrome() - if len(chromePath) > 0 { - os.Setenv("LORCACHROME", chromePath) - } - ui, err := lorca.New("http://localhost:8088", "", 1024, 768) if err != nil { log.Fatal(err) @@ -118,3 +118,14 @@ func locateChrome() string { return "" } + +// set LORCACHROME for Lorca to pick up at init time +func setLorcaChromeLocation() { + chromePath := locateChrome() + log.Printf("chromePath: %s", chromePath) + if len(chromePath) > 0 { + os.Setenv("LORCACHROME", chromePath) + } +} + +setLorcaChromeLocation() From 628ae4eb4ba0cba4b39b65629a99115bad2cc8e3 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Wed, 20 Jan 2021 20:07:35 -0800 Subject: [PATCH 08/20] Win: Chrome path logic --- win/main.go | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/win/main.go b/win/main.go index f9a590870..7aa19fa30 100644 --- a/win/main.go +++ b/win/main.go @@ -34,9 +34,16 @@ func main() { // log.Printf("PID: %s", strconv.FormatInt(int64(os.Getpid()), 10)) hideConsole() + // Try to find Chrome if Lorca can't find it if len(lorca.ChromeExecutable) == 0 { - lorca.PromptDownload() - log.Fatal("Chrome not installed") + chromePath := locateChrome() + log.Printf("chromePath: %s", chromePath) + if len(chromePath) > 0 { + lorca.ChromeExecutable = chromePath + } else { + lorca.PromptDownload() + log.Fatal("Chrome not installed") + } } ctx, cancel := context.WithCancel(context.Background()) @@ -70,13 +77,6 @@ func hideConsole() { // This duplicates the logic in Lorca, but adds Edge as an option for Windows, fallback to standard logic for other OSes func locateChrome() string { - // If env variable "LORCACHROME" specified and it exists - if path, ok := os.LookupEnv("LORCACHROME"); ok { - if _, err := os.Stat(path); err == nil { - return path - } - } - var paths []string switch runtime.GOOS { // case "darwin": @@ -118,14 +118,3 @@ func locateChrome() string { return "" } - -// set LORCACHROME for Lorca to pick up at init time -func setLorcaChromeLocation() { - chromePath := locateChrome() - log.Printf("chromePath: %s", chromePath) - if len(chromePath) > 0 { - os.Setenv("LORCACHROME", chromePath) - } -} - -setLorcaChromeLocation() From 7eed80d3a64a7d9bfb6ab1eef5ed70099adb1068 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Wed, 20 Jan 2021 20:28:43 -0800 Subject: [PATCH 09/20] Update to latest Lorca for chrome path --- win/go.mod | 2 +- win/go.sum | 8 ++++++++ win/main.go | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/win/go.mod b/win/go.mod index fd803680f..7819ec104 100644 --- a/win/go.mod +++ b/win/go.mod @@ -4,5 +4,5 @@ go 1.15 require ( github.com/gonutz/w32 v1.0.0 - github.com/zserge/lorca v0.1.9 + github.com/zserge/lorca v0.1.10-0.20200301195127-a3e43396a47e ) diff --git a/win/go.sum b/win/go.sum index 005734b98..46f7ad0c5 100644 --- a/win/go.sum +++ b/win/go.sum @@ -2,8 +2,16 @@ github.com/gonutz/w32 v1.0.0 h1:3t1z6ZfkFvirjFYBx9pHeHBuKoN/VBVk9yHb/m2Ll/k= github.com/gonutz/w32 v1.0.0/go.mod h1:Rc/YP5K9gv0FW4p6X9qL3E7Y56lfMflEol1fLElfMW4= github.com/zserge/lorca v0.1.9 h1:vbDdkqdp2/rmeg8GlyCewY2X8Z+b0s7BqWyIQL/gakc= github.com/zserge/lorca v0.1.9/go.mod h1:bVmnIbIRlOcoV285KIRSe4bUABKi7R7384Ycuum6e4A= +github.com/zserge/lorca v0.1.10-0.20200301195127-a3e43396a47e h1:RqKGfaG8v1WBC6JX5vhG7GocwY1lENlMiraQibyGRsY= +github.com/zserge/lorca v0.1.10-0.20200301195127-a3e43396a47e/go.mod h1:bVmnIbIRlOcoV285KIRSe4bUABKi7R7384Ycuum6e4A= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0 h1:MsuvTghUPjX762sGLnGsxC3HM0B5r83wEtYcYR8/vRs= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/win/main.go b/win/main.go index 7aa19fa30..12e98d4fd 100644 --- a/win/main.go +++ b/win/main.go @@ -35,11 +35,11 @@ func main() { hideConsole() // Try to find Chrome if Lorca can't find it - if len(lorca.ChromeExecutable) == 0 { + if len(lorca.ChromeExecutable()) == 0 { chromePath := locateChrome() log.Printf("chromePath: %s", chromePath) if len(chromePath) > 0 { - lorca.ChromeExecutable = chromePath + os.Setenv("LORCACHROME", chromePath) } else { lorca.PromptDownload() log.Fatal("Chrome not installed") From 1286349a228af9e61ddd35b7a033244379f7102f Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Thu, 21 Jan 2021 10:16:40 -0800 Subject: [PATCH 10/20] Change password --- server/api/api.go | 1 + server/api/auth.go | 61 ++++++++++++- server/app/auth.go | 29 ++++++- server/services/store/sqlstore/user.go | 12 +++ server/services/store/store.go | 1 + webapp/i18n/en.json | 4 + webapp/src/app.tsx | 20 ++--- webapp/src/components/sidebar.tsx | 7 ++ webapp/src/octoClient.ts | 12 +++ webapp/src/pages/changePasswordPage.scss | 64 ++++++++++++++ webapp/src/pages/changePasswordPage.tsx | 104 +++++++++++++++++++++++ webapp/src/pages/registerPage.tsx | 2 +- 12 files changed, 304 insertions(+), 13 deletions(-) create mode 100644 webapp/src/pages/changePasswordPage.scss create mode 100644 webapp/src/pages/changePasswordPage.tsx diff --git a/server/api/api.go b/server/api/api.go index 066d12306..206a6fa2c 100644 --- a/server/api/api.go +++ b/server/api/api.go @@ -42,6 +42,7 @@ func (a *API) RegisterRoutes(r *mux.Router) { r.HandleFunc("/api/v1/users/me", a.sessionRequired(a.handleGetMe)).Methods("GET") r.HandleFunc("/api/v1/users/{userID}", a.sessionRequired(a.handleGetUser)).Methods("GET") + r.HandleFunc("/api/v1/users/{userID}/changepassword", a.sessionRequired(a.handleChangePassword)).Methods("POST") r.HandleFunc("/api/v1/login", a.handleLogin).Methods("POST") r.HandleFunc("/api/v1/register", a.handleRegister).Methods("POST") diff --git a/server/api/auth.go b/server/api/auth.go index 223c73fa1..d4d6a146e 100644 --- a/server/api/auth.go +++ b/server/api/auth.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/gorilla/mux" "github.com/mattermost/mattermost-octo-tasks/server/model" "github.com/mattermost/mattermost-octo-tasks/server/services/auth" ) @@ -39,9 +40,38 @@ func (rd *RegisterData) IsValid() error { if !strings.Contains(rd.Email, "@") { return errors.New("Invalid email format") } - if !strings.Contains(rd.Password, "") { + if rd.Password == "" { return errors.New("Password is required") } + if err := isValidPassword(rd.Password); err != nil { + return err + } + return nil +} + +type ChangePasswordData struct { + OldPassword string `json:"oldPassword"` + NewPassword string `json:"newPassword"` +} + +func (rd *ChangePasswordData) IsValid() error { + if rd.OldPassword == "" { + return errors.New("Old password is required") + } + if rd.NewPassword == "" { + return errors.New("New password is required") + } + if err := isValidPassword(rd.NewPassword); err != nil { + return err + } + + return nil +} + +func isValidPassword(password string) error { + if len(password) < 8 { + return errors.New("Password must be at least 8 characters") + } return nil } @@ -131,6 +161,35 @@ func (a *API) handleRegister(w http.ResponseWriter, r *http.Request) { jsonBytesResponse(w, http.StatusOK, nil) } +func (a *API) handleChangePassword(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + userID := vars["userID"] + + requestBody, err := ioutil.ReadAll(r.Body) + if err != nil { + errorResponse(w, http.StatusInternalServerError, nil, err) + return + } + + var requestData ChangePasswordData + if err := json.Unmarshal(requestBody, &requestData); err != nil { + errorResponse(w, http.StatusInternalServerError, nil, err) + return + } + + if err = requestData.IsValid(); err != nil { + errorResponse(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}, err) + return + } + + if err = a.app().ChangePassword(userID, requestData.OldPassword, requestData.NewPassword); err != nil { + errorResponse(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}, err) + return + } + + jsonBytesResponse(w, http.StatusOK, nil) +} + func (a *API) sessionRequired(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) { return a.attachSession(handler, true) } diff --git a/server/app/auth.go b/server/app/auth.go index 7bf89b92f..8210cb4dc 100644 --- a/server/app/auth.go +++ b/server/app/auth.go @@ -68,7 +68,7 @@ func (a *App) Login(username string, email string, password string, mfaToken str } if !auth.ComparePassword(user.Password, password) { - log.Printf("Not valid passowrd. %s (%s)\n", password, user.Password) + log.Printf("Invalid password for userID: %s\n", user.ID) return "", errors.New("invalid username or password") } @@ -132,3 +132,30 @@ func (a *App) RegisterUser(username string, email string, password string) error return nil } + +func (a *App) ChangePassword(userID string, oldPassword string, newPassword string) error { + var user *model.User + if userID != "" { + var err error + user, err = a.store.GetUserById(userID) + if err != nil { + return errors.Wrap(err, "invalid username or password") + } + } + + if user == nil { + return errors.New("invalid username or password") + } + + if !auth.ComparePassword(user.Password, oldPassword) { + log.Printf("Invalid password for userID: %s\n", user.ID) + return errors.New("invalid username or password") + } + + err := a.store.UpdateUserPasswordByID(userID, auth.HashPassword(newPassword)) + if err != nil { + return errors.Wrap(err, "unable to update password") + } + + return nil +} diff --git a/server/services/store/sqlstore/user.go b/server/services/store/sqlstore/user.go index dcf141d47..7c7c78d81 100644 --- a/server/services/store/sqlstore/user.go +++ b/server/services/store/sqlstore/user.go @@ -93,3 +93,15 @@ func (s *SQLStore) UpdateUser(user *model.User) error { _, err = query.Exec() return err } + +func (s *SQLStore) UpdateUserPasswordByID(userID string, password string) error { + now := time.Now().Unix() + + query := s.getQueryBuilder().Update("users"). + Set("password", password). + Set("update_at", now). + Where(sq.Eq{"id": userID}) + + _, err := query.Exec() + return err +} diff --git a/server/services/store/store.go b/server/services/store/store.go index 4a70169f8..51405e673 100644 --- a/server/services/store/store.go +++ b/server/services/store/store.go @@ -27,6 +27,7 @@ type Store interface { GetUserByUsername(username string) (*model.User, error) CreateUser(user *model.User) error UpdateUser(user *model.User) error + UpdateUserPasswordByID(userID string, password string) error GetSession(token string, expireTime int64) (*model.Session, error) CreateSession(session *model.Session) error diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index e20fb1fef..04562309a 100644 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -10,6 +10,7 @@ "BoardComponent.no-property": "No {property}", "BoardComponent.no-property-title": "Items with an empty {property} property will go here. This column cannot be removed.", "BoardComponent.show": "Show", + "BoardPage.syncFailed": "Board may be deleted or access revoked.", "CardDetail.add-content": "Add content", "CardDetail.add-icon": "Add icon", "CardDetail.add-property": "+ Add a property", @@ -63,6 +64,7 @@ "RegistrationLink.confirmRegenerateToken": "This will invalidate previously shared links. Continue?", "RegistrationLink.copiedLink": "Copied!", "RegistrationLink.copyLink": "Copy link", + "RegistrationLink.description": "Share this link for others to create accounts:", "RegistrationLink.regenerateToken": "Regenerate token", "RegistrationLink.tokenRegenerated": "Registration link regenerated", "ShareBoard.confirmRegenerateToken": "This will invalidate previously shared links. Continue?", @@ -74,6 +76,7 @@ "ShareBoard.unshare": "Anyone with the link can view this board", "Sidebar.add-board": "+ Add Board", "Sidebar.add-template": "+ New template", + "Sidebar.changePassword": "Change password", "Sidebar.dark-theme": "Dark theme", "Sidebar.default-theme": "Default theme", "Sidebar.delete-board": "Delete board", @@ -86,6 +89,7 @@ "Sidebar.import-archive": "Import archive", "Sidebar.invite-users": "Invite Users", "Sidebar.light-theme": "Light theme", + "Sidebar.logout": "Log out", "Sidebar.no-views-in-board": "No pages inside", "Sidebar.select-a-template": "Select a template", "Sidebar.set-language": "Set language", diff --git a/webapp/src/app.tsx b/webapp/src/app.tsx index e9d0a2a94..4c81d5966 100644 --- a/webapp/src/app.tsx +++ b/webapp/src/app.tsx @@ -2,24 +2,21 @@ // See LICENSE.txt for license information. import React from 'react' import {IntlProvider} from 'react-intl' - import { BrowserRouter as Router, - Switch, - Route, Redirect, + Route, + Switch, } from 'react-router-dom' -import client from './octoClient' -import {IUser, UserContext} from './user' - -import {getCurrentLanguage, getMessages, storeLanguage} from './i18n' - import {FlashMessages} from './components/flashMessages' - +import {getCurrentLanguage, getMessages, storeLanguage} from './i18n' +import client from './octoClient' +import BoardPage from './pages/boardPage' +import ChangePasswordPage from './pages/changePasswordPage' import LoginPage from './pages/loginPage' import RegisterPage from './pages/registerPage' -import BoardPage from './pages/boardPage' +import {IUser, UserContext} from './user' type State = { language: string, @@ -65,6 +62,9 @@ export default class App extends React.PureComponent { + + + { window.location.href = '/login' }} /> + { + window.location.href = '/change_password' + }} + /> diff --git a/webapp/src/octoClient.ts b/webapp/src/octoClient.ts index cd0e69ba3..e71cbbd22 100644 --- a/webapp/src/octoClient.ts +++ b/webapp/src/octoClient.ts @@ -70,6 +70,18 @@ class OctoClient { return {code: response.status, json} } + async changePassword(userId: string, oldPassword: string, newPassword: string): Promise<{code: number, json: any}> { + const path = `/api/v1/users/${encodeURIComponent(userId)}/changepassword` + const body = JSON.stringify({oldPassword, newPassword}) + const response = await fetch(this.serverUrl + path, { + method: 'POST', + headers: this.headers(), + body, + }) + const json = (await this.getJson(response)) + return {code: response.status, json} + } + private headers() { return { Accept: 'application/json', diff --git a/webapp/src/pages/changePasswordPage.scss b/webapp/src/pages/changePasswordPage.scss new file mode 100644 index 000000000..c0b0b6cf1 --- /dev/null +++ b/webapp/src/pages/changePasswordPage.scss @@ -0,0 +1,64 @@ +.ChangePasswordPage { + border: 1px solid #cccccc; + border-radius: 15px; + width: 450px; + height: 400px; + margin: 150px auto; + padding: 40px; + display: flex; + align-items: center; + justify-content: flex-start; + flex-direction: column; + box-shadow: rgba(var(--main-fg), 0.1) 0px 0px 0px 1px, rgba(var(--main-fg), 0.3) 0px 4px 8px; + + @media screen and (max-width: 430px) { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 100%; + height: 100%; + margin: auto; + padding-top: 10px; + } + + .title { + font-size: 16px; + font-weight: 500; + } + + .oldPassword, .newPassword { + margin-bottom: 10px; + + label { + display: inline-block; + width: 140px; + } + + input { + display: inline-block; + width: 250px; + border: 1px solid #cccccc; + border-radius: 4px; + padding: 7px; + min-height: 44px; + } + } + + > .Button { + margin-top: 10px; + margin-bottom: 20px; + min-height: 38px; + min-width: 250px; + } + + .error { + color: #900000; + } + + .succeeded { + background-color: #ccffcc; + padding: 5px; + } +} diff --git a/webapp/src/pages/changePasswordPage.tsx b/webapp/src/pages/changePasswordPage.tsx new file mode 100644 index 000000000..b722d8472 --- /dev/null +++ b/webapp/src/pages/changePasswordPage.tsx @@ -0,0 +1,104 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. +import React from 'react' + +import { + withRouter, + RouteComponentProps, + Link, +} from 'react-router-dom' + +import Button from '../widgets/buttons/button' +import client from '../octoClient' +import './changePasswordPage.scss' +import {UserContext} from '../user' + +type Props = RouteComponentProps + +type State = { + oldPassword: string + newPassword: string + errorMessage?: string + succeeded: boolean +} + +class ChangePasswordPage extends React.PureComponent { + state: State = { + oldPassword: '', + newPassword: '', + succeeded: false, + } + + private handleSubmit = async (userId: string): Promise => { + const response = await client.changePassword(userId, this.state.oldPassword, this.state.newPassword) + if (response.code === 200) { + this.setState({succeeded: true}) + } else { + this.setState({errorMessage: `Change password failed: ${response.json?.error}`}) + } + } + + private closeClicked = () => { + this.props.history.push('/') + } + + render(): React.ReactNode { + return ( +
+
{'Change Password'}
+ + + {(user) => { + if (user) { + return (<> +
+ this.setState({oldPassword: e.target.value, errorMessage: undefined})} + /> +
+
+ this.setState({newPassword: e.target.value, errorMessage: undefined})} + /> +
+ + {this.state.errorMessage && +
+ {this.state.errorMessage} +
+ } + {this.state.succeeded && + {'Password changed, click to continue.'} + } + {!this.state.succeeded && + {'Cancel'} + } + ) + } + return ( + {'Log in first'} + ) + }} +
+
+ ) + } +} + +export default withRouter(ChangePasswordPage) diff --git a/webapp/src/pages/registerPage.tsx b/webapp/src/pages/registerPage.tsx index 79c8ab115..b70d59ebe 100644 --- a/webapp/src/pages/registerPage.tsx +++ b/webapp/src/pages/registerPage.tsx @@ -44,7 +44,7 @@ class RegisterPage extends React.PureComponent { } else if (response.code === 401) { this.setState({errorMessage: 'Invalid registration link, please contact your administrator'}) } else { - this.setState({errorMessage: response.json.error}) + this.setState({errorMessage: response.json?.error}) } } From dfbc07c06dc06d8163753ff31a2b19052ff531f0 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Thu, 21 Jan 2021 10:25:35 -0800 Subject: [PATCH 11/20] make generate --- server/services/store/mockstore/mockstore.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/server/services/store/mockstore/mockstore.go b/server/services/store/mockstore/mockstore.go index 1ccf5a012..77b613326 100644 --- a/server/services/store/mockstore/mockstore.go +++ b/server/services/store/mockstore/mockstore.go @@ -427,6 +427,20 @@ func (mr *MockStoreMockRecorder) UpdateUser(arg0 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUser", reflect.TypeOf((*MockStore)(nil).UpdateUser), arg0) } +// UpdateUserPasswordByID mocks base method +func (m *MockStore) UpdateUserPasswordByID(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserPasswordByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateUserPasswordByID indicates an expected call of UpdateUserPasswordByID +func (mr *MockStoreMockRecorder) UpdateUserPasswordByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserPasswordByID", reflect.TypeOf((*MockStore)(nil).UpdateUserPasswordByID), arg0, arg1) +} + // UpsertSharing mocks base method func (m *MockStore) UpsertSharing(arg0 model.Sharing) error { m.ctrl.T.Helper() From 2bddb0cfc0757eda33278f29a4da4f3ff8a3341c Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Thu, 21 Jan 2021 10:42:05 -0800 Subject: [PATCH 12/20] Remove user menu for single-user --- webapp/i18n/en.json | 1 + webapp/src/components/sidebar.scss | 3 +- webapp/src/components/sidebar.tsx | 75 ++++++++++++++++++------------ 3 files changed, 48 insertions(+), 31 deletions(-) diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index 04562309a..152b40c0e 100644 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -97,6 +97,7 @@ "Sidebar.settings": "Settings", "Sidebar.spanish": "Spanish", "Sidebar.template-from-board": "New template from board", + "Sidebar.title": "Boards", "Sidebar.untitled": "Untitled", "Sidebar.untitled-board": "(Untitled Board)", "Sidebar.untitled-view": "(Untitled View)", diff --git a/webapp/src/components/sidebar.scss b/webapp/src/components/sidebar.scss index dfb3e096e..c9df79af4 100644 --- a/webapp/src/components/sidebar.scss +++ b/webapp/src/components/sidebar.scss @@ -44,8 +44,9 @@ padding: 3px 20px; margin-bottom: 5px; - >.username { + >.heading { line-height: 30px; + cursor: default; } >.IconButton { diff --git a/webapp/src/components/sidebar.tsx b/webapp/src/components/sidebar.tsx index 0648e17cd..725c2e503 100644 --- a/webapp/src/components/sidebar.tsx +++ b/webapp/src/components/sidebar.tsx @@ -9,7 +9,7 @@ import {BoardView, MutableBoardView} from '../blocks/boardView' import mutator from '../mutator' import octoClient from '../octoClient' import {darkTheme, defaultTheme, lightTheme, setTheme} from '../theme' -import {UserContext} from '../user' +import {IUser, UserContext} from '../user' import {WorkspaceTree} from '../viewModel/workspaceTree' import Button from '../widgets/buttons/button' import IconButton from '../widgets/buttons/iconButton' @@ -87,35 +87,21 @@ class Sidebar extends React.Component { return (
- - {(user) => ( -
- - - - { - octoClient.logout() - window.location.href = '/login' - }} - /> - { - window.location.href = '/change_password' - }} - /> - - - -
- )} -
+
+ + {(user) => { + if (user) { + if (user.id === 'single-user') { + return ( +
{intl.formatMessage({id: 'Sidebar.title', defaultMessage: 'Boards'})}
+ ) + } + return this.renderUserMenu(user) + } + return
+ }} + +
{ ) } + private renderUserMenu(user: IUser): JSX.Element { + const {intl} = this.props + + return ( + + + + { + octoClient.logout() + window.location.href = '/login' + }} + /> + { + window.location.href = '/change_password' + }} + /> + + + ) + } + private boardClicked(board: Board): void { this.props.showBoard(board.id) } From 98858f9d32dc70c115d25fa0261a47add561976d Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Thu, 21 Jan 2021 10:52:44 -0800 Subject: [PATCH 13/20] Move invite users option to user menu --- webapp/src/components/modal.scss | 3 + webapp/src/components/modal.tsx | 2 +- .../components/registrationLinkComponent.scss | 2 + .../components/registrationLinkComponent.tsx | 2 +- webapp/src/components/sidebar.tsx | 185 +++++++++--------- 5 files changed, 100 insertions(+), 94 deletions(-) diff --git a/webapp/src/components/modal.scss b/webapp/src/components/modal.scss index 84c316f70..9a8a5f5c0 100644 --- a/webapp/src/components/modal.scss +++ b/webapp/src/components/modal.scss @@ -23,6 +23,9 @@ bottom: 25px; left: 25px; } + &.bottom-right { + left: 0; + } } .hideOnWidescreen { diff --git a/webapp/src/components/modal.tsx b/webapp/src/components/modal.tsx index 064b5a309..50631170a 100644 --- a/webapp/src/components/modal.tsx +++ b/webapp/src/components/modal.tsx @@ -10,7 +10,7 @@ import './modal.scss' type Props = { onClose: () => void intl: IntlShape - position?: 'top'|'bottom' + position?: 'top'|'bottom'|'bottom-right' } class Modal extends React.PureComponent { diff --git a/webapp/src/components/registrationLinkComponent.scss b/webapp/src/components/registrationLinkComponent.scss index 30be8feac..f249e2334 100644 --- a/webapp/src/components/registrationLinkComponent.scss +++ b/webapp/src/components/registrationLinkComponent.scss @@ -3,6 +3,8 @@ flex-direction: column; padding: 5px; color: rgb(var(--main-fg)); + font-weight: normal; + line-height: normal; > .row { display: flex; diff --git a/webapp/src/components/registrationLinkComponent.tsx b/webapp/src/components/registrationLinkComponent.tsx index db7ff5c93..1d695aac9 100644 --- a/webapp/src/components/registrationLinkComponent.tsx +++ b/webapp/src/components/registrationLinkComponent.tsx @@ -42,7 +42,7 @@ class RegistrationLinkComponent extends React.PureComponent { return (
diff --git a/webapp/src/components/sidebar.tsx b/webapp/src/components/sidebar.tsx index 725c2e503..a18397ca5 100644 --- a/webapp/src/components/sidebar.tsx +++ b/webapp/src/components/sidebar.tsx @@ -284,79 +284,63 @@ class Sidebar extends React.Component { - - - - - { - this.setState({showRegistrationLinkDialog: true}) - }} - /> - Archiver.importFullArchive()} - /> - Archiver.exportFullArchive()} - /> - - this.props.setLanguage('en')} - /> - this.props.setLanguage('es')} - /> - - - setTheme(defaultTheme)} - /> - setTheme(darkTheme)} - /> - setTheme(lightTheme)} - /> - - - - {this.state.showRegistrationLinkDialog && - { - this.setState({showRegistrationLinkDialog: false}) - }} + + + + Archiver.importFullArchive()} + /> + Archiver.exportFullArchive()} + /> + + this.props.setLanguage('en')} + /> + this.props.setLanguage('es')} + /> + + + setTheme(defaultTheme)} + /> + setTheme(darkTheme)} + /> + setTheme(lightTheme)} + /> + + +
) } @@ -365,28 +349,45 @@ class Sidebar extends React.Component { const {intl} = this.props return ( - - - - { - octoClient.logout() - window.location.href = '/login' + + + + + { + octoClient.logout() + window.location.href = '/login' + }} + /> + { + window.location.href = '/change_password' + }} + /> + { + this.setState({showRegistrationLinkDialog: true}) + }} + /> + + + + {this.state.showRegistrationLinkDialog && + { + this.setState({showRegistrationLinkDialog: false}) }} /> - { - window.location.href = '/change_password' - }} - /> - - + } + ) } From e4c375747e381789f4de3315e75b721ef3eedaf2 Mon Sep 17 00:00:00 2001 From: Chen-I Lim Date: Thu, 21 Jan 2021 11:32:26 -0800 Subject: [PATCH 14/20] Naming --- website/Makefile | 2 +- website/README.md | 4 ++-- website/site/config.toml | 12 ++++++------ .../content/contribute/getting-started/_index.md | 2 +- .../getting-started/contribution-checklist.md | 2 +- .../getting-started/core-committers.md | 4 ++-- .../content/download/personal-edition/_index.md | 2 +- .../content/download/personal-edition/ubuntu.md | 16 ++++++++-------- website/site/content/guide/user/_index.md | 2 +- website/site/layouts/blog/list.html | 2 +- website/site/layouts/partials/hero.html | 4 ++-- website/site/static/img/logo-white.svg | 2 +- website/site/static/img/logo.svg | 2 +- website/site/themes/config.toml | 10 +++++----- 14 files changed, 33 insertions(+), 33 deletions(-) diff --git a/website/Makefile b/website/Makefile index 22766a597..c89a14133 100644 --- a/website/Makefile +++ b/website/Makefile @@ -1,5 +1,5 @@ -BASE_URL?=http://www.matternote.com +BASE_URL?=http://www.matterdeck.com .PHONY: dist dist: diff --git a/website/README.md b/website/README.md index 4b25861ce..cf7ba150f 100644 --- a/website/README.md +++ b/website/README.md @@ -1,6 +1,6 @@ -# Matternote website +# Matterdeck website -Website for Matternote, built using [Hugo](https://gohugo.io/). +Website for Matterdeck, built using [Hugo](https://gohugo.io/). ## How to build diff --git a/website/site/config.toml b/website/site/config.toml index 22ad95a35..638c74bb8 100644 --- a/website/site/config.toml +++ b/website/site/config.toml @@ -3,7 +3,7 @@ baseURL = "https://tasks.octo.mattermost.com/" canonifyURLs = true #relativeURLs = true -title = "Matternote" +title = "Matterdeck" languageCode = "en-us" publishDir = "../docs" pygmentsCodeFences = true @@ -48,7 +48,7 @@ pygmentsStyle = "manni" # Navigation [params.navigation] - brand = "Matternote" + brand = "Matterdeck" home = "Home" # You can add custom links before or after the default links @@ -92,7 +92,7 @@ pygmentsStyle = "manni" # Hero section [params.hero] - title = "Get Matternote" + title = "Get Matterdeck" subtitle = '' # Intro section @@ -100,7 +100,7 @@ pygmentsStyle = "manni" [params.intro] [[params.intro.item]] title = "Download" - description = "Download Matternote here." + description = "Download Matterdeck here." url = "download/personal-edition" button = "Download Now" icon = "/img/download-icon.svg" @@ -108,7 +108,7 @@ pygmentsStyle = "manni" [[params.intro.item]] title = "Read Guide" - description = "Read the User's Guide to ge the most out of Matternote." + description = "Read the User's Guide to ge the most out of Matterdeck." url = "guide/user" button = "User's Guide" icon = "/img/use-icon.svg" @@ -116,7 +116,7 @@ pygmentsStyle = "manni" [[params.intro.item]] title = "Contribute" - description = "Help build the future of productivity and submit code directly to the Matternote open-source project." + description = "Help build the future of productivity and submit code directly to the Matterdeck open-source project." url = "contribute/getting-started" button = "Start Contributing" icon = "/img/contribute-icon.svg" diff --git a/website/site/content/contribute/getting-started/_index.md b/website/site/content/contribute/getting-started/_index.md index dea02a208..617d84276 100644 --- a/website/site/content/contribute/getting-started/_index.md +++ b/website/site/content/contribute/getting-started/_index.md @@ -5,7 +5,7 @@ section: "contribute" weight: 1 --- -Welcome to the Matternote project! +Welcome to the Matterdeck project! We're very glad you want to check it out and perhaps contribute code our repository in GitHub. diff --git a/website/site/content/contribute/getting-started/contribution-checklist.md b/website/site/content/contribute/getting-started/contribution-checklist.md index 573032261..e488f5bbf 100644 --- a/website/site/content/contribute/getting-started/contribution-checklist.md +++ b/website/site/content/contribute/getting-started/contribution-checklist.md @@ -7,7 +7,7 @@ subsection: Getting Started Thanks for your interest in contributing code! - + diff --git a/website/site/content/contribute/getting-started/core-committers.md b/website/site/content/contribute/getting-started/core-committers.md index 7c9a11554..7c53e7032 100644 --- a/website/site/content/contribute/getting-started/core-committers.md +++ b/website/site/content/contribute/getting-started/core-committers.md @@ -5,12 +5,12 @@ weight: 4 subsection: Getting Started --- -A core committer is a maintainer on the Matternote project who has merge access to the repositories. They are responsible for reviewing pull requests, cultivating the developer community, and guiding the technical vision of Matternote. If you have a question or need some help, these are the people to ask. +A core committer is a maintainer on the Matterdeck project who has merge access to the repositories. They are responsible for reviewing pull requests, cultivating the developer community, and guiding the technical vision of Matterdeck. If you have a question or need some help, these are the people to ask. Core Committers --------------- -Below is the list of core committers working on Matternote: +Below is the list of core committers working on Matterdeck: - **Chen Lim** - @chen-i.lim on [community.mattermost.com](https://community.mattermost.com/core/messages/@chen-i.lim) and [@chenilim](https://github.com/chenilim) on GitHub diff --git a/website/site/content/download/personal-edition/_index.md b/website/site/content/download/personal-edition/_index.md index ba0ae2cf0..68368f125 100644 --- a/website/site/content/download/personal-edition/_index.md +++ b/website/site/content/download/personal-edition/_index.md @@ -5,6 +5,6 @@ section: "download" weight: 1 --- -If you are new to Matternote, [Personal Desktop](desktop) is the fastest way to try it out. +If you are new to Matterdeck, [Personal Desktop](desktop) is the fastest way to try it out. You can also set up [Personal Server](ubuntu) on Ubuntu to use it with your team, and import boards from Personal Desktop. diff --git a/website/site/content/download/personal-edition/ubuntu.md b/website/site/content/download/personal-edition/ubuntu.md index 42b5b5ca4..6f73a986a 100644 --- a/website/site/content/download/personal-edition/ubuntu.md +++ b/website/site/content/download/personal-edition/ubuntu.md @@ -5,7 +5,7 @@ subsection: Personal Edition weight: 2 --- -Matternote Personal Server allows your team to work together on shared project boards. +Matterdeck Personal Server allows your team to work together on shared project boards. Follow these steps it up on an Ubuntu server. @@ -15,7 +15,7 @@ Popular hosted options include: * [Digital Ocean](https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-18-04) * [Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EC2_GetStarted.html) -## Install Matternote +## Install Matterdeck [Download the Ubuntu archive package here](/download), then unpack it to /opt/octo: @@ -26,7 +26,7 @@ sudo mv octo /opt ## Install NGINX -By default, the Matternote server runs on port 8000 (specified in config.json). We recommend running NGINX as a web proxy to forward http and websocket requests from port 80 to it. To install NGINX, run: +By default, the Matterdeck server runs on port 8000 (specified in config.json). We recommend running NGINX as a web proxy to forward http and websocket requests from port 80 to it. To install NGINX, run: ``` sudo apt update @@ -99,7 +99,7 @@ server { ## Install Postgresql (Recommended) -Matternote stores data in a SQLite database by default, but we recommend running against Postgres in production (we've tested against Postgres 10.15). To install, run: +Matterdeck stores data in a SQLite database by default, but we recommend running against Postgres in production (we've tested against Postgres 10.15). To install, run: ``` sudo apt install postgresql postgresql-contrib @@ -123,7 +123,7 @@ Exit the postgres user session: exit ``` -Edit the Matternote config.json: +Edit the Matterdeck config.json: ``` nano /opt/octo/config.json @@ -134,7 +134,7 @@ Change the dbconfig setting to use the postgres database you created: "dbconfig": "postgres://tasksuser:tasksuser-password@localhost/octo?sslmode=disable&connect_timeout=10", ``` -## Configure Matternote to run as a service +## Configure Matterdeck to run as a service This will keep the server running across reboots. First, create a new service config file: @@ -145,7 +145,7 @@ sudo nano /lib/systemd/system/octo.service Paste in the following: ``` [Unit] -Description=Tasks server +Description=Matterdeck server [Service] Type=simple @@ -167,7 +167,7 @@ sudo systemctl enable octo.service ## Test the server -At this point, the Matternote server should be running. +At this point, the Matterdeck server should be running. Test that it's running locally with: ``` diff --git a/website/site/content/guide/user/_index.md b/website/site/content/guide/user/_index.md index 784844aff..51ffe707e 100644 --- a/website/site/content/guide/user/_index.md +++ b/website/site/content/guide/user/_index.md @@ -7,7 +7,7 @@ weight: 2 ## Adding new Boards -1. Click "+ Add Board" at the lower left of the sidebar to add a new board to Matternote. +1. Click "+ Add Board" at the lower left of the sidebar to add a new board to Matterdeck. 2. Pick "Project Tasks" from the list of templates. 3. This shows the first view of the new board, which is a table of all tasks ![image](./all%20tasks.png) diff --git a/website/site/layouts/blog/list.html b/website/site/layouts/blog/list.html index 2ff2b4c53..349d1be4a 100644 --- a/website/site/layouts/blog/list.html +++ b/website/site/layouts/blog/list.html @@ -13,7 +13,7 @@
-

Matternote Developer Blog

+

Matterdeck Developer Blog

{{ range (.Paginate .Data.Pages).Pages.ByDate.Reverse }} {{ .Render "summary" }} {{ end }} diff --git a/website/site/layouts/partials/hero.html b/website/site/layouts/partials/hero.html index 840805c6a..1073bd60d 100755 --- a/website/site/layouts/partials/hero.html +++ b/website/site/layouts/partials/hero.html @@ -8,7 +8,7 @@

- Matternote is an easy-to-use project management system, perfect for organizing your personal todos or running team projects. + Matterdeck is an easy-to-use project management system, perfect for organizing your personal todos or running team projects.

@@ -20,7 +20,7 @@

- Matternote is open source! Check out the source code here, and contribute to the future of this project. + Matterdeck is open source! Check out the source code here, and contribute to the future of this project.