diff --git a/api/auth.go b/api/auth.go index aa1a6aef..ddb7998d 100644 --- a/api/auth.go +++ b/api/auth.go @@ -1,6 +1,6 @@ package api -type Login struct { +type Signin struct { Email string `json:"email"` Password string `json:"password"` } diff --git a/server/auth.go b/server/auth.go index 440c7a72..1e26b017 100644 --- a/server/auth.go +++ b/server/auth.go @@ -13,33 +13,33 @@ import ( ) func (s *Server) registerAuthRoutes(g *echo.Group) { - g.POST("/auth/login", func(c echo.Context) error { - login := &api.Login{} - if err := json.NewDecoder(c.Request().Body).Decode(login); err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Malformatted login request").SetInternal(err) + g.POST("/auth/signin", func(c echo.Context) error { + signin := &api.Signin{} + if err := json.NewDecoder(c.Request().Body).Decode(signin); err != nil { + return echo.NewHTTPError(http.StatusBadRequest, "Malformatted signin request").SetInternal(err) } userFind := &api.UserFind{ - Email: &login.Email, + Email: &signin.Email, } user, err := s.Store.FindUser(userFind) if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Failed to find user by email %s", login.Email)).SetInternal(err) + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Failed to find user by email %s", signin.Email)).SetInternal(err) } if user == nil { - return echo.NewHTTPError(http.StatusUnauthorized, fmt.Sprintf("User not found with email %s", login.Email)) + return echo.NewHTTPError(http.StatusUnauthorized, fmt.Sprintf("User not found with email %s", signin.Email)) } else if user.RowStatus == api.Archived { - return echo.NewHTTPError(http.StatusForbidden, fmt.Sprintf("User has been archived with email %s", login.Email)) + return echo.NewHTTPError(http.StatusForbidden, fmt.Sprintf("User has been archived with email %s", signin.Email)) } // Compare the stored hashed password, with the hashed version of the password that was received. - if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(login.Password)); err != nil { + if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(signin.Password)); err != nil { // If the two passwords don't match, return a 401 status. return echo.NewHTTPError(http.StatusUnauthorized, "Incorrect password").SetInternal(err) } if err = setUserSession(c, user); err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to set login session").SetInternal(err) + return echo.NewHTTPError(http.StatusInternalServerError, "Failed to set signin session").SetInternal(err) } c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) diff --git a/server/memo.go b/server/memo.go index 107e4714..144d5d01 100644 --- a/server/memo.go +++ b/server/memo.go @@ -60,31 +60,17 @@ func (s *Server) registerMemoRoutes(g *echo.Group) { }) g.GET("/memo", func(c echo.Context) error { - userID, ok := c.Get(getUserIDContextKey()).(int) - if !ok { - if c.QueryParam("userID") != "" { - var err error - userID, err = strconv.Atoi(c.QueryParam("userID")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.QueryParam("userID"))) - } - } else { - ownerUserType := api.Owner - ownerUser, err := s.Store.FindUser(&api.UserFind{ - Role: &ownerUserType, - }) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find owner user").SetInternal(err) - } - if ownerUser == nil { - return echo.NewHTTPError(http.StatusNotFound, "Owner user do not exist") - } - userID = ownerUser.ID - } - } + memoFind := &api.MemoFind{} - memoFind := &api.MemoFind{ - CreatorID: &userID, + if userID, err := strconv.Atoi(c.QueryParam("creatorId")); err == nil { + memoFind.CreatorID = &userID + } else { + userID, ok := c.Get(getUserIDContextKey()).(int) + if !ok { + return echo.NewHTTPError(http.StatusBadRequest, "Missing creatorId to find memo") + } + + memoFind.CreatorID = &userID } rowStatus := api.RowStatus(c.QueryParam("rowStatus")) diff --git a/server/server.go b/server/server.go index 9f18ed18..bc80c3af 100644 --- a/server/server.go +++ b/server/server.go @@ -45,7 +45,7 @@ func NewServer(profile *profile.Profile) *Server { HTML5: true, })) - // In dev mode, set the const secret key to make login session persistence. + // In dev mode, set the const secret key to make signin session persistence. secret := []byte("usememos") if profile.Mode == "prod" { secret = securecookie.GenerateRandomKey(16) diff --git a/server/shortcut.go b/server/shortcut.go index 5728fa56..0adbffa9 100644 --- a/server/shortcut.go +++ b/server/shortcut.go @@ -59,32 +59,19 @@ func (s *Server) registerShortcutRoutes(g *echo.Group) { }) g.GET("/shortcut", func(c echo.Context) error { - userID, ok := c.Get(getUserIDContextKey()).(int) - if !ok { - if c.QueryParam("userID") != "" { - var err error - userID, err = strconv.Atoi(c.QueryParam("userID")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.QueryParam("userID"))) - } - } else { - ownerUserType := api.Owner - ownerUser, err := s.Store.FindUser(&api.UserFind{ - Role: &ownerUserType, - }) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find owner user").SetInternal(err) - } - if ownerUser == nil { - return echo.NewHTTPError(http.StatusNotFound, "Owner user do not exist") - } - userID = ownerUser.ID + shortcutFind := &api.ShortcutFind{} + + if userID, err := strconv.Atoi(c.QueryParam("creatorId")); err == nil { + shortcutFind.CreatorID = &userID + } else { + userID, ok := c.Get(getUserIDContextKey()).(int) + if !ok { + return echo.NewHTTPError(http.StatusBadRequest, "Missing creatorId to find shortcut") } + + shortcutFind.CreatorID = &userID } - shortcutFind := &api.ShortcutFind{ - CreatorID: &userID, - } list, err := s.Store.FindShortcutList(shortcutFind) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to fetch shortcut list").SetInternal(err) diff --git a/server/tag.go b/server/tag.go index 0887c048..a79b6105 100644 --- a/server/tag.go +++ b/server/tag.go @@ -2,7 +2,6 @@ package server import ( "encoding/json" - "fmt" "net/http" "regexp" "sort" @@ -15,37 +14,24 @@ import ( func (s *Server) registerTagRoutes(g *echo.Group) { g.GET("/tag", func(c echo.Context) error { - userID, ok := c.Get(getUserIDContextKey()).(int) - if !ok { - if c.QueryParam("userID") != "" { - var err error - userID, err = strconv.Atoi(c.QueryParam("userID")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.QueryParam("userID"))) - } - } else { - ownerUserType := api.Owner - ownerUser, err := s.Store.FindUser(&api.UserFind{ - Role: &ownerUserType, - }) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find owner user").SetInternal(err) - } - if ownerUser == nil { - return echo.NewHTTPError(http.StatusNotFound, "Owner user do not exist") - } - userID = ownerUser.ID - } - } - contentSearch := "#" normalRowStatus := api.Normal memoFind := api.MemoFind{ - CreatorID: &userID, ContentSearch: &contentSearch, RowStatus: &normalRowStatus, } + if userID, err := strconv.Atoi(c.QueryParam("creatorId")); err == nil { + memoFind.CreatorID = &userID + } else { + userID, ok := c.Get(getUserIDContextKey()).(int) + if !ok { + return echo.NewHTTPError(http.StatusBadRequest, "Missing creatorId to find shortcut") + } + + memoFind.CreatorID = &userID + } + memoList, err := s.Store.FindMemoList(&memoFind) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find memo list").SetInternal(err) diff --git a/store/db/seed/10002__memo.sql b/store/db/seed/10002__memo.sql index 3ed4dfba..2604d382 100644 --- a/store/db/seed/10002__memo.sql +++ b/store/db/seed/10002__memo.sql @@ -52,6 +52,24 @@ INSERT INTO VALUES ( 104, - '好好学习,天天向上。🤜🤛', + '#TODO +- [x] Take more photos about **🌄 sunset**; +- [ ] Clean the classroom; +- [ ] Watch *👦 The Boys*; +(👆 click to toggle status) +', + 102 + ); + +INSERT INTO + memo ( + `id`, + `content`, + `creator_id` + ) +VALUES + ( + 105, + '三人行,必有我师焉!👨‍🏫', 102 ); diff --git a/web/package.json b/web/package.json index 668f5dda..1f43555c 100644 --- a/web/package.json +++ b/web/package.json @@ -11,12 +11,14 @@ "@reduxjs/toolkit": "^1.8.1", "axios": "^0.27.2", "lodash-es": "^4.17.21", + "qs": "^6.11.0", "react": "^18.1.0", "react-dom": "^18.1.0", "react-redux": "^8.0.1" }, "devDependencies": { "@types/lodash-es": "^4.17.5", + "@types/qs": "^6.9.7", "@types/react": "^18.0.9", "@types/react-dom": "^18.0.4", "@typescript-eslint/eslint-plugin": "^5.6.0", diff --git a/web/src/components/Memo.tsx b/web/src/components/Memo.tsx index 955c25bc..806e3aa9 100644 --- a/web/src/components/Memo.tsx +++ b/web/src/components/Memo.tsx @@ -112,7 +112,11 @@ const Memo: React.FC = (props: Props) => { } else { locationService.setTagQuery(tagName); } - } else if (targetEl.classList.contains("todo-block") && userService.isNotVisitor()) { + } else if (targetEl.classList.contains("todo-block")) { + if (userService.isVisitorMode()) { + return; + } + const status = targetEl.dataset?.value; const todoElementList = [...(memoContainerRef.current?.querySelectorAll(`span.todo-block[data-value=${status}]`) ?? [])]; for (const element of todoElementList) { @@ -158,40 +162,38 @@ const Memo: React.FC = (props: Props) => { PINNED - {userService.isNotVisitor() && ( -
- - - -
-
-
-
- - {memo.pinned ? "Unpin" : "Pin"} -
-
- - Edit -
-
- - Share -
+
+ + + +
+
+
+
+ + {memo.pinned ? "Unpin" : "Pin"} +
+
+ + Edit +
+
+ + Share
- - Mark - - - View Story - - - Archive -
+ + Mark + + + View Story + + + Archive +
- )} +
= (props: Props) => { -
); diff --git a/web/src/components/ShortcutList.tsx b/web/src/components/ShortcutList.tsx index b79736d9..f94d5e49 100644 --- a/web/src/components/ShortcutList.tsx +++ b/web/src/components/ShortcutList.tsx @@ -4,6 +4,7 @@ import { useAppSelector } from "../store"; import * as utils from "../helpers/utils"; import useToggle from "../hooks/useToggle"; import useLoading from "../hooks/useLoading"; +import Only from "./common/OnlyWhen"; import toastHelper from "./Toast"; import showCreateShortcutDialog from "./CreateShortcutDialog"; import "../less/shortcut-list.less"; @@ -38,11 +39,11 @@ const ShortcutList: React.FC = () => {

Shortcuts - {userService.isNotVisitor() && ( + showCreateShortcutDialog()}> add shortcut - )} +

