Skip to content

Commit

Permalink
Merge pull request #59 from ufosc/feature/api-docs
Browse files Browse the repository at this point in the history
add user change routes, various api docs
  • Loading branch information
IkeHunter authored Oct 2, 2024
2 parents b8c3609 + 4dda6e9 commit 87c108e
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 32 deletions.
2 changes: 1 addition & 1 deletion docker-compose.network.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ services:
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper-jbx:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka-jbx:9092,PLAINTEXT_HOST://localhost:29092
# KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:9092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
Expand Down
2 changes: 2 additions & 0 deletions packages/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ export const LOG_NS = process.env.LOG_NS || 'server'

export const KAFKA_BROKERS = process.env.KAFKA_BROKERS?.split(',') ?? ['kafka:9092']
export const KAFKA_GROUP_ID = process.env.KAFKA_GROUP_ID ?? 'jbx-server'
export const KAFKA_CONNECT_TIMEOUT_MS = +(process.env.KAFKA_CONNECT_TIMEOUT_MS ?? 60000)
export const KAFKA_REQ_TIMEOUT_MS = +(process.env.KAFKA_REQ_TIMEOUT_MS ?? KAFKA_CONNECT_TIMEOUT_MS)
8 changes: 4 additions & 4 deletions packages/lib/kafka.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { Kafka, Partitioners, logLevel, type Message } from 'kafkajs'
import { KAFKA_BROKERS, KAFKA_GROUP_ID, NODE_ENV } from '@jukebox/config'
import { KAFKA_BROKERS, KAFKA_CONNECT_TIMEOUT_MS, KAFKA_GROUP_ID, KAFKA_REQ_TIMEOUT_MS, NODE_ENV } from '@jukebox/config'
import { logger } from './logger'

