Commit 8f51791d authored by Johnny's avatar Johnny

chore: update user setting definition

parent 3b8bfe72
......@@ -403,15 +403,15 @@ message UserSetting {
};
// The name of the user setting.
// Format: users/{user}/settings/{setting}
// Format: users/{user}/settings/{setting}, {setting} is the key for the setting.
// For example, "users/123/settings/GENERAL" for general settings.
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
oneof value {
GeneralSetting general_setting = 2;
SessionsSetting sessions_setting = 3;
AccessTokensSetting access_tokens_setting = 4;
ShortcutsSetting shortcuts_setting = 5;
WebhooksSetting webhooks_setting = 6;
WebhooksSetting webhooks_setting = 5;
}
// Enumeration of user setting keys.
......@@ -423,10 +423,8 @@ message UserSetting {
SESSIONS = 2;
// ACCESS_TOKENS is the key for access tokens.
ACCESS_TOKENS = 3;
// SHORTCUTS is the key for user shortcuts.
SHORTCUTS = 4;
// WEBHOOKS is the key for user webhooks.
WEBHOOKS = 5;
WEBHOOKS = 4;
}
// General user settings configuration.
......@@ -446,81 +444,19 @@ message UserSetting {
// User authentication sessions configuration.
message SessionsSetting {
// List of active user sessions.
repeated Session sessions = 1;
// User session information.
message Session {
// Unique session identifier.
string session_id = 1 [(google.api.field_behavior) = OUTPUT_ONLY];
// Timestamp when the session was created.
google.protobuf.Timestamp create_time = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
// Timestamp when the session was last accessed.
// Used for sliding expiration calculation (last_accessed_time + 2 weeks).
google.protobuf.Timestamp last_accessed_time = 3 [(google.api.field_behavior) = OUTPUT_ONLY];
// Client information associated with this session.
ClientInfo client_info = 4 [(google.api.field_behavior) = OUTPUT_ONLY];
}
// Client information for a session.
message ClientInfo {
// User agent string of the client.
string user_agent = 1 [(google.api.field_behavior) = OUTPUT_ONLY];
// IP address of the client.
string ip_address = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
// Optional. Device type (e.g., "mobile", "desktop", "tablet").
string device_type = 3 [(google.api.field_behavior) = OUTPUT_ONLY];
// Optional. Operating system (e.g., "iOS 17.0", "Windows 11").
string os = 4 [(google.api.field_behavior) = OUTPUT_ONLY];
// Optional. Browser name and version (e.g., "Chrome 119.0").
string browser = 5 [(google.api.field_behavior) = OUTPUT_ONLY];
}
repeated UserSession sessions = 1;
}
// User access tokens configuration.
message AccessTokensSetting {
// List of user access tokens.
repeated AccessToken access_tokens = 1;
// User access token information.
message AccessToken {
// The access token is a JWT token.
// Including expiration time, issuer, etc.
string access_token = 1 [(google.api.field_behavior) = OUTPUT_ONLY];
// A description for the access token.
string description = 2 [(google.api.field_behavior) = OPTIONAL];
}
}
// User shortcuts configuration.
message ShortcutsSetting {
// List of user shortcuts.
repeated Shortcut shortcuts = 1;
// User shortcut definition.
message Shortcut {
// Unique identifier for the shortcut.
string id = 1 [(google.api.field_behavior) = REQUIRED];
// Display title for the shortcut.
string title = 2 [(google.api.field_behavior) = REQUIRED];
// Filter expression for the shortcut.
string filter = 3 [(google.api.field_behavior) = REQUIRED];
}
repeated UserAccessToken access_tokens = 1;
}
// User webhooks configuration.
message WebhooksSetting {
// List of user webhooks.
repeated Webhook webhooks = 1;
// User webhook definition.
message Webhook {
// Unique identifier for the webhook.
string id = 1 [(google.api.field_behavior) = REQUIRED];
// Descriptive title for the webhook.
string title = 2 [(google.api.field_behavior) = REQUIRED];
// The webhook URL endpoint.
string url = 3 [(google.api.field_behavior) = REQUIRED];
}
repeated UserWebhook webhooks = 1;
}
}
......
This diff is collapsed.
......@@ -2256,19 +2256,6 @@ paths:
$ref: '#/components/schemas/Status'
components:
schemas:
AccessTokensSetting_AccessToken:
type: object
properties:
accessToken:
readOnly: true
type: string
description: |-
The access token is a JWT token.
Including expiration time, issuer, etc.
description:
type: string
description: A description for the access token.
description: User access token information.
Activity:
type: object
properties:
......@@ -3344,55 +3331,6 @@ components:
type: integer
description: The total count of matching users.
format: int32
SessionsSetting_ClientInfo:
type: object
properties:
userAgent:
readOnly: true
type: string
description: User agent string of the client.
ipAddress:
readOnly: true
type: string
description: IP address of the client.
deviceType:
readOnly: true
type: string
description: Optional. Device type (e.g., "mobile", "desktop", "tablet").
os:
readOnly: true
type: string
description: Optional. Operating system (e.g., "iOS 17.0", "Windows 11").
browser:
readOnly: true
type: string
description: Optional. Browser name and version (e.g., "Chrome 119.0").
description: Client information for a session.
SessionsSetting_Session:
type: object
properties:
sessionId:
readOnly: true
type: string
description: Unique session identifier.
createTime:
readOnly: true
type: string
description: Timestamp when the session was created.
format: date-time
lastAccessedTime:
readOnly: true
type: string
description: |-
Timestamp when the session was last accessed.
Used for sliding expiration calculation (last_accessed_time + 2 weeks).
format: date-time
clientInfo:
readOnly: true
allOf:
- $ref: '#/components/schemas/SessionsSetting_ClientInfo'
description: Client information associated with this session.
description: User session information.
SetMemoAttachmentsRequest:
required:
- name
......@@ -3441,23 +3379,6 @@ components:
filter:
type: string
description: The filter expression for the shortcut.
ShortcutsSetting_Shortcut:
required:
- id
- title
- filter
type: object
properties:
id:
type: string
description: Unique identifier for the shortcut.
title:
type: string
description: Display title for the shortcut.
filter:
type: string
description: Filter expression for the shortcut.
description: User shortcut definition.
SpoilerNode:
type: object
properties:
......@@ -3738,15 +3659,14 @@ components:
type: string
description: |-
The name of the user setting.
Format: users/{user}/settings/{setting}
Format: users/{user}/settings/{setting}, {setting} is the key for the setting.
For example, "users/123/settings/GENERAL" for general settings.
generalSetting:
$ref: '#/components/schemas/UserSetting_GeneralSetting'
sessionsSetting:
$ref: '#/components/schemas/UserSetting_SessionsSetting'
accessTokensSetting:
$ref: '#/components/schemas/UserSetting_AccessTokensSetting'
shortcutsSetting:
$ref: '#/components/schemas/UserSetting_ShortcutsSetting'
webhooksSetting:
$ref: '#/components/schemas/UserSetting_WebhooksSetting'
description: User settings message
......@@ -3756,7 +3676,7 @@ components:
accessTokens:
type: array
items:
$ref: '#/components/schemas/AccessTokensSetting_AccessToken'
$ref: '#/components/schemas/UserAccessToken'
description: List of user access tokens.
description: User access tokens configuration.
UserSetting_GeneralSetting:
......@@ -3784,25 +3704,16 @@ components:
sessions:
type: array
items:
$ref: '#/components/schemas/SessionsSetting_Session'
$ref: '#/components/schemas/UserSession'
description: List of active user sessions.
description: User authentication sessions configuration.
UserSetting_ShortcutsSetting:
type: object
properties:
shortcuts:
type: array
items:
$ref: '#/components/schemas/ShortcutsSetting_Shortcut'
description: List of user shortcuts.
description: User shortcuts configuration.
UserSetting_WebhooksSetting:
type: object
properties:
webhooks:
type: array
items:
$ref: '#/components/schemas/WebhooksSetting_Webhook'
$ref: '#/components/schemas/UserWebhook'
description: List of user webhooks.
description: User webhooks configuration.
UserStats:
......@@ -3880,23 +3791,6 @@ components:
description: The last update time of the webhook.
format: date-time
description: UserWebhook represents a webhook owned by a user.
WebhooksSetting_Webhook:
required:
- id
- title
- url
type: object
properties:
id:
type: string
description: Unique identifier for the webhook.
title:
type: string
description: Descriptive title for the webhook.
url:
type: string
description: The webhook URL endpoint.
description: User webhook definition.
WorkspaceProfile:
type: object
properties:
......
......@@ -1067,15 +1067,13 @@ func ExtractUserIDAndSettingKeyFromName(name string) (int32, string, error) {
// convertSettingKeyToStore converts API setting key to store enum.
func convertSettingKeyToStore(key string) (storepb.UserSetting_Key, error) {
switch key {
case "general":
case v1pb.UserSetting_Key_name[int32(v1pb.UserSetting_GENERAL)]:
return storepb.UserSetting_GENERAL, nil
case "sessions":
case v1pb.UserSetting_Key_name[int32(v1pb.UserSetting_SESSIONS)]:
return storepb.UserSetting_SESSIONS, nil
case "access-tokens":
case v1pb.UserSetting_Key_name[int32(v1pb.UserSetting_ACCESS_TOKENS)]:
return storepb.UserSetting_ACCESS_TOKENS, nil
case "shortcuts":
return storepb.UserSetting_SHORTCUTS, nil
case "webhooks":
case v1pb.UserSetting_Key_name[int32(v1pb.UserSetting_WEBHOOKS)]:
return storepb.UserSetting_WEBHOOKS, nil
default:
return storepb.UserSetting_KEY_UNSPECIFIED, errors.Errorf("unknown setting key: %s", key)
......@@ -1086,15 +1084,15 @@ func convertSettingKeyToStore(key string) (storepb.UserSetting_Key, error) {
func convertSettingKeyFromStore(key storepb.UserSetting_Key) string {
switch key {
case storepb.UserSetting_GENERAL:
return "general"
return v1pb.UserSetting_Key_name[int32(v1pb.UserSetting_GENERAL)]
case storepb.UserSetting_SESSIONS:
return "sessions"
return v1pb.UserSetting_Key_name[int32(v1pb.UserSetting_SESSIONS)]
case storepb.UserSetting_ACCESS_TOKENS:
return "access-tokens"
return v1pb.UserSetting_Key_name[int32(v1pb.UserSetting_ACCESS_TOKENS)]
case storepb.UserSetting_SHORTCUTS:
return "shortcuts"
return "SHORTCUTS" // Not defined in API proto
case storepb.UserSetting_WEBHOOKS:
return "webhooks"
return v1pb.UserSetting_Key_name[int32(v1pb.UserSetting_WEBHOOKS)]
default:
return "unknown"
}
......@@ -1117,25 +1115,19 @@ func convertUserSettingFromStore(storeSetting *storepb.UserSetting, userID int32
case storepb.UserSetting_SESSIONS:
setting.Value = &v1pb.UserSetting_SessionsSetting_{
SessionsSetting: &v1pb.UserSetting_SessionsSetting{
Sessions: []*v1pb.UserSetting_SessionsSetting_Session{},
Sessions: []*v1pb.UserSession{},
},
}
case storepb.UserSetting_ACCESS_TOKENS:
setting.Value = &v1pb.UserSetting_AccessTokensSetting_{
AccessTokensSetting: &v1pb.UserSetting_AccessTokensSetting{
AccessTokens: []*v1pb.UserSetting_AccessTokensSetting_AccessToken{},
},
}
case storepb.UserSetting_SHORTCUTS:
setting.Value = &v1pb.UserSetting_ShortcutsSetting_{
ShortcutsSetting: &v1pb.UserSetting_ShortcutsSetting{
Shortcuts: []*v1pb.UserSetting_ShortcutsSetting_Shortcut{},
AccessTokens: []*v1pb.UserAccessToken{},
},
}
case storepb.UserSetting_WEBHOOKS:
setting.Value = &v1pb.UserSetting_WebhooksSetting_{
WebhooksSetting: &v1pb.UserSetting_WebhooksSetting{
Webhooks: []*v1pb.UserSetting_WebhooksSetting_Webhook{},
Webhooks: []*v1pb.UserWebhook{},
},
}
}
......@@ -1165,13 +1157,14 @@ func convertUserSettingFromStore(storeSetting *storepb.UserSetting, userID int32
}
case storepb.UserSetting_SESSIONS:
sessions := storeSetting.GetSessions()
apiSessions := make([]*v1pb.UserSetting_SessionsSetting_Session, 0, len(sessions.Sessions))
apiSessions := make([]*v1pb.UserSession, 0, len(sessions.Sessions))
for _, session := range sessions.Sessions {
apiSession := &v1pb.UserSetting_SessionsSetting_Session{
apiSession := &v1pb.UserSession{
Name: fmt.Sprintf("users/%d/sessions/%s", userID, session.SessionId),
SessionId: session.SessionId,
CreateTime: session.CreateTime,
LastAccessedTime: session.LastAccessedTime,
ClientInfo: &v1pb.UserSetting_SessionsSetting_ClientInfo{
ClientInfo: &v1pb.UserSession_ClientInfo{
UserAgent: session.ClientInfo.UserAgent,
IpAddress: session.ClientInfo.IpAddress,
DeviceType: session.ClientInfo.DeviceType,
......@@ -1188,9 +1181,10 @@ func convertUserSettingFromStore(storeSetting *storepb.UserSetting, userID int32
}
case storepb.UserSetting_ACCESS_TOKENS:
accessTokens := storeSetting.GetAccessTokens()
apiTokens := make([]*v1pb.UserSetting_AccessTokensSetting_AccessToken, 0, len(accessTokens.AccessTokens))
apiTokens := make([]*v1pb.UserAccessToken, 0, len(accessTokens.AccessTokens))
for _, token := range accessTokens.AccessTokens {
apiToken := &v1pb.UserSetting_AccessTokensSetting_AccessToken{
apiToken := &v1pb.UserAccessToken{
Name: fmt.Sprintf("users/%d/accessTokens/%s", userID, token.AccessToken),
AccessToken: token.AccessToken,
Description: token.Description,
}
......@@ -1201,30 +1195,14 @@ func convertUserSettingFromStore(storeSetting *storepb.UserSetting, userID int32
AccessTokens: apiTokens,
},
}
case storepb.UserSetting_SHORTCUTS:
shortcuts := storeSetting.GetShortcuts()
apiShortcuts := make([]*v1pb.UserSetting_ShortcutsSetting_Shortcut, 0, len(shortcuts.Shortcuts))
for _, shortcut := range shortcuts.Shortcuts {
apiShortcut := &v1pb.UserSetting_ShortcutsSetting_Shortcut{
Id: shortcut.Id,
Title: shortcut.Title,
Filter: shortcut.Filter,
}
apiShortcuts = append(apiShortcuts, apiShortcut)
}
setting.Value = &v1pb.UserSetting_ShortcutsSetting_{
ShortcutsSetting: &v1pb.UserSetting_ShortcutsSetting{
Shortcuts: apiShortcuts,
},
}
case storepb.UserSetting_WEBHOOKS:
webhooks := storeSetting.GetWebhooks()
apiWebhooks := make([]*v1pb.UserSetting_WebhooksSetting_Webhook, 0, len(webhooks.Webhooks))
apiWebhooks := make([]*v1pb.UserWebhook, 0, len(webhooks.Webhooks))
for _, webhook := range webhooks.Webhooks {
apiWebhook := &v1pb.UserSetting_WebhooksSetting_Webhook{
Id: webhook.Id,
Title: webhook.Title,
Url: webhook.Url,
apiWebhook := &v1pb.UserWebhook{
Name: fmt.Sprintf("users/%d/webhooks/%s", userID, webhook.Id),
Url: webhook.Url,
DisplayName: webhook.Title,
}
apiWebhooks = append(apiWebhooks, apiWebhook)
}
......@@ -1303,32 +1281,13 @@ func convertUserSettingToStore(apiSetting *v1pb.UserSetting, userID int32, key s
} else {
return nil, errors.Errorf("access tokens setting is required")
}
case storepb.UserSetting_SHORTCUTS:
if shortcuts := apiSetting.GetShortcutsSetting(); shortcuts != nil {
storeShortcuts := make([]*storepb.ShortcutsUserSetting_Shortcut, 0, len(shortcuts.Shortcuts))
for _, shortcut := range shortcuts.Shortcuts {
storeShortcut := &storepb.ShortcutsUserSetting_Shortcut{
Id: shortcut.Id,
Title: shortcut.Title,
Filter: shortcut.Filter,
}
storeShortcuts = append(storeShortcuts, storeShortcut)
}
storeSetting.Value = &storepb.UserSetting_Shortcuts{
Shortcuts: &storepb.ShortcutsUserSetting{
Shortcuts: storeShortcuts,
},
}
} else {
return nil, errors.Errorf("shortcuts setting is required")
}
case storepb.UserSetting_WEBHOOKS:
if webhooks := apiSetting.GetWebhooksSetting(); webhooks != nil {
storeWebhooks := make([]*storepb.WebhooksUserSetting_Webhook, 0, len(webhooks.Webhooks))
for _, webhook := range webhooks.Webhooks {
storeWebhook := &storepb.WebhooksUserSetting_Webhook{
Id: webhook.Id,
Title: webhook.Title,
Id: extractWebhookIDFromName(webhook.Name),
Title: webhook.DisplayName,
Url: webhook.Url,
}
storeWebhooks = append(storeWebhooks, storeWebhook)
......@@ -1347,3 +1306,13 @@ func convertUserSettingToStore(apiSetting *v1pb.UserSetting, userID int32, key s
return storeSetting, nil
}
// extractWebhookIDFromName extracts webhook ID from resource name.
// e.g., "users/123/webhooks/webhook-id" -> "webhook-id".
func extractWebhookIDFromName(name string) string {
parts := strings.Split(name, "/")
if len(parts) >= 4 && parts[0] == "users" && parts[2] == "webhooks" {
return parts[3]
}
return ""
}
......@@ -6,10 +6,10 @@ import { Shortcut } from "@/types/proto/api/v1/shortcut_service";
import {
User,
UserSetting,
UserSetting_Key,
UserSetting_GeneralSetting,
UserSetting_SessionsSetting,
UserSetting_AccessTokensSetting,
UserSetting_ShortcutsSetting,
UserSetting_WebhooksSetting,
UserStats,
} from "@/types/proto/api/v1/user_service";
......@@ -21,7 +21,6 @@ class LocalState {
userGeneralSetting?: UserSetting_GeneralSetting;
userSessionsSetting?: UserSetting_SessionsSetting;
userAccessTokensSetting?: UserSetting_AccessTokensSetting;
userShortcutsSetting?: UserSetting_ShortcutsSetting;
userWebhooksSetting?: UserSetting_WebhooksSetting;
shortcuts: Shortcut[] = [];
inboxes: Inbox[] = [];
......@@ -145,7 +144,7 @@ const userStore = (() => {
throw new Error("No current user");
}
const settingName = `${state.currentUser}/settings/general`;
const settingName = `${state.currentUser}/settings/${UserSetting_Key.GENERAL}`;
const userSetting: UserSetting = {
name: settingName,
generalSetting: generalSetting as UserSetting_GeneralSetting,
......@@ -166,7 +165,7 @@ const userStore = (() => {
throw new Error("No current user");
}
const settingName = `${state.currentUser}/settings/general`;
const settingName = `${state.currentUser}/settings/${UserSetting_Key.GENERAL}`;
const userSetting = await userServiceClient.getUserSetting({ name: settingName });
state.setPartial({
......@@ -187,24 +186,13 @@ const userStore = (() => {
const generalSetting = settings.find((s) => s.generalSetting)?.generalSetting;
const sessionsSetting = settings.find((s) => s.sessionsSetting)?.sessionsSetting;
const accessTokensSetting = settings.find((s) => s.accessTokensSetting)?.accessTokensSetting;
const shortcutsSetting = settings.find((s) => s.shortcutsSetting)?.shortcutsSetting;
const webhooksSetting = settings.find((s) => s.webhooksSetting)?.webhooksSetting;
// Convert user setting shortcuts to proper Shortcut format
const shortcuts: Shortcut[] =
shortcutsSetting?.shortcuts.map((shortcut) => ({
name: `${state.currentUser}/shortcuts/${shortcut.id}`,
title: shortcut.title,
filter: shortcut.filter,
})) || [];
state.setPartial({
userGeneralSetting: generalSetting,
userSessionsSetting: sessionsSetting,
userAccessTokensSetting: accessTokensSetting,
userShortcutsSetting: shortcutsSetting,
userWebhooksSetting: webhooksSetting,
shortcuts,
});
};
......
This diff is collapsed.
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