{sortedShortcuts.map((s) => { @@ -66,9 +67,6 @@ const ShortcutContainer: React.FC = (props: ShortcutCont if (isActive) { locationService.setMemoShortcut(undefined); } else { - if (!["/"].includes(locationService.getState().pathname)) { - locationService.setPathname("/"); - } locationService.setMemoShortcut(shortcut.id); } }; @@ -116,30 +114,28 @@ const ShortcutContainer: React.FC = (props: ShortcutCont
{shortcut.title}
- {userService.isNotVisitor() && ( -
- - - -
-
- - {shortcut.rowStatus === "ARCHIVED" ? "Unpin" : "Pin"} - - - Edit - - - {showConfirmDeleteBtn ? "Delete!" : "Delete"} - -
+
+ + + +
+
+ + {shortcut.rowStatus === "ARCHIVED" ? "Unpin" : "Pin"} + + + Edit + + + {showConfirmDeleteBtn ? "Delete!" : "Delete"} +
- )} +
); diff --git a/web/src/components/Sidebar.tsx b/web/src/components/Sidebar.tsx index 3b6c6498..0e760c7a 100644 --- a/web/src/components/Sidebar.tsx +++ b/web/src/components/Sidebar.tsx @@ -1,6 +1,7 @@ import { useAppSelector } from "../store"; import * as utils from "../helpers/utils"; import { userService } from "../services"; +import Only from "./common/OnlyWhen"; import showDailyReviewDialog from "./DailyReviewDialog"; import showSettingDialog from "./SettingDialog"; import showArchivedMemoDialog from "./ArchivedMemoDialog"; @@ -49,21 +50,19 @@ const Sidebar: React.FC = () => {
- {userService.isNotVisitor() && ( - <> -
- - - -
- - )} + +
+ + + +
+
diff --git a/web/src/components/TagList.tsx b/web/src/components/TagList.tsx index 7232e178..fa6ddfb8 100644 --- a/web/src/components/TagList.tsx +++ b/web/src/components/TagList.tsx @@ -71,7 +71,7 @@ const TagList: React.FC = () => { {tags.map((t, idx) => ( ))} - +

Enter #tag to create a tag

@@ -97,9 +97,6 @@ const TagItemContainer: React.FC = (props: TagItemContain locationService.setTagQuery(undefined); } else { utils.copyTextToClipboard(`#${tag.text} `); - if (!["/"].includes(locationService.getState().pathname)) { - locationService.setPathname("/"); - } locationService.setTagQuery(tag.text); } }; diff --git a/web/src/components/UserBanner.tsx b/web/src/components/UserBanner.tsx index 656422b1..0d429b69 100644 --- a/web/src/components/UserBanner.tsx +++ b/web/src/components/UserBanner.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect, useState } from "react"; import * as api from "../helpers/api"; -import { getUserIdFromPath } from "../services/userService"; +import userService from "../services/userService"; import { locationService } from "../services"; import { useAppSelector } from "../store"; import toastHelper from "./Toast"; @@ -31,15 +31,18 @@ const UserBanner: React.FC = () => { setUsername(status.owner.name); }); } else { - api - .getUserNameById(Number(getUserIdFromPath())) - .then(({ data }) => { - const { data: username } = data; - setUsername(username); - }) - .catch(() => { - toastHelper.error("User not found"); - }); + const currentUserId = userService.getCurrentUserId(); + if (currentUserId) { + api + .getUserNameById(currentUserId) + .then(({ data }) => { + const { data: username } = data; + setUsername(username); + }) + .catch(() => { + toastHelper.error("User not found"); + }); + } } } }, []); diff --git a/web/src/helpers/api.ts b/web/src/helpers/api.ts index 5da6c325..307b5867 100644 --- a/web/src/helpers/api.ts +++ b/web/src/helpers/api.ts @@ -12,8 +12,8 @@ export function getSystemStatus() { return axios.get>("/api/status"); } -export function login(email: string, password: string) { - return axios.post>("/api/auth/login", { +export function signin(email: string, password: string) { + return axios.post>("/api/auth/signin", { email, password, }); @@ -52,12 +52,15 @@ export function patchUser(userPatch: UserPatch) { return axios.patch>("/api/user/me", userPatch); } -export function getMemoList(userId?: number) { - return axios.get>(`/api/memo${userId ? "?userID=" + userId : ""}`); -} - -export function getArchivedMemoList(userId?: number) { - return axios.get>(`/api/memo?rowStatus=ARCHIVED${userId ? "&userID=" + userId : ""}`); +export function getMemoList(memoFind?: MemoFind) { + const queryList = []; + if (memoFind?.creatorId) { + queryList.push(`creatorId=${memoFind.creatorId}`); + } + if (memoFind?.rowStatus) { + queryList.push(`rowStatus=${memoFind.rowStatus}`); + } + return axios.get>(`/api/memo?${queryList.join("&")}`); } export function createMemo(memoCreate: MemoCreate) { @@ -84,8 +87,12 @@ export function deleteMemo(memoId: MemoId) { return axios.delete(`/api/memo/${memoId}`); } -export function getShortcutList(userId?: number) { - return axios.get>(`/api/shortcut${userId ? "?userID=" + userId : ""}`); +export function getShortcutList(shortcutFind: ShortcutFind) { + const queryList = []; + if (shortcutFind?.creatorId) { + queryList.push(`creatorId=${shortcutFind.creatorId}`); + } + return axios.get>(`/api/shortcut?${queryList.join("&")}`); } export function createShortcut(shortcutCreate: ShortcutCreate) { @@ -104,6 +111,10 @@ export function uploadFile(formData: FormData) { return axios.post>("/api/resource", formData); } -export function getTagList(userId?: number) { - return axios.get>(`/api/tag${userId ? "?userID=" + userId : ""}`); +export function getTagList(tagFind?: TagFind) { + const queryList = []; + if (tagFind?.creatorId) { + queryList.push(`creatorId=${tagFind.creatorId}`); + } + return axios.get>(`/api/tag?${queryList.join("&")}`); } diff --git a/web/src/helpers/utils.ts b/web/src/helpers/utils.ts index 49a522fa..284fcf8c 100644 --- a/web/src/helpers/utils.ts +++ b/web/src/helpers/utils.ts @@ -126,38 +126,6 @@ export function throttle(fn: FunctionType, delay: number) { }; } -export function transformObjectToParamsString(object: KVObject): string { - const params = []; - const keys = Object.keys(object).sort(); - - for (const key of keys) { - const val = object[key]; - if (val) { - if (typeof val === "object") { - params.push(...transformObjectToParamsString(val).split("&")); - } else { - params.push(`${key}=${val}`); - } - } - } - - return params.join("&"); -} - -export function transformParamsStringToObject(paramsString: string): KVObject { - const object: KVObject = {}; - const params = paramsString.split("&"); - - for (const p of params) { - const [key, val] = p.split("="); - if (key && val) { - object[key] = val; - } - } - - return object; -} - export function filterObjectNullKeys(object: KVObject): KVObject { if (!object) { return {}; diff --git a/web/src/pages/Home.tsx b/web/src/pages/Home.tsx index 7bd2d37f..5961ea51 100644 --- a/web/src/pages/Home.tsx +++ b/web/src/pages/Home.tsx @@ -1,7 +1,8 @@ import { useEffect } from "react"; -import { locationService, userService } from "../services"; -import Sidebar from "../components/Sidebar"; +import { userService } from "../services"; import useLoading from "../hooks/useLoading"; +import Only from "../components/common/OnlyWhen"; +import Sidebar from "../components/Sidebar"; import MemosHeader from "../components/MemosHeader"; import MemoEditor from "../components/MemoEditor"; import MemoFilter from "../components/MemoFilter"; @@ -12,25 +13,14 @@ function Home() { const loadingState = useLoading(); useEffect(() => { - if (window.location.pathname !== locationService.getState().pathname) { - locationService.replaceHistory("/"); - } - const { user } = userService.getState(); - if (!user) { - userService - .doSignIn() - .catch(() => { - // do nth - }) - .finally(() => { - if (userService.getState().user && locationService.getState().pathname !== "/") { - locationService.replaceHistory("/"); - } - loadingState.setFinish(); - }); - } else { - loadingState.setFinish(); - } + userService + .doSignIn() + .catch(() => { + // do nth + }) + .finally(() => { + loadingState.setFinish(); + }); }, []); return ( @@ -41,7 +31,9 @@ function Home() {
- {userService.isNotVisitor() && } + + +
diff --git a/web/src/pages/Signin.tsx b/web/src/pages/Signin.tsx index 3a6a2d47..2781419b 100644 --- a/web/src/pages/Signin.tsx +++ b/web/src/pages/Signin.tsx @@ -63,7 +63,7 @@ const Signin: React.FC = () => { try { actionBtnLoadingState.setLoading(); - await api.login(email, password); + await api.signin(email, password); const user = await userService.doSignIn(); if (user) { locationService.replaceHistory("/"); diff --git a/web/src/services/locationService.ts b/web/src/services/locationService.ts index 117e1c42..58e5eec0 100644 --- a/web/src/services/locationService.ts +++ b/web/src/services/locationService.ts @@ -1,10 +1,10 @@ -import * as utils from "../helpers/utils"; +import { stringify } from "qs"; import store from "../store"; import { setQuery, setPathname, Query } from "../store/modules/location"; const updateLocationUrl = (method: "replace" | "push" = "replace") => { const { query, pathname, hash } = store.getState().location; - let queryString = utils.transformObjectToParamsString(query ?? {}); + let queryString = stringify(query); if (queryString) { queryString = "?" + queryString; } else { diff --git a/web/src/services/memoService.ts b/web/src/services/memoService.ts index 72864668..f7190ac6 100644 --- a/web/src/services/memoService.ts +++ b/web/src/services/memoService.ts @@ -1,7 +1,7 @@ import * as api from "../helpers/api"; import { createMemo, patchMemo, setMemos, setTags } from "../store/modules/memo"; import store from "../store"; -import { getUserIdFromPath } from "./userService"; +import userService from "./userService"; const convertResponseModelMemo = (memo: Memo): Memo => { return { @@ -17,7 +17,10 @@ const memoService = { }, fetchAllMemos: async () => { - const { data } = (await api.getMemoList(getUserIdFromPath())).data; + const memoFind: MemoFind = { + creatorId: userService.getCurrentUserId(), + }; + const { data } = (await api.getMemoList(memoFind)).data; const memos = data.filter((m) => m.rowStatus !== "ARCHIVED").map((m) => convertResponseModelMemo(m)); store.dispatch(setMemos(memos)); @@ -25,7 +28,11 @@ const memoService = { }, fetchArchivedMemos: async () => { - const { data } = (await api.getArchivedMemoList(getUserIdFromPath())).data; + const memoFind: MemoFind = { + creatorId: userService.getCurrentUserId(), + rowStatus: "ARCHIVED", + }; + const { data } = (await api.getMemoList(memoFind)).data; const archivedMemos = data.map((m) => { return convertResponseModelMemo(m); }); @@ -43,7 +50,10 @@ const memoService = { }, updateTagsState: async () => { - const { data } = (await api.getTagList(getUserIdFromPath())).data; + const tagFind: TagFind = { + creatorId: userService.getCurrentUserId(), + }; + const { data } = (await api.getTagList(tagFind)).data; store.dispatch(setTags(data)); }, diff --git a/web/src/services/shortcutService.ts b/web/src/services/shortcutService.ts index 9a0af527..a39b830e 100644 --- a/web/src/services/shortcutService.ts +++ b/web/src/services/shortcutService.ts @@ -1,7 +1,7 @@ import * as api from "../helpers/api"; import store from "../store/"; import { createShortcut, deleteShortcut, patchShortcut, setShortcuts } from "../store/modules/shortcut"; -import { getUserIdFromPath } from "./userService"; +import userService from "./userService"; const convertResponseModelShortcut = (shortcut: Shortcut): Shortcut => { return { @@ -17,7 +17,10 @@ const shortcutService = { }, getMyAllShortcuts: async () => { - const { data } = (await api.getShortcutList(getUserIdFromPath())).data; + const shortcutFind: ShortcutFind = { + creatorId: userService.getCurrentUserId(), + }; + const { data } = (await api.getShortcutList(shortcutFind)).data; const shortcuts = data.map((s) => convertResponseModelShortcut(s)); store.dispatch(setShortcuts(shortcuts)); }, diff --git a/web/src/services/userService.ts b/web/src/services/userService.ts index 74ec1298..3b0f0e85 100644 --- a/web/src/services/userService.ts +++ b/web/src/services/userService.ts @@ -1,3 +1,4 @@ +import { isUndefined } from "lodash-es"; import { locationService } from "."; import * as api from "../helpers/api"; import store from "../store"; @@ -11,18 +12,26 @@ const convertResponseModelUser = (user: User): User => { }; }; -export const getUserIdFromPath = () => { - const path = locationService.getState().pathname.slice(3); - return !isNaN(Number(path)) ? Number(path) : undefined; -}; - const userService = { getState: () => { return store.getState().user; }, - isNotVisitor: () => { - return store.getState().user.user !== undefined; + isVisitorMode: () => { + return !isUndefined(userService.getUserIdFromPath()); + }, + + getCurrentUserId: () => { + return userService.getUserIdFromPath() ?? store.getState().user.user?.id; + }, + + getUserIdFromPath: () => { + const userIdRegex = /^\/u\/(\d+).*/; + const result = locationService.getState().pathname.match(userIdRegex); + if (result && result.length === 2) { + return Number(result[1]); + } + return undefined; }, doSignIn: async () => { diff --git a/web/src/store/modules/location.ts b/web/src/store/modules/location.ts index 2c2bdc76..ad3e83b6 100644 --- a/web/src/store/modules/location.ts +++ b/web/src/store/modules/location.ts @@ -20,7 +20,8 @@ interface State { } const getValidPathname = (pathname: string): string => { - if (["/", "/signin"].includes(pathname) || pathname.match(/^\/u\/(\d+)/)) { + const userPageUrlRegex = /^\/u\/\d+.*/; + if (["/", "/signin"].includes(pathname) || userPageUrlRegex.test(pathname)) { return pathname; } else { return "/"; diff --git a/web/src/types/modules/memo.d.ts b/web/src/types/modules/memo.d.ts index 63fbf979..058eceac 100644 --- a/web/src/types/modules/memo.d.ts +++ b/web/src/types/modules/memo.d.ts @@ -22,3 +22,8 @@ interface MemoPatch { content?: string; rowStatus?: RowStatus; } + +interface MemoFind { + creatorId?: UserId; + rowStatus?: RowStatus; +} diff --git a/web/src/types/modules/shortcut.d.ts b/web/src/types/modules/shortcut.d.ts index 10f66685..c8ff0685 100644 --- a/web/src/types/modules/shortcut.d.ts +++ b/web/src/types/modules/shortcut.d.ts @@ -3,6 +3,7 @@ type ShortcutId = number; interface Shortcut { id: ShortcutId; + creatorId: UserId; rowStatus: RowStatus; createdTs: TimeStamp; updatedTs: TimeStamp; @@ -22,3 +23,7 @@ interface ShortcutPatch { payload?: string; rowStatus?: RowStatus; } + +interface ShortcutFind { + creatorId?: UserId; +} diff --git a/web/src/types/modules/tag.d.ts b/web/src/types/modules/tag.d.ts new file mode 100644 index 00000000..3e45f16c --- /dev/null +++ b/web/src/types/modules/tag.d.ts @@ -0,0 +1,3 @@ +interface TagFind { + creatorId?: UserId; +} diff --git a/web/yarn.lock b/web/yarn.lock index 8d2cb10c..0105138c 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -358,6 +358,11 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== +"@types/qs@^6.9.7": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + "@types/react-dom@^18.0.4": version "18.0.4" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.4.tgz#dcbcadb277bcf6c411ceff70069424c57797d375" @@ -1988,6 +1993,13 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +qs@^6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"