Compare commits
	
		
			2 commits
		
	
	
		
			1f8206ec88
			...
			040ae43652
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 040ae43652 | ||
|   | 90722673f8 | 
					 14 changed files with 400 additions and 26 deletions
				
			
		
							
								
								
									
										4
									
								
								README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								README.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | ||||||
|  | Clean up avant une nouvelle année scolaire : | ||||||
|  | - Effacer les mails de tous les utilisateurs (users.email) dans la base de données. | ||||||
|  | - Mettre la dernière activité à 1 mois pour l'autocomplete (auth) | ||||||
|  | - Supprimer les repas (meals) (et les plats associés avec cascade) | ||||||
|  | @ -1,5 +1,10 @@ | ||||||
| import type { HttpContext } from '@adonisjs/core/http' | import type { HttpContext } from '@adonisjs/core/http' | ||||||
| import { registerValidator, requestLoginValidator, verifyCodeValidator } from '#validators/auth' | import { | ||||||
|  |   credentialsValidator, | ||||||
|  |   registerValidator, | ||||||
|  |   requestLoginValidator, | ||||||
|  |   verifyCodeValidator, | ||||||
|  | } from '#validators/auth' | ||||||
| import mail from '@adonisjs/mail/services/main' | import mail from '@adonisjs/mail/services/main' | ||||||
| import { AuthService } from '#services/auth_service' | import { AuthService } from '#services/auth_service' | ||||||
| import { inject } from '@adonisjs/core' | import { inject } from '@adonisjs/core' | ||||||
|  | @ -7,6 +12,7 @@ import app from '@adonisjs/core/services/app' | ||||||
| import env from '#start/env' | import env from '#start/env' | ||||||
| import User from '#models/user' | import User from '#models/user' | ||||||
| import { DateTime } from 'luxon' | import { DateTime } from 'luxon' | ||||||
|  | import redis from '@adonisjs/redis/services/main' | ||||||
| 
 | 
 | ||||||