const toWinstonLogLevel = (level: logLevel) => {
Expand Down Expand Up @@ -50,13 +50,13 @@ const getKafkaInstance = () => {
brokers: KAFKA_BROKERS,
logLevel: logLevel.INFO,
logCreator: WinstonLogCreator,
connectionTimeout: 20000,
requestTimeout: 20000,
connectionTimeout: KAFKA_CONNECT_TIMEOUT_MS,
requestTimeout: KAFKA_REQ_TIMEOUT_MS,

retry: {
retries: 5,
restartOnFailure: async () => true,
maxRetryTime: 20000
maxRetryTime: KAFKA_REQ_TIMEOUT_MS
}
})
} else {
Expand Down
13 changes: 11 additions & 2 deletions server/docs/swagger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,22 @@ const doc = {
definitions: {
IGroupFields: { name: '', ownerId: '' } as IGroupFields,
IGroup: { id: '', name: '', ownerId: '' } as IGroup,
IUser: new class implements IUser {
IUser: new (class implements IUser {
id: string = 'some-id'
email: string = '[email protected]'
firstName?: string | undefined
lastName?: string | undefined
image?: string | undefined
}()
})(),
IUserDetails: {
id: 'abc123',
firstName: 'John',
email: '[email protected]',
lastName: 'Doe',
groups: [{ id: '456def', name: 'Example Group', ownerId: 'abc123' }],
image:
'https://static.vecteezy.com/system/resources/thumbnails/001/840/618/small_2x/picture-profile-icon-male-icon-human-or-people-sign-and-symbol-free-vector.jpg'
} as IUser & { groups: IGroup[] }
}
}
const generateResponseDocs = () => {
Expand Down
119 changes: 100 additions & 19 deletions server/docs/swagger_output.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"title": "Jukebox API",
"description": "Documentation automatically generated by the <b>swagger-autogen</b> module."
},
"host": "localhost:8000",
"host": "localhost:8080",
"basePath": "/",
"tags": [
{
Expand Down Expand Up @@ -534,24 +534,65 @@
"description": "",
"responses": {
"200": {
"schema": {
"$ref": "#/definitions/IUserDetails"
},
"description": "OK"
},
"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": []
}
]
},
"put": {
"description": "",
"parameters": [
{
"name": "body",
"in": "body",
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"example": "66e9f875b14c1ccc11b3d8f0"
"firstName": {
"example": "any"
},
"email": {
"type": "string",
"example": "[email protected]"
"lastName": {
"example": "any"
},
"image": {
"example": "any"
}
},
"xml": {
"name": "main"
}
},
"description": "OK"
},
}
}
],
"responses": {
"400": {
"schema": {
"$ref": "#/definitions/Error400"
Expand Down Expand Up @@ -1423,12 +1464,7 @@
},
"description": "Not implemented"
}
},
"security": [
{
"Bearer": []
}
]
}
}
},
"/api/group/groups/{id}": {
Expand Down Expand Up @@ -1658,6 +1694,51 @@
}
}
},
"IUserDetails": {
"type": "object",
"properties": {
"id": {
"type": "string",
"example": "abc123"
},
"firstName": {
"type": "string",
"example": "John"
},
"email": {
"type": "string",
"example": "[email protected]"
},
"lastName": {
"type": "string",
"example": "Doe"
},
"groups": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"example": "456def"
},
"name": {
"type": "string",
"example": "Example Group"
},
"ownerId": {
"type": "string",
"example": "abc123"
}
}
}
},
"image": {
"type": "string",
"example": "https://static.vecteezy.com/system/resources/thumbnails/001/840/618/small_2x/picture-profile-icon-male-icon-human-or-people-sign-and-symbol-free-vector.jpg"
}
}
},
"Success200": {
"type": "object",
"properties": {
Expand Down
3 changes: 2 additions & 1 deletion server/models/groupModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ const GroupSchema = new mongoose.Schema<GroupFields, GroupModel, GroupMethods>(
type: Types.ObjectId,
ref: 'SpotifyAuth',
unique: true,
dropDups: true
dropDups: true,
sparse: true
},
defaultDeviceId: {
type: String
Expand Down
2 changes: 1 addition & 1 deletion server/routes/groupRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ router.get('/:id/spotify/auth', isAuthenticated, views.getGroupSpotifyAuthView)
router.post('/:id/spotify/auth', isAuthenticated, views.assignSpotifyAccountView)

router.post('/groups', isAuthenticated, views.groupCreateView)
router.get('/groups', isAuthenticated, views.groupListView)
router.get('/groups', views.groupListView)
router.get('/groups/:id', isAuthenticated, views.groupGetView)
router.put('/groups/:id', isAuthenticated, views.groupUpdateView)
router.patch('/groups/:id', isAuthenticated, views.groupPartialUpdateView)
Expand Down
1 change: 1 addition & 0 deletions server/routes/userRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ router.post('/request-password-reset', isAuthenticated, views.requestPasswordRes
router.post('/reset-password', isAuthenticated, views.resetPasswordView)

router.get('/me', isAuthenticated, views.currentUserView)
router.put('/me', isAuthenticated, views.updateCurrentUserView)
router.get('/me/spotify-accounts', isAuthenticated, views.connectedSpotifyAccounts)

/**== User Management ==**/
Expand Down
16 changes: 12 additions & 4 deletions server/views/userViews.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,23 @@ export const currentUserView = apiAuthRequest(async (req, res, next) => {

/*
#swagger.responses[200] = {
schema: {
id: "66e9f875b14c1ccc11b3d8f0",
email: "[email protected]"
},
schema: { $ref: "#/definitions/IUserDetails" },
}
*/
return { ...userSerialized, groups }
})

export const updateCurrentUserView = apiAuthRequest(async (req, res, next) => {
const attrs: Partial<IUser> = {
firstName: req.body.firstName,
lastName: req.body.lastName,
image: req.body.image
}
const { user } = res.locals

return await User.findOneAndUpdate({ id: user._id }, attrs, { new: true }).exec()
})

// TODO: Remove authentication requirement, send email to user
export const requestPasswordResetView = apiRequest(async (req, res, next) => {
/**
Expand Down

0 comments on commit 87c108e

Please sign in to comment.