feat: add preferences
This commit is contained in:
parent
1082f29143
commit
b2d23dd6d8
7 changed files with 121 additions and 29 deletions
17
app/controllers/subjects_controller.ts
Normal file
17
app/controllers/subjects_controller.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { HttpContext } from '@adonisjs/core/http'
|
||||
import { inject } from '@adonisjs/core'
|
||||
import { SubjectService } from '#services/subject_service'
|
||||
|
||||
@inject()
|
||||
export default class SubjectsController {
|
||||
constructor(private subjectService: SubjectService) {}
|
||||
|
||||
// GET /subjects
|
||||
async index({ auth }: HttpContext) {
|
||||
const data = await this.subjectService.getAll(auth.user!.className)
|
||||
return {
|
||||
success: true,
|
||||
data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
import User from '#models/user'
|
||||
import { createUserValidator } from '#validators/user'
|
||||
import { SubjectService } from '#services/subject_service'
|
||||
import { updateUserValidator } from '#validators/user'
|
||||
import { inject } from '@adonisjs/core'
|
||||
import type { HttpContext } from '@adonisjs/core/http'
|
||||
import { cuid } from '@adonisjs/core/helpers'
|
||||
|
||||
@inject()
|
||||
export default class UserController {
|
||||
constructor(private subjectService: SubjectService) {}
|
||||
|
||||
// GET /users/@me
|
||||
async me({ auth }: HttpContext) {
|
||||
return {
|
||||
|
|
@ -12,17 +15,40 @@ export default class UserController {
|
|||
}
|
||||
}
|
||||
|
||||
// POST /users
|
||||
async create({ request }: HttpContext) {
|
||||
const payload = await request.validateUsing(createUserValidator)
|
||||
// Save avatar
|
||||
const avatar = `avatars/${cuid()}.${payload.avatar.extname}`
|
||||
await payload.avatar.moveToDisk(avatar)
|
||||
// const avatar = await drive.use().getSignedUrl(key)
|
||||
return User.create({
|
||||
...payload,
|
||||
// TODO: No avatar for now!!
|
||||
// avatar,
|
||||
})
|
||||
// POST /users/@me
|
||||
// Update user preferences (for subjects)
|
||||
async update({ request, response, auth }: HttpContext) {
|
||||
const user = auth.user!
|
||||
const { preferences: data } = await request.validateUsing(updateUserValidator)
|
||||
const preferences = user.extras?.preferences || []
|
||||
|
||||
// Validate subject names
|
||||
const validSubjects = await this.subjectService.getAll(user.className)
|
||||
for (const { name, emoji, color } of data) {
|
||||
if (!validSubjects.includes(name)) {
|
||||
return response.badRequest({
|
||||
message: `Invalid subject name: ${name}`,
|
||||
})
|
||||
}
|
||||
const existing = preferences.find((p: any) => p.name === name)
|
||||
if (existing) {
|
||||
// Update
|
||||
existing.emoji = emoji
|
||||
existing.color = color
|
||||
} else {
|
||||
// Create new preference
|
||||
preferences.push({ name, emoji, color })
|
||||
}
|
||||
}
|
||||
|
||||
user.extras = {
|
||||
...user.extras,
|
||||
preferences,
|
||||
}
|
||||
await user.save()
|
||||
return {
|
||||
success: true,
|
||||
data: user,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ export default class User extends BaseModel {
|
|||
@column()
|
||||
declare className: string
|
||||
|
||||
@column({ serializeAs: null})
|
||||
@column({ serializeAs: null })
|
||||
declare firstName: string
|
||||
|
||||
@column({ serializeAs: null})
|
||||
@column({ serializeAs: null })
|
||||
declare lastName: string
|
||||
|
||||
@computed()
|
||||
|
|
@ -25,6 +25,14 @@ export default class User extends BaseModel {
|
|||
@column({ serializeAs: null })
|
||||
declare email: string
|
||||
|
||||
@column({ serializeAs: null })
|
||||
declare extras: Record<string, any>
|
||||
|
||||
@computed()
|
||||
get preferences(): { name: string; emoji: string; color: string }[] {
|
||||
return this.extras?.preferences || []
|
||||
}
|
||||
|
||||
@column.dateTime({ autoCreate: true })
|
||||
declare createdAt: DateTime
|
||||
|
||||
|
|
|
|||
18
app/services/subject_service.ts
Normal file
18
app/services/subject_service.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import Colle from '#models/colle'
|
||||
import Subject from '#models/subject'
|
||||
|
||||
export class SubjectService {
|
||||
async getAll(className: string): Promise<string[]> {
|
||||
const subjectsIds = (
|
||||
await Colle.query()
|
||||
.distinct('subjectId')
|
||||
.select('subjectId')
|
||||
.whereHas('student', (query) => {
|
||||
query.where('className', className)
|
||||
})
|
||||
).map((colle) => colle.subjectId)
|
||||
|
||||
const subjects = await Subject.query().whereIn('id', subjectsIds).select('name')
|
||||
return subjects.map((subject) => subject.name)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
import vine from '@vinejs/vine'
|
||||
|
||||
export const createUserValidator = vine.compile(
|
||||
export const updateUserValidator = vine.compile(
|
||||
vine.object({
|
||||
firstName: vine.string().minLength(2).maxLength(50),
|
||||
lastName: vine.string().minLength(2).maxLength(50),
|
||||
className: vine.string().minLength(2).maxLength(10),
|
||||
avatar: vine.file(),
|
||||
preferences: vine.array(
|
||||
vine.object({
|
||||
name: vine.string(),
|
||||
emoji: vine.string().maxLength(12),
|
||||
color: vine.string().maxLength(12),
|
||||
})
|
||||
),
|
||||
})
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
import { BaseSchema } from '@adonisjs/lucid/schema'
|
||||
|
||||
export default class extends BaseSchema {
|
||||
protected tableName = 'users'
|
||||
|
||||
async up() {
|
||||
this.schema.alterTable(this.tableName, (table) => {
|
||||
// Adding a JSON column for extras (can hold flexible data)
|
||||
table.jsonb('extras').nullable().after('updated_at')
|
||||
})
|
||||
}
|
||||
|
||||
async down() {
|
||||
this.schema.alterTable(this.tableName, (table) => {
|
||||
table.dropColumn('extras')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -8,12 +8,13 @@
|
|||
*/
|
||||
|
||||
import router from '@adonisjs/core/services/router'
|
||||
import transmit from '@adonisjs/transmit/services/main'
|
||||
// import transmit from '@adonisjs/transmit/services/main'
|
||||
import { authThrottle } from './limiters.js'
|
||||
import { throttle } from './limiter.js'
|
||||
import { middleware } from './kernel.js'
|
||||
|
||||
transmit.registerRoutes()
|
||||
// TODO: Magic link login
|
||||
// transmit.registerRoutes()
|
||||
|
||||
const AuthController = () => import('#controllers/auth_controller')
|
||||
|
||||
|
|
@ -29,8 +30,11 @@ router.group(() => {
|
|||
})
|
||||
|
||||
const UserController = () => import('#controllers/user_controller')
|
||||
|
||||
router.get('/users/@me', [UserController, 'me']).use(middleware.auth())
|
||||
router.post('/users/@me', [UserController, 'update']).use(middleware.auth())
|
||||
|
||||
const SubjectsController = () => import('#controllers/subjects_controller')
|
||||
router.get('/subjects', [SubjectsController, 'index']).use(middleware.auth())
|
||||
|
||||
// TEST ROUTE
|
||||
import redis from '@adonisjs/redis/services/main'
|
||||
|
|
@ -38,7 +42,8 @@ import redis from '@adonisjs/redis/services/main'
|
|||
router.get('/', async () => {
|
||||
await redis.publish("jobs_queue", JSON.stringify({
|
||||
type: 1,
|
||||
date: "09/12/2024"
|
||||
date: "20/09/2019",
|
||||
class_name: "MPSI 2",
|
||||
}))
|
||||
return { message: 'Hello, world!' }
|
||||
})
|
||||
|
|
@ -51,8 +56,5 @@ router.group(() => {
|
|||
router.post('/upcoming', [CollesController, 'createUpcoming'])
|
||||
router.get('/', [CollesController, 'index']).use(middleware.auth())
|
||||
router.get('/:colleId', [CollesController, 'show']).use(middleware.auth())
|
||||
// router.get('/colles/:id', 'CollesController.show')
|
||||
// router.put('/colles/:id', 'CollesController.update')
|
||||
// router.delete('/colles/:id', 'CollesController.delete')
|
||||
}
|
||||
).prefix('/colles')
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue