mirror of
https://github.com/usememos/memos.git
synced 2025-01-01 18:58:12 +03:00
feat: remove user wx_open_id key
This commit is contained in:
parent
1edf40ef69
commit
50c8947ad5
@ -39,7 +39,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())
|
||||
@ -225,7 +225,7 @@ func handleGithubAuthCallback(w http.ResponseWriter, r *http.Request) {
|
||||
username = githubUser.Name + utils.GenUUID()
|
||||
usernameUsable, _ = store.CheckUsernameUsable(username)
|
||||
}
|
||||
user, _ = store.CreateNewUser(username, username, githubUser.Login, "")
|
||||
user, _ = store.CreateNewUser(username, username, githubUser.Login)
|
||||
}
|
||||
|
||||
session.Values["user_id"] = user.Id
|
||||
@ -237,6 +237,8 @@ func handleGithubAuthCallback(w http.ResponseWriter, r *http.Request) {
|
||||
func RegisterAuthRoutes(r *mux.Router) {
|
||||
authRouter := r.PathPrefix("/api/auth").Subrouter()
|
||||
|
||||
authRouter.Use(JSONResponseMiddleWare)
|
||||
|
||||
authRouter.HandleFunc("/signup", handleUserSignUp).Methods("POST")
|
||||
authRouter.HandleFunc("/signin", handleUserSignIn).Methods("POST")
|
||||
authRouter.HandleFunc("/signout", handleUserSignOut).Methods("POST")
|
||||
|
@ -105,6 +105,7 @@ func handleDeleteMemo(w http.ResponseWriter, r *http.Request) {
|
||||
func RegisterMemoRoutes(r *mux.Router) {
|
||||
memoRouter := r.PathPrefix("/api/memo").Subrouter()
|
||||
|
||||
memoRouter.Use(JSONResponseMiddleWare)
|
||||
memoRouter.Use(AuthCheckerMiddleWare)
|
||||
|
||||
memoRouter.HandleFunc("/all", handleGetMyMemos).Methods("GET")
|
||||
|
@ -18,6 +18,14 @@ func AuthCheckerMiddleWare(next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
func JSONResponseMiddleWare(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func CorsMiddleWare(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
|
@ -103,6 +103,7 @@ func handleDeleteQuery(w http.ResponseWriter, r *http.Request) {
|
||||
func RegisterQueryRoutes(r *mux.Router) {
|
||||
queryRouter := r.PathPrefix("/api/query").Subrouter()
|
||||
|
||||
queryRouter.Use(JSONResponseMiddleWare)
|
||||
queryRouter.Use(AuthCheckerMiddleWare)
|
||||
|
||||
queryRouter.HandleFunc("/all", handleGetMyQueries).Methods("GET")
|
||||
|
13
api/user.go
13
api/user.go
@ -61,18 +61,6 @@ func handleUpdateMyUserInfo(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
if userPatch.WxOpenId != nil {
|
||||
wxOpenIdUsable, _ := store.CheckWxOpenIdUsable(*userPatch.GithubName)
|
||||
if !wxOpenIdUsable {
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: false,
|
||||
Message: "Wx open id is existed",
|
||||
Data: nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
user, err := store.UpdateUser(userId, &userPatch)
|
||||
|
||||
if err != nil {
|
||||
@ -145,6 +133,7 @@ func handleValidPassword(w http.ResponseWriter, r *http.Request) {
|
||||
func RegisterUserRoutes(r *mux.Router) {
|
||||
userRouter := r.PathPrefix("/api/user").Subrouter()
|
||||
|
||||
userRouter.Use(JSONResponseMiddleWare)
|
||||
userRouter.Use(AuthCheckerMiddleWare)
|
||||
|
||||
userRouter.HandleFunc("/me", handleGetMyUserInfo).Methods("GET")
|
||||
|
@ -1,44 +1,46 @@
|
||||
DROP TABLE IF EXISTS `memos`;
|
||||
DROP TABLE IF EXISTS `queries`;
|
||||
DROP TABLE IF EXISTS `users`;
|
||||
|
||||
CREATE TABLE `users` (
|
||||
`id` TEXT NOT NULL PRIMARY KEY,
|
||||
`username` TEXT NOT NULL,
|
||||
`password` TEXT NOT NULL,
|
||||
`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`)
|
||||
);
|
||||
|
||||
CREATE TABLE `queries` (
|
||||
`id` TEXT NOT NULL PRIMARY KEY,
|
||||
`user_id` TEXT NOT NULL,
|
||||
`title` TEXT NOT NULL,
|
||||
`querystring` TEXT NOT NULL,
|
||||
`created_at` TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`pinned_at` TEXT DEFAULT '',
|
||||
`created_at` TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')),
|
||||
`updated_at` TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')),
|
||||
`pinned_at` TEXT NOT NULL DEFAULT '',
|
||||
FOREIGN KEY(`user_id`) REFERENCES `users`(`id`)
|
||||
);
|
||||
|
||||
DROP TABLE IF EXISTS `memos`;
|
||||
CREATE TABLE `memos` (
|
||||
`id` TEXT NOT NULL PRIMARY KEY,
|
||||
`content` TEXT NOT NULL,
|
||||
`user_id` TEXT NOT NULL,
|
||||
`created_at` TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`deleted_at` TEXT DEFAULT '',
|
||||
`created_at` TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')),
|
||||
`updated_at` TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')),
|
||||
`deleted_at` TEXT NOT NULL DEFAULT '',
|
||||
FOREIGN KEY(`user_id`) REFERENCES `users`(`id`)
|
||||
);
|
||||
|
||||
DROP TABLE IF EXISTS `users`;
|
||||
CREATE TABLE `users` (
|
||||
`id` TEXT NOT NULL PRIMARY KEY,
|
||||
`username` TEXT NOT NULL,
|
||||
`password` TEXT NOT NULL,
|
||||
`github_name` TEXT DEFAULT '',
|
||||
`wx_open_id` TEXT DEFAULT '',
|
||||
`created_at` TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(`username`, `github_name`, `wx_open_id`)
|
||||
);
|
||||
|
||||
INSERT INTO `users`
|
||||
(`id`, `username`, `password`)
|
||||
VALUES
|
||||
('1', 'guest', '123456');
|
||||
('1', 'guest', '123456'),
|
||||
('2', 'test', '123456');
|
||||
|
||||
INSERT INTO `memos`
|
||||
(`id`, `content`, `user_id`)
|
||||
VALUES
|
||||
('1', '👋 Welcome to memos', '1');
|
||||
('1', '👋 Welcome to memos', '1'),
|
||||
('2', '👋 Welcome to memos', '2');
|
||||
|
@ -18,12 +18,12 @@ func main() {
|
||||
api.RegisterMemoRoutes(r)
|
||||
api.RegisterQueryRoutes(r)
|
||||
|
||||
spa := api.SPAHandler{
|
||||
webServe := api.SPAHandler{
|
||||
StaticPath: "./web/dist",
|
||||
IndexPath: "index.html",
|
||||
}
|
||||
|
||||
r.PathPrefix("/").Handler(spa)
|
||||
r.PathPrefix("/").Handler(webServe)
|
||||
|
||||
http.ListenAndServe(":8080", r)
|
||||
}
|
||||
|
@ -11,26 +11,24 @@ type User struct {
|
||||
Id string `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
WxOpenId string `json:"wxOpenId"`
|
||||
GithubName string `json:"githubName"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
func CreateNewUser(username string, password string, githubName string, wxOpenId string) (User, error) {
|
||||
func CreateNewUser(username string, password string, githubName string) (User, error) {
|
||||
nowDateTimeStr := utils.GetNowDateTimeStr()
|
||||
newUser := User{
|
||||
Id: utils.GenUUID(),
|
||||
Username: username,
|
||||
Password: password,
|
||||
WxOpenId: wxOpenId,
|
||||
GithubName: githubName,
|
||||
CreatedAt: nowDateTimeStr,
|
||||
UpdatedAt: nowDateTimeStr,
|
||||
}
|
||||
|
||||
query := `INSERT INTO users (id, username, password, wx_open_id, github_name, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)`
|
||||
_, err := DB.Exec(query, newUser.Id, newUser.Username, newUser.Password, newUser.WxOpenId, newUser.GithubName, newUser.CreatedAt, newUser.UpdatedAt)
|
||||
query := `INSERT INTO users (id, username, password, github_name, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)`
|
||||
_, err := DB.Exec(query, newUser.Id, newUser.Username, newUser.Password, newUser.GithubName, newUser.CreatedAt, newUser.UpdatedAt)
|
||||
|
||||
return newUser, err
|
||||
}
|
||||
@ -39,7 +37,6 @@ type UserPatch struct {
|
||||
Username *string
|
||||
Password *string
|
||||
GithubName *string
|
||||
WxOpenId *string
|
||||
}
|
||||
|
||||
func UpdateUser(id string, userPatch *UserPatch) (User, error) {
|
||||
@ -58,10 +55,6 @@ func UpdateUser(id string, userPatch *UserPatch) (User, error) {
|
||||
user.GithubName = *v
|
||||
set, args = append(set, "github_name=?"), append(args, *v)
|
||||
}
|
||||
if v := userPatch.WxOpenId; v != nil {
|
||||
user.WxOpenId = *v
|
||||
set, args = append(set, "wx_open_id=?"), append(args, *v)
|
||||
}
|
||||
set, args = append(set, "updated_at=?"), append(args, utils.GetNowDateTimeStr())
|
||||
args = append(args, id)
|
||||
|
||||
@ -72,30 +65,23 @@ func UpdateUser(id string, userPatch *UserPatch) (User, error) {
|
||||
}
|
||||
|
||||
func GetUserById(id string) (User, error) {
|
||||
query := `SELECT id, username, password, wx_open_id, github_name, created_at, updated_at FROM users WHERE id=?`
|
||||
query := `SELECT id, username, password, github_name, created_at, updated_at FROM users WHERE id=?`
|
||||
user := User{}
|
||||
err := DB.QueryRow(query, id).Scan(&user.Id, &user.Username, &user.Password, &user.WxOpenId, &user.GithubName, &user.CreatedAt, &user.UpdatedAt)
|
||||
err := DB.QueryRow(query, id).Scan(&user.Id, &user.Username, &user.Password, &user.GithubName, &user.CreatedAt, &user.UpdatedAt)
|
||||
return user, err
|
||||
}
|
||||
|
||||
func GetUserByUsernameAndPassword(username string, password string) (User, error) {
|
||||
query := `SELECT id, username, password, wx_open_id, github_name, created_at, updated_at FROM users WHERE username=? AND password=?`
|
||||
query := `SELECT id, username, password, github_name, 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.WxOpenId, &user.GithubName, &user.CreatedAt, &user.UpdatedAt)
|
||||
err := DB.QueryRow(query, username, password).Scan(&user.Id, &user.Username, &user.Password, &user.GithubName, &user.CreatedAt, &user.UpdatedAt)
|
||||
return user, err
|
||||
}
|
||||
|
||||
func GetUserByGithubName(githubName string) (User, error) {
|
||||
query := `SELECT id, username, password, wx_open_id, github_name, created_at, updated_at FROM users WHERE github_name=?`
|
||||
query := `SELECT id, username, password, 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.WxOpenId, &user.GithubName, &user.CreatedAt, &user.UpdatedAt)
|
||||
return user, err
|
||||
}
|
||||
|
||||
func GetUserByWxOpenId(wxOpenId string) (User, error) {
|
||||
query := `SELECT id, username, password, wx_open_id, github_name, created_at, updated_at FROM users WHERE id=?`
|
||||
user := User{}
|
||||
err := DB.QueryRow(query, wxOpenId).Scan(&user.Id, &user.Username, &user.Password, &user.WxOpenId, &user.GithubName, &user.CreatedAt, &user.UpdatedAt)
|
||||
err := DB.QueryRow(query, githubName).Scan(&user.Id, &user.Username, &user.Password, &user.GithubName, &user.CreatedAt, &user.UpdatedAt)
|
||||
return user, err
|
||||
}
|
||||
|
||||
@ -133,23 +119,6 @@ func CheckGithubNameUsable(githubName string) (bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func CheckWxOpenIdUsable(wxOpenId string) (bool, error) {
|
||||
query := `SELECT * FROM users WHERE wx_open_id=?`
|
||||
query = fmt.Sprintf("SELECT COUNT(*) FROM (%s)", query)
|
||||
|
||||
var count uint
|
||||
err := DB.QueryRow(query, wxOpenId).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)
|
||||
|
@ -1,79 +0,0 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { userService } from "../services";
|
||||
import { showDialog } from "./Dialog";
|
||||
import toastHelper from "./Toast";
|
||||
import "../less/change-password-dialog.less";
|
||||
|
||||
interface Props extends DialogProps {}
|
||||
|
||||
const BindWxOpenIdDialog: React.FC<Props> = ({ destroy }: Props) => {
|
||||
const [wxOpenId, setWxOpenId] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
// do nth
|
||||
}, []);
|
||||
|
||||
const handleCloseBtnClick = () => {
|
||||
destroy();
|
||||
};
|
||||
|
||||
const handleWxOpenIdChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const text = e.target.value as string;
|
||||
setWxOpenId(text);
|
||||
};
|
||||
|
||||
const handleSaveBtnClick = async () => {
|
||||
if (wxOpenId === "") {
|
||||
toastHelper.error("微信 id 不能为空");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await userService.updateWxOpenId(wxOpenId);
|
||||
userService.doSignIn();
|
||||
toastHelper.info("绑定成功!");
|
||||
handleCloseBtnClick();
|
||||
} catch (error: any) {
|
||||
toastHelper.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="dialog-header-container">
|
||||
<p className="title-text">绑定微信 OpenID</p>
|
||||
<button className="btn close-btn" onClick={handleCloseBtnClick}>
|
||||
<img className="icon-img" src="/icons/close.svg" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="dialog-content-container">
|
||||
<p className="tip-text">
|
||||
关注微信公众号“小谈闲事”,主动发送任意消息,即可获取 <strong>OpenID</strong> 。
|
||||
</p>
|
||||
<label className="form-label input-form-label">
|
||||
<span className={"normal-text " + (wxOpenId === "" ? "" : "not-null")}>微信 OpenID</span>
|
||||
<input type="text" value={wxOpenId} onChange={handleWxOpenIdChanged} />
|
||||
</label>
|
||||
<div className="btns-container">
|
||||
<span className="btn cancel-btn" onClick={handleCloseBtnClick}>
|
||||
取消
|
||||
</span>
|
||||
<span className="btn confirm-btn" onClick={handleSaveBtnClick}>
|
||||
保存
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
function showBindWxOpenIdDialog() {
|
||||
showDialog(
|
||||
{
|
||||
className: "bind-wxid-dialog",
|
||||
},
|
||||
BindWxOpenIdDialog
|
||||
);
|
||||
}
|
||||
|
||||
export default showBindWxOpenIdDialog;
|
@ -6,7 +6,6 @@ import { validate, ValidatorConfig } from "../helpers/validator";
|
||||
import Only from "./common/OnlyWhen";
|
||||
import toastHelper from "./Toast";
|
||||
import showChangePasswordDialog from "./ChangePasswordDialog";
|
||||
import showBindWxOpenIdDialog from "./BindWxOpenIdDialog";
|
||||
import "../less/my-account-section.less";
|
||||
|
||||
const validateConfig: ValidatorConfig = {
|
||||
@ -88,20 +87,6 @@ const MyAccountSection: React.FC<Props> = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleUnbindWxBtnClick = async () => {
|
||||
if (showConfirmUnbindWxBtn) {
|
||||
try {
|
||||
await userService.updateWxOpenId("");
|
||||
await userService.doSignIn();
|
||||
} catch (error: any) {
|
||||
toastHelper.error(error.message);
|
||||
}
|
||||
setShowConfirmUnbindWxBtn(false);
|
||||
} else {
|
||||
setShowConfirmUnbindWxBtn(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePreventDefault = (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
};
|
||||
@ -155,33 +140,6 @@ const MyAccountSection: React.FC<Props> = () => {
|
||||
<Only when={window.location.origin.includes("justsven.top")}>
|
||||
<div className="section-container connect-section-container">
|
||||
<p className="title-text">关联账号</p>
|
||||
<label className="form-label input-form-label hidden">
|
||||
<span className="normal-text">微信 OpenID:</span>
|
||||
{user.wxOpenId ? (
|
||||
<>
|
||||
<span className="value-text">************</span>
|
||||
<span
|
||||
className={`btn-text unbind-btn ${showConfirmUnbindWxBtn ? "final-confirm" : ""}`}
|
||||
onMouseLeave={() => setShowConfirmUnbindWxBtn(false)}
|
||||
onClick={handleUnbindWxBtnClick}
|
||||
>
|
||||
{showConfirmUnbindWxBtn ? "确定取消绑定!" : "取消绑定"}
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="value-text">空</span>
|
||||
<span
|
||||
className="btn-text bind-btn"
|
||||
onClick={() => {
|
||||
showBindWxOpenIdDialog();
|
||||
}}
|
||||
>
|
||||
绑定 ID
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</label>
|
||||
<label className="form-label input-form-label">
|
||||
<span className="normal-text">GitHub:</span>
|
||||
{user.githubName ? (
|
||||
|
@ -55,14 +55,7 @@ namespace api {
|
||||
return request<boolean>("POST", "/api/user/validpassword", { password });
|
||||
}
|
||||
|
||||
interface UserInfoPatch {
|
||||
username?: string;
|
||||
password?: string;
|
||||
githubName?: string;
|
||||
wxOpenId?: string;
|
||||
}
|
||||
|
||||
export function updateUserinfo(userinfo: UserInfoPatch) {
|
||||
export function updateUserinfo(userinfo: Partial<{ username: string; password: string; githubName: string }>) {
|
||||
return request("PATCH", "/api/user/me", userinfo);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
@import "./mixin.less";
|
||||
|
||||
.change-password-dialog,
|
||||
.bind-wxid-dialog {
|
||||
.change-password-dialog {
|
||||
> .dialog-container {
|
||||
width: 300px;
|
||||
border-radius: 8px;
|
||||
@ -92,8 +91,7 @@
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 875px) {
|
||||
.dialog-wrapper.change-password-dialog,
|
||||
.dialog-wrapper.bind-wxid-dialog {
|
||||
.dialog-wrapper.change-password-dialog {
|
||||
padding: 24px 16px;
|
||||
padding-top: 64px;
|
||||
|
||||
|
@ -4,4 +4,3 @@ What should service do?
|
||||
|
||||
- request data api and throw error;
|
||||
- dispatch state actions;
|
||||
- should be a class;
|
||||
|
@ -56,12 +56,6 @@ class UserService {
|
||||
password,
|
||||
});
|
||||
}
|
||||
|
||||
public async updateWxOpenId(wxOpenId: string): Promise<void> {
|
||||
await api.updateUserinfo({
|
||||
wxOpenId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const userService = new UserService();
|
||||
|
7
web/src/types/models.d.ts
vendored
7
web/src/types/models.d.ts
vendored
@ -7,18 +7,17 @@ declare namespace Model {
|
||||
|
||||
interface User extends BaseModel {
|
||||
username: string;
|
||||
githubName?: string;
|
||||
wxOpenId?: string;
|
||||
githubName: string;
|
||||
}
|
||||
|
||||
interface Memo extends BaseModel {
|
||||
content: string;
|
||||
deletedAt?: string;
|
||||
deletedAt: string;
|
||||
}
|
||||
|
||||
interface Query extends BaseModel {
|
||||
title: string;
|
||||
querystring: string;
|
||||
pinnedAt?: string;
|
||||
pinnedAt: string;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user