Skip to content

Commit

Permalink
refactor: add schemas to user admin controller (#1692)
Browse files Browse the repository at this point in the history
* refactor: add schemas to user admin controller

* refactor: remove unused SessionService

* refactor: fix search query type confusion

* refactor: add schemas to user controller (#1693)

* refactor: add schemas to user controller

* refactor: fix getAllUserSplashes method name

* refactor: name and email should not be required on create

* refactor: only some user fields may be updated

* refactor: should not require any fields on user update  (#1730)

* refactor: send 400 instead of 500 on missing username and email

* refactor: should not require any fields for user update

* refactor: note that earlier versions required name or email

* refactor: merge roleDescriptionSchema and roleSchema
  • Loading branch information
olav committed Jun 22, 2022
1 parent cecca59 commit ab75d40
Show file tree
Hide file tree
Showing 43 changed files with 1,420 additions and 235 deletions.
2 changes: 1 addition & 1 deletion src/lib/db/user-splash-store.ts
Expand Up @@ -38,7 +38,7 @@ export default class UserSplashStore implements IUserSplashStore {
this.logger = getLogger('user-splash-store.ts');
}

async getAllUserSplashs(userId: number): Promise<IUserSplash[]> {
async getAllUserSplashes(userId: number): Promise<IUserSplash[]> {
const userSplash = await this.db
.table<IUserSplashTable>(TABLE)
.select()
Expand Down
3 changes: 1 addition & 2 deletions src/lib/db/user-store.ts
Expand Up @@ -8,7 +8,6 @@ import NotFoundError from '../error/notfound-error';
import {
ICreateUser,
IUserLookup,
IUserSearch,
IUserStore,
IUserUpdateFields,
} from '../types/stores/user-store';
Expand Down Expand Up @@ -116,7 +115,7 @@ class UserStore implements IUserStore {
return users.map(rowToUser);
}

async search(query: IUserSearch): Promise<User[]> {
async search(query: string): Promise<User[]> {
const users = await this.db
.select(USER_COLUMNS_PUBLIC)
.from(TABLE)
Expand Down
24 changes: 22 additions & 2 deletions src/lib/openapi/index.ts
Expand Up @@ -8,6 +8,7 @@ import { contextFieldsSchema } from './spec/context-fields-schema';
import { createApiTokenSchema } from './spec/create-api-token-schema';
import { createFeatureSchema } from './spec/create-feature-schema';
import { createStrategySchema } from './spec/create-strategy-schema';
import { createUserSchema } from './spec/create-user-schema';
import { environmentSchema } from './spec/environment-schema';
import { environmentsSchema } from './spec/environments-schema';
import { featureEnvironmentSchema } from './spec/feature-environment-schema';
Expand All @@ -22,16 +23,21 @@ import { healthCheckSchema } from './spec/health-check-schema';
import { healthOverviewSchema } from './spec/health-overview-schema';
import { healthReportSchema } from './spec/health-report-schema';
import { legalValueSchema } from './spec/legal-value-schema';
import { idSchema } from './spec/id-schema';
import { mapValues } from '../util/map-values';
import { nameSchema } from './spec/name-schema';
import { meSchema } from './spec/me-schema';
import { omitKeys } from '../util/omit-keys';
import { overrideSchema } from './spec/override-schema';
import { parametersSchema } from './spec/parameters-schema';
import { passwordSchema } from './spec/password-schema';
import { patchSchema } from './spec/patch-schema';
import { patchesSchema } from './spec/patches-schema';
import { permissionSchema } from './spec/permission-schema';
import { projectEnvironmentSchema } from './spec/project-environment-schema';
import { projectSchema } from './spec/project-schema';
import { projectsSchema } from './spec/projects-schema';
import { roleSchema } from './spec/role-schema';
import { sortOrderSchema } from './spec/sort-order-schema';
import { splashSchema } from './spec/splash-schema';
import { strategySchema } from './spec/strategy-schema';
Expand All @@ -45,6 +51,10 @@ import { updateStrategySchema } from './spec/update-strategy-schema';
import { updateApiTokenSchema } from './spec/update-api-token-schema';
import { updateTagTypeSchema } from './spec/update-tag-type-schema';
import { upsertContextFieldSchema } from './spec/upsert-context-field-schema';
import { updateUserSchema } from './spec/update-user-schema';
import { userSchema } from './spec/user-schema';
import { usersSchema } from './spec/users-schema';
import { usersSearchSchema } from './spec/users-search-schema';
import { validateTagTypeSchema } from './spec/validate-tag-type-schema';
import { variantSchema } from './spec/variant-schema';
import { variantsSchema } from './spec/variants-schema';
Expand All @@ -57,7 +67,6 @@ import { applicationSchema } from './spec/application-schema';
import { applicationsSchema } from './spec/applications-schema';
import { tagWithVersionSchema } from './spec/tag-with-version-schema';
import { tokenUserSchema } from './spec/token-user-schema';
import { roleDescriptionSchema } from './spec/role-description-schema';
import { changePasswordSchema } from './spec/change-password-schema';
import { validatePasswordSchema } from './spec/validate-password-schema';
import { resetPasswordSchema } from './spec/reset-password-schema';
Expand All @@ -66,6 +75,7 @@ import { segmentSchema } from './spec/segment-schema';
import { stateSchema } from './spec/state-schema';
import { featureTagSchema } from './spec/feature-tag-schema';
import { exportParametersSchema } from './spec/export-parameters-schema';
import { emailSchema } from './spec/email-schema';

// All schemas in `openapi/spec` should be listed here.
export const schemas = {
Expand All @@ -85,6 +95,8 @@ export const schemas = {
createApiTokenSchema,
createFeatureSchema,
createStrategySchema,
createUserSchema,
emailSchema,
environmentSchema,
environmentsSchema,
exportParametersSchema,
Expand All @@ -103,15 +115,19 @@ export const schemas = {
healthReportSchema,
legalValueSchema,
nameSchema,
idSchema,
meSchema,
overrideSchema,
parametersSchema,
passwordSchema,
patchSchema,
patchesSchema,
permissionSchema,
projectEnvironmentSchema,
projectSchema,
projectsSchema,
resetPasswordSchema,
roleDescriptionSchema,
roleSchema,
segmentSchema,
sortOrderSchema,
splashSchema,
Expand All @@ -131,6 +147,10 @@ export const schemas = {
upsertContextFieldSchema,
validatePasswordSchema,
validateTagTypeSchema,
updateUserSchema,
userSchema,
usersSchema,
usersSearchSchema,
variantSchema,
variantsSchema,
versionSchema,
Expand Down
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`resetPasswordSchema empty 1`] = `
exports[`emailSchema 1`] = `
Object {
"data": Object {},
"errors": Array [
Expand All @@ -14,6 +14,6 @@ Object {
"schemaPath": "#/required",
},
],
"schema": "#/components/schemas/resetPasswordSchema",
"schema": "#/components/schemas/emailSchema",
}
`;
65 changes: 65 additions & 0 deletions src/lib/openapi/spec/__snapshots__/me-schema.test.ts.snap
@@ -0,0 +1,65 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`meSchema empty 1`] = `
Object {
"data": Object {},
"errors": Array [
Object {
"instancePath": "",
"keyword": "required",
"message": "must have required property 'user'",
"params": Object {
"missingProperty": "user",
},
"schemaPath": "#/required",
},
],
"schema": "#/components/schemas/meSchema",
}
`;

exports[`meSchema missing permissions 1`] = `
Object {
"data": Object {
"user": Object {
"id": 1,
},
},
"errors": Array [
Object {
"instancePath": "",
"keyword": "required",
"message": "must have required property 'permissions'",
"params": Object {
"missingProperty": "permissions",
},
"schemaPath": "#/required",
},
],
"schema": "#/components/schemas/meSchema",
}
`;

exports[`meSchema missing splash 1`] = `
Object {
"data": Object {
"feedback": Array [],
"permissions": Array [],
"user": Object {
"id": 1,
},
},
"errors": Array [
Object {
"instancePath": "",
"keyword": "required",
"message": "must have required property 'splash'",
"params": Object {
"missingProperty": "splash",
},
"schemaPath": "#/required",
},
],
"schema": "#/components/schemas/meSchema",
}
`;
@@ -1,19 +1,19 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`roleDescriptionSchema empty 1`] = `
exports[`roleSchema 1`] = `
Object {
"data": Object {},
"errors": Array [
Object {
"instancePath": "",
"keyword": "required",
"message": "must have required property 'description'",
"message": "must have required property 'id'",
"params": Object {
"missingProperty": "description",
"missingProperty": "id",
},
"schemaPath": "#/required",
},
],
"schema": "#/components/schemas/roleDescriptionSchema",
"schema": "#/components/schemas/roleSchema",
}
`;
31 changes: 31 additions & 0 deletions src/lib/openapi/spec/create-user-schema.ts
@@ -0,0 +1,31 @@
import { FromSchema } from 'json-schema-to-ts';

export const createUserSchema = {
$id: '#/components/schemas/createUserSchema',
type: 'object',
additionalProperties: false,
required: ['rootRole'],
properties: {
username: {
type: 'string',
},
email: {
type: 'string',
},
name: {
type: 'string',
},
password: {
type: 'string',
},
rootRole: {
type: 'number',
},
sendEmail: {
type: 'boolean',
},
},
components: {},
} as const;

export type CreateUserSchema = FromSchema<typeof createUserSchema>;
16 changes: 16 additions & 0 deletions src/lib/openapi/spec/email-schema.test.ts
@@ -0,0 +1,16 @@
import { validateSchema } from '../validate';
import { EmailSchema } from './email-schema';

test('emailSchema', () => {
const data: EmailSchema = {
email: '',
};

expect(
validateSchema('#/components/schemas/emailSchema', data),
).toBeUndefined();

expect(
validateSchema('#/components/schemas/emailSchema', {}),
).toMatchSnapshot();
});
16 changes: 16 additions & 0 deletions src/lib/openapi/spec/email-schema.ts
@@ -0,0 +1,16 @@
import { FromSchema } from 'json-schema-to-ts';

export const emailSchema = {
$id: '#/components/schemas/emailSchema',
type: 'object',
additionalProperties: false,
required: ['email'],
properties: {
email: {
type: 'string',
},
},
components: {},
} as const;

export type EmailSchema = FromSchema<typeof emailSchema>;
16 changes: 16 additions & 0 deletions src/lib/openapi/spec/id-schema.ts
@@ -0,0 +1,16 @@
import { FromSchema } from 'json-schema-to-ts';

export const idSchema = {
$id: '#/components/schemas/idSchema',
type: 'object',
additionalProperties: false,
required: ['id'],
properties: {
id: {
type: 'string',
},
},
components: {},
} as const;

export type IdSchema = FromSchema<typeof idSchema>;
37 changes: 37 additions & 0 deletions src/lib/openapi/spec/me-schema.test.ts
@@ -0,0 +1,37 @@
import { validateSchema } from '../validate';
import { MeSchema } from './me-schema';

test('meSchema', () => {
const data: MeSchema = {
user: { id: 1 },
permissions: [{ permission: 'a' }],
feedback: [{ userId: 1, feedbackId: 'a', neverShow: false }],
splash: { a: true },
};

expect(
validateSchema('#/components/schemas/meSchema', data),
).toBeUndefined();
});

test('meSchema empty', () => {
expect(
validateSchema('#/components/schemas/meSchema', {}),
).toMatchSnapshot();
});

test('meSchema missing permissions', () => {
expect(
validateSchema('#/components/schemas/meSchema', { user: { id: 1 } }),
).toMatchSnapshot();
});

test('meSchema missing splash', () => {
expect(
validateSchema('#/components/schemas/meSchema', {
user: { id: 1 },
permissions: [],
feedback: [],
}),
).toMatchSnapshot();
});
43 changes: 43 additions & 0 deletions src/lib/openapi/spec/me-schema.ts
@@ -0,0 +1,43 @@
import { FromSchema } from 'json-schema-to-ts';
import { userSchema } from './user-schema';
import { permissionSchema } from './permission-schema';
import { feedbackSchema } from './feedback-schema';

export const meSchema = {
$id: '#/components/schemas/meSchema',
type: 'object',
additionalProperties: false,
required: ['user', 'permissions', 'feedback', 'splash'],
properties: {
user: {
$ref: '#/components/schemas/userSchema',
},
permissions: {
type: 'array',
items: {
$ref: '#/components/schemas/permissionSchema',
},
},
feedback: {
type: 'array',
items: {
$ref: '#/components/schemas/feedbackSchema',
},
},
splash: {
type: 'object',
additionalProperties: {
type: 'boolean',
},
},
},
components: {
schemas: {
userSchema,
permissionSchema,
feedbackSchema,
},
},
} as const;

export type MeSchema = FromSchema<typeof meSchema>;

0 comments on commit ab75d40

Please sign in to comment.