From 896821ef2092a150b10e6d7b9bcd96d78e2e2226 Mon Sep 17 00:00:00 2001 From: Isaac Hunter Date: Mon, 30 Sep 2024 20:03:45 -0400 Subject: [PATCH] add summaries to user api --- server/docs/swagger.ts | 11 +- server/docs/swagger_output.json | 308 +++++++++++++++++++------------- server/views/groupViews.ts | 5 +- server/views/userViews.ts | 72 +++++--- 4 files changed, 241 insertions(+), 155 deletions(-) diff --git a/server/docs/swagger.ts b/server/docs/swagger.ts index 88f666b..deb8adc 100644 --- a/server/docs/swagger.ts +++ b/server/docs/swagger.ts @@ -1,5 +1,5 @@ import { BASE_URL } from 'server/config' -import type { IGroup, IGroupFields } from 'server/models' +import type { IGroup, IGroupFields, IUser } from 'server/models' import { ResponseCodes, formatJsonResponse } from 'server/utils' import swaggerAutogen from 'swagger-autogen' @@ -44,7 +44,14 @@ const doc = { }, definitions: { IGroupFields: { name: '', ownerId: '' } as IGroupFields, - IGroup: { id: '', name: '', ownerId: '' } as IGroup + IGroup: { id: '', name: '', ownerId: '' } as IGroup, + IUser: new class implements IUser { + id: string = 'some-id' + email: string = 'user@example.com' + firstName?: string | undefined + lastName?: string | undefined + image?: string | undefined + }() } } const generateResponseDocs = () => { diff --git a/server/docs/swagger_output.json b/server/docs/swagger_output.json index 9dbc017..9bcefb3 100644 --- a/server/docs/swagger_output.json +++ b/server/docs/swagger_output.json @@ -253,7 +253,8 @@ "tags": [ "User" ], - "description": "", + "summary": "Register new user", + "description": "Create a new user account", "parameters": [ { "name": "body", @@ -261,10 +262,10 @@ "schema": { "type": "object", "properties": { - "schema": { + "email": { "example": "any" }, - "description": { + "password": { "example": "any" } } @@ -272,24 +273,11 @@ } ], "responses": { - "201": { + "200": { + "description": "Return created user", "schema": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "66ec5cc706ebdf0462a024d2" - }, - "email": { - "type": "string", - "example": "email@gmail.com" - } - }, - "xml": { - "name": "main" - } - }, - "description": "Monitor updated" + "$ref": "#/definitions/IUser" + } }, "400": { "schema": { @@ -323,6 +311,7 @@ "tags": [ "User" ], + "summary": "Get token for logging in a user", "description": "", "parameters": [ { @@ -331,10 +320,10 @@ "schema": { "type": "object", "properties": { - "schema": { + "email": { "example": "any" }, - "description": { + "password": { "example": "any" } } @@ -348,14 +337,14 @@ "properties": { "token": { "type": "string", - "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NmVjNWNjNzA2ZWJkZjA0NjJhMDI0ZDIiLCJpYXQiOjE3MjY3NjYzNDIsIm5iZiI6MTcyNjc2NjM0MiwiZXhwIjoxNzI2OTM5MTQyLCJpc3MiOiJqdWtlYm94In0.JWGMcuOjFKFAhi5ZJfaISl40AmCxwXVKBzmvh-6NHWg" + "example": "example-token" } }, "xml": { "name": "main" } }, - "description": "Monitor updated" + "description": "OK" }, "400": { "schema": { @@ -389,6 +378,7 @@ "tags": [ "User" ], + "summary": "Request a password reset for authenticated user (TODO)", "description": "", "parameters": [ { @@ -425,7 +415,7 @@ "name": "main" } }, - "description": "Monitor updated" + "description": "OK" }, "400": { "schema": { @@ -464,6 +454,7 @@ "tags": [ "User" ], + "summary": "Allow user to reset password from reset request (TODO)", "description": "", "parameters": [ { @@ -500,7 +491,7 @@ "name": "main" } }, - "description": "Monitor updated" + "description": "OK" }, "400": { "schema": { @@ -539,6 +530,7 @@ "tags": [ "User" ], + "summary": "Get info about the authenticated user", "description": "", "responses": { "200": { @@ -551,14 +543,14 @@ }, "email": { "type": "string", - "example": "email" + "example": "user@example.com" } }, "xml": { "name": "main" } }, - "description": "Monitor updated" + "description": "OK" }, "400": { "schema": { @@ -597,8 +589,19 @@ "tags": [ "User" ], + "summary": "Get connected spotify accounts for user", "description": "", "responses": { + "200": { + "schema": { + "type": "object", + "properties": {}, + "xml": { + "name": "main" + } + }, + "description": "OK" + }, "400": { "schema": { "$ref": "#/definitions/Error400" @@ -636,6 +639,7 @@ "tags": [ "User" ], + "summary": "Create a new user", "description": "", "responses": { "400": { @@ -673,6 +677,7 @@ "tags": [ "User" ], + "summary": "Get a list of all users", "description": "", "responses": { "400": { @@ -712,6 +717,7 @@ "tags": [ "User" ], + "summary": "Get a single user by id", "description": "", "parameters": [ { @@ -757,6 +763,7 @@ "tags": [ "User" ], + "summary": "Update all fields on a user", "description": "", "parameters": [ { @@ -802,6 +809,7 @@ "tags": [ "User" ], + "summary": "Update some fields on a user", "description": "", "parameters": [ { @@ -847,6 +855,7 @@ "tags": [ "User" ], + "summary": "Delete a user by id", "description": "", "parameters": [ { @@ -889,92 +898,6 @@ ] } }, - "/api/group/{id}/spotify": { - "post": { - "tags": [ - "Group" - ], - "description": "", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "body", - "in": "body", - "schema": { - "type": "object", - "properties": { - "spotifyEmail": { - "example": "any" - } - } - } - } - ], - "responses": { - "200": { - "schema": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "66e9f064f4b6247a0c26291e" - }, - "ownerId": { - "type": "string", - "example": "66e8a2e7f4b6247a0c262910" - }, - "name": { - "type": "string", - "example": "group" - }, - "spotifyAuthId": { - "type": "string", - "example": "66e9fbbcb14c1ccc11b3d8fd" - } - }, - "xml": { - "name": "main" - } - }, - "description": "Monitor updated" - }, - "400": { - "schema": { - "$ref": "#/definitions/Error400" - }, - "description": "Bad request" - }, - "404": { - "schema": { - "$ref": "#/definitions/Error404" - }, - "description": "Not found" - }, - "500": { - "schema": { - "$ref": "#/definitions/Error500" - }, - "description": "Internal Server Error" - }, - "501": { - "schema": { - "$ref": "#/definitions/Error501" - }, - "description": "Not implemented" - } - }, - "security": [ - { - "Bearer": [] - } - ] - } - }, "/api/group/{id}/spotify/current-track": { "get": { "tags": [ @@ -1120,18 +1043,60 @@ "in": "path", "required": true, "type": "string" - }, - { - "name": "body", - "in": "body", - "description": "Group Object", - "required": true, - "schema": { - "$ref": "#/definitions/IGroupFields" - } } ], "responses": { + "200": { + "schema": { + "type": "object", + "properties": { + "devices": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "ff25d0139c6039819da122cacbdb275fe83e5286" + }, + "is_active": { + "type": "boolean", + "example": false + }, + "is_private_session": { + "type": "boolean", + "example": false + }, + "is_restricted": { + "type": "boolean", + "example": false + }, + "name": { + "type": "string", + "example": "Nabeel’s MacBook Air" + }, + "supports_volume": { + "type": "boolean", + "example": true + }, + "type": { + "type": "string", + "example": "Computer" + }, + "volume_percent": { + "type": "number", + "example": 81 + } + } + } + } + }, + "xml": { + "name": "main" + } + }, + "description": "Success" + }, "400": { "schema": { "$ref": "#/definitions/Error400" @@ -1287,6 +1252,90 @@ "Bearer": [] } ] + }, + "post": { + "tags": [ + "Group" + ], + "description": "", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "schema": { + "type": "object", + "properties": { + "spotifyEmail": { + "example": "any" + } + } + } + } + ], + "responses": { + "200": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "66e9f064f4b6247a0c26291e" + }, + "ownerId": { + "type": "string", + "example": "66e8a2e7f4b6247a0c262910" + }, + "name": { + "type": "string", + "example": "group" + }, + "spotifyAuthId": { + "type": "string", + "example": "66e9fbbcb14c1ccc11b3d8fd" + } + }, + "xml": { + "name": "main" + } + }, + "description": "Monitor updated" + }, + "400": { + "schema": { + "$ref": "#/definitions/Error400" + }, + "description": "Bad request" + }, + "404": { + "schema": { + "$ref": "#/definitions/Error404" + }, + "description": "Not found" + }, + "500": { + "schema": { + "$ref": "#/definitions/Error500" + }, + "description": "Internal Server Error" + }, + "501": { + "schema": { + "$ref": "#/definitions/Error501" + }, + "description": "Not implemented" + } + }, + "security": [ + { + "Bearer": [] + } + ] } }, "/api/group/groups": { @@ -1596,6 +1645,19 @@ } } }, + "IUser": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "some-id" + }, + "email": { + "type": "string", + "example": "user@example.com" + } + } + }, "Success200": { "type": "object", "properties": { diff --git a/server/views/groupViews.ts b/server/views/groupViews.ts index 7ee77e9..e1e3815 100644 --- a/server/views/groupViews.ts +++ b/server/views/groupViews.ts @@ -62,7 +62,7 @@ export const getGroupDevicesView = apiAuthRequest(async (req, res) => { #swagger.tags = ['Group'] #swagger.responses[200] = { schema: { - "devices": [ + devices: [ { "id": "ff25d0139c6039819da122cacbdb275fe83e5286", "is_active": false, @@ -72,7 +72,8 @@ export const getGroupDevicesView = apiAuthRequest(async (req, res) => { "supports_volume": true, "type": "Computer", "volume_percent": 81 - }," + } + ] }, description: "Success" } diff --git a/server/views/userViews.ts b/server/views/userViews.ts index 809149b..319ef69 100644 --- a/server/views/userViews.ts +++ b/server/views/userViews.ts @@ -13,20 +13,21 @@ export const registerUserView = apiRequest( /** @swagger #swagger.tags = ['User'] - #swagger.responses[201] = { - schema: { - "id": "66ec5cc706ebdf0462a024d2", - "email": "email@gmail.com" - }, - description: "Monitor updated" - } - */ + #swagger.summary = "Register new user" + #swagger.description = "Create a new user account" + */ const { email, password } = req.body if (!email || !password) throw new Error('Missing email or password.') const user = await registerUser(email, password) const serialized: IUser = user.serialize() + /* + #swagger.responses[200] = { + description: 'Return created user', + schema: { $ref: '#/definitions/IUser' } + } + */ return serialized }, { onSuccess: httpCreated } @@ -35,17 +36,19 @@ export const loginUserView = apiRequest(async (req, res, next) => { /** @swagger #swagger.tags = ['User'] - #swagger.responses[200] = { - schema: { - "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NmVjNWNjNzA2ZWJkZjA0NjJhMDI0ZDIiLCJpYXQiOjE3MjY3NjYzNDIsIm5iZiI6MTcyNjc2NjM0MiwiZXhwIjoxNzI2OTM5MTQyLCJpc3MiOiJqdWtlYm94In0.JWGMcuOjFKFAhi5ZJfaISl40AmCxwXVKBzmvh-6NHWg" - }, - description: "Monitor updated" - } + #swagger.summary = "Get token for logging in a user" */ const { email, password } = req.body if (!email || !password) throw new Error('Missing email or password.') const token = await getUserToken(email, password) + /* + #swagger.responses[200] = { + schema: { + "token": "example-token" + }, + } + */ return { token } }) @@ -53,33 +56,38 @@ export const currentUserView = apiAuthRequest(async (req, res, next) => { /** @swagger #swagger.tags = ['User'] - #swagger.responses[200] = { - schema: { - "id": "66e9f875b14c1ccc11b3d8f0", - "email": "email" - }, - description: "Monitor updated" - } + #swagger.summary = "Get info about the authenticated user" + */ const { user } = res.locals const userSerialized: IUser = user.serialize() const userGroups = await Group.find({ ownerId: user._id }) - + const groups = userGroups.map((group) => ({ id: group._id, name: group.name })) + /* + #swagger.responses[200] = { + schema: { + id: "66e9f875b14c1ccc11b3d8f0", + email: "user@example.com" + }, + } + */ return { ...userSerialized, groups } }) +// TODO: Remove authentication requirement, send email to user export const requestPasswordResetView = apiRequest(async (req, res, next) => { /** @swagger #swagger.tags = ['User'] + #swagger.summary = "Request a password reset for authenticated user (TODO)" #swagger.responses[200] = { schema: { "status": 200, "type": "Ok" }, - description: "Monitor updated" + description: "" } */ const { email } = req.body @@ -92,12 +100,13 @@ export const resetPasswordView = apiRequest(async (req, res, next) => { /** @swagger #swagger.tags = ['User'] + #swagger.summary = "Allow user to reset password from reset request (TODO)" #swagger.responses[200] = { schema: { "status": 200, "type": "Ok" }, - description: "Monitor updated" + description: "" } */ // FIXME: Insecure password reset, HIGH security risk @@ -111,11 +120,12 @@ export const connectedSpotifyAccounts = apiAuthRequest(async (req, res, next) => /** @swagger #swagger.tags = ['User'] + #swagger.summary = "Get connected spotify accounts for user" #swagger.responses[200] = { schema: { - "email" + }, - description: "Monitor updated" + description: "" } */ const { user } = res.locals @@ -129,8 +139,9 @@ const UserViewset = new Viewset(User, cleanUser) export const userCreateView = apiAuthRequest(async (...args: ApiArgs) => { /** @swagger + #swagger.summary = "Create a new user" #swagger.tags = ['User'] - # + */ const user: IUser = await UserViewset.create(...args) @@ -140,6 +151,7 @@ export const userCreateView = apiAuthRequest(async (...args: ApiArgs) => { export const userListView = apiAuthRequest(async (...args: ApiArgs) => { /** @swagger + #swagger.summary = "Get a list of all users" #swagger.tags = ['User'] */ const users: IUser[] = await UserViewset.list(...args) @@ -148,7 +160,8 @@ export const userListView = apiAuthRequest(async (...args: ApiArgs) => { }) export const userGetView = apiAuthRequest(async (...args: ApiArgs) => { /** - @swagger + @swaggeď + #swagger.summary = "Get a single user by id" #swagger.tags = ['User'] */ const user: IUser = await UserViewset.get(...args) @@ -158,6 +171,7 @@ export const userGetView = apiAuthRequest(async (...args: ApiArgs) => { export const userUpdateView = apiAuthRequest(async (...args: ApiArgs) => { /** @swagger + #swagger.summary = "Update all fields on a user" #swagger.tags = ['User'] */ const user: IUser = await UserViewset.update(...args) @@ -167,6 +181,7 @@ export const userUpdateView = apiAuthRequest(async (...args: ApiArgs) => { export const userPartialUpdateView = apiAuthRequest(async (...args: ApiArgs) => { /** @swagger + #swagger.summary = "Update some fields on a user" #swagger.tags = ['User'] */ const user: IUser = await UserViewset.partialUpdate(...args) @@ -176,6 +191,7 @@ export const userPartialUpdateView = apiAuthRequest(async (...args: ApiArgs) => export const userDeleteView = apiAuthRequest(async (...args: ApiArgs) => { /** @swagger + #swagger.summary = "Delete a user by id" #swagger.tags = ['User'] */ const user: IUser = await UserViewset.delete(...args)