diff --git a/components/schemas/UserSettingObject.yaml b/components/schemas/UserSettingObject.yaml new file mode 100644 index 0000000..8bbdff7 --- /dev/null +++ b/components/schemas/UserSettingObject.yaml @@ -0,0 +1,21 @@ +type: object +description: | + User settings as flattened key-value pairs. + - 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 + 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: + UNIT_TEMPERATURE: 'C' + UNIT_TEMPERATURE_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..8c21922 --- /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 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. + 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: 'PROFILE_LANGUAGE_CODE' + 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: + PROFILE_LANGUAGE_CODE: 'en' + PROFILE_LANGUAGE_CODE_lastUpdated: 1732187742 + UNIT_TEMPERATURE: 'C' + UNIT_TEMPERATURE_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'