Compare commits
4 commits
e1ff2961e6
...
0164870be5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0164870be5 | ||
|
|
f39a0be9f0 | ||
|
|
e8ca067ae8 | ||
|
|
9061da4f09 |
9 changed files with 138 additions and 8260 deletions
42
.forgejo/workflows/build.yml
Normal file
42
.forgejo/workflows/build.yml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
name: Build and Publish Docker Image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=tag
|
||||
type=sha
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
30
Dockerfile
Normal file
30
Dockerfile
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
ARG NODE_IMAGE=node:22-slim
|
||||
|
||||
###### First Stage - Creating base ######
|
||||
FROM $NODE_IMAGE as base
|
||||
RUN mkdir -p /home/node/app && chown node:node /home/node/app
|
||||
RUN npm install --global pnpm
|
||||
WORKDIR /home/node/app
|
||||
USER node
|
||||
RUN mkdir tmp
|
||||
|
||||
###### Second Stage - Installing dependencies ######
|
||||
FROM base AS dependencies
|
||||
COPY --chown=node:node ./package*.json ./
|
||||
RUN pnpm install
|
||||
COPY --chown=node:node . .
|
||||
|
||||
###### Third Stage - Building Stage ######
|
||||
FROM dependencies AS build
|
||||
RUN node ace build
|
||||
|
||||
###### Final Stage - Production ######
|
||||
FROM base as production
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=3333
|
||||
ENV HOST=0.0.0.0
|
||||
COPY --chown=node:node ./package.json ./
|
||||
COPY --chown=node:node ./pnpm-lock.yaml ./
|
||||
RUN pnpm install --prod
|
||||
COPY --chown=node:node --from=build /home/node/app/build .
|
||||
EXPOSE 3333
|
||||
|
|
@ -53,12 +53,22 @@ export default class CollesController {
|
|||
return response.notFound({ message: 'Colle not found' })
|
||||
}
|
||||
|
||||
const relatives = await Colle.query()
|
||||
.where('subjectId', colle.subjectId)
|
||||
.where('date', colle.date.toISO()!)
|
||||
.where('id', '!=', colle.id) // Exclude the current colle
|
||||
.whereHas('student', (query) => {
|
||||
query.where('className', auth.user!.className)
|
||||
})
|
||||
.preload('student')
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
...colle.serialize(),
|
||||
bjid: colle.bjid,
|
||||
bjsecret: colle.bjsecret,
|
||||
relatives,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
47
app/middleware/bearer_token_auth_middleware.ts
Normal file
47
app/middleware/bearer_token_auth_middleware.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import env from '#start/env'
|
||||
import type { HttpContext } from '@adonisjs/core/http'
|
||||
import type { NextFn } from '@adonisjs/core/types/http'
|
||||
|
||||
export default class BearerTokenAuthMiddleware {
|
||||
async handle({ response, request }: HttpContext, next: NextFn) {
|
||||
// Get the authorization header
|
||||
const authHeader = request.header('authorization')
|
||||
if (!authHeader) {
|
||||
return response.status(401).json({
|
||||
error: 'Authorization header is required',
|
||||
})
|
||||
}
|
||||
|
||||
// Check if it's a Bearer token
|
||||
if (!authHeader.startsWith('Bearer ')) {
|
||||
return response.status(401).json({
|
||||
error: 'Authorization header must be a Bearer token',
|
||||
})
|
||||
}
|
||||
|
||||
// Extract the token
|
||||
const token = authHeader.substring(7) // Remove 'Bearer ' prefix
|
||||
if (!token) {
|
||||
return response.status(401).json({
|
||||
error: 'Token is required',
|
||||
})
|
||||
}
|
||||
|
||||
// Get the valid token from environment
|
||||
const validToken = env.get('API_BEARER_TOKEN')
|
||||
if (!validToken) {
|
||||
return response.status(500).json({
|
||||
error: 'Server configuration error: API token not configured',
|
||||
})
|
||||
}
|
||||
|
||||
// Validate the token
|
||||
if (token !== validToken) {
|
||||
return response.status(401).json({
|
||||
error: 'Invalid token',
|
||||
})
|
||||
}
|
||||
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import { DateTime } from 'luxon'
|
|||
import { UAParser } from 'ua-parser-js'
|
||||
import webpush, { PushSubscription } from 'web-push'
|
||||
|
||||
const MAX_FAILED_ATTEMPTS = 1
|
||||
const MAX_FAILED_ATTEMPTS = 5
|
||||
|
||||
export const EVENTS = {
|
||||
SYSTEM: 1 << 0,
|
||||
|
|
@ -41,7 +41,6 @@ export class NotificationService {
|
|||
}
|
||||
|
||||
private pushNotification(subscription: PushSubscription, payload: Record<string, any>) {
|
||||
console.log(payload)
|
||||
return webpush.sendNotification(subscription, JSON.stringify(payload))
|
||||
}
|
||||
|
||||
|
|
|
|||
8239
package-lock.json
generated
8239
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -71,4 +71,6 @@ export default await Env.create(new URL('../', import.meta.url), {
|
|||
VAPID_DETAILS: Env.schema.string(),
|
||||
VAPID_PUBLIC_KEY: Env.schema.string(),
|
||||
VAPID_PRIVATE_KEY: Env.schema.string(),
|
||||
|
||||
API_BEARER_TOKEN: Env.schema.string(),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -36,5 +36,6 @@ router.use([() => import('@adonisjs/core/bodyparser_middleware'), () => import('
|
|||
*/
|
||||
export const middleware = router.named({
|
||||
guest: () => import('#middleware/guest_middleware'),
|
||||
auth: () => import('#middleware/auth_middleware')
|
||||
auth: () => import('#middleware/auth_middleware'),
|
||||
internal: () => import('#middleware/bearer_token_auth_middleware'),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import router from '@adonisjs/core/services/router'
|
|||
import { authThrottle } from './limiters.js'
|
||||
import { throttle } from './limiter.js'
|
||||
import { middleware } from './kernel.js'
|
||||
import redis from '@adonisjs/redis/services/main'
|
||||
|
||||
// TODO: Magic link login
|
||||
// transmit.registerRoutes()
|
||||
|
|
@ -40,9 +39,8 @@ router.get('/subjects', [SubjectsController, 'index']).use(middleware.auth())
|
|||
const CollesController = () => import('#controllers/colles_controller')
|
||||
router
|
||||
.group(() => {
|
||||
// TODO: PRIVATE ROUTES
|
||||
router.post('/', [CollesController, 'create'])
|
||||
router.post('/upcoming', [CollesController, 'createUpcoming'])
|
||||
router.post('/', [CollesController, 'create']).use(middleware.internal())
|
||||
router.post('/upcoming', [CollesController, 'createUpcoming']).use(middleware.internal())
|
||||
router.post('/:colleId/refresh', [CollesController, 'refresh']).use(middleware.auth())
|
||||
router.get('/', [CollesController, 'index']).use(middleware.auth())
|
||||
router.get('/:colleId', [CollesController, 'show']).use(middleware.auth())
|
||||
|
|
@ -56,7 +54,7 @@ router
|
|||
router.post('/', [NotificationsController, 'subscribe'])
|
||||
router.post('/:id/unsubscribe', [NotificationsController, 'unsubscribe'])
|
||||
router.post('/:id', [NotificationsController, 'update'])
|
||||
router.post('/:id/test', [NotificationsController, 'test']).use(middleware.auth())
|
||||
router.post('/:id/test', [NotificationsController, 'test'])
|
||||
})
|
||||
.prefix('/notifications')
|
||||
.use(middleware.auth())
|
||||
|
|
@ -71,16 +69,4 @@ router
|
|||
router.post('/back-fetch', [InternalsController, 'backFetch'])
|
||||
})
|
||||
.prefix('/internals')
|
||||
// TODO: Token authentication
|
||||
|
||||
router.get('/', async () => {
|
||||
await redis.publish(
|
||||
'jobs_queue',
|
||||
JSON.stringify({
|
||||
type: 1, // Fetch day colles
|
||||
// Format DD/MM/YYYY
|
||||
date: '06/06/2025',
|
||||
class_name: 'MPSI 2',
|
||||
})
|
||||
)
|
||||
})
|
||||
.use(middleware.internal())
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue