Unverified Commit b787d1c7 authored by Zisu Zhang's avatar Zisu Zhang Committed by GitHub

feat: support disable change username and nickname (#3911)

* feat: support disable change username and nickname

* chore: update UX
parent 6f3d5762
This diff is collapsed.
...@@ -50,6 +50,11 @@ message WorkspaceGeneralSetting { ...@@ -50,6 +50,11 @@ message WorkspaceGeneralSetting {
// 0: Sunday, 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday // 0: Sunday, 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday
// Default is Sunday. // Default is Sunday.
int32 week_start_day_offset = 6; int32 week_start_day_offset = 6;
// disallow_change_username disallows changing username.
bool disallow_change_username = 7;
// disallow_change_nickname disallows changing nickname.
bool disallow_change_nickname = 8;
} }
message WorkspaceCustomProfile { message WorkspaceCustomProfile {
......
This diff is collapsed.
...@@ -45,6 +45,11 @@ message WorkspaceGeneralSetting { ...@@ -45,6 +45,11 @@ message WorkspaceGeneralSetting {
// 0: Sunday, 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday // 0: Sunday, 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday
// Default is Sunday. // Default is Sunday.
int32 week_start_day_offset = 6; int32 week_start_day_offset = 6;
// disallow_change_username disallows changing username.
bool disallow_change_username = 7;
// disallow_change_nickname disallows changing nickname.
bool disallow_change_nickname = 8;
} }
message WorkspaceCustomProfile { message WorkspaceCustomProfile {
......
...@@ -166,6 +166,11 @@ func (s *APIV1Service) CreateUser(ctx context.Context, request *v1pb.CreateUserR ...@@ -166,6 +166,11 @@ func (s *APIV1Service) CreateUser(ctx context.Context, request *v1pb.CreateUserR
} }
func (s *APIV1Service) UpdateUser(ctx context.Context, request *v1pb.UpdateUserRequest) (*v1pb.User, error) { func (s *APIV1Service) UpdateUser(ctx context.Context, request *v1pb.UpdateUserRequest) (*v1pb.User, error) {
workspaceGeneralSetting, err := s.Store.GetWorkspaceGeneralSetting(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, fmt.Sprintf("failed to get workspace general setting, err: %s", err))
}
userID, err := ExtractUserIDFromName(request.User.Name) userID, err := ExtractUserIDFromName(request.User.Name)
if err != nil { if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid user name: %v", err) return nil, status.Errorf(codes.InvalidArgument, "invalid user name: %v", err)
...@@ -196,11 +201,17 @@ func (s *APIV1Service) UpdateUser(ctx context.Context, request *v1pb.UpdateUserR ...@@ -196,11 +201,17 @@ func (s *APIV1Service) UpdateUser(ctx context.Context, request *v1pb.UpdateUserR
} }
for _, field := range request.UpdateMask.Paths { for _, field := range request.UpdateMask.Paths {
if field == "username" { if field == "username" {
if workspaceGeneralSetting.DisallowChangeUsername {
return nil, status.Errorf(codes.PermissionDenied, "permission denied: disallow change username")
}
if !util.UIDMatcher.MatchString(strings.ToLower(request.User.Username)) { if !util.UIDMatcher.MatchString(strings.ToLower(request.User.Username)) {
return nil, status.Errorf(codes.InvalidArgument, "invalid username: %s", request.User.Username) return nil, status.Errorf(codes.InvalidArgument, "invalid username: %s", request.User.Username)
} }
update.Username = &request.User.Username update.Username = &request.User.Username
} else if field == "nickname" { } else if field == "nickname" {
if workspaceGeneralSetting.DisallowChangeNickname {
return nil, status.Errorf(codes.PermissionDenied, "permission denied: disallow change nickname")
}
update.Nickname = &request.User.Nickname update.Nickname = &request.User.Nickname
} else if field == "email" { } else if field == "email" {
update.Email = &request.User.Email update.Email = &request.User.Email
......
...@@ -137,6 +137,8 @@ func convertWorkspaceGeneralSettingFromStore(setting *storepb.WorkspaceGeneralSe ...@@ -137,6 +137,8 @@ func convertWorkspaceGeneralSettingFromStore(setting *storepb.WorkspaceGeneralSe
AdditionalScript: setting.AdditionalScript, AdditionalScript: setting.AdditionalScript,
AdditionalStyle: setting.AdditionalStyle, AdditionalStyle: setting.AdditionalStyle,
WeekStartDayOffset: setting.WeekStartDayOffset, WeekStartDayOffset: setting.WeekStartDayOffset,
DisallowChangeUsername: setting.DisallowChangeUsername,
DisallowChangeNickname: setting.DisallowChangeNickname,
} }
if setting.CustomProfile != nil { if setting.CustomProfile != nil {
generalSetting.CustomProfile = &v1pb.WorkspaceCustomProfile{ generalSetting.CustomProfile = &v1pb.WorkspaceCustomProfile{
...@@ -160,6 +162,8 @@ func convertWorkspaceGeneralSettingToStore(setting *v1pb.WorkspaceGeneralSetting ...@@ -160,6 +162,8 @@ func convertWorkspaceGeneralSettingToStore(setting *v1pb.WorkspaceGeneralSetting
AdditionalScript: setting.AdditionalScript, AdditionalScript: setting.AdditionalScript,
AdditionalStyle: setting.AdditionalStyle, AdditionalStyle: setting.AdditionalStyle,
WeekStartDayOffset: setting.WeekStartDayOffset, WeekStartDayOffset: setting.WeekStartDayOffset,
DisallowChangeUsername: setting.DisallowChangeUsername,
DisallowChangeNickname: setting.DisallowChangeNickname,
} }
if setting.CustomProfile != nil { if setting.CustomProfile != nil {
generalSetting.CustomProfile = &storepb.WorkspaceCustomProfile{ generalSetting.CustomProfile = &storepb.WorkspaceCustomProfile{
......
...@@ -113,6 +113,20 @@ const WorkspaceSection = () => { ...@@ -113,6 +113,20 @@ const WorkspaceSection = () => {
onChange={(event) => updatePartialSetting({ disallowPasswordAuth: event.target.checked })} onChange={(event) => updatePartialSetting({ disallowPasswordAuth: event.target.checked })}
/> />
</div> </div>
<div className="w-full flex flex-row justify-between items-center">
<span>Disallow Change Username</span>
<Switch
checked={workspaceGeneralSetting.disallowChangeUsername}
onChange={(event) => updatePartialSetting({ disallowChangeUsername: event.target.checked })}
/>
</div>
<div className="w-full flex flex-row justify-between items-center">
<span>Disallow Change Nickname</span>
<Switch
checked={workspaceGeneralSetting.disallowChangeNickname}
onChange={(event) => updatePartialSetting({ disallowChangeNickname: event.target.checked })}
/>
</div>
<div className="w-full flex flex-row justify-between items-center"> <div className="w-full flex flex-row justify-between items-center">
<span className="truncate">Week start day</span> <span className="truncate">Week start day</span>
<Select <Select
......
...@@ -5,8 +5,9 @@ import { useState } from "react"; ...@@ -5,8 +5,9 @@ import { useState } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import { convertFileToBase64 } from "@/helpers/utils"; import { convertFileToBase64 } from "@/helpers/utils";
import useCurrentUser from "@/hooks/useCurrentUser"; import useCurrentUser from "@/hooks/useCurrentUser";
import { userNamePrefix, useUserStore } from "@/store/v1"; import { userNamePrefix, useUserStore, useWorkspaceSettingStore } from "@/store/v1";
import { User as UserPb } from "@/types/proto/api/v1/user_service"; import { User as UserPb } from "@/types/proto/api/v1/user_service";
import { WorkspaceGeneralSetting, WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import { generateDialog } from "./Dialog"; import { generateDialog } from "./Dialog";
import UserAvatar from "./UserAvatar"; import UserAvatar from "./UserAvatar";
...@@ -32,6 +33,9 @@ const UpdateAccountDialog: React.FC<Props> = ({ destroy }: Props) => { ...@@ -32,6 +33,9 @@ const UpdateAccountDialog: React.FC<Props> = ({ destroy }: Props) => {
email: currentUser.email, email: currentUser.email,
description: currentUser.description, description: currentUser.description,
}); });
const workspaceSettingStore = useWorkspaceSettingStore();
const workspaceGeneralSetting =
workspaceSettingStore.getWorkspaceSettingByKey(WorkspaceSettingKey.GENERAL)?.generalSetting || WorkspaceGeneralSetting.fromPartial({});
const handleCloseBtnClick = () => { const handleCloseBtnClick = () => {
destroy(); destroy();
...@@ -168,12 +172,22 @@ const UpdateAccountDialog: React.FC<Props> = ({ destroy }: Props) => { ...@@ -168,12 +172,22 @@ const UpdateAccountDialog: React.FC<Props> = ({ destroy }: Props) => {
{t("common.username")} {t("common.username")}
<span className="text-sm text-gray-400 ml-1">({t("setting.account-section.username-note")})</span> <span className="text-sm text-gray-400 ml-1">({t("setting.account-section.username-note")})</span>
</p> </p>
<Input className="w-full" value={state.username} onChange={handleUsernameChanged} /> <Input
className="w-full"
value={state.username}
onChange={handleUsernameChanged}
disabled={workspaceGeneralSetting.disallowChangeUsername}
/>
<p className="text-sm"> <p className="text-sm">
{t("common.nickname")} {t("common.nickname")}
<span className="text-sm text-gray-400 ml-1">({t("setting.account-section.nickname-note")})</span> <span className="text-sm text-gray-400 ml-1">({t("setting.account-section.nickname-note")})</span>
</p> </p>
<Input className="w-full" value={state.nickname} onChange={handleNicknameChanged} /> <Input
className="w-full"
value={state.nickname}
onChange={handleNicknameChanged}
disabled={workspaceGeneralSetting.disallowChangeNickname}
/>
<p className="text-sm"> <p className="text-sm">
{t("common.email")} {t("common.email")}
<span className="text-sm text-gray-400 ml-1">({t("setting.account-section.email-note")})</span> <span className="text-sm text-gray-400 ml-1">({t("setting.account-section.email-note")})</span>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment