From 9bec29a03e3a81772c921bfeb105a249c4f2e8e7 Mon Sep 17 00:00:00 2001 From: email Date: Sun, 9 Jan 2022 11:44:12 +0800 Subject: [PATCH] feat: support open api with webhooks --- api/auth.go | 129 +----------------------- api/user.go | 28 ++--- api/webhooks.go | 55 ++++++++++ resources/initial_db.sql | 9 +- resources/memos.db | Bin 245760 -> 245760 bytes server/main.go | 1 + store/user.go | 90 ++++++----------- web/src/components/MenuBtnsPopup.tsx | 1 + web/src/components/MyAccountSection.tsx | 76 ++++++-------- web/src/helpers/api.ts | 9 +- web/src/less/mixin.less | 1 + web/src/less/my-account-section.less | 77 +++++++------- web/src/less/preferences-section.less | 2 +- web/src/pages/Signin.tsx | 54 +++++----- web/src/services/userService.ts | 15 +-- web/src/stores/userStore.ts | 19 +++- web/src/types/models.d.ts | 2 +- 17 files changed, 238 insertions(+), 330 deletions(-) create mode 100644 api/webhooks.go diff --git a/api/auth.go b/api/auth.go index 48913772c..d6a7212ac 100644 --- a/api/auth.go +++ b/api/auth.go @@ -1,14 +1,9 @@ package api import ( - "bytes" "encoding/json" - "fmt" - "io/ioutil" "memos/api/e" - "memos/config" "memos/store" - "memos/utils" "net/http" "github.com/gorilla/mux" @@ -38,7 +33,7 @@ func handleUserSignUp(w http.ResponseWriter, r *http.Request) { return } - user, err := store.CreateNewUser(userSignup.Username, userSignup.Password, "") + user, err := store.CreateNewUser(userSignup.Username, userSignup.Password) if err != nil { e.ErrorHandler(w, "DATABASE_ERROR", err.Error()) @@ -107,127 +102,6 @@ func handleUserSignOut(w http.ResponseWriter, r *http.Request) { }) } -func handleGithubAuthCallback(w http.ResponseWriter, r *http.Request) { - code := r.URL.Query().Get("code") - - requestBody := map[string]string{ - "client_id": config.GITHUB_CLIENTID, - "client_secret": config.GITHUB_SECRET, - "code": code, - } - - requestJSON, _ := json.Marshal(requestBody) - - // POST request to get access_token - req, err := http.NewRequest( - "POST", - "https://github.com/login/oauth/access_token", - bytes.NewBuffer(requestJSON), - ) - - if err != nil { - e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Error in request github api") - return - } - - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Accept", "application/json") - - resp, err := http.DefaultClient.Do(req) - if err != nil { - e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Error in request github api") - return - } - - // Response body converted to stringified JSON - respBody, _ := ioutil.ReadAll(resp.Body) - - // Represents the response received from Github - type GithubAccessTokenResponse struct { - AccessToken string `json:"access_token"` - TokenType string `json:"token_type"` - Scope string `json:"scope"` - } - - ghResp := GithubAccessTokenResponse{} - json.Unmarshal(respBody, &ghResp) - - githubAccessToken := ghResp.AccessToken - - // Get request to a set URL - req, err = http.NewRequest( - "GET", - "https://api.github.com/user", - nil, - ) - if err != nil { - e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Error in request github api") - return - } - - authorizationHeaderValue := fmt.Sprintf("token %s", githubAccessToken) - req.Header.Set("Authorization", authorizationHeaderValue) - - resp, err = http.DefaultClient.Do(req) - - if err != nil { - e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Error in request github api") - return - } - - respBody, _ = ioutil.ReadAll(resp.Body) - - githubData := string(respBody) - - type GithubUser struct { - Login string `json:"login"` - Name string `json:"name"` - } - - githubUser := GithubUser{} - json.Unmarshal([]byte(githubData), &githubUser) - - session, _ := SessionStore.Get(r, "session") - userId := fmt.Sprintf("%v", session.Values["user_id"]) - - if userId != "" { - githubNameUsable, err := store.CheckGithubNameUsable(githubUser.Login) - - if err != nil { - e.ErrorHandler(w, "DATABASE_ERROR", "Error in CheckGithubNameUsable") - return - } - - if !githubNameUsable { - e.ErrorHandler(w, "DATABASE_ERROR", "Error in CheckGithubNameUsable") - return - } - - userPatch := store.UserPatch{ - GithubName: &githubUser.Login, - } - - store.UpdateUser(userId, &userPatch) - } - - user, err := store.GetUserByGithubName(githubUser.Login) - - if err != nil { - username := githubUser.Name - usernameUsable, _ := store.CheckUsernameUsable(username) - for !usernameUsable { - username = githubUser.Name + utils.GenUUID() - usernameUsable, _ = store.CheckUsernameUsable(username) - } - user, _ = store.CreateNewUser(username, username, githubUser.Login) - } - - session.Values["user_id"] = user.Id - session.Save(r, w) - - http.Redirect(w, r, "/", http.StatusTemporaryRedirect) -} - func RegisterAuthRoutes(r *mux.Router) { authRouter := r.PathPrefix("/api/auth").Subrouter() @@ -236,5 +110,4 @@ func RegisterAuthRoutes(r *mux.Router) { authRouter.HandleFunc("/signup", handleUserSignUp).Methods("POST") authRouter.HandleFunc("/signin", handleUserSignIn).Methods("POST") authRouter.HandleFunc("/signout", handleUserSignOut).Methods("POST") - authRouter.HandleFunc("/github", handleGithubAuthCallback).Methods("GET") } diff --git a/api/user.go b/api/user.go index e8b92f0a1..a46917249 100644 --- a/api/user.go +++ b/api/user.go @@ -29,16 +29,16 @@ func handleGetMyUserInfo(w http.ResponseWriter, r *http.Request) { func handleUpdateMyUserInfo(w http.ResponseWriter, r *http.Request) { userId, _ := GetUserIdInSession(r) - userPatch := store.UserPatch{} - err := json.NewDecoder(r.Body).Decode(&userPatch) + updateUserPatch := store.UpdateUserPatch{} + err := json.NewDecoder(r.Body).Decode(&updateUserPatch) if err != nil { e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Bad request") return } - if userPatch.Username != nil { - usernameUsable, _ := store.CheckUsernameUsable(*userPatch.Username) + if updateUserPatch.Username != nil { + usernameUsable, _ := store.CheckUsernameUsable(*updateUserPatch.Username) if !usernameUsable { json.NewEncoder(w).Encode(Response{ Succeed: false, @@ -49,19 +49,7 @@ func handleUpdateMyUserInfo(w http.ResponseWriter, r *http.Request) { } } - if userPatch.GithubName != nil { - githubNameUsable, _ := store.CheckGithubNameUsable(*userPatch.GithubName) - if !githubNameUsable { - json.NewEncoder(w).Encode(Response{ - Succeed: false, - Message: "GitHub name is existed", - Data: nil, - }) - return - } - } - - user, err := store.UpdateUser(userId, &userPatch) + user, err := store.UpdateUser(userId, &updateUserPatch) if err != nil { e.ErrorHandler(w, "DATABASE_ERROR", err.Error()) @@ -75,10 +63,10 @@ func handleUpdateMyUserInfo(w http.ResponseWriter, r *http.Request) { }) } -func handleRefreshUserOpenId(w http.ResponseWriter, r *http.Request) { +func handleResetUserOpenId(w http.ResponseWriter, r *http.Request) { userId, _ := GetUserIdInSession(r) - openId, err := store.UpdateUserOpenId(userId) + openId, err := store.ResetUserOpenId(userId) if err != nil { e.ErrorHandler(w, "DATABASE_ERROR", err.Error()) @@ -155,7 +143,7 @@ func RegisterUserRoutes(r *mux.Router) { userRouter.HandleFunc("/me", handleGetMyUserInfo).Methods("GET") userRouter.HandleFunc("/me", handleUpdateMyUserInfo).Methods("PATCH") - userRouter.HandleFunc("/open_id/new", handleRefreshUserOpenId).Methods("POST") + userRouter.HandleFunc("/open_id/new", handleResetUserOpenId).Methods("POST") userRouter.HandleFunc("/checkusername", handleCheckUsername).Methods("POST") userRouter.HandleFunc("/validpassword", handleValidPassword).Methods("POST") } diff --git a/api/webhooks.go b/api/webhooks.go new file mode 100644 index 000000000..a5fa30753 --- /dev/null +++ b/api/webhooks.go @@ -0,0 +1,55 @@ +package api + +import ( + "encoding/json" + "memos/api/e" + "memos/store" + "net/http" + + "github.com/gorilla/mux" +) + +func handleCreateMemoByWH(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + openId := vars["openId"] + + type CreateMemoDataBody struct { + Content string `json:"content"` + } + + createMemo := CreateMemoDataBody{} + err := json.NewDecoder(r.Body).Decode(&createMemo) + + if err != nil { + e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Bad request") + return + } + + user, err := store.GetUserByOpenId(openId) + + if err != nil { + e.ErrorHandler(w, "DATABASE_ERROR", err.Error()) + return + } + + memo, err := store.CreateNewMemo(createMemo.Content, user.Id) + + if err != nil { + e.ErrorHandler(w, "DATABASE_ERROR", err.Error()) + return + } + + json.NewEncoder(w).Encode(Response{ + Succeed: true, + Message: "", + Data: memo, + }) +} + +func RegisterWebHooksRoutes(r *mux.Router) { + memoRouter := r.PathPrefix("/api/whs").Subrouter() + + memoRouter.Use(JSONResponseMiddleWare) + + memoRouter.HandleFunc("/memo/{openId}", handleCreateMemoByWH).Methods("POST") +} diff --git a/resources/initial_db.sql b/resources/initial_db.sql index b62eb4042..625811eeb 100644 --- a/resources/initial_db.sql +++ b/resources/initial_db.sql @@ -8,10 +8,9 @@ CREATE TABLE `users` ( `username` TEXT NOT NULL, `password` TEXT NOT NULL, `open_id` TEXT NOT NULL DEFAULT '', - `github_name` TEXT NOT NULL DEFAULT '', `created_at` TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')), `updated_at` TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')), - UNIQUE(`username`, `github_name`) + UNIQUE(`username`, `open_id`) ); CREATE TABLE `queries` ( @@ -48,10 +47,10 @@ CREATE TABLE `resources` ( INSERT INTO `users` - (`id`, `username`, `password`) + (`id`, `username`, `password`, `open_id`) VALUES - ('1', 'guest', '123456'), - ('2', 'test', '123456'); + ('1', 'guest', '123456', 'guest_open_id'), + ('2', 'mine', '123456', 'mine_open_id'); INSERT INTO `memos` (`id`, `content`, `user_id`) diff --git a/resources/memos.db b/resources/memos.db index dcd93ca84970ff32bbf71bb55c8d39de654e4420..14d2984204376f308cfd573783460e4e5975daeb 100644 GIT binary patch delta 580 zcmZo@;BRQ)pCBc~EXcsXU<1UQKy1Xoz@$D=$4Ch%su!HV%m0IclQWos&yD{q|014N zK5?#BJW-s%T-$k1ZWa_+!9H1o<1Y)>9>$c(nw(mjRXIPia5Y6TvWtt0Gqws&R^nSV z`5WI{_WXj>y!gzN$@BP=x%qc6F!2jB@C)-70Zm}%ua9M9=NFd@H8wU(FHJ2jF*GtZ zF*QpuwMb4gNww5XG_o+zHAyl{)=e}pG}kpvv@}aH0m>SiS{NA^8R;4r>Ka%o7#dm` zTUZ%bVi9s-V&@l?R5dm>%FWD6g_sUv#X}vHheZz-Az;{eh)b%Yx)SVQm_b-HVG-J- zz$n1Y{}LDmOBwi=@?YL8s4$a1T9-vUloMPj zBrmVAu~A8CafzXkv5Bdfk%5t+uAz~xp^1W#ft9hDm5C7+AuC1>esQo?!}L-T^>Tq7 z@|9sThr&;Oh^yW(@PFff19a5`ei2R!ndzd&`#CbWv#&2?%uCGjlvnKD#S0+YX QQ$bq+V_N~!vI6D+06y7e-v9sr diff --git a/server/main.go b/server/main.go index 34f3332cc..32dc5646b 100644 --- a/server/main.go +++ b/server/main.go @@ -18,6 +18,7 @@ func main() { api.RegisterMemoRoutes(r) api.RegisterQueryRoutes(r) api.RegisterResourceRoutes(r) + api.RegisterWebHooksRoutes(r) webServe := api.SPAHandler{ StaticPath: "./web/dist", diff --git a/store/user.go b/store/user.go index b61132484..cec5fa469 100644 --- a/store/user.go +++ b/store/user.go @@ -8,40 +8,37 @@ import ( ) type User struct { - Id string `json:"id"` - Username string `json:"username"` - Password string `json:"password"` - OpenId string `json:"openId"` - GithubName string `json:"githubName"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` + Id string `json:"id"` + Username string `json:"username"` + Password string `json:"password"` + OpenId string `json:"openId"` + CreatedAt string `json:"createdAt"` + UpdatedAt string `json:"updatedAt"` } -func CreateNewUser(username string, password string, githubName string) (User, error) { +func CreateNewUser(username string, password string) (User, error) { nowDateTimeStr := utils.GetNowDateTimeStr() newUser := User{ - Id: utils.GenUUID(), - Username: username, - Password: password, - OpenId: utils.GenUUID(), - GithubName: githubName, - CreatedAt: nowDateTimeStr, - UpdatedAt: nowDateTimeStr, + Id: utils.GenUUID(), + Username: username, + Password: password, + OpenId: utils.GenUUID(), + CreatedAt: nowDateTimeStr, + UpdatedAt: nowDateTimeStr, } - query := `INSERT INTO users (id, username, password, open_id, github_name, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)` - _, err := DB.Exec(query, newUser.Id, newUser.Username, newUser.Password, newUser.OpenId, newUser.GithubName, newUser.CreatedAt, newUser.UpdatedAt) + query := `INSERT INTO users (id, username, password, open_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)` + _, err := DB.Exec(query, newUser.Id, newUser.Username, newUser.Password, newUser.OpenId, newUser.CreatedAt, newUser.UpdatedAt) return newUser, FormatDBError(err) } -type UserPatch struct { - Username *string - Password *string - GithubName *string +type UpdateUserPatch struct { + Username *string + Password *string } -func UpdateUser(id string, userPatch *UserPatch) (User, error) { +func UpdateUser(id string, updateUserPatch *UpdateUserPatch) (User, error) { user := User{} user, err := GetUserById(id) @@ -51,18 +48,14 @@ func UpdateUser(id string, userPatch *UserPatch) (User, error) { set, args := []string{}, []interface{}{} - if v := userPatch.Username; v != nil { + if v := updateUserPatch.Username; v != nil { user.Username = *v set, args = append(set, "username=?"), append(args, *v) } - if v := userPatch.Password; v != nil { + if v := updateUserPatch.Password; v != nil { user.Password = *v set, args = append(set, "password=?"), append(args, *v) } - if v := userPatch.GithubName; v != nil { - user.GithubName = *v - set, args = append(set, "github_name=?"), append(args, *v) - } set, args = append(set, "updated_at=?"), append(args, utils.GetNowDateTimeStr()) args = append(args, id) @@ -72,7 +65,7 @@ func UpdateUser(id string, userPatch *UserPatch) (User, error) { return user, FormatDBError(err) } -func UpdateUserOpenId(userId string) (string, error) { +func ResetUserOpenId(userId string) (string, error) { openId := utils.GenUUID() query := `UPDATE users SET open_id=? WHERE id=?` _, err := DB.Exec(query, openId, userId) @@ -80,23 +73,23 @@ func UpdateUserOpenId(userId string) (string, error) { } func GetUserById(id string) (User, error) { - query := `SELECT id, username, password, open_id, github_name, created_at, updated_at FROM users WHERE id=?` + query := `SELECT id, username, password, open_id, created_at, updated_at FROM users WHERE id=?` user := User{} - err := DB.QueryRow(query, id).Scan(&user.Id, &user.Username, &user.Password, &user.OpenId, &user.GithubName, &user.CreatedAt, &user.UpdatedAt) + err := DB.QueryRow(query, id).Scan(&user.Id, &user.Username, &user.Password, &user.OpenId, &user.CreatedAt, &user.UpdatedAt) + return user, FormatDBError(err) +} + +func GetUserByOpenId(openId string) (User, error) { + query := `SELECT id, username, password, open_id, created_at, updated_at FROM users WHERE open_id=?` + user := User{} + err := DB.QueryRow(query, openId).Scan(&user.Id, &user.Username, &user.Password, &user.OpenId, &user.CreatedAt, &user.UpdatedAt) return user, FormatDBError(err) } func GetUserByUsernameAndPassword(username string, password string) (User, error) { - query := `SELECT id, username, password, open_id, github_name, created_at, updated_at FROM users WHERE username=? AND password=?` + query := `SELECT id, username, password, open_id, created_at, updated_at FROM users WHERE username=? AND password=?` user := User{} - err := DB.QueryRow(query, username, password).Scan(&user.Id, &user.Username, &user.Password, &user.OpenId, &user.GithubName, &user.CreatedAt, &user.UpdatedAt) - return user, FormatDBError(err) -} - -func GetUserByGithubName(githubName string) (User, error) { - query := `SELECT id, username, password, open_id, github_name, created_at, updated_at FROM users WHERE github_name=?` - user := User{} - err := DB.QueryRow(query, githubName).Scan(&user.Id, &user.Username, &user.Password, &user.OpenId, &user.GithubName, &user.CreatedAt, &user.UpdatedAt) + err := DB.QueryRow(query, username, password).Scan(&user.Id, &user.Username, &user.Password, &user.OpenId, &user.CreatedAt, &user.UpdatedAt) return user, FormatDBError(err) } @@ -118,23 +111,6 @@ func CheckUsernameUsable(username string) (bool, error) { return usable, nil } -func CheckGithubNameUsable(githubName string) (bool, error) { - query := `SELECT * FROM users WHERE github_name=?` - query = fmt.Sprintf("SELECT COUNT(*) FROM (%s)", query) - - var count uint - err := DB.QueryRow(query, githubName).Scan(&count) - if err != nil && err != sql.ErrNoRows { - return false, FormatDBError(err) - } - - if count > 0 { - return false, nil - } else { - return true, nil - } -} - func CheckPasswordValid(id string, password string) (bool, error) { query := `SELECT * FROM users WHERE id=? AND password=?` query = fmt.Sprintf("SELECT COUNT(*) FROM (%s)", query) diff --git a/web/src/components/MenuBtnsPopup.tsx b/web/src/components/MenuBtnsPopup.tsx index 383def720..5414ed68b 100644 --- a/web/src/components/MenuBtnsPopup.tsx +++ b/web/src/components/MenuBtnsPopup.tsx @@ -43,6 +43,7 @@ const MenuBtnsPopup: React.FC = (props: Props) => { const handleSignOutBtnClick = async () => { await userService.doSignOut(); locationService.replaceHistory("/signin"); + window.location.reload(); }; return ( diff --git a/web/src/components/MyAccountSection.tsx b/web/src/components/MyAccountSection.tsx index d7b3ee2a5..617c4474d 100644 --- a/web/src/components/MyAccountSection.tsx +++ b/web/src/components/MyAccountSection.tsx @@ -3,7 +3,8 @@ import appContext from "../stores/appContext"; import { userService } from "../services"; import utils from "../helpers/utils"; import { validate, ValidatorConfig } from "../helpers/validator"; -import Only from "./common/OnlyWhen"; +import useLoading from "../hooks/useLoading"; +import useToggle from "../hooks/useToggle"; import toastHelper from "./Toast"; import showChangePasswordDialog from "./ChangePasswordDialog"; import "../less/my-account-section.less"; @@ -21,7 +22,9 @@ const MyAccountSection: React.FC = () => { const { userState } = useContext(appContext); const user = userState.user as Model.User; const [username, setUsername] = useState(user.username); - const [showConfirmUnbindGithubBtn, setShowConfirmUnbindGithubBtn] = useState(false); + const resetBtnClickLoadingState = useLoading(false); + const [showConfirmResetAPIBtn, toggleConfirmResetAPIBtn] = useToggle(false); + const openAPIRoute = `${window.location.origin}/api/whs/memo/${user.openId}`; const handleUsernameChanged = (e: React.ChangeEvent) => { const nextUsername = e.target.value as string; @@ -69,18 +72,23 @@ const MyAccountSection: React.FC = () => { showChangePasswordDialog(); }; - const handleUnbindGithubBtnClick = async () => { - if (showConfirmUnbindGithubBtn) { - try { - await userService.removeGithubName(); - await userService.doSignIn(); - } catch (error: any) { - toastHelper.error(error.message); - } - setShowConfirmUnbindGithubBtn(false); - } else { - setShowConfirmUnbindGithubBtn(true); + const handleResetOpenIdBtnClick = async () => { + if (!showConfirmResetAPIBtn) { + toggleConfirmResetAPIBtn(true); + return; } + if (resetBtnClickLoadingState.isLoading) { + return; + } + + resetBtnClickLoadingState.setLoading(); + try { + await userService.resetOpenId(); + } catch (error) { + // do nth + } + resetBtnClickLoadingState.setFinish(); + toggleConfirmResetAPIBtn(false); }; const handlePreventDefault = (e: React.MouseEvent) => { @@ -124,39 +132,17 @@ const MyAccountSection: React.FC = () => { - {/* Account Binding Settings: only can use for domain: memos.justsven.top */} - -
-

关联账号

- +
+

Open API(实验性功能)

+

{openAPIRoute}

+ + {showConfirmResetAPIBtn ? "⚠️ 确定重置 API" : "重置 API"} + +
+

使用方法:

+
{`POST ${openAPIRoute}\nContent-type: application/json\n{\n  "content": "Hello, #memos ${window.location.origin}"\n}`}
- +
); }; diff --git a/web/src/helpers/api.ts b/web/src/helpers/api.ts index ea0c1ca81..a06000d8e 100644 --- a/web/src/helpers/api.ts +++ b/web/src/helpers/api.ts @@ -87,7 +87,7 @@ namespace api { }); } - export function updateUserinfo(userinfo: Partial<{ username: string; password: string; githubName: string }>) { + export function updateUserinfo(userinfo: Partial<{ username: string; password: string }>) { return request({ method: "PATCH", url: "/api/user/me", @@ -95,6 +95,13 @@ namespace api { }); } + export function resetOpenId() { + return request({ + method: "POST", + url: "/api/user/open_id/new", + }); + } + export function getMyMemos() { return request({ method: "GET", diff --git a/web/src/less/mixin.less b/web/src/less/mixin.less index 9e5bbc353..43a8b15fb 100644 --- a/web/src/less/mixin.less +++ b/web/src/less/mixin.less @@ -11,6 +11,7 @@ @bg-lightgray: #eaeaea; @bg-blue: #1337a3; @bg-yellow: yellow; +@bg-red: #fcf0f0; @bg-light-blue: #eef3fe; @bg-paper-yellow: #fbf4de; diff --git a/web/src/less/my-account-section.less b/web/src/less/my-account-section.less index ae1af7e91..32d13aa15 100644 --- a/web/src/less/my-account-section.less +++ b/web/src/less/my-account-section.less @@ -2,7 +2,7 @@ .account-section-container { > .form-label { - height: 28px; + min-height: 28px; &.username-label { > input { @@ -62,43 +62,52 @@ } } -.connect-section-container { - > .form-label { - height: 28px; +.openapi-section-container { + > .value-text { + width: 100%; + border: 1px solid lightgray; + padding: 4px 6px; + border-radius: 4px; + line-height: 1.6; + } - > .value-text { - max-width: 128px; - min-height: 20px; - overflow: hidden; - text-overflow: ellipsis; + > .reset-btn { + margin-top: 4px; + padding: 4px 8px; + background-color: @bg-red; + border: 1px solid red; + color: red; + border-radius: 4px; + line-height: 1.6; + cursor: pointer; + user-select: none; + + &:hover { + opacity: 0.8; } - > .btn-text { - padding: 0 8px; - margin-left: 12px; + &.loading { + opacity: 0.6; + cursor: wait; + } + } + + > .usage-guide-container { + .flex(column, flex-start, flex-start); + margin-top: 8px; + + > .title-text { + line-height: 2; + } + + > pre { + background-color: @bg-whitegray; + padding: 8px 12px; border-radius: 4px; - font-size: 12px; - line-height: 28px; - cursor: pointer; - - &:hover { - opacity: 0.8; - } - - &.bind-btn { - color: white; - background-color: @text-green; - text-decoration: none; - } - - &.unbind-btn { - color: #d28653; - background-color: @bg-lightgray; - - &.final-confirm { - font-weight: bold; - } - } + line-height: 1.4; + word-break: break-all; + word-wrap: break-word; + white-space: pre-wrap; } } } diff --git a/web/src/less/preferences-section.less b/web/src/less/preferences-section.less index 257f8a34c..bc76823dd 100644 --- a/web/src/less/preferences-section.less +++ b/web/src/less/preferences-section.less @@ -9,7 +9,7 @@ } > .form-label { - height: 28px; + min-height: 28px; cursor: pointer; > .icon-img { diff --git a/web/src/pages/Signin.tsx b/web/src/pages/Signin.tsx index 02a7f44b0..5fb162f92 100644 --- a/web/src/pages/Signin.tsx +++ b/web/src/pages/Signin.tsx @@ -3,7 +3,6 @@ import api from "../helpers/api"; import { validate, ValidatorConfig } from "../helpers/validator"; import useLoading from "../hooks/useLoading"; import { locationService, userService } from "../services"; -import Only from "../components/common/OnlyWhen"; import toastHelper from "../components/Toast"; import "../less/signin.less"; @@ -20,7 +19,7 @@ const Signin: React.FC = () => { const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [showAutoSigninAsGuest, setShowAutoSigninAsGuest] = useState(true); - const signinBtnClickLoadingState = useLoading(false); + const signinBtnsClickLoadingState = useLoading(false); const autoSigninAsGuestBtn = useRef(null); const signinBtn = useRef(null); @@ -49,12 +48,8 @@ const Signin: React.FC = () => { setPassword(text); }; - const handleSignUpBtnClick = async () => { - toastHelper.info("注册已关闭"); - }; - - const handleSignInBtnClick = async () => { - if (signinBtnClickLoadingState.isLoading) { + const handleSigninBtnsClick = async (action: "signin" | "signup" = "signin") => { + if (signinBtnsClickLoadingState.isLoading) { return; } @@ -71,8 +66,11 @@ const Signin: React.FC = () => { } try { - signinBtnClickLoadingState.setLoading(); - const actionFunc = api.signin; + signinBtnsClickLoadingState.setLoading(); + let actionFunc = api.signin; + if (action === "signup") { + actionFunc = api.signup; + } const { succeed, message } = await actionFunc(username, password); if (!succeed && message) { @@ -90,11 +88,11 @@ const Signin: React.FC = () => { console.error(error); toastHelper.error("😟 " + error.message); } - signinBtnClickLoadingState.setFinish(); + signinBtnsClickLoadingState.setFinish(); }; const handleSwitchAccountSigninBtnClick = () => { - if (signinBtnClickLoadingState.isLoading) { + if (signinBtnsClickLoadingState.isLoading) { return; } @@ -102,12 +100,12 @@ const Signin: React.FC = () => { }; const handleAutoSigninAsGuestBtnClick = async () => { - if (signinBtnClickLoadingState.isLoading) { + if (signinBtnsClickLoadingState.isLoading) { return; } try { - signinBtnClickLoadingState.setLoading(); + signinBtnsClickLoadingState.setLoading(); const { succeed, message } = await api.signin("guest", "123456"); if (!succeed && message) { @@ -125,7 +123,7 @@ const Signin: React.FC = () => { console.error(error); toastHelper.error("😟 " + error.message); } - signinBtnClickLoadingState.setFinish(); + signinBtnsClickLoadingState.setFinish(); }; return ( @@ -141,13 +139,13 @@ const Signin: React.FC = () => {
👉 快速登录进行体验
已有账号,我要自己登录 @@ -167,32 +165,26 @@ const Signin: React.FC = () => {
- +
{/* nth */}
/ - / diff --git a/web/src/services/userService.ts b/web/src/services/userService.ts index 5af589ff4..b035647fe 100644 --- a/web/src/services/userService.ts +++ b/web/src/services/userService.ts @@ -40,12 +40,6 @@ class UserService { }); } - public async removeGithubName(): Promise { - await api.updateUserinfo({ - githubName: "", - }); - } - public async checkPasswordValid(password: string): Promise { const { data: isValid } = await api.checkPasswordValid(password); return isValid; @@ -56,6 +50,15 @@ class UserService { password, }); } + + public async resetOpenId(): Promise { + const { data: openId } = await api.resetOpenId(); + appStore.dispatch({ + type: "RESET_OPENID", + payload: openId, + }); + return openId; + } } const userService = new UserService(); diff --git a/web/src/stores/userStore.ts b/web/src/stores/userStore.ts index 49ecea7da..4fa2831db 100644 --- a/web/src/stores/userStore.ts +++ b/web/src/stores/userStore.ts @@ -12,7 +12,12 @@ interface SignOutAction { payload: null; } -export type Actions = SignInAction | SignOutAction; +interface ResetOpenIdAction { + type: "RESET_OPENID"; + payload: string; +} + +export type Actions = SignInAction | SignOutAction | ResetOpenIdAction; export function reducer(state: State, action: Actions): State { switch (action.type) { @@ -26,6 +31,18 @@ export function reducer(state: State, action: Actions): State { user: null, }; } + case "RESET_OPENID": { + if (!state.user) { + return state; + } + + return { + user: { + ...state.user, + openId: action.payload, + }, + }; + } default: { return state; } diff --git a/web/src/types/models.d.ts b/web/src/types/models.d.ts index 82a0d19c1..7988d0518 100644 --- a/web/src/types/models.d.ts +++ b/web/src/types/models.d.ts @@ -7,7 +7,7 @@ declare namespace Model { interface User extends BaseModel { username: string; - githubName: string; + openId: string; } interface Memo extends BaseModel {