Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add user change routes, various api docs #59

Merged
merged 1 commit into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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