fix: update workspace general setting

pull/2998/head
Steven 1 year ago
parent ce133ad69b
commit e602aeecc1

@ -5,9 +5,7 @@ import (
"net/http"
"github.com/labstack/echo/v4"
"go.uber.org/zap"
"github.com/usememos/memos/internal/log"
"github.com/usememos/memos/server/profile"
"github.com/usememos/memos/store"
)
@ -18,18 +16,12 @@ type SystemStatus struct {
DBSize int64 `json:"dbSize"`
// System settings
// Allow sign up.
AllowSignUp bool `json:"allowSignUp"`
// Disable password login.
DisablePasswordLogin bool `json:"disablePasswordLogin"`
// Disable public memos.
DisablePublicMemos bool `json:"disablePublicMemos"`
// Max upload size.
MaxUploadSizeMiB int `json:"maxUploadSizeMiB"`
// Additional style.
AdditionalStyle string `json:"additionalStyle"`
// Additional script.
AdditionalScript string `json:"additionalScript"`
// Customized server profile, including server name and external url.
CustomizedProfile CustomizedProfile `json:"customizedProfile"`
// Storage service ID.
@ -74,8 +66,6 @@ func (s *APIV1Service) GetSystemStatus(c echo.Context) error {
Mode: s.Profile.Mode,
Version: s.Profile.Version,
},
// Allow sign up by default.
AllowSignUp: true,
MaxUploadSizeMiB: 32,
CustomizedProfile: CustomizedProfile{
Name: "Memos",
@ -101,10 +91,7 @@ func (s *APIV1Service) GetSystemStatus(c echo.Context) error {
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find workspace general setting").SetInternal(err)
}
systemStatus.AllowSignUp = !workspaceGeneralSetting.DisallowSignup
systemStatus.DisablePasswordLogin = workspaceGeneralSetting.DisallowPasswordLogin
systemStatus.AdditionalStyle = workspaceGeneralSetting.AdditionalStyle
systemStatus.AdditionalScript = workspaceGeneralSetting.AdditionalScript
systemSettingList, err := s.Store.ListWorkspaceSettings(ctx, &store.FindWorkspaceSetting{})
if err != nil {
@ -140,7 +127,7 @@ func (s *APIV1Service) GetSystemStatus(c echo.Context) error {
case SystemSettingMemoDisplayWithUpdatedTsName.String():
systemStatus.MemoDisplayWithUpdatedTs = baseValue.(bool)
default:
log.Warn("Unknown system setting name", zap.String("setting name", systemSetting.Name))
// Skip unknown system setting.
}
}

@ -3,20 +3,20 @@ package v2
import "strings"
var authenticationAllowlistMethods = map[string]bool{
"/memos.api.v2.WorkspaceService/GetWorkspaceProfile": true,
"/memos.api.v2.WorkspaceService/GetWorkspaceSetting": true,
"/memos.api.v2.AuthService/GetAuthStatus": true,
"/memos.api.v2.AuthService/SignIn": true,
"/memos.api.v2.AuthService/SignInWithSSO": true,
"/memos.api.v2.AuthService/SignOut": true,
"/memos.api.v2.AuthService/SignUp": true,
"/memos.api.v2.UserService/GetUser": true,
"/memos.api.v2.MemoService/ListMemos": true,
"/memos.api.v2.MemoService/GetMemo": true,
"/memos.api.v2.MemoService/GetMemoByName": true,
"/memos.api.v2.MemoService/ListMemoResources": true,
"/memos.api.v2.MemoService/ListMemoRelations": true,
"/memos.api.v2.MemoService/ListMemoComments": true,
"/memos.api.v2.WorkspaceService/GetWorkspaceProfile": true,
"/memos.api.v2.WorkspaceSettingService/GetWorkspaceSetting": true,
"/memos.api.v2.AuthService/GetAuthStatus": true,
"/memos.api.v2.AuthService/SignIn": true,
"/memos.api.v2.AuthService/SignInWithSSO": true,
"/memos.api.v2.AuthService/SignOut": true,
"/memos.api.v2.AuthService/SignUp": true,
"/memos.api.v2.UserService/GetUser": true,
"/memos.api.v2.MemoService/ListMemos": true,
"/memos.api.v2.MemoService/GetMemo": true,
"/memos.api.v2.MemoService/GetMemoByName": true,
"/memos.api.v2.MemoService/ListMemoResources": true,
"/memos.api.v2.MemoService/ListMemoRelations": true,
"/memos.api.v2.MemoService/ListMemoComments": true,
}
// isUnauthorizeAllowedMethod returns whether the method is exempted from authentication.

@ -1,5 +1,4 @@
import { useColorScheme } from "@mui/joy";
import mermaid from "mermaid";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { Outlet } from "react-router-dom";
@ -7,19 +6,22 @@ import storage from "./helpers/storage";
import { getSystemColorScheme } from "./helpers/utils";
import useNavigateTo from "./hooks/useNavigateTo";
import { useGlobalStore } from "./store/module";
import { useUserStore } from "./store/v1";
import { useUserStore, useWorkspaceSettingStore } from "./store/v1";
import { WorkspaceGeneralSetting, WorkspaceSettingKey } from "./types/proto/store/workspace_setting";
const App = () => {
const { i18n } = useTranslation();
const navigateTo = useNavigateTo();
const { mode, setMode } = useColorScheme();
const globalStore = useGlobalStore();
const workspaceSettingStore = useWorkspaceSettingStore();
const userStore = useUserStore();
const [loading, setLoading] = useState(true);
const { appearance, locale, systemStatus } = globalStore.state;
const userSetting = userStore.userSetting;
mermaid.initialize({ startOnLoad: false, theme: mode });
const workspaceGeneralSetting =
workspaceSettingStore.getWorkspaceSettingByKey(WorkspaceSettingKey.WORKSPACE_SETTING_GENERAL).generalSetting ||
WorkspaceGeneralSetting.fromPartial({});
// Redirect to sign up page if no host.
useEffect(() => {
@ -30,6 +32,7 @@ const App = () => {
useEffect(() => {
const initialState = async () => {
await workspaceSettingStore.fetchWorkspaceSetting(WorkspaceSettingKey.WORKSPACE_SETTING_GENERAL);
try {
await userStore.fetchCurrentUser();
} catch (error) {
@ -61,21 +64,21 @@ const App = () => {
}, []);
useEffect(() => {
if (systemStatus.additionalStyle) {
if (workspaceGeneralSetting.additionalStyle) {
const styleEl = document.createElement("style");
styleEl.innerHTML = systemStatus.additionalStyle;
styleEl.innerHTML = workspaceGeneralSetting.additionalStyle;
styleEl.setAttribute("type", "text/css");
document.body.insertAdjacentElement("beforeend", styleEl);
}
}, [systemStatus.additionalStyle]);
}, [workspaceGeneralSetting.additionalStyle]);
useEffect(() => {
if (systemStatus.additionalScript) {
if (workspaceGeneralSetting.additionalScript) {
const scriptEl = document.createElement("script");
scriptEl.innerHTML = systemStatus.additionalScript;
scriptEl.innerHTML = workspaceGeneralSetting.additionalScript;
document.head.appendChild(scriptEl);
}
}, [systemStatus.additionalScript]);
}, [workspaceGeneralSetting.additionalScript]);
// Dynamic update metadata with customized profile.
useEffect(() => {

@ -1,3 +1,4 @@
import { useColorScheme } from "@mui/joy";
import mermaid from "mermaid";
import { useEffect, useRef } from "react";
@ -6,14 +7,16 @@ interface Props {
}
const MermaidBlock: React.FC<Props> = ({ content }: Props) => {
const { mode } = useColorScheme();
const mermaidDockBlock = useRef<null>(null);
mermaid.initialize({ startOnLoad: false, theme: mode });
useEffect(() => {
if (!mermaidDockBlock.current) {
return;
}
// Render mermaid when mounted
// Render mermaid when mounted.
mermaid.run({
nodes: [mermaidDockBlock.current],
});

@ -72,13 +72,14 @@ const SystemSection = () => {
};
const handleDisablePasswordLoginChanged = async (value: boolean) => {
setWorkspaceGeneralSetting({ ...workspaceGeneralSetting, disallowPasswordLogin: value });
const setting = { ...workspaceGeneralSetting, disallowPasswordLogin: value };
await workspaceSettingServiceClient.setWorkspaceSetting({
setting: {
name: `${WorkspaceSettingPrefix}${WorkspaceSettingKey.WORKSPACE_SETTING_GENERAL}`,
generalSetting: workspaceGeneralSetting,
generalSetting: setting,
},
});
setWorkspaceGeneralSetting(setting);
};
const handleUpdateCustomizedProfileButtonClick = () => {
@ -223,7 +224,7 @@ const SystemSection = () => {
<p className="font-medium text-gray-700 dark:text-gray-500">{t("common.settings")}</p>
<div className="w-full flex flex-row justify-between items-center">
<span className="normal-text">{t("setting.system-section.allow-user-signup")}</span>
<Switch checked={workspaceGeneralSetting.disallowSignup} onChange={(event) => handleAllowSignUpChanged(event.target.checked)} />
<Switch checked={!workspaceGeneralSetting.disallowSignup} onChange={(event) => handleAllowSignUpChanged(event.target.checked)} />
</div>
<div className="w-full flex flex-row justify-between items-center">
<span className="normal-text">{t("setting.system-section.disable-password-login")}</span>

@ -11,13 +11,16 @@ import { absolutifyLink } from "@/helpers/utils";
import useLoading from "@/hooks/useLoading";
import useNavigateTo from "@/hooks/useNavigateTo";
import { useGlobalStore } from "@/store/module";
import { useUserStore } from "@/store/v1";
import { useUserStore, useWorkspaceSettingStore } from "@/store/v1";
import { WorkspaceGeneralSetting } from "@/types/proto/api/v2/workspace_setting_service";
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { useTranslate } from "@/utils/i18n";
const SignIn = () => {
const t = useTranslate();
const navigateTo = useNavigateTo();
const globalStore = useGlobalStore();
const workspaceSettingStore = useWorkspaceSettingStore();
const userStore = useUserStore();
const actionBtnLoadingState = useLoading(false);
const { appearance, locale, systemStatus } = globalStore.state;
@ -25,8 +28,12 @@ const SignIn = () => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [remember, setRemember] = useState(true);
const disablePasswordLogin = systemStatus.disablePasswordLogin;
const [identityProviderList, setIdentityProviderList] = useState<IdentityProvider[]>([]);
const workspaceGeneralSetting =
workspaceSettingStore.getWorkspaceSettingByKey(WorkspaceSettingKey.WORKSPACE_SETTING_GENERAL).generalSetting ||
WorkspaceGeneralSetting.fromPartial({});
console.log("workspaceGeneralSetting", workspaceGeneralSetting);
useEffect(() => {
const fetchIdentityProviderList = async () => {
@ -112,7 +119,7 @@ const SignIn = () => {
<img className="h-14 w-auto rounded-full shadow" src={systemStatus.customizedProfile.logoUrl} alt="" />
<p className="ml-2 text-5xl text-black opacity-80 dark:text-gray-200">{systemStatus.customizedProfile.name}</p>
</div>
{!disablePasswordLogin && (
{!workspaceGeneralSetting.disallowPasswordLogin && (
<>
<form className="w-full mt-2" onSubmit={handleFormSubmit}>
<div className="flex flex-col justify-start items-start w-full gap-4">
@ -164,7 +171,7 @@ const SignIn = () => {
</Button>
</div>
</form>
{systemStatus.allowSignUp && (
{!workspaceGeneralSetting.disallowSignup && (
<p className="w-full mt-4 text-sm">
<span className="dark:text-gray-500">{t("auth.sign-up-tip")}</span>
<Link to="/auth/signup" className="cursor-pointer ml-2 text-blue-600 hover:underline" unstable_viewTransition>
@ -176,7 +183,7 @@ const SignIn = () => {
)}
{identityProviderList.length > 0 && (
<>
{!disablePasswordLogin && <Divider className="!my-4">{t("common.or")}</Divider>}
{!workspaceGeneralSetting.disallowPasswordLogin && <Divider className="!my-4">{t("common.or")}</Divider>}
<div className="w-full flex flex-col space-y-2">
{identityProviderList.map((identityProvider) => (
<Button

@ -10,12 +10,9 @@ export const initialGlobalState = async () => {
locale: "en" as Locale,
appearance: "system" as Appearance,
systemStatus: {
allowSignUp: false,
disablePasswordLogin: false,
disablePublicMemos: false,
maxUploadSizeMiB: 0,
additionalStyle: "",
additionalScript: "",
memoDisplayWithUpdatedTs: false,
customizedProfile: {
name: "Memos",

@ -17,11 +17,8 @@ const globalSlice = createSlice({
mode: "demo",
version: "",
},
allowSignUp: false,
disablePasswordLogin: false,
disablePublicMemos: false,
additionalStyle: "",
additionalScript: "",
memoDisplayWithUpdatedTs: false,
customizedProfile: {
name: "Memos",

@ -3,3 +3,4 @@ export * from "./memo";
export * from "./inbox";
export * from "./resourceName";
export * from "./resource";
export * from "./workspaceSetting";

@ -0,0 +1,29 @@
import { create } from "zustand";
import { combine } from "zustand/middleware";
import { workspaceSettingServiceClient } from "@/grpcweb";
import { WorkspaceSetting } from "@/types/proto/api/v2/workspace_setting_service";
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { WorkspaceSettingPrefix } from "./resourceName";
interface State {
workspaceSettingByName: Record<string, WorkspaceSetting>;
}
const getDefaultState = (): State => ({
workspaceSettingByName: {},
});
export const useWorkspaceSettingStore = create(
combine(getDefaultState(), (set, get) => ({
fetchWorkspaceSetting: async (key: WorkspaceSettingKey) => {
const { setting } = await workspaceSettingServiceClient.getWorkspaceSetting({ name: `${WorkspaceSettingPrefix}${key}` });
if (!setting) {
throw new Error("Workspace setting not found");
}
set({ workspaceSettingByName: { ...get().workspaceSettingByName, [setting.name]: setting } });
},
getWorkspaceSettingByKey: (key: WorkspaceSettingKey) => {
return get().workspaceSettingByName[`${WorkspaceSettingPrefix}${key}`];
},
})),
);

@ -15,12 +15,9 @@ interface SystemStatus {
host?: User;
profile: Profile;
// System settings
allowSignUp: boolean;
disablePasswordLogin: boolean;
disablePublicMemos: boolean;
maxUploadSizeMiB: number;
additionalStyle: string;
additionalScript: string;
customizedProfile: CustomizedProfile;
storageServiceId: number;
localStoragePath: string;

Loading…
Cancel
Save