From 7a10ae914dc942b1c989a48f1f3b1590b8aa9ac4 Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Thu, 7 May 2026 19:05:28 +0200 Subject: [PATCH 1/2] Add user settings endpoint schemas --- components/schemas/UserSettingObject.yaml | 19 +++ userapi/openapi.yaml | 10 +- userapi/user-settings.yaml | 153 ++++++++++++++++++++++ 3 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 components/schemas/UserSettingObject.yaml create mode 100644 userapi/user-settings.yaml diff --git a/components/schemas/UserSettingObject.yaml b/components/schemas/UserSettingObject.yaml new file mode 100644 index 0000000..e607b18 --- /dev/null +++ b/components/schemas/UserSettingObject.yaml @@ -0,0 +1,19 @@ +type: object +description: | + User settings as flattened key-value pairs. + - Setting values are stored with keys matching the setting name. + - Each setting has a corresponding `{settingName}_lastUpdated` field containing an epoch timestamp. + - Setting values are strings, timestamp fields are integers (epoch seconds). +patternProperties: + '^(?!.*_lastUpdated$).+$': + type: string + maxLength: 65535 + description: Setting value + '^.+_lastUpdated$': + type: integer + format: int64 + description: Epoch timestamp in seconds for when the setting was last updated +additionalProperties: false +example: + description: 'Lorem Ipsum is simply dummy text' + description_lastUpdated: 1773306016 diff --git a/userapi/openapi.yaml b/userapi/openapi.yaml index a6e7298..e52d5cb 100644 --- a/userapi/openapi.yaml +++ b/userapi/openapi.yaml @@ -34,7 +34,8 @@ tags: description: Sensor sharing and unsharing - name: Subscription description: User subscription management - + - name: User-Settings + description: User settings management paths: /air_firmwareupdate: @@ -43,7 +44,7 @@ paths: $ref: './alerts.yaml' /push-register: $ref: './push-register.yaml' - /register: + /register: $ref: './register.yaml' /sensor-settings: $ref: './sensor-settings.yaml' @@ -57,11 +58,12 @@ paths: $ref: './share.yaml' /subscription: $ref: './subscription.yaml' + /settings: + $ref: './user-settings.yaml' /unshare: $ref: './unshare.yaml' - /verify: + /verify: $ref: './verify.yaml' - components: securitySchemes: diff --git a/userapi/user-settings.yaml b/userapi/user-settings.yaml new file mode 100644 index 0000000..231a47f --- /dev/null +++ b/userapi/user-settings.yaml @@ -0,0 +1,153 @@ +post: + summary: Configure a user setting + description: Creates or updates a setting for the authenticated user. + operationId: setUserSetting + tags: + - User-Settings + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - name + - value + additionalProperties: false + properties: + name: + type: string + description: User setting name. + maxLength: 320 + pattern: '^(?!.*_lastUpdated$)[a-zA-Z0-9_.-]+$' + value: + type: string + description: User setting value. + maxLength: 65535 + timestamp: + type: integer + format: int64 + description: Optional epoch timestamp for the setting. If missing, it is assumed to be the current time. + examples: + basic: + value: + name: 'language' + value: 'en' + + responses: + '200': + description: Setting stored or updated successfully + content: + application/json: + schema: + allOf: + - $ref: '../components/schemas/Success.yaml' + - type: object + properties: + data: + $ref: '../components/schemas/SettingSetResult.yaml' + examples: + updated: + value: + result: success + data: + action: 'updated' + added: + value: + result: success + data: + action: 'added' + + '400': + description: INVALID - Missing or malformed fields. + content: + application/json: + schema: + $ref: '../components/schemas/Error.yaml' + examples: + invalid: + value: + result: 'error' + error: 'Missing required field: name' + code: 'ER_INVALID_ARGUMENT' + + '401': + description: UNAUTHORIZED - Auth token missing or invalid. + content: + application/json: + schema: + $ref: '../components/schemas/Error.yaml' + examples: + unauthorized: + value: + result: 'error' + error: 'UNAUTHORIZED' + code: 'ER_UNAUTHORIZED' + + '409': + description: CONFLICT - Setting with same or newer timestamp already exists. + content: + application/json: + schema: + $ref: '../components/schemas/Error.yaml' + examples: + conflict: + value: + result: 'error' + error: 'Newer setting already exists' + code: 'ER_CONFLICT' + sub_code: 'ER_OLD_ENTRY' + +get: + summary: Get user settings + description: Returns settings for the authenticated user. + operationId: getUserSettings + tags: + - User-Settings + security: + - bearerAuth: [] + + responses: + '200': + description: User settings fetched successfully + content: + application/json: + schema: + allOf: + - $ref: '../components/schemas/Success.yaml' + - type: object + required: + - data + properties: + data: + type: object + required: + - settings + properties: + settings: + $ref: '../components/schemas/UserSettingObject.yaml' + examples: + basic: + value: + result: success + data: + settings: + language: 'en' + language_lastUpdated: 1732187742 + dashboardLayout: '{"cards":["temperature","humidity"]}' + dashboardLayout_lastUpdated: 1732187742 + + '401': + description: UNAUTHORIZED - Auth token missing or invalid. + content: + application/json: + schema: + $ref: '../components/schemas/Error.yaml' + examples: + unauthorized: + value: + result: 'error' + error: 'UNAUTHORIZED' + code: 'ER_UNAUTHORIZED' From 74f8802f0b30acc86e750f97d655abd34d32a0fe Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Thu, 7 May 2026 22:20:11 +0200 Subject: [PATCH 2/2] fixup! Add user settings endpoint schemas --- components/schemas/UserSettingObject.yaml | 8 +++++--- userapi/user-settings.yaml | 16 ++++++++-------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/components/schemas/UserSettingObject.yaml b/components/schemas/UserSettingObject.yaml index e607b18..8bbdff7 100644 --- a/components/schemas/UserSettingObject.yaml +++ b/components/schemas/UserSettingObject.yaml @@ -1,9 +1,11 @@ type: object description: | User settings as flattened key-value pairs. - - Setting values are stored with keys matching the setting name. + - Setting values are returned with uppercase setting names. - Each setting has a corresponding `{settingName}_lastUpdated` field containing an epoch timestamp. - Setting values are strings, timestamp fields are integers (epoch seconds). +propertyNames: + pattern: '^(?!.*_lastUpdated_lastUpdated$)(?!.*(?:^|_)[A-F0-9]{16,}(?:_|_lastUpdated$|$))(?!.*(?:^|_)\d{8,}(?:_|_lastUpdated$|$))[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+(?:_lastUpdated)?$' patternProperties: '^(?!.*_lastUpdated$).+$': type: string @@ -15,5 +17,5 @@ patternProperties: description: Epoch timestamp in seconds for when the setting was last updated additionalProperties: false example: - description: 'Lorem Ipsum is simply dummy text' - description_lastUpdated: 1773306016 + UNIT_TEMPERATURE: 'C' + UNIT_TEMPERATURE_lastUpdated: 1773306016 diff --git a/userapi/user-settings.yaml b/userapi/user-settings.yaml index 231a47f..8c21922 100644 --- a/userapi/user-settings.yaml +++ b/userapi/user-settings.yaml @@ -19,9 +19,9 @@ post: properties: name: type: string - description: User setting name. - maxLength: 320 - pattern: '^(?!.*_lastUpdated$)[a-zA-Z0-9_.-]+$' + description: User setting name in snake case, for example `UNIT_TEMPERATURE`, `profile_language_code`, or `settings_123`. Names are stored in uppercase. + maxLength: 80 + pattern: '^(?!.*_[Ll][Aa][Ss][Tt][Uu][Pp][Dd][Aa][Tt][Ee][Dd]$)(?!.*(?:^|_)[A-Fa-f0-9]{16,}(?:_|$))(?!.*(?:^|_)\d{8,}(?:_|$))[A-Za-z][A-Za-z0-9]*(?:_[A-Za-z0-9]+)+$' value: type: string description: User setting value. @@ -33,7 +33,7 @@ post: examples: basic: value: - name: 'language' + name: 'PROFILE_LANGUAGE_CODE' value: 'en' responses: @@ -134,10 +134,10 @@ get: result: success data: settings: - language: 'en' - language_lastUpdated: 1732187742 - dashboardLayout: '{"cards":["temperature","humidity"]}' - dashboardLayout_lastUpdated: 1732187742 + PROFILE_LANGUAGE_CODE: 'en' + PROFILE_LANGUAGE_CODE_lastUpdated: 1732187742 + UNIT_TEMPERATURE: 'C' + UNIT_TEMPERATURE_lastUpdated: 1732187742 '401': description: UNAUTHORIZED - Auth token missing or invalid.