diff options
author | Chocobozzz <me@florianbigard.com> | 2022-10-28 16:15:04 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2022-10-28 16:34:08 +0200 |
commit | 9e5cf66be7ad897e106f283bee73a165c72e74de (patch) | |
tree | 16de6f775c412281236b8f99be8e5118e5a6ff71 | |
parent | 3f9decbd01d25f1b1805e2764dff4beae7d36c19 (diff) | |
download | PeerTube-9e5cf66be7ad897e106f283bee73a165c72e74de.tar.gz PeerTube-9e5cf66be7ad897e106f283bee73a165c72e74de.tar.zst PeerTube-9e5cf66be7ad897e106f283bee73a165c72e74de.zip |
Breaking API: Consistency with role id/label
-rw-r--r-- | client/src/app/+admin/overview/users/user-edit/user-edit.ts | 2 | ||||
-rw-r--r-- | client/src/app/+admin/overview/users/user-edit/user-update.component.ts | 2 | ||||
-rw-r--r-- | client/src/app/+admin/overview/users/user-list/user-list.component.html | 4 | ||||
-rw-r--r-- | client/src/app/app.component.ts | 4 | ||||
-rw-r--r-- | client/src/app/core/auth/auth-user.model.ts | 6 | ||||
-rw-r--r-- | client/src/app/core/users/user-local-storage.service.ts | 11 | ||||
-rw-r--r-- | client/src/app/core/users/user.model.ts | 10 | ||||
-rw-r--r-- | client/src/app/shared/shared-users/user-admin.service.ts | 5 | ||||
-rw-r--r-- | server/models/user/user.ts | 6 | ||||
-rw-r--r-- | server/tests/api/users/users.ts | 6 | ||||
-rw-r--r-- | server/tests/plugins/external-auth.ts | 6 | ||||
-rw-r--r-- | server/tests/plugins/id-and-pass-auth.ts | 8 | ||||
-rw-r--r-- | shared/models/users/user.model.ts | 6 | ||||
-rw-r--r-- | support/doc/api/openapi.yaml | 17 |
14 files changed, 55 insertions, 38 deletions
diff --git a/client/src/app/+admin/overview/users/user-edit/user-edit.ts b/client/src/app/+admin/overview/users/user-edit/user-edit.ts index 5428f6ce9..1edca7fbf 100644 --- a/client/src/app/+admin/overview/users/user-edit/user-edit.ts +++ b/client/src/app/+admin/overview/users/user-edit/user-edit.ts | |||
@@ -49,7 +49,7 @@ export abstract class UserEdit extends FormReactive implements OnInit { | |||
49 | buildRoles () { | 49 | buildRoles () { |
50 | const authUser = this.auth.getUser() | 50 | const authUser = this.auth.getUser() |
51 | 51 | ||
52 | if (authUser.role === UserRole.ADMINISTRATOR) { | 52 | if (authUser.role.id === UserRole.ADMINISTRATOR) { |
53 | this.roles = Object.keys(USER_ROLE_LABELS) | 53 | this.roles = Object.keys(USER_ROLE_LABELS) |
54 | .map(key => ({ value: key.toString(), label: USER_ROLE_LABELS[key] })) | 54 | .map(key => ({ value: key.toString(), label: USER_ROLE_LABELS[key] })) |
55 | return | 55 | return |
diff --git a/client/src/app/+admin/overview/users/user-edit/user-update.component.ts b/client/src/app/+admin/overview/users/user-edit/user-update.component.ts index 71212b19c..25d02f000 100644 --- a/client/src/app/+admin/overview/users/user-edit/user-update.component.ts +++ b/client/src/app/+admin/overview/users/user-edit/user-update.component.ts | |||
@@ -144,7 +144,7 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy { | |||
144 | 144 | ||
145 | this.form.patchValue({ | 145 | this.form.patchValue({ |
146 | email: userJson.email, | 146 | email: userJson.email, |
147 | role: userJson.role.toString(), | 147 | role: userJson.role.id.toString(), |
148 | videoQuota: userJson.videoQuota, | 148 | videoQuota: userJson.videoQuota, |
149 | videoQuotaDaily: userJson.videoQuotaDaily, | 149 | videoQuotaDaily: userJson.videoQuotaDaily, |
150 | pluginAuth: userJson.pluginAuth, | 150 | pluginAuth: userJson.pluginAuth, |
diff --git a/client/src/app/+admin/overview/users/user-list/user-list.component.html b/client/src/app/+admin/overview/users/user-list/user-list.component.html index c7af7dfae..a96ce561c 100644 --- a/client/src/app/+admin/overview/users/user-list/user-list.component.html +++ b/client/src/app/+admin/overview/users/user-list/user-list.component.html | |||
@@ -106,8 +106,8 @@ | |||
106 | </td> | 106 | </td> |
107 | 107 | ||
108 | <td *ngIf="isSelected('role')"> | 108 | <td *ngIf="isSelected('role')"> |
109 | <span *ngIf="user.blocked" class="pt-badge badge-banned" i18n-title title="The user was banned">{{ user.roleLabel }}</span> | 109 | <span *ngIf="user.blocked" class="pt-badge badge-banned" i18n-title title="The user was banned">{{ user.role.label }}</span> |
110 | <span *ngIf="!user.blocked" class="pt-badge" [ngClass]="getRoleClass(user.role)">{{ user.roleLabel }}</span> | 110 | <span *ngIf="!user.blocked" class="pt-badge" [ngClass]="getRoleClass(user.role.id)">{{ user.role.label }}</span> |
111 | </td> | 111 | </td> |
112 | 112 | ||
113 | <td *ngIf="isSelected('email')" [title]="user.email"> | 113 | <td *ngIf="isSelected('email')" [title]="user.email"> |
diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index a2ad4806c..f2488aa59 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts | |||
@@ -247,12 +247,12 @@ export class AppComponent implements OnInit, AfterViewInit { | |||
247 | 247 | ||
248 | // Admin modal | 248 | // Admin modal |
249 | userSub.pipe( | 249 | userSub.pipe( |
250 | filter(user => user.role === UserRole.ADMINISTRATOR) | 250 | filter(user => user.role.id === UserRole.ADMINISTRATOR) |
251 | ).subscribe(user => this.openAdminModalsIfNeeded(user)) | 251 | ).subscribe(user => this.openAdminModalsIfNeeded(user)) |
252 | 252 | ||
253 | // Account modal | 253 | // Account modal |
254 | userSub.pipe( | 254 | userSub.pipe( |
255 | filter(user => user.role !== UserRole.ADMINISTRATOR) | 255 | filter(user => user.role.id !== UserRole.ADMINISTRATOR) |
256 | ).subscribe(user => this.openAccountModalsIfNeeded(user)) | 256 | ).subscribe(user => this.openAccountModalsIfNeeded(user)) |
257 | } | 257 | } |
258 | 258 | ||
diff --git a/client/src/app/core/auth/auth-user.model.ts b/client/src/app/core/auth/auth-user.model.ts index a12325421..226075265 100644 --- a/client/src/app/core/auth/auth-user.model.ts +++ b/client/src/app/core/auth/auth-user.model.ts | |||
@@ -43,16 +43,16 @@ export class AuthUser extends User implements ServerMyUserModel { | |||
43 | } | 43 | } |
44 | 44 | ||
45 | hasRight (right: UserRight) { | 45 | hasRight (right: UserRight) { |
46 | return hasUserRight(this.role, right) | 46 | return hasUserRight(this.role.id, right) |
47 | } | 47 | } |
48 | 48 | ||
49 | canManage (user: ServerUserModel) { | 49 | canManage (user: ServerUserModel) { |
50 | const myRole = this.role | 50 | const myRole = this.role.id |
51 | 51 | ||
52 | if (myRole === UserRole.ADMINISTRATOR) return true | 52 | if (myRole === UserRole.ADMINISTRATOR) return true |
53 | 53 | ||
54 | // I'm a moderator: I can only manage users | 54 | // I'm a moderator: I can only manage users |
55 | return user.role === UserRole.USER | 55 | return user.role.id === UserRole.USER |
56 | } | 56 | } |
57 | 57 | ||
58 | computeCanSeeVideosLink (quotaObservable: Observable<UserVideoQuota>): Observable<boolean> { | 58 | computeCanSeeVideosLink (quotaObservable: Observable<UserVideoQuota>): Observable<boolean> { |
diff --git a/client/src/app/core/users/user-local-storage.service.ts b/client/src/app/core/users/user-local-storage.service.ts index f1588bdd2..a047efe8e 100644 --- a/client/src/app/core/users/user-local-storage.service.ts +++ b/client/src/app/core/users/user-local-storage.service.ts | |||
@@ -59,7 +59,10 @@ export class UserLocalStorageService { | |||
59 | id: parseInt(this.localStorageService.getItem(UserLocalStorageKeys.ID), 10), | 59 | id: parseInt(this.localStorageService.getItem(UserLocalStorageKeys.ID), 10), |
60 | username: this.localStorageService.getItem(UserLocalStorageKeys.USERNAME), | 60 | username: this.localStorageService.getItem(UserLocalStorageKeys.USERNAME), |
61 | email: this.localStorageService.getItem(UserLocalStorageKeys.EMAIL), | 61 | email: this.localStorageService.getItem(UserLocalStorageKeys.EMAIL), |
62 | role: parseInt(this.localStorageService.getItem(UserLocalStorageKeys.ROLE), 10) as UserRole, | 62 | role: { |
63 | id: parseInt(this.localStorageService.getItem(UserLocalStorageKeys.ROLE), 10) as UserRole, | ||
64 | label: '' | ||
65 | }, | ||
63 | 66 | ||
64 | ...this.getUserInfo() | 67 | ...this.getUserInfo() |
65 | } | 68 | } |
@@ -69,12 +72,14 @@ export class UserLocalStorageService { | |||
69 | id: number | 72 | id: number |
70 | username: string | 73 | username: string |
71 | email: string | 74 | email: string |
72 | role: UserRole | 75 | role: { |
76 | id: UserRole | ||
77 | } | ||
73 | }) { | 78 | }) { |
74 | this.localStorageService.setItem(UserLocalStorageKeys.ID, user.id.toString()) | 79 | this.localStorageService.setItem(UserLocalStorageKeys.ID, user.id.toString()) |
75 | this.localStorageService.setItem(UserLocalStorageKeys.USERNAME, user.username) | 80 | this.localStorageService.setItem(UserLocalStorageKeys.USERNAME, user.username) |
76 | this.localStorageService.setItem(UserLocalStorageKeys.EMAIL, user.email) | 81 | this.localStorageService.setItem(UserLocalStorageKeys.EMAIL, user.email) |
77 | this.localStorageService.setItem(UserLocalStorageKeys.ROLE, user.role.toString()) | 82 | this.localStorageService.setItem(UserLocalStorageKeys.ROLE, user.role.id.toString()) |
78 | } | 83 | } |
79 | 84 | ||
80 | flushLoggedInUser () { | 85 | flushLoggedInUser () { |
diff --git a/client/src/app/core/users/user.model.ts b/client/src/app/core/users/user.model.ts index 8385a4012..5534bca33 100644 --- a/client/src/app/core/users/user.model.ts +++ b/client/src/app/core/users/user.model.ts | |||
@@ -34,8 +34,10 @@ export class User implements UserServerModel { | |||
34 | videosHistoryEnabled: boolean | 34 | videosHistoryEnabled: boolean |
35 | videoLanguages: string[] | 35 | videoLanguages: string[] |
36 | 36 | ||
37 | role: UserRole | 37 | role: { |
38 | roleLabel: string | 38 | id: UserRole |
39 | label: string | ||
40 | } | ||
39 | 41 | ||
40 | videoQuota: number | 42 | videoQuota: number |
41 | videoQuotaDaily: number | 43 | videoQuotaDaily: number |
@@ -123,7 +125,7 @@ export class User implements UserServerModel { | |||
123 | } | 125 | } |
124 | 126 | ||
125 | hasRight (right: UserRight) { | 127 | hasRight (right: UserRight) { |
126 | return hasUserRight(this.role, right) | 128 | return hasUserRight(this.role.id, right) |
127 | } | 129 | } |
128 | 130 | ||
129 | patch (obj: UserServerModel) { | 131 | patch (obj: UserServerModel) { |
@@ -148,6 +150,6 @@ export class User implements UserServerModel { | |||
148 | isAutoBlocked (serverConfig: HTMLServerConfig) { | 150 | isAutoBlocked (serverConfig: HTMLServerConfig) { |
149 | if (serverConfig.autoBlacklist.videos.ofUsers.enabled !== true) return false | 151 | if (serverConfig.autoBlacklist.videos.ofUsers.enabled !== true) return false |
150 | 152 | ||
151 | return this.role === UserRole.USER && this.adminFlags !== UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST | 153 | return this.role.id === UserRole.USER && this.adminFlags !== UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST |
152 | } | 154 | } |
153 | } | 155 | } |
diff --git a/client/src/app/shared/shared-users/user-admin.service.ts b/client/src/app/shared/shared-users/user-admin.service.ts index 4128358dc..0b04023a3 100644 --- a/client/src/app/shared/shared-users/user-admin.service.ts +++ b/client/src/app/shared/shared-users/user-admin.service.ts | |||
@@ -125,7 +125,10 @@ export class UserAdminService { | |||
125 | } | 125 | } |
126 | 126 | ||
127 | return Object.assign(user, { | 127 | return Object.assign(user, { |
128 | roleLabel: roleLabels[user.role], | 128 | role: { |
129 | id: user.role.id, | ||
130 | label: roleLabels[user.role.id] | ||
131 | }, | ||
129 | videoQuota, | 132 | videoQuota, |
130 | videoQuotaUsed, | 133 | videoQuotaUsed, |
131 | rawVideoQuota: user.videoQuota, | 134 | rawVideoQuota: user.videoQuota, |
diff --git a/server/models/user/user.ts b/server/models/user/user.ts index 34329580b..f70feed73 100644 --- a/server/models/user/user.ts +++ b/server/models/user/user.ts | |||
@@ -891,8 +891,10 @@ export class UserModel extends Model<Partial<AttributesOnly<UserModel>>> { | |||
891 | autoPlayNextVideoPlaylist: this.autoPlayNextVideoPlaylist, | 891 | autoPlayNextVideoPlaylist: this.autoPlayNextVideoPlaylist, |
892 | videoLanguages: this.videoLanguages, | 892 | videoLanguages: this.videoLanguages, |
893 | 893 | ||
894 | role: this.role, | 894 | role: { |
895 | roleLabel: USER_ROLE_LABELS[this.role], | 895 | id: this.role, |
896 | label: USER_ROLE_LABELS[this.role] | ||
897 | }, | ||
896 | 898 | ||
897 | videoQuota: this.videoQuota, | 899 | videoQuota: this.videoQuota, |
898 | videoQuotaDaily: this.videoQuotaDaily, | 900 | videoQuotaDaily: this.videoQuotaDaily, |
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts index 3952a7aed..421b3ce16 100644 --- a/server/tests/api/users/users.ts +++ b/server/tests/api/users/users.ts | |||
@@ -219,7 +219,7 @@ describe('Test users', function () { | |||
219 | expect(user.email).to.equal('user_1@example.com') | 219 | expect(user.email).to.equal('user_1@example.com') |
220 | expect(user.nsfwPolicy).to.equal('display') | 220 | expect(user.nsfwPolicy).to.equal('display') |
221 | expect(user.videoQuota).to.equal(2 * 1024 * 1024) | 221 | expect(user.videoQuota).to.equal(2 * 1024 * 1024) |
222 | expect(user.roleLabel).to.equal('User') | 222 | expect(user.role.label).to.equal('User') |
223 | expect(user.id).to.be.a('number') | 223 | expect(user.id).to.be.a('number') |
224 | expect(user.account.displayName).to.equal('user_1') | 224 | expect(user.account.displayName).to.equal('user_1') |
225 | expect(user.account.description).to.be.null | 225 | expect(user.account.description).to.be.null |
@@ -277,7 +277,7 @@ describe('Test users', function () { | |||
277 | const user = data[0] | 277 | const user = data[0] |
278 | expect(user.username).to.equal('root') | 278 | expect(user.username).to.equal('root') |
279 | expect(user.email).to.equal('admin' + server.internalServerNumber + '@example.com') | 279 | expect(user.email).to.equal('admin' + server.internalServerNumber + '@example.com') |
280 | expect(user.roleLabel).to.equal('Administrator') | 280 | expect(user.role.label).to.equal('Administrator') |
281 | expect(user.nsfwPolicy).to.equal('display') | 281 | expect(user.nsfwPolicy).to.equal('display') |
282 | }) | 282 | }) |
283 | 283 | ||
@@ -531,7 +531,7 @@ describe('Test users', function () { | |||
531 | expect(user.emailVerified).to.be.true | 531 | expect(user.emailVerified).to.be.true |
532 | expect(user.nsfwPolicy).to.equal('do_not_list') | 532 | expect(user.nsfwPolicy).to.equal('do_not_list') |
533 | expect(user.videoQuota).to.equal(42) | 533 | expect(user.videoQuota).to.equal(42) |
534 | expect(user.roleLabel).to.equal('Moderator') | 534 | expect(user.role.label).to.equal('Moderator') |
535 | expect(user.id).to.be.a('number') | 535 | expect(user.id).to.be.a('number') |
536 | expect(user.adminFlags).to.equal(UserAdminFlag.NONE) | 536 | expect(user.adminFlags).to.equal(UserAdminFlag.NONE) |
537 | expect(user.pluginAuth).to.equal('toto') | 537 | expect(user.pluginAuth).to.equal('toto') |
diff --git a/server/tests/plugins/external-auth.ts b/server/tests/plugins/external-auth.ts index e08b83791..437777e90 100644 --- a/server/tests/plugins/external-auth.ts +++ b/server/tests/plugins/external-auth.ts | |||
@@ -155,7 +155,7 @@ describe('Test external auth plugins', function () { | |||
155 | expect(body.username).to.equal('cyan') | 155 | expect(body.username).to.equal('cyan') |
156 | expect(body.account.displayName).to.equal('cyan') | 156 | expect(body.account.displayName).to.equal('cyan') |
157 | expect(body.email).to.equal('cyan@example.com') | 157 | expect(body.email).to.equal('cyan@example.com') |
158 | expect(body.role).to.equal(UserRole.USER) | 158 | expect(body.role.id).to.equal(UserRole.USER) |
159 | } | 159 | } |
160 | }) | 160 | }) |
161 | 161 | ||
@@ -177,7 +177,7 @@ describe('Test external auth plugins', function () { | |||
177 | expect(body.username).to.equal('kefka') | 177 | expect(body.username).to.equal('kefka') |
178 | expect(body.account.displayName).to.equal('Kefka Palazzo') | 178 | expect(body.account.displayName).to.equal('Kefka Palazzo') |
179 | expect(body.email).to.equal('kefka@example.com') | 179 | expect(body.email).to.equal('kefka@example.com') |
180 | expect(body.role).to.equal(UserRole.ADMINISTRATOR) | 180 | expect(body.role.id).to.equal(UserRole.ADMINISTRATOR) |
181 | } | 181 | } |
182 | }) | 182 | }) |
183 | 183 | ||
@@ -237,7 +237,7 @@ describe('Test external auth plugins', function () { | |||
237 | expect(body.username).to.equal('cyan') | 237 | expect(body.username).to.equal('cyan') |
238 | expect(body.account.displayName).to.equal('Cyan Garamonde') | 238 | expect(body.account.displayName).to.equal('Cyan Garamonde') |
239 | expect(body.account.description).to.equal('Retainer to the king of Doma') | 239 | expect(body.account.description).to.equal('Retainer to the king of Doma') |
240 | expect(body.role).to.equal(UserRole.USER) | 240 | expect(body.role.id).to.equal(UserRole.USER) |
241 | }) | 241 | }) |
242 | 242 | ||
243 | it('Should not update an external auth email', async function () { | 243 | it('Should not update an external auth email', async function () { |
diff --git a/server/tests/plugins/id-and-pass-auth.ts b/server/tests/plugins/id-and-pass-auth.ts index 85faac5a8..fc24a5656 100644 --- a/server/tests/plugins/id-and-pass-auth.ts +++ b/server/tests/plugins/id-and-pass-auth.ts | |||
@@ -48,7 +48,7 @@ describe('Test id and pass auth plugins', function () { | |||
48 | 48 | ||
49 | expect(body.username).to.equal('spyro') | 49 | expect(body.username).to.equal('spyro') |
50 | expect(body.account.displayName).to.equal('Spyro the Dragon') | 50 | expect(body.account.displayName).to.equal('Spyro the Dragon') |
51 | expect(body.role).to.equal(UserRole.USER) | 51 | expect(body.role.id).to.equal(UserRole.USER) |
52 | }) | 52 | }) |
53 | 53 | ||
54 | it('Should login Crash, create the user and use the token', async function () { | 54 | it('Should login Crash, create the user and use the token', async function () { |
@@ -63,7 +63,7 @@ describe('Test id and pass auth plugins', function () { | |||
63 | 63 | ||
64 | expect(body.username).to.equal('crash') | 64 | expect(body.username).to.equal('crash') |
65 | expect(body.account.displayName).to.equal('Crash Bandicoot') | 65 | expect(body.account.displayName).to.equal('Crash Bandicoot') |
66 | expect(body.role).to.equal(UserRole.MODERATOR) | 66 | expect(body.role.id).to.equal(UserRole.MODERATOR) |
67 | } | 67 | } |
68 | }) | 68 | }) |
69 | 69 | ||
@@ -79,7 +79,7 @@ describe('Test id and pass auth plugins', function () { | |||
79 | 79 | ||
80 | expect(body.username).to.equal('laguna') | 80 | expect(body.username).to.equal('laguna') |
81 | expect(body.account.displayName).to.equal('laguna') | 81 | expect(body.account.displayName).to.equal('laguna') |
82 | expect(body.role).to.equal(UserRole.USER) | 82 | expect(body.role.id).to.equal(UserRole.USER) |
83 | } | 83 | } |
84 | }) | 84 | }) |
85 | 85 | ||
@@ -129,7 +129,7 @@ describe('Test id and pass auth plugins', function () { | |||
129 | expect(body.username).to.equal('crash') | 129 | expect(body.username).to.equal('crash') |
130 | expect(body.account.displayName).to.equal('Beautiful Crash') | 130 | expect(body.account.displayName).to.equal('Beautiful Crash') |
131 | expect(body.account.description).to.equal('Mutant eastern barred bandicoot') | 131 | expect(body.account.description).to.equal('Mutant eastern barred bandicoot') |
132 | expect(body.role).to.equal(UserRole.MODERATOR) | 132 | expect(body.role.id).to.equal(UserRole.MODERATOR) |
133 | }) | 133 | }) |
134 | 134 | ||
135 | it('Should reject token of laguna by the plugin hook', async function () { | 135 | it('Should reject token of laguna by the plugin hook', async function () { |
diff --git a/shared/models/users/user.model.ts b/shared/models/users/user.model.ts index 7b6494ff8..761a2edba 100644 --- a/shared/models/users/user.model.ts +++ b/shared/models/users/user.model.ts | |||
@@ -28,8 +28,10 @@ export interface User { | |||
28 | videosHistoryEnabled: boolean | 28 | videosHistoryEnabled: boolean |
29 | videoLanguages: string[] | 29 | videoLanguages: string[] |
30 | 30 | ||
31 | role: UserRole | 31 | role: { |
32 | roleLabel: string | 32 | id: UserRole |
33 | label: string | ||
34 | } | ||
33 | 35 | ||
34 | videoQuota: number | 36 | videoQuota: number |
35 | videoQuotaDaily: number | 37 | videoQuotaDaily: number |
diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml index 7ffe8c67b..69a6eff72 100644 --- a/support/doc/api/openapi.yaml +++ b/support/doc/api/openapi.yaml | |||
@@ -7522,13 +7522,16 @@ components: | |||
7522 | nsfwPolicy: | 7522 | nsfwPolicy: |
7523 | $ref: '#/components/schemas/NSFWPolicy' | 7523 | $ref: '#/components/schemas/NSFWPolicy' |
7524 | role: | 7524 | role: |
7525 | $ref: '#/components/schemas/UserRole' | 7525 | type: object |
7526 | roleLabel: | 7526 | properties: |
7527 | type: string | 7527 | id: |
7528 | enum: | 7528 | $ref: '#/components/schemas/UserRole' |
7529 | - User | 7529 | label: |
7530 | - Moderator | 7530 | type: string |
7531 | - Administrator | 7531 | enum: |
7532 | - User | ||
7533 | - Moderator | ||
7534 | - Administrator | ||
7532 | theme: | 7535 | theme: |
7533 | type: string | 7536 | type: string |
7534 | description: Theme enabled by this user | 7537 | description: Theme enabled by this user |