diff --git a/server/server_account.go b/server/server_account.go index de5a41d5..6efb2f43 100644 --- a/server/server_account.go +++ b/server/server_account.go @@ -85,6 +85,7 @@ func (s *Server) handleAccountGet(w http.ResponseWriter, r *http.Request, v *vis response.Username = u.Name response.Role = string(u.Role) response.SyncTopic = u.SyncTopic + response.Provisioned = u.Provisioned if u.Prefs != nil { if u.Prefs.Language != nil { response.Language = *u.Prefs.Language @@ -139,11 +140,12 @@ func (s *Server) handleAccountGet(w http.ResponseWriter, r *http.Request, v *vis lastOrigin = t.LastOrigin.String() } response.Tokens = append(response.Tokens, &apiAccountTokenResponse{ - Token: t.Value, - Label: t.Label, - LastAccess: t.LastAccess.Unix(), - LastOrigin: lastOrigin, - Expires: t.Expires.Unix(), + Token: t.Value, + Label: t.Label, + LastAccess: t.LastAccess.Unix(), + LastOrigin: lastOrigin, + Expires: t.Expires.Unix(), + Provisioned: t.Provisioned, }) } } diff --git a/server/types.go b/server/types.go index 65492e46..b8a82883 100644 --- a/server/types.go +++ b/server/types.go @@ -360,11 +360,12 @@ type apiAccountTokenUpdateRequest struct { } type apiAccountTokenResponse struct { - Token string `json:"token"` - Label string `json:"label,omitempty"` - LastAccess int64 `json:"last_access,omitempty"` - LastOrigin string `json:"last_origin,omitempty"` - Expires int64 `json:"expires,omitempty"` // Unix timestamp + Token string `json:"token"` + Label string `json:"label,omitempty"` + LastAccess int64 `json:"last_access,omitempty"` + LastOrigin string `json:"last_origin,omitempty"` + Expires int64 `json:"expires,omitempty"` // Unix timestamp + Provisioned bool `json:"provisioned,omitempty"` // True if this token was provisioned by the server config } type apiAccountPhoneNumberVerifyRequest struct { @@ -426,6 +427,7 @@ type apiAccountResponse struct { Username string `json:"username"` Role string `json:"role,omitempty"` SyncTopic string `json:"sync_topic,omitempty"` + Provisioned bool `json:"provisioned,omitempty"` Language string `json:"language,omitempty"` Notification *user.NotificationPrefs `json:"notification,omitempty"` Subscriptions []*user.Subscription `json:"subscriptions,omitempty"` diff --git a/web/public/static/langs/en.json b/web/public/static/langs/en.json index 3ad04ea7..1dbf763d 100644 --- a/web/public/static/langs/en.json +++ b/web/public/static/langs/en.json @@ -212,6 +212,7 @@ "account_basics_phone_numbers_dialog_check_verification_button": "Confirm code", "account_basics_phone_numbers_dialog_channel_sms": "SMS", "account_basics_phone_numbers_dialog_channel_call": "Call", + "account_basics_cannot_edit_or_delete_provisioned_user": "A provisioned user cannot be edited or deleted from the web app", "account_usage_title": "Usage", "account_usage_of_limit": "of {{limit}}", "account_usage_unlimited": "Unlimited", @@ -291,6 +292,7 @@ "account_tokens_table_current_session": "Current browser session", "account_tokens_table_copied_to_clipboard": "Access token copied", "account_tokens_table_cannot_delete_or_edit": "Cannot edit or delete current session token", + "account_tokens_table_cannot_delete_or_edit_provisioned_token": "Cannot edit or delete provisioned token", "account_tokens_table_create_token_button": "Create access token", "account_tokens_table_last_origin_tooltip": "From IP address {{ip}}, click to lookup", "account_tokens_dialog_title_create": "Create access token", diff --git a/web/src/app/errors.js b/web/src/app/errors.js index 0f39d705..28f49af1 100644 --- a/web/src/app/errors.js +++ b/web/src/app/errors.js @@ -31,14 +31,6 @@ export class TopicReservedError extends Error { } } -export class ProvisionedUserPasswordError extends Error { - static CODE = 40905; // errHTTPConflictTopicReserved - - constructor() { - super("Cannot change the password of a provisioned user"); - } -} - export class AccountCreateLimitReachedError extends Error { static CODE = 42906; // errHTTPTooManyRequestsLimitAccountCreation diff --git a/web/src/components/Account.jsx b/web/src/components/Account.jsx index 319353df..65aa38e8 100644 --- a/web/src/components/Account.jsx +++ b/web/src/components/Account.jsx @@ -100,15 +100,13 @@ const Username = () => {
{session.username()} - {account?.role === Role.ADMIN ? ( + {account?.role === Role.ADMIN && ( <> {" "} 👑 - ) : ( - "" )}
@@ -119,6 +117,7 @@ const ChangePassword = () => { const { t } = useTranslation(); const [dialogKey, setDialogKey] = useState(0); const [dialogOpen, setDialogOpen] = useState(false); + const { account } = useContext(AccountContext); const labelId = "prefChangePassword"; const handleDialogOpen = () => { @@ -136,9 +135,19 @@ const ChangePassword = () => { ⬤⬤⬤⬤⬤⬤⬤⬤⬤⬤ - - - + {!account?.provisioned ? ( + + + + ) : ( + + + + + + + + )} @@ -888,7 +897,7 @@ const TokensTable = (props) => { - {token.token !== session.token() && ( + {token.token !== session.token() && !token.provisioned && ( <> handleEditClick(token)} aria-label={t("account_tokens_dialog_title_edit")}> @@ -910,6 +919,18 @@ const TokensTable = (props) => { )} + {token.provisioned && ( + + + + + + + + + + + )} ))} @@ -1048,6 +1069,7 @@ const DeleteAccount = () => { const { t } = useTranslation(); const [dialogKey, setDialogKey] = useState(0); const [dialogOpen, setDialogOpen] = useState(false); + const { account } = useContext(AccountContext); const handleDialogOpen = () => { setDialogKey((prev) => prev + 1); @@ -1061,9 +1083,19 @@ const DeleteAccount = () => { return (
- + {!account?.provisioned ? ( + + ) : ( + + + + + + )}