| @inject() | @inject() | ||||||
| export default class AuthController { | export default class AuthController { | ||||||
|  | @ -126,10 +132,7 @@ export default class AuthController { | ||||||
|       }) |       }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const user = await User.query() |     const user = await User.query().where('id', userId).where('className', className).first() | ||||||
|       .where('id', userId) |  | ||||||
|       .where('className', className) |  | ||||||
|       .first() |  | ||||||
|     if (!user) { |     if (!user) { | ||||||
|       return response.badRequest({ |       return response.badRequest({ | ||||||
|         success: false, |         success: false, | ||||||
|  | @ -163,6 +166,29 @@ export default class AuthController { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   // POST /auth/test
 | ||||||
|  |   public async testCredentials({ request, auth }: HttpContext) { | ||||||
|  |     const { username, password } = await request.validateUsing(credentialsValidator) | ||||||
|  |     await redis.publish( | ||||||
|  |       'jobs_queue', | ||||||
|  |       JSON.stringify({ | ||||||
|  |         type: 5, // Test credentials
 | ||||||
|  |         bj_username: username, | ||||||
|  |         bj_password: password, | ||||||
|  |         user_id: auth.user!.id, | ||||||
|  |         class_name: env.get('DEFAULT_CLASS_NAME'), | ||||||
|  |       }) | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     return { success: true, message: 'Testing credentials...' } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // GET /auth/status
 | ||||||
|  |   public async status({ auth }: HttpContext) { | ||||||
|  |     const redisKey = `auth_success_${auth.user!.id}` | ||||||
|  |     return { success: true, data: { authenticated: await redis.get(redisKey) } } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   // TODO: Magic link login
 |   // TODO: Magic link login
 | ||||||
|   // magicLink({ }: HttpContext) {
 |   // magicLink({ }: HttpContext) {
 | ||||||
|   //   // Validate signed url (adonis)
 |   //   // Validate signed url (adonis)
 | ||||||
|  |  | ||||||
|  | @ -1,3 +1,7 @@ | ||||||
|  | import Meal from '#models/meal' | ||||||
|  | import MealRegistration from '#models/meal_registration' | ||||||
|  | import env from '#start/env' | ||||||
|  | import { updateMealsRegistrationsValidator } from '#validators/meal' | ||||||
| import type { HttpContext } from '@adonisjs/core/http' | import type { HttpContext } from '@adonisjs/core/http' | ||||||
| import redis from '@adonisjs/redis/services/main' | import redis from '@adonisjs/redis/services/main' | ||||||
| import { DateTime } from 'luxon' | import { DateTime } from 'luxon' | ||||||
|  | @ -20,6 +24,46 @@ export default class InternalsController { | ||||||
|       console.log(`Colles fetching for class ${className} completed.`) |       console.log(`Colles fetching for class ${className} completed.`) | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   // POST /internals/fetch-meals
 | ||||||
|  |   async fetchMeals({ response }: HttpContext) { | ||||||
|  |     await redis.publish( | ||||||
|  |       'jobs_queue', | ||||||
|  |       JSON.stringify({ | ||||||
|  |         type: 3, // Fetch meals
 | ||||||
|  |         class_name: env.get('DEFAULT_CLASS_NAME'), | ||||||
|  |       }) | ||||||
|  |     ) | ||||||
|  |     return response.send({ success: true, message: 'Fetching meals...' }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // POST /internals/meals-registrations
 | ||||||
|  |   async updateMealsRegistrations({ response, request }: HttpContext) { | ||||||
|  |     const { userId, meals } = await request.validateUsing(updateMealsRegistrationsValidator) | ||||||
|  | 
 | ||||||
|  |     // Remove all existing registrations for the user
 | ||||||
|  |     await MealRegistration.query().where('user_id', userId).delete() | ||||||
|  |     for (const mealData of meals) { | ||||||
|  |       const meal = await Meal.query() | ||||||
|  |         .where({ | ||||||
|  |           date: mealData.date, | ||||||
|  |           type: mealData.meal_type === 'lunch' ? 0 : 1, | ||||||
|  |         }) | ||||||
|  |         .first() | ||||||
|  |       if (meal) { | ||||||
|  |         // Create a new registration
 | ||||||
|  |         await MealRegistration.create({ | ||||||
|  |           mealId: meal.id, | ||||||
|  |           userId: userId, | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return response.send({ | ||||||
|  |       success: true, | ||||||
|  |       message: 'Meal registrations updated successfully', | ||||||
|  |     }) | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function queue(className: string) { | async function queue(className: string) { | ||||||
|  |  | ||||||
							
								
								
									
										134
									
								
								app/controllers/meals_controller.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								app/controllers/meals_controller.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,134 @@ | ||||||
|  | import Meal from '#models/meal' | ||||||
|  | import MealRegistration from '#models/meal_registration' | ||||||
|  | import { credentialsValidator } from '#validators/auth' | ||||||
|  | import { createMealValidator } from '#validators/meal' | ||||||
|  | import type { HttpContext } from '@adonisjs/core/http' | ||||||
|  | import redis from '@adonisjs/redis/services/main' | ||||||
|  | import { DateTime } from 'luxon' | ||||||
|  | 
 | ||||||
|  | export default class MealsController { | ||||||
|  |   // POST /meals
 | ||||||
|  |   public async create({ request }: HttpContext) { | ||||||
|  |     const data = await request.validateUsing(createMealValidator) | ||||||
|  | 
 | ||||||
|  |     if ('meals' in data) { | ||||||
|  |       // Remove all already submittable meals
 | ||||||
|  |       await Meal.query().where('submittable', true).update({ submittable: false }) | ||||||
|  |       // Set new meals as submittable
 | ||||||
|  |       for (const mealData of data.meals) { | ||||||
|  |         const meal = await Meal.query() | ||||||
|  |           .where('date', mealData.date) | ||||||
|  |           .where('type', mealData.meal_type === 'lunch' ? 0 : 1) | ||||||
|  |           .first() | ||||||
|  |         if (meal) { | ||||||
|  |           meal.submittable = true | ||||||
|  |           await meal.save() | ||||||
|  |         } else { | ||||||
|  |           console.warn('Meal to set as submittable not found:', mealData) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       return { message: 'Meals updated successfully' } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const { date, type, courses } = data | ||||||
|  |     const mealType = type === 'Déjeuner' ? 0 : 1 | ||||||
|  | 
 | ||||||
|  |     // Check if a meal with the same date and type already exists
 | ||||||
|  |     const existingMeal = await Meal.query() | ||||||
|  |       .where({ date, type: mealType }) | ||||||
|  |       .preload('courses') | ||||||
|  |       .first() | ||||||
|  |     if (existingMeal) { | ||||||
|  |       // Check if the existing meal has the same courses
 | ||||||
|  |       const existingCourseNames = existingMeal.courses.map((course) => course.description) | ||||||
|  |       const newCourseNames = courses.map((course) => course.description) | ||||||
|  |       if ( | ||||||
|  |         existingCourseNames.length === newCourseNames.length && | ||||||
|  |         existingCourseNames.every((name) => newCourseNames.includes(name)) | ||||||
|  |       ) { | ||||||
|  |         return existingMeal | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // If not, delete the existing meal (and its courses, thanks to cascade delete)
 | ||||||
|  |       await existingMeal.delete() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Create the new meal
 | ||||||
|  |     const meal = await Meal.create({ | ||||||
|  |       date, | ||||||
|  |       type: mealType, | ||||||
|  |     }) | ||||||
|  |     await meal.related('courses').createMany(courses) | ||||||
|  |     return meal | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // GET /meals
 | ||||||
|  |   public async index({ auth }: HttpContext) { | ||||||
|  |     const meals = await Meal.query().orderBy('date', 'asc').preload('courses') | ||||||
|  |     const data = meals.map(async (meal) => { | ||||||
|  |       if (meal.submittable) { | ||||||
|  |         const isRegistered = await MealRegistration.query() | ||||||
|  |           .where('meal_id', meal.id) | ||||||
|  |           .where('user_id', auth.user!.id) | ||||||
|  |           .first() | ||||||
|  |         // Remove temporary registrations that are older than 5 minutes
 | ||||||
|  |         if (isRegistered?.temporary) { | ||||||
|  |           const oneHourAgo = DateTime.now().minus({ minutes: 5 }) | ||||||
|  |           if (isRegistered.createdAt < oneHourAgo) { | ||||||
|  |             await isRegistered.delete() | ||||||
|  |             return meal.serialize() | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         return { | ||||||
|  |           ...meal.serialize(), | ||||||
|  |           isRegistered: !!isRegistered, | ||||||
|  |         } | ||||||
|  |       } else { | ||||||
|  |         return meal.serialize() | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|  | 
 | ||||||
|  |     return Promise.all(data) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // POST /meals/:id
 | ||||||
|  |   // TODO: Unregister from meal
 | ||||||
|  |   public async registerForMeal({ params, auth, response, request }: HttpContext) { | ||||||
|  |     const { username, password } = await request.validateUsing(credentialsValidator) | ||||||
|  | 
 | ||||||
|  |     const meal = await Meal.find(params.id) | ||||||
|  |     if (!meal) { | ||||||
|  |       return response.notFound({ message: 'Meal not found' }) | ||||||
|  |     } | ||||||
|  |     if (!meal.submittable) { | ||||||
|  |       return response.badRequest({ message: 'Meal is not submittable' }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Create a bullshit registration
 | ||||||
|  |     // (to confirm to the user that the registration is in progress...)
 | ||||||
|  |     // that will eventually be deleted if the registration fails (worker callback)
 | ||||||
|  |     await MealRegistration.firstOrCreate({ | ||||||
|  |       mealId: meal.id, | ||||||
|  |       userId: auth.user!.id, | ||||||
|  |       temporary: true, | ||||||
|  |     }) | ||||||
|  | 
 | ||||||
|  |     // Register the user for the meal
 | ||||||
|  |     await redis.publish( | ||||||
|  |       'jobs_queue', | ||||||
|  |       JSON.stringify({ | ||||||
|  |         type: 4, // Submit meals
 | ||||||
|  |         meal: { | ||||||
|  |           date: DateTime.fromJSDate(meal.date).toISODate(), | ||||||
|  |           meal_type: meal.type === 0 ? 'lunch' : 'dinner', | ||||||
|  |         }, | ||||||
|  |         class_name: auth.user!.className, | ||||||
|  |         user_id: auth.user!.id, | ||||||
|  |         bj_username: username, | ||||||
|  |         bj_password: password, | ||||||
|  |       }) | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     return { success: true, message: 'Registration in progress' } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								app/models/course.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								app/models/course.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | ||||||
|  | import { BaseModel, column } from '@adonisjs/lucid/orm' | ||||||
|  | 
 | ||||||
|  | export default class Course extends BaseModel { | ||||||
|  |   @column({ isPrimary: true }) | ||||||
|  |   declare id: number | ||||||
|  | 
 | ||||||
|  |   @column() | ||||||
|  |   declare mealId: number | ||||||
|  | 
 | ||||||
|  |   @column() | ||||||
|  |   declare name: string | ||||||
|  | 
 | ||||||
|  |   @column() | ||||||
|  |   declare description: string | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								app/models/meal.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								app/models/meal.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | ||||||
|  | import { BaseModel, column, computed, hasMany } from '@adonisjs/lucid/orm' | ||||||
|  | import Course from './course.js' | ||||||
|  | import type { HasMany } from '@adonisjs/lucid/types/relations' | ||||||
|  | 
 | ||||||
|  | export default class Meal extends BaseModel { | ||||||
|  |   @column({ isPrimary: true }) | ||||||
|  |   declare id: number | ||||||
|  | 
 | ||||||
|  |   @column() | ||||||
|  |   declare date: Date | ||||||
|  | 
 | ||||||
|  |   @column() | ||||||
|  |   declare type: 0 | 1 // 0 = lunch, 1 = dinner
 | ||||||
|  | 
 | ||||||
|  |   @column() | ||||||
|  |   declare submittable: boolean | ||||||
|  | 
 | ||||||
|  |   @computed() | ||||||
|  |   get name() { | ||||||
|  |     return this.type === 0 ? 'Déjeuner' : 'Dîner' | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @hasMany(() => Course) | ||||||
|  |   declare courses: HasMany<typeof Course> | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								app/models/meal_registration.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/models/meal_registration.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | ||||||
|  | import { BaseModel, column } from '@adonisjs/lucid/orm' | ||||||
|  | import { DateTime } from 'luxon' | ||||||
|  | 
 | ||||||
|  | export default class MealRegistration extends BaseModel { | ||||||
|  |   @column({ isPrimary: true }) | ||||||
|  |   declare id: number | ||||||
|  | 
 | ||||||
|  |   @column() | ||||||
|  |   declare mealId: number | ||||||
|  | 
 | ||||||
|  |   @column() | ||||||
|  |   declare userId: number | ||||||
|  | 
 | ||||||
|  |   @column() | ||||||
|  |   declare temporary: boolean | ||||||
|  | 
 | ||||||
|  |   @column.dateTime({ autoCreate: true }) | ||||||
|  |   declare createdAt: DateTime | ||||||
|  | } | ||||||
|  | @ -27,6 +27,13 @@ export const registerValidator = vine.compile( | ||||||
|   }) |   }) | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | export const credentialsValidator = vine.compile( | ||||||
|  |   vine.object({ | ||||||
|  |     username: vine.string().minLength(1).maxLength(255), | ||||||
|  |     password: vine.string().minLength(1).maxLength(255), | ||||||
|  |   }) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| // TODO: Magic link login
 | // TODO: Magic link login
 | ||||||
| // export const magicLinkValidator = vine.compile(
 | // export const magicLinkValidator = vine.compile(
 | ||||||
| //   vine.object({
 | //   vine.object({
 | ||||||
|  |  | ||||||
							
								
								
									
										40
									
								
								app/validators/meal.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								app/validators/meal.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | ||||||
|  | import vine from '@vinejs/vine' | ||||||
|  | 
 | ||||||
|  | const meals = vine.array( | ||||||
|  |   vine.object({ | ||||||
|  |     date: vine.string(), // YYYY-MM-DD
 | ||||||
|  |     meal_type: vine.string().in(['dinner', 'lunch']), | ||||||
|  |   }) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | export const createMealValidator = vine.compile( | ||||||
|  |   vine.union([ | ||||||
|  |     vine.union.if( | ||||||
|  |       (data) => vine.helpers.isObject(data) && 'meals' in data, | ||||||
|  |       vine.object({ | ||||||
|  |         meals, | ||||||
|  |       }) | ||||||
|  |     ), | ||||||
|  |     vine.union.else( | ||||||
|  |       vine.object({ | ||||||
|  |         date: vine.date(), | ||||||
|  |         type: vine.string().in(['Déjeuner', 'Dîner']), | ||||||
|  |         courses: vine | ||||||
|  |           .array( | ||||||
|  |             vine.object({ | ||||||
|  |               name: vine.string().minLength(1).maxLength(255), | ||||||
|  |               description: vine.string().minLength(1), | ||||||
|  |             }) | ||||||
|  |           ) | ||||||
|  |           .minLength(1), | ||||||
|  |       }) | ||||||
|  |     ), | ||||||
|  |   ]) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | export const updateMealsRegistrationsValidator = vine.compile( | ||||||
|  |   vine.object({ | ||||||
|  |     userId: vine.number().min(1), | ||||||
|  |     meals, | ||||||
|  |   }) | ||||||
|  | ) | ||||||
							
								
								
									
										18
									
								
								database/migrations/1756124105948_create_meals_table.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								database/migrations/1756124105948_create_meals_table.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | ||||||
|  | import { BaseSchema } from '@adonisjs/lucid/schema' | ||||||
|  | 
 | ||||||
|  | export default class extends BaseSchema { | ||||||
|  |   protected tableName = 'meals' | ||||||
|  | 
 | ||||||
|  |   async up() { | ||||||
|  |     this.schema.createTable(this.tableName, (table) => { | ||||||
|  |       table.increments('id') | ||||||
|  |       table.date('date').notNullable() | ||||||
|  |       table.integer('type').notNullable() // 0 = lunch, 1 = dinner
 | ||||||
|  |       table.boolean('submittable').defaultTo(false) | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async down() { | ||||||
|  |     this.schema.dropTable(this.tableName) | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								database/migrations/1756124135995_create_courses_table.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								database/migrations/1756124135995_create_courses_table.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | ||||||
|  | import { BaseSchema } from '@adonisjs/lucid/schema' | ||||||
|  | 
 | ||||||
|  | export default class extends BaseSchema { | ||||||
|  |   protected tableName = 'courses' | ||||||
|  | 
 | ||||||
|  |   async up() { | ||||||
|  |     this.schema.createTable(this.tableName, (table) => { | ||||||
|  |       table.increments('id') | ||||||
|  |       table.integer('meal_id').unsigned().references('id').inTable('meals').onDelete('CASCADE') | ||||||
|  |       table.string('name').notNullable() | ||||||
|  |       table.text('description').notNullable() | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async down() { | ||||||
|  |     this.schema.dropTable(this.tableName) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,19 @@ | ||||||
|  | import { BaseSchema } from '@adonisjs/lucid/schema' | ||||||
|  | 
 | ||||||
|  | export default class extends BaseSchema { | ||||||
|  |   protected tableName = 'meal_registrations' | ||||||
|  | 
 | ||||||
|  |   async up() { | ||||||
|  |     this.schema.createTable(this.tableName, (table) => { | ||||||
|  |       table.increments('id') | ||||||
|  |       table.integer('meal_id').unsigned().references('id').inTable('meals').onDelete('CASCADE') | ||||||
|  |       table.integer('user_id').unsigned().references('id').inTable('users').onDelete('CASCADE') | ||||||
|  |       table.boolean('temporary').defaultTo(false) | ||||||
|  |       table.timestamp('created_at').notNullable() | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async down() { | ||||||
|  |     this.schema.dropTable(this.tableName) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -74,5 +74,5 @@ export default await Env.create(new URL('../', import.meta.url), { | ||||||
| 
 | 
 | ||||||
|   API_BEARER_TOKEN: Env.schema.string(), |   API_BEARER_TOKEN: Env.schema.string(), | ||||||
| 
 | 
 | ||||||
|   MENUS_PATH: Env.schema.string(), |   DEFAULT_CLASS_NAME: Env.schema.string(), | ||||||
| }) | }) | ||||||
|  |  | ||||||
|  | @ -18,16 +18,20 @@ import { middleware } from './kernel.js' | ||||||
| 
 | 
 | ||||||
| const AuthController = () => import('#controllers/auth_controller') | const AuthController = () => import('#controllers/auth_controller') | ||||||
| 
 | 
 | ||||||
| router.group(() => { | router | ||||||
|   router.post('/auth/request', [AuthController, 'requestLogin']).use(authThrottle) |   .group(() => { | ||||||
|   router.post('/auth/verify', [AuthController, 'verifyCode']).use(throttle) |     router.post('/request', [AuthController, 'requestLogin']).use(authThrottle) | ||||||
|   router.post('/auth/register', [AuthController, 'register']).use(throttle) |     router.post('/verify', [AuthController, 'verifyCode']).use(throttle) | ||||||
|   router.post('/auth/logout', [AuthController, 'logout']) |     router.post('/register', [AuthController, 'register']).use(throttle) | ||||||
|   router.get('/auth/autocomplete', [AuthController, 'listNames']).use(throttle) |     router.post('/logout', [AuthController, 'logout']) | ||||||
|   // TODO: Magic link login
 |     router.get('/autocomplete', [AuthController, 'listNames']).use(throttle) | ||||||
|   // router.get('/auth/magic-link', 'AuthController.magicLink').use(throttle)
 |     router.post('/test', [AuthController, 'testCredentials']).use(throttle).use(middleware.auth()) | ||||||
|   // router.get('/auth/listen', 'AuthController.listen')
 |     router.get('/status', [AuthController, 'status']).use(middleware.auth()) | ||||||
| }) |     // TODO: Magic link login
 | ||||||
|  |     // router.get('/auth/magic-link', 'AuthController.magicLink').use(throttle)
 | ||||||
|  |     // router.get('/auth/listen', 'AuthController.listen')
 | ||||||
|  |   }) | ||||||
|  |   .prefix('/auth') | ||||||
| 
 | 
 | ||||||
| const UserController = () => import('#controllers/user_controller') | const UserController = () => import('#controllers/user_controller') | ||||||
| router.get('/users/@me', [UserController, 'me']).use(middleware.auth()) | router.get('/users/@me', [UserController, 'me']).use(middleware.auth()) | ||||||
|  | @ -67,20 +71,21 @@ const InternalsController = () => import('#controllers/internals_controller') | ||||||
| router | router | ||||||
|   .group(() => { |   .group(() => { | ||||||
|     router.post('/back-fetch', [InternalsController, 'backFetch']) |     router.post('/back-fetch', [InternalsController, 'backFetch']) | ||||||
|  |     router.post('/fetch-meals', [InternalsController, 'fetchMeals']) | ||||||
|  |     router.post('/meals-registrations', [InternalsController, 'updateMealsRegistrations']) | ||||||
|   }) |   }) | ||||||
|   .prefix('/internals') |   .prefix('/internals') | ||||||
|   .use(middleware.internal()) |   .use(middleware.internal()) | ||||||
| 
 | 
 | ||||||
|  | const MealsController = () => import('#controllers/meals_controller') | ||||||
|  | router | ||||||
|  |   .group(() => { | ||||||
|  |     router.post('/', [MealsController, 'create']).use(middleware.internal()) | ||||||
|  |     router.get('/', [MealsController, 'index']).use(middleware.auth()) | ||||||
|  |     router.post('/:id', [MealsController, 'registerForMeal']).use(middleware.auth()) | ||||||
|  |   }) | ||||||
|  |   .prefix('/meals') | ||||||
|  | 
 | ||||||
| router.get('/health', async () => { | router.get('/health', async () => { | ||||||
|   return { status: 'ok' } |   return { status: 'ok' } | ||||||
| }) | }) | ||||||
| 
 |  | ||||||
| // BETA: Serve menus.json file
 |  | ||||||
| import fs from 'node:fs/promises' |  | ||||||
| import env from './env.js' |  | ||||||
| 
 |  | ||||||
| router.get('/menus', async () => { |  | ||||||
|   // Return menus.json file
 |  | ||||||
|   const data = await fs.readFile(env.get('MENUS_PATH'), 'utf-8') |  | ||||||
|   return JSON.parse(data) |  | ||||||
| }) |  | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue