From 671f17a2888a123eb0494b786be5b31761af4af7 Mon Sep 17 00:00:00 2001 From: Antoine Date: Mon, 6 Jul 2026 14:48:04 +0200 Subject: [PATCH 01/27] feat(front): contact informations in admin user page --- frontend/src/components/Admin/adminUser.tsx | 229 ++++++++++-------- frontend/src/interfaces/user.interface.ts | 6 + .../src/services/requests/user.service.ts | 8 +- 3 files changed, 143 insertions(+), 100 deletions(-) diff --git a/frontend/src/components/Admin/adminUser.tsx b/frontend/src/components/Admin/adminUser.tsx index e1a7a74..79a1fa8 100644 --- a/frontend/src/components/Admin/adminUser.tsx +++ b/frontend/src/components/Admin/adminUser.tsx @@ -2,10 +2,11 @@ import { useEffect, useState } from 'react'; import Select from 'react-select'; import Swal from 'sweetalert2'; -import { type User } from '../../interfaces/user.interface'; +import { type User,type UserContactInformation } from '../../interfaces/user.interface'; import { renewTokenUser, requestPasswordUser } from '../../services/requests/auth.service'; import { deleteUserByAdmin, + getUserContactInformation, getUsersAdmin, syncnewStudent, updateUserByAdmin, @@ -46,6 +47,7 @@ export const AdminUser = () => { const [users, setUsers] = useState([]); const [selectedUser, setSelectedUser] = useState(null); const [formData, setFormData] = useState>({}); + const [contactInformation, setContactInformation] = useState>({}); useEffect(() => { const fetchUsers = async () => { @@ -55,11 +57,12 @@ export const AdminUser = () => { fetchUsers(); }, []); - const handleUserSelect = (option: any) => { + const handleUserSelect = async (option: any) => { const user = users.find((u) => u.userId === option.value); if (user) { setSelectedUser(user); setFormData({ ...user }); + setContactInformation({ ...(await getUserContactInformation(user.userId)) }); } }; @@ -165,104 +168,132 @@ export const AdminUser = () => { }; return ( - - - - 👤 Gérer un utilisateur - - - - - - - - -

- Attention : la donnée récupérée dépend de la date de synchro choisie -

- - b.value === formData.branch) || null} - onChange={handleSelectChange('branch')} - options={branchOptions} - placeholder="Choisir une filière" - isClearable - /> - - - - ({ + value: u.userId, + label: `${u.firstName} ${u.lastName} (${u.email})`, + }))} + onChange={handleUserSelect} + /> + + {selectedUser && ( +
+ + + + +

+ Attention : la donnée récupérée dépend de la date de synchro choisie +

+ + b.value === formData.branch) || null} + onChange={handleSelectChange('branch')} + options={branchOptions} + placeholder="Choisir une filière" + isClearable + /> + + + + + -
- )} -
-
+ + + + )} + ); }; diff --git a/frontend/src/interfaces/user.interface.ts b/frontend/src/interfaces/user.interface.ts index 680dd49..ea26891 100644 --- a/frontend/src/interfaces/user.interface.ts +++ b/frontend/src/interfaces/user.interface.ts @@ -9,3 +9,9 @@ export interface User { contact: string; discord_id: string; } + +export interface UserContactInformation { + userId: number; + urgency_contact_name: string; + urgency_contact_phone: number; +} \ No newline at end of file diff --git a/frontend/src/services/requests/user.service.ts b/frontend/src/services/requests/user.service.ts index 80ac24c..3198def 100644 --- a/frontend/src/services/requests/user.service.ts +++ b/frontend/src/services/requests/user.service.ts @@ -1,4 +1,4 @@ -import { type User } from '../../interfaces/user.interface'; +import { type User, type UserContactInformation } from '../../interfaces/user.interface'; import api from '../api'; export const getPermission = (): string | null => { @@ -46,6 +46,12 @@ export const getCurrentUser = async () => { return res.data.data; }; +export const getUserContactInformation = async (userId: number) => { + const response = await api.get(`/user/admin/getusercontactinformation/${userId}`); + const users: UserContactInformation = response.data.data; + return users; +}; + export const updateCurrentUser = async (data: Partial) => { const response = await api.patch("/user/user/me", data); return response.data From 7ad8db8e50f45de505ab5f194c2fe3f426f8e87a Mon Sep 17 00:00:00 2001 From: Antoine Date: Mon, 6 Jul 2026 15:12:24 +0200 Subject: [PATCH 02/27] feat(back): add endpoint and service for retrieving user contact information --- backend/src/controllers/user.controller.ts | 11 +++++++++++ backend/src/routes/user.routes.ts | 1 + .../schemas/Relational/userinformation.schema.ts | 10 ++++++++++ backend/src/services/user.service.ts | 16 ++++++++++++++++ 4 files changed, 38 insertions(+) create mode 100644 backend/src/schemas/Relational/userinformation.schema.ts diff --git a/backend/src/controllers/user.controller.ts b/backend/src/controllers/user.controller.ts index d7008dd..d85e247 100644 --- a/backend/src/controllers/user.controller.ts +++ b/backend/src/controllers/user.controller.ts @@ -87,6 +87,17 @@ export const getCurrentUser = async (req: Request, res: Response) => { } }; +export const getUserContactInformation = async (req: Request, res: Response) => { + const { userId } = req.params; + + try { + const userContactInfo = await user_service.getUserContactInformation(parseInt(userId)); + Ok(res, { data: userContactInfo }); + } catch { + Error(res, { msg: 'Erreur lors de la récupération des informations de contact de l\'utilisateur.' }); + } +}; + export const updateProfile = async (req: Request, res: Response) => { const userId = req.user?.userId; const { branch, contact } = req.body; diff --git a/backend/src/routes/user.routes.ts b/backend/src/routes/user.routes.ts index ae2f9d2..c83d3fa 100644 --- a/backend/src/routes/user.routes.ts +++ b/backend/src/routes/user.routes.ts @@ -8,6 +8,7 @@ const userRouter = express.Router(); userRouter.get('/admin/getusersbypermission', checkRole("Admin", []), userController.getUsersByPermission); userRouter.patch('/admin/user/:userId', checkRole("Admin", []), userController.adminUpdateUser); userRouter.delete('/admin/user/:userId', checkRole("Admin", []), userController.adminDeleteUser); +userRouter.get('/admin/getusercontactinformation/:userId', checkRole("Admin", []), userController.getUserContactInformation); userRouter.get('/admin/getusers', checkRole("Admin", ["Respo CE"]), userController.getUsersAdmin); userRouter.post('/admin/syncnewstudent', checkRole("Admin", []), userController.syncNewstudent); diff --git a/backend/src/schemas/Relational/userinformation.schema.ts b/backend/src/schemas/Relational/userinformation.schema.ts new file mode 100644 index 0000000..056bc55 --- /dev/null +++ b/backend/src/schemas/Relational/userinformation.schema.ts @@ -0,0 +1,10 @@ +import { pgTable, integer, text } from "drizzle-orm/pg-core"; +import { userSchema } from "../Basic/user.schema"; + +export const userinformationSchema = pgTable("userinformations", { + user_id: integer("user_id").primaryKey().references(() => userSchema.id, { onDelete: "cascade" }), + urgency_contact_name: text("urgency_contact_name"), + urgency_contact_phone: integer("urgency_contact_phone"), +}); + +export type UserInformation = typeof userinformationSchema.$inferSelect; \ No newline at end of file diff --git a/backend/src/services/user.service.ts b/backend/src/services/user.service.ts index c457be9..1729606 100644 --- a/backend/src/services/user.service.ts +++ b/backend/src/services/user.service.ts @@ -133,6 +133,22 @@ export const getUsers = async () => { } }; +export const getUserContactInformation = async (userId: number) => { + try { + const user = await db.select( + { + userId: userSchema.id, + urgency_contact_name: userSchema.contact, + urgency_contact_phone: userSchema.contact + } + ).from(userSchema).where(eq(userSchema.id, userId)); + return user[0]; + } catch (err) { + console.error('Erreur lors de la récupération des informations de contact de l\'utilisateur ', err); + throw new Error('Erreur de base de données'); + } +}; + export const getUsersAll = async () => { try { const users = await db.select().from(userSchema); From 3e152d3eb763a33d7d9ea09284fb250f5b87f528 Mon Sep 17 00:00:00 2001 From: Antoine Date: Mon, 6 Jul 2026 15:17:23 +0200 Subject: [PATCH 03/27] fix(back): wrong table --- backend/src/schemas/Relational/userinformation.schema.ts | 4 ++-- backend/src/services/user.service.ts | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/backend/src/schemas/Relational/userinformation.schema.ts b/backend/src/schemas/Relational/userinformation.schema.ts index 056bc55..084db9a 100644 --- a/backend/src/schemas/Relational/userinformation.schema.ts +++ b/backend/src/schemas/Relational/userinformation.schema.ts @@ -1,10 +1,10 @@ import { pgTable, integer, text } from "drizzle-orm/pg-core"; import { userSchema } from "../Basic/user.schema"; -export const userinformationSchema = pgTable("userinformations", { +export const userInformationSchema = pgTable("user_informations", { user_id: integer("user_id").primaryKey().references(() => userSchema.id, { onDelete: "cascade" }), urgency_contact_name: text("urgency_contact_name"), urgency_contact_phone: integer("urgency_contact_phone"), }); -export type UserInformation = typeof userinformationSchema.$inferSelect; \ No newline at end of file +export type UserInformation = typeof userInformationSchema.$inferSelect; \ No newline at end of file diff --git a/backend/src/services/user.service.ts b/backend/src/services/user.service.ts index 1729606..bed7eb5 100644 --- a/backend/src/services/user.service.ts +++ b/backend/src/services/user.service.ts @@ -6,6 +6,7 @@ import { registrationSchema } from '../schemas/Relational/registration.schema'; import { getFaction } from './faction.service'; import { getUserRoles } from './role.service'; import { getTeam, getTeamFaction, getUserTeam } from './team.service'; +import { userInformationSchema } from '../schemas/Relational/userinformation.schema'; // Fonction pour récupérer un utilisateur par email export const getUserByEmail = async (email: string) => { @@ -137,11 +138,11 @@ export const getUserContactInformation = async (userId: number) => { try { const user = await db.select( { - userId: userSchema.id, - urgency_contact_name: userSchema.contact, - urgency_contact_phone: userSchema.contact + userId: userInformationSchema.user_id, + urgency_contact_name: userInformationSchema.urgency_contact_name, + urgency_contact_phone: userInformationSchema.urgency_contact_phone } - ).from(userSchema).where(eq(userSchema.id, userId)); + ).from(userInformationSchema).where(eq(userInformationSchema.user_id, userId)); return user[0]; } catch (err) { console.error('Erreur lors de la récupération des informations de contact de l\'utilisateur ', err); From 4571f0be8426f1b8203e24bfcf7403a15f91e7c1 Mon Sep 17 00:00:00 2001 From: Antoine Date: Mon, 6 Jul 2026 15:46:07 +0200 Subject: [PATCH 04/27] feat(front): Add header when form isn't complete --- frontend/src/components/navbar.tsx | 138 ++++++++++-------- .../src/services/requests/user.service.ts | 10 +- 2 files changed, 88 insertions(+), 60 deletions(-) diff --git a/frontend/src/components/navbar.tsx b/frontend/src/components/navbar.tsx index f0975ba..fe5da5a 100644 --- a/frontend/src/components/navbar.tsx +++ b/frontend/src/components/navbar.tsx @@ -5,6 +5,7 @@ import { Fragment, useEffect, useState } from "react"; import { NavLink, useLocation } from "react-router-dom"; import { decodeToken, getToken } from "../services/requests/auth.service"; +import { getCurrentUserContactInformation } from "../services/requests/user.service"; interface NavItem { label: string; @@ -25,6 +26,7 @@ export const Navbar = () => { const isAuthenticated = Boolean(token); const { userPermission, userRoles = [] } = token ? decodeToken(token) : { userPermission: undefined, userRoles: [] }; const roles = [userPermission, ...userRoles.map(r => r.roleName)].filter(Boolean) as string[]; + const [hasContactInformation, setHasContactInformation] = useState(false); const handleLogout = () => { localStorage.removeItem("authToken"); @@ -33,6 +35,18 @@ export const Navbar = () => { useEffect(() => { setMenuOpen(false); + const fetchContactInformation = async () => { + try { + const contactInfo = await getCurrentUserContactInformation(); + setHasContactInformation(contactInfo.urgency_contact_phone !== null); + } catch (error) { + console.error("Erreur lors de la récupération des informations de contact :", error); + } + }; + + if (isAuthenticated) { + fetchContactInformation(); + } }, [pathname]); const navItems: NavItem[] = [ @@ -126,72 +140,80 @@ export const Navbar = () => { }; return ( - + + {/* Contact Information Warning */ hasContactInformation === false && isAuthenticated && ( +
+

ATTENTION : Tu n'as pas complété le formulaire VSS ainsi que tes informations d'urgence. Merci de le faire au plus vite !

+
+ )} + ); }; diff --git a/frontend/src/services/requests/user.service.ts b/frontend/src/services/requests/user.service.ts index 3198def..1134c17 100644 --- a/frontend/src/services/requests/user.service.ts +++ b/frontend/src/services/requests/user.service.ts @@ -41,13 +41,19 @@ export const getUsersByPermission = async () => { return users; } +export const getUserContactInformation = async (userId: number) => { + const response = await api.get(`/user/admin/getusercontactinformation/${userId}`); + const users: UserContactInformation = response.data.data; + return users; +}; + export const getCurrentUser = async () => { const res = await api.get("/user/user/me"); return res.data.data; }; -export const getUserContactInformation = async (userId: number) => { - const response = await api.get(`/user/admin/getusercontactinformation/${userId}`); +export const getCurrentUserContactInformation = async () => { + const response = await api.get(`/user/user/getusercontactinformation`); const users: UserContactInformation = response.data.data; return users; }; From 4e53913af818988a2dc5f9fc5b7db8cf96e6ecc7 Mon Sep 17 00:00:00 2001 From: Antoine Date: Sat, 11 Jul 2026 19:16:44 +0200 Subject: [PATCH 05/27] feat(front): add urgency modal (empty) and header button --- .../Relational/userinformation.schema.ts | 1 + backend/src/services/user.service.ts | 3 +- frontend/src/components/auth/authForm.tsx | 2 +- frontend/src/components/home/urgencyModal.tsx | 20 ++ frontend/src/components/navbar.tsx | 241 ++++++++---------- frontend/src/components/ui/modal.tsx | 129 ++++++++++ frontend/src/pages/home.tsx | 11 +- 7 files changed, 268 insertions(+), 139 deletions(-) create mode 100644 frontend/src/components/home/urgencyModal.tsx create mode 100644 frontend/src/components/ui/modal.tsx diff --git a/backend/src/schemas/Relational/userinformation.schema.ts b/backend/src/schemas/Relational/userinformation.schema.ts index 084db9a..bfdceea 100644 --- a/backend/src/schemas/Relational/userinformation.schema.ts +++ b/backend/src/schemas/Relational/userinformation.schema.ts @@ -5,6 +5,7 @@ export const userInformationSchema = pgTable("user_informations", { user_id: integer("user_id").primaryKey().references(() => userSchema.id, { onDelete: "cascade" }), urgency_contact_name: text("urgency_contact_name"), urgency_contact_phone: integer("urgency_contact_phone"), + contact_CE: text("contact_CE"), }); export type UserInformation = typeof userInformationSchema.$inferSelect; \ No newline at end of file diff --git a/backend/src/services/user.service.ts b/backend/src/services/user.service.ts index bed7eb5..5ba7bcb 100644 --- a/backend/src/services/user.service.ts +++ b/backend/src/services/user.service.ts @@ -140,7 +140,8 @@ export const getUserContactInformation = async (userId: number) => { { userId: userInformationSchema.user_id, urgency_contact_name: userInformationSchema.urgency_contact_name, - urgency_contact_phone: userInformationSchema.urgency_contact_phone + urgency_contact_phone: userInformationSchema.urgency_contact_phone, + contact_CE: userInformationSchema.contact_CE } ).from(userInformationSchema).where(eq(userInformationSchema.user_id, userId)); return user[0]; diff --git a/frontend/src/components/auth/authForm.tsx b/frontend/src/components/auth/authForm.tsx index bf98f29..64f0f32 100644 --- a/frontend/src/components/auth/authForm.tsx +++ b/frontend/src/components/auth/authForm.tsx @@ -31,7 +31,7 @@ export const AuthForm = () => { const token = await loginUser(formData.email, formData.password); if (token) { localStorage.setItem("authToken", token); - window.location.href = "/home"; + window.location.href = "/home?login=true"; } } catch (err: any) { console.error(err); diff --git a/frontend/src/components/home/urgencyModal.tsx b/frontend/src/components/home/urgencyModal.tsx new file mode 100644 index 0000000..343fe2a --- /dev/null +++ b/frontend/src/components/home/urgencyModal.tsx @@ -0,0 +1,20 @@ +import { useSearchParams } from 'react-router-dom'; + +import Modal from '../ui/modal'; + +function UrgencyModal() { + const [searchParams, setSearchParams] = useSearchParams(); + + const isLogin = searchParams.get('login') === 'true'; + + return ( + setSearchParams({})} + buttons={null} + /> + ); +} + +export default UrgencyModal; diff --git a/frontend/src/components/navbar.tsx b/frontend/src/components/navbar.tsx index fe5da5a..12a6e1c 100644 --- a/frontend/src/components/navbar.tsx +++ b/frontend/src/components/navbar.tsx @@ -1,11 +1,12 @@ -import { Bars4Icon, CogIcon, HomeIcon, UsersIcon } from "@heroicons/react/24/outline"; -import { XMarkIcon, } from "@heroicons/react/24/solid"; -import { AnimatePresence, motion } from "framer-motion"; -import { Fragment, useEffect, useState } from "react"; -import { NavLink, useLocation } from "react-router-dom"; +import { Bars4Icon, CogIcon, HomeIcon, UsersIcon } from '@heroicons/react/24/outline'; +import { XMarkIcon } from '@heroicons/react/24/solid'; +import { AnimatePresence, motion } from 'framer-motion'; +import { Fragment, useEffect, useState } from 'react'; +import { NavLink, useLocation, useSearchParams } from 'react-router-dom'; -import { decodeToken, getToken } from "../services/requests/auth.service"; -import { getCurrentUserContactInformation } from "../services/requests/user.service"; +import { decodeToken, getToken } from '../services/requests/auth.service'; +import { getCurrentUserContactInformation } from '../services/requests/user.service'; +import { Button } from './ui/button'; interface NavItem { label: string; @@ -13,10 +14,10 @@ interface NavItem { icon?: React.ComponentType>; rolesAllowed?: string[]; // ["Admin", "Respo CE", ...] public?: boolean; - showWhen?: "always" | "auth" | "guest"; - kind?: "link" | "action"; + showWhen?: 'always' | 'auth' | 'guest'; + kind?: 'link' | 'action'; onClick?: () => void; - children?: NavItem[]; // pour dropdown + children?: NavItem[]; // pour dropdown } export const Navbar = () => { @@ -24,13 +25,16 @@ export const Navbar = () => { const token = getToken(); const [menuOpen, setMenuOpen] = useState(false); const isAuthenticated = Boolean(token); - const { userPermission, userRoles = [] } = token ? decodeToken(token) : { userPermission: undefined, userRoles: [] }; - const roles = [userPermission, ...userRoles.map(r => r.roleName)].filter(Boolean) as string[]; + const { userPermission, userRoles = [] } = token + ? decodeToken(token) + : { userPermission: undefined, userRoles: [] }; + const roles = [userPermission, ...userRoles.map((r) => r.roleName)].filter(Boolean) as string[]; const [hasContactInformation, setHasContactInformation] = useState(false); + const [, setSearchParams] = useSearchParams(); const handleLogout = () => { - localStorage.removeItem("authToken"); - window.location.href = "/"; + localStorage.removeItem('authToken'); + window.location.href = '/'; }; useEffect(() => { @@ -40,7 +44,7 @@ export const Navbar = () => { const contactInfo = await getCurrentUserContactInformation(); setHasContactInformation(contactInfo.urgency_contact_phone !== null); } catch (error) { - console.error("Erreur lors de la récupération des informations de contact :", error); + console.error('Erreur lors de la récupération des informations de contact :', error); } }; @@ -50,90 +54,88 @@ export const Navbar = () => { }, [pathname]); const navItems: NavItem[] = [ - { label: "Home", to: "/home", icon: HomeIcon }, - { label: "Plannings", to: "/plannings" }, - { label: "Parrainage", to: "/parrainage" }, - { label: "Challenges", to: "/challenges" }, - { label: "Mes Actus", to: "/news" }, + { label: 'Home', to: '/home', icon: HomeIcon }, + { label: 'Plannings', to: '/plannings' }, + { label: 'Parrainage', to: '/parrainage' }, + { label: 'Challenges', to: '/challenges' }, + { label: 'Mes Actus', to: '/news' }, { - label: "Permanences", - to: "#", + label: 'Permanences', + to: '#', children: [ - { label: "Listes des permanences", to: "/permanenceslist", rolesAllowed: ["Admin", "Student"] }, - { label: "Mes permanences", to: "/mypermanences", rolesAllowed: ["Admin", "Student"] }, - { label: "Faire l'appel", to: "/permanencesappeal", rolesAllowed: ["Admin", "Student"] }, + { label: 'Listes des permanences', to: '/permanenceslist', rolesAllowed: ['Admin', 'Student'] }, + { label: 'Mes permanences', to: '/mypermanences', rolesAllowed: ['Admin', 'Student'] }, + { label: "Faire l'appel", to: '/permanencesappeal', rolesAllowed: ['Admin', 'Student'] }, ], }, { - label: "Events", - to: "#", + label: 'Events', + to: '#', children: [ - { label: "Shotgun", to: "/shotgun", rolesAllowed: ["Admin", "Student"] }, - { label: "WEI", to: "/wei" }, - { label: "SDI", to: "/sdi" }, - { label: "Repas", to: "/food" }, - { label: "Defis Commissions", to: "/games", rolesAllowed: ["Admin", "Student"] }, + { label: 'Shotgun', to: '/shotgun', rolesAllowed: ['Admin', 'Student'] }, + { label: 'WEI', to: '/wei' }, + { label: 'SDI', to: '/sdi' }, + { label: 'Repas', to: '/food' }, + { label: 'Defis Commissions', to: '/games', rolesAllowed: ['Admin', 'Student'] }, ], }, - { label: "Mon compte", to: "/profil", icon: UsersIcon }, + { label: 'Mon compte', to: '/profil', icon: UsersIcon }, { - label: "Admin", - to: "#", + label: 'Admin', + to: '#', icon: CogIcon, children: [ - { label: "Bus", to: "/admin/bus", rolesAllowed: ["Admin"] }, - { label: "Challenge", to: "/admin/challenge", rolesAllowed: ["Admin", "Arbitre"] }, - { label: "Email", to: "/admin/email", rolesAllowed: ["Admin"] }, - { label: "Events", to: "/admin/events", rolesAllowed: ["Admin"] }, - { label: "Export / Import", to: "/admin/export-import", rolesAllowed: ["Admin"] }, - { label: "Factions", to: "/admin/factions", rolesAllowed: ["Admin", "Respo CE"] }, - { label: "Games", to: "/admin/games", rolesAllowed: ["Admin"] }, - { label: "News", to: "/admin/news", rolesAllowed: ["Admin", "Communication"] }, - { label: "Permanences", to: "/admin/permanences", rolesAllowed: ["Admin", "Respo CE"] }, - { label: "Roles", to: "/admin/roles", rolesAllowed: ["Admin"] }, - { label: "Shotgun", to: "/admin/shotgun", rolesAllowed: ["Admin", "Respo CE"] }, - { label: "Teams", to: "/admin/teams", rolesAllowed: ["Admin", "Respo CE"] }, - { label: "Tentes", to: "/admin/tent", rolesAllowed: ["Admin"] }, - { label: "Users", to: "/admin/users", rolesAllowed: ["Admin"] }, + { label: 'Bus', to: '/admin/bus', rolesAllowed: ['Admin'] }, + { label: 'Challenge', to: '/admin/challenge', rolesAllowed: ['Admin', 'Arbitre'] }, + { label: 'Email', to: '/admin/email', rolesAllowed: ['Admin'] }, + { label: 'Events', to: '/admin/events', rolesAllowed: ['Admin'] }, + { label: 'Export / Import', to: '/admin/export-import', rolesAllowed: ['Admin'] }, + { label: 'Factions', to: '/admin/factions', rolesAllowed: ['Admin', 'Respo CE'] }, + { label: 'Games', to: '/admin/games', rolesAllowed: ['Admin'] }, + { label: 'News', to: '/admin/news', rolesAllowed: ['Admin', 'Communication'] }, + { label: 'Permanences', to: '/admin/permanences', rolesAllowed: ['Admin', 'Respo CE'] }, + { label: 'Roles', to: '/admin/roles', rolesAllowed: ['Admin'] }, + { label: 'Shotgun', to: '/admin/shotgun', rolesAllowed: ['Admin', 'Respo CE'] }, + { label: 'Teams', to: '/admin/teams', rolesAllowed: ['Admin', 'Respo CE'] }, + { label: 'Tentes', to: '/admin/tent', rolesAllowed: ['Admin'] }, + { label: 'Users', to: '/admin/users', rolesAllowed: ['Admin'] }, ], }, { - label: "Déconnexion", - to: "/", - kind: "action", - showWhen: "auth", + label: 'Déconnexion', + to: '/', + kind: 'action', + showWhen: 'auth', onClick: handleLogout, }, { - label: "Se connecter", - to: "/", + label: 'Se connecter', + to: '/', public: true, - showWhen: "guest", + showWhen: 'guest', }, - ]; - const canShowItem = (item: NavItem): boolean => { - if (item.showWhen === "auth") return isAuthenticated; - if (item.showWhen === "guest") return !isAuthenticated; + if (item.showWhen === 'auth') return isAuthenticated; + if (item.showWhen === 'guest') return !isAuthenticated; if (!isAuthenticated) { if (item.public) return true; if (item.children && item.children.length > 0) { - return item.children.some(child => canShowItem(child)); + return item.children.some((child) => canShowItem(child)); } return false; } if (item.rolesAllowed) { - return item.rolesAllowed.some(r => roles.includes(r)); + return item.rolesAllowed.some((r) => roles.includes(r)); } if (item.children && item.children.length > 0) { - return item.children.some(child => canShowItem(child)); + return item.children.some((child) => canShowItem(child)); } return true; @@ -152,29 +154,24 @@ export const Navbar = () => { {/* Menu desktop */}
    - {navItems.map(item => + {navItems.map((item) => canShowItem(item) ? (
  • {item.children ? ( - ) : item.kind === "action" ? ( + ) : item.kind === 'action' ? ( ) : ( )}
  • - ) : null + ) : null, )}
@@ -184,15 +181,14 @@ export const Navbar = () => { {menuOpen && ( - {navItems.map(item => + className="lg:hidden bg-blue-700 overflow-hidden"> + {navItems.map((item) => canShowItem(item) ? ( {!item.children ? ( - item.kind === "action" ? ( + item.kind === 'action' ? ( ) : ( @@ -201,67 +197,50 @@ export const Navbar = () => { )} - ) : null + ) : null, )} )} - {/* Contact Information Warning */ hasContactInformation === false && isAuthenticated && ( -
-

ATTENTION : Tu n'as pas complété le formulaire VSS ainsi que tes informations d'urgence. Merci de le faire au plus vite !

-
- )} + { + /* Contact Information Warning */ hasContactInformation === false && isAuthenticated && ( +
+

+ ATTENTION : Tu n'as pas complété le formulaire VSS ainsi que tes informations d'urgence. + Merci de le faire au plus vite ! +

+ +
+ ) + } ); }; -const NavActionItem = ({ - item, - mobile = false, -}: { - item: NavItem; - mobile?: boolean; -}) => { - const base = mobile ? "block py-2 px-4 text-left w-full" : "inline-flex items-center py-2"; +const NavActionItem = ({ item, mobile = false }: { item: NavItem; mobile?: boolean }) => { + const base = mobile ? 'block py-2 px-4 text-left w-full' : 'inline-flex items-center py-2'; return ( - ); }; // Composant MenuItem -const MenuItem = ({ - item, - active = false, - mobile = false, -}: { - item: NavItem; - active?: boolean; - mobile?: boolean; -}) => { - const base = mobile ? "block py-2 px-4" : "inline-flex items-center py-2"; - const activeClass = active - ? "text-yellow-300 font-semibold border-b-2 border-yellow-300" - : "hover:text-yellow-200"; +const MenuItem = ({ item, active = false, mobile = false }: { item: NavItem; active?: boolean; mobile?: boolean }) => { + const base = mobile ? 'block py-2 px-4' : 'inline-flex items-center py-2'; + const activeClass = active ? 'text-yellow-300 font-semibold border-b-2 border-yellow-300' : 'hover:text-yellow-200'; return ( - - {item.icon && ( - - )} + + {item.icon && } {item.label} ); @@ -278,7 +257,7 @@ const Dropdown = ({ canShowItem: (item: NavItem) => boolean; }) => { const [open, setOpen] = useState(false); - const trigger = mobile ? "p-4" : "py-2 cursor-pointer"; + const trigger = mobile ? 'p-4' : 'py-2 cursor-pointer'; return (
@@ -288,8 +267,7 @@ const Dropdown = ({ className={`${trigger} flex items-center justify-between`} aria-expanded={open} aria-controls={`submenu-${item.label}`} - aria-haspopup="menu" - > + aria-haspopup="menu"> {item.icon && } {item.label} @@ -300,19 +278,18 @@ const Dropdown = ({ initial={{ opacity: 0, y: -10 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -10 }} - className={`absolute bg-white text-black rounded shadow-md z-50 ${mobile ? "static mt-2" : "top-full left-0 mt-1" - }`} - role="menu" - > - {item.children! - .filter(child => canShowItem(child)) - .map(child => ( + className={`absolute bg-white text-black rounded shadow-md z-50 ${ + mobile ? 'static mt-2' : 'top-full left-0 mt-1' + }`} + role="menu"> + {item + .children!.filter((child) => canShowItem(child)) + .map((child) => (
  • + role="menuitem"> {child.label}
  • diff --git a/frontend/src/components/ui/modal.tsx b/frontend/src/components/ui/modal.tsx new file mode 100644 index 0000000..a2f92cf --- /dev/null +++ b/frontend/src/components/ui/modal.tsx @@ -0,0 +1,129 @@ +'use client'; +import { type ReactNode, useEffect } from 'react'; + +import { Button } from '../ui/button'; + +/** + * Displays a modal window. + */ +const Modal = ({ + title = '', + children = '', + buttons = '', + visible = false, + closable = true, + closeOnOutsideClick = false, + onCancel = () => {}, + onOk = () => {}, + className = '', + containerClassName = '', + modalButtonsClassName = '', +}: { + /** Modal window title */ + title?: ReactNode; + /** Modal window content */ + children?: ReactNode; + /** Modal window buttons. + * Pass `null` to hide the footer entirely. + * Pass `""` (default) to get the default Annuler/Ok buttons. */ + buttons?: ReactNode | null; + /** Whether the modal window is visible or not */ + visible: boolean; + /** Whether the modal window is closable or not */ + closable?: boolean; + /** Whether clicking outside the modal closes it */ + closeOnOutsideClick?: boolean; + /** Function called when the user clicks on "Annuler" default button, + * or on the close button, or presses Escape */ + onCancel: () => void; + /** Function called when the user clicks on "Ok" default button */ + onOk?: () => void; + /** An optional class name to add to the modal */ + className?: string; + /** An optional class name to add to the modal container */ + containerClassName?: string; + /** An optional class name to add to the modal buttons container */ + modalButtonsClassName?: string; +}) => { + const buttonsContent = + buttons === null ? null : buttons !== '' ? ( + buttons + ) : ( + <> + + + + ); + + useEffect(() => { + const listener = (e: KeyboardEvent) => { + if (e.key === 'Escape') { + onCancel(); + } + }; + + if (visible) { + window.addEventListener('keydown', listener); + } + + return () => { + window.removeEventListener('keydown', listener); + }; + }, [onCancel, visible]); + + return ( +
    +
    + + )} +
    + +
    {children}
    + + {/* Render footer only if buttonsContent is not null */} + {buttonsContent && ( +
    + {buttonsContent} +
    + )} +
    +
    + + ); +}; + +export default Modal; diff --git a/frontend/src/pages/home.tsx b/frontend/src/pages/home.tsx index 54d9601..44a9259 100644 --- a/frontend/src/pages/home.tsx +++ b/frontend/src/pages/home.tsx @@ -1,14 +1,15 @@ -import { Footer } from "../components/footer"; -import { Infos } from "../components/home/infosSection"; -import { SocialLinks } from "../components/home/socialSection"; -import { Navbar } from "../components/navbar"; +import { Footer } from '../components/footer'; +import { Infos } from '../components/home/infosSection'; +import { SocialLinks } from '../components/home/socialSection'; +import UrgencyModal from '../components/home/urgencyModal'; +import { Navbar } from '../components/navbar'; const HomePage = () => (
    + -
    ); From 5c34228cfb48ec55e14cdc3a4695eab2be1b7843 Mon Sep 17 00:00:00 2001 From: Antoine Date: Sun, 12 Jul 2026 11:54:40 +0200 Subject: [PATCH 06/27] feat(back): add user contact information creation endpoints --- backend/src/controllers/user.controller.ts | 15 ++- backend/src/routes/user.routes.ts | 17 ++- backend/src/services/user.service.ts | 142 +++++++++++---------- backend/types/express.d.ts | 4 +- backend/types/user.d.ts | 5 + 5 files changed, 110 insertions(+), 73 deletions(-) create mode 100644 backend/types/user.d.ts diff --git a/backend/src/controllers/user.controller.ts b/backend/src/controllers/user.controller.ts index d85e247..ff104cf 100644 --- a/backend/src/controllers/user.controller.ts +++ b/backend/src/controllers/user.controller.ts @@ -6,6 +6,7 @@ import * as user_service from '../services/user.service'; import { noSyncEmails } from '../utils/no_sync_list'; import { Error, Ok } from '../utils/responses'; import * as SIEP_Utils from '../utils/siep'; +import { type UserContactInformation } from '../../types/user'; export const getUsersAdmin = async (req: Request, res: Response) => { try { @@ -94,7 +95,19 @@ export const getUserContactInformation = async (req: Request, res: Response) => const userContactInfo = await user_service.getUserContactInformation(parseInt(userId)); Ok(res, { data: userContactInfo }); } catch { - Error(res, { msg: 'Erreur lors de la récupération des informations de contact de l\'utilisateur.' }); + Error(res, { msg: "Erreur lors de la récupération des informations de contact de l'utilisateur." }); + } +}; + +export const createUserContactInformation = async (req: Request, res: Response) => { + const userId = req.user?.userId; + const { contact }: { contact: UserContactInformation } = req.body; + + try { + const result = await user_service.createUserContactInformation(parseInt(userId), contact); + Ok(res, { msg: 'Informations de contact créées', data: result }); + } catch { + Error(res, { msg: 'Erreur lors de la création des informations de contact.' }); } }; diff --git a/backend/src/routes/user.routes.ts b/backend/src/routes/user.routes.ts index c83d3fa..05f0bd0 100644 --- a/backend/src/routes/user.routes.ts +++ b/backend/src/routes/user.routes.ts @@ -5,16 +5,21 @@ import { checkRole } from '../middlewares/user.middleware'; const userRouter = express.Router(); // Admin routes -userRouter.get('/admin/getusersbypermission', checkRole("Admin", []), userController.getUsersByPermission); -userRouter.patch('/admin/user/:userId', checkRole("Admin", []), userController.adminUpdateUser); -userRouter.delete('/admin/user/:userId', checkRole("Admin", []), userController.adminDeleteUser); -userRouter.get('/admin/getusercontactinformation/:userId', checkRole("Admin", []), userController.getUserContactInformation); -userRouter.get('/admin/getusers', checkRole("Admin", ["Respo CE"]), userController.getUsersAdmin); -userRouter.post('/admin/syncnewstudent', checkRole("Admin", []), userController.syncNewstudent); +userRouter.get('/admin/getusersbypermission', checkRole('Admin', []), userController.getUsersByPermission); +userRouter.patch('/admin/user/:userId', checkRole('Admin', []), userController.adminUpdateUser); +userRouter.delete('/admin/user/:userId', checkRole('Admin', []), userController.adminDeleteUser); +userRouter.get( + '/admin/getusercontactinformation/:userId', + checkRole('Admin', []), + userController.getUserContactInformation, +); +userRouter.get('/admin/getusers', checkRole('Admin', ['Respo CE']), userController.getUsersAdmin); +userRouter.post('/admin/syncnewstudent', checkRole('Admin', []), userController.syncNewstudent); // User routes userRouter.patch('/user/me', userController.updateProfile); userRouter.get('/user/me', userController.getCurrentUser); userRouter.get('/user/getusers', userController.getUsers); +userRouter.post('/user/usercontactinformation', userController.createUserContactInformation); export default userRouter; diff --git a/backend/src/services/user.service.ts b/backend/src/services/user.service.ts index 5ba7bcb..2a80a9b 100644 --- a/backend/src/services/user.service.ts +++ b/backend/src/services/user.service.ts @@ -7,6 +7,7 @@ import { getFaction } from './faction.service'; import { getUserRoles } from './role.service'; import { getTeam, getTeamFaction, getUserTeam } from './team.service'; import { userInformationSchema } from '../schemas/Relational/userinformation.schema'; +import { type UserContactInformation } from '../../types/user'; // Fonction pour récupérer un utilisateur par email export const getUserByEmail = async (email: string) => { @@ -14,15 +15,15 @@ export const getUserByEmail = async (email: string) => { const users = await db.select().from(userSchema).where(eq(userSchema.email, email)); return users[0]; } catch (err) { - console.error('Erreur lors de la récupération de l\'utilisateur par email:', err); + console.error("Erreur lors de la récupération de l'utilisateur par email:", err); throw new Error('Erreur de base de données'); } }; export const getUserById = async (userId: number) => { try { - const user = await db.select( - { + const user = await db + .select({ userId: userSchema.id, firstName: userSchema.first_name, lastName: userSchema.last_name, @@ -31,12 +32,13 @@ export const getUserById = async (userId: number) => { branch: userSchema.branch, contact: userSchema.contact, permission: userSchema.permission, - discord_id: userSchema.discord_id - } - ).from(userSchema).where(eq(userSchema.id, userId)); + discord_id: userSchema.discord_id, + }) + .from(userSchema) + .where(eq(userSchema.id, userId)); return user[0]; } catch (err) { - console.error('Erreur lors de la récupération de l\'utilisateur par email:', err); + console.error("Erreur lors de la récupération de l'utilisateur par email:", err); throw new Error('Erreur de base de données'); } }; @@ -49,7 +51,8 @@ export const createUser = async ( majeur: boolean, permission: string, branch: string, - password: string) => { + password: string, +) => { try { // Hacher le mot de passe const hashedPassword = await bcrypt.hash(password, 10); @@ -58,17 +61,17 @@ export const createUser = async ( first_name: firstName, last_name: lastName, email: email, - branch: branch === "CV_ING" ? "RI" : branch, + branch: branch === 'CV_ING' ? 'RI' : branch, majeur: majeur, password: hashedPassword, - permission: permission + permission: permission, }; // Insérer un nouvel utilisateur dans la base de données - const result = await db.insert(userSchema).values(newUser).returning() + const result = await db.insert(userSchema).values(newUser).returning(); return result[0]; } catch (err) { - console.error('Erreur lors de la création de l\'utilisateur:', err); + console.error("Erreur lors de la création de l'utilisateur:", err); throw new Error('Erreur de base de données'); } }; @@ -80,24 +83,25 @@ export const comparePassword = async (enteredPassword: string, storedPassword: s export const updateUserStudent = async (firstName: string, lastName: string, email: string) => { try { - const result = await db.update(userSchema) + const result = await db + .update(userSchema) .set({ first_name: firstName, - last_name: lastName + last_name: lastName, }) .where(eq(userSchema.email, email)); return result.rows[0]; } catch (err) { - console.error('Erreur lors de la récupération et de l\'update de l\'utilisateur par email:', err); + console.error("Erreur lors de la récupération et de l'update de l'utilisateur par email:", err); throw new Error('Erreur de base de données'); } -} +}; export const getUsersAdmin = async () => { try { - const users = await db.select( - { + const users = await db + .select({ userId: userSchema.id, firstName: userSchema.first_name, lastName: userSchema.last_name, @@ -106,9 +110,9 @@ export const getUsersAdmin = async () => { branch: userSchema.branch, contact: userSchema.contact, permission: userSchema.permission, - discord_id: userSchema.discord_id - } - ).from(userSchema); + discord_id: userSchema.discord_id, + }) + .from(userSchema); return users; } catch (err) { console.error('Erreur lors de la récupération des utilisateurs ', err); @@ -118,15 +122,15 @@ export const getUsersAdmin = async () => { export const getUsers = async () => { try { - const users = await db.select( - { + const users = await db + .select({ userId: userSchema.id, firstName: userSchema.first_name, lastName: userSchema.last_name, permission: userSchema.permission, - email: userSchema.email - } - ).from(userSchema); + email: userSchema.email, + }) + .from(userSchema); return users; } catch (err) { console.error('Erreur lors de la récupération des utilisateurs ', err); @@ -136,17 +140,35 @@ export const getUsers = async () => { export const getUserContactInformation = async (userId: number) => { try { - const user = await db.select( - { + const user = await db + .select({ userId: userInformationSchema.user_id, urgency_contact_name: userInformationSchema.urgency_contact_name, urgency_contact_phone: userInformationSchema.urgency_contact_phone, - contact_CE: userInformationSchema.contact_CE - } - ).from(userInformationSchema).where(eq(userInformationSchema.user_id, userId)); + contact_CE: userInformationSchema.contact_CE, + }) + .from(userInformationSchema) + .where(eq(userInformationSchema.user_id, userId)); return user[0]; } catch (err) { - console.error('Erreur lors de la récupération des informations de contact de l\'utilisateur ', err); + console.error("Erreur lors de la récupération des informations de contact de l'utilisateur ", err); + throw new Error('Erreur de base de données'); + } +}; + +export const createUserContactInformation = async (userId: number, contact: UserContactInformation) => { + try { + const newContactInfo = { + user_id: userId, + urgency_contact_name: contact.UrgencyContactName, + urgency_contact_phone: contact.UrgencyContactPhone, + contact_CE: contact.ContactCE, + }; + + const result = await db.insert(userInformationSchema).values(newContactInfo).returning(); + return result[0]; + } catch (err) { + console.error("Erreur lors de la création des informations de contact de l'utilisateur:", err); throw new Error('Erreur de base de données'); } }; @@ -182,10 +204,9 @@ export const getUsersAll = async () => { factionName, roles, }; - }) + }), ); - return userWithTeam; } catch (err) { console.error('Erreur lors de la récupération des utilisateurs ', err); @@ -195,15 +216,16 @@ export const getUsersAll = async () => { export const getUsersbyPermission = async (permission: string) => { try { - const users = await db.select( - { + const users = await db + .select({ userId: userSchema.id, firstName: userSchema.first_name, lastName: userSchema.last_name, email: userSchema.email, - branch: userSchema.branch - } - ).from(userSchema).where(eq(userSchema.permission, permission)); + branch: userSchema.branch, + }) + .from(userSchema) + .where(eq(userSchema.permission, permission)); return users; } catch (err) { console.error('Erreur lors de la récupération des utilisateurs ', err); @@ -213,29 +235,27 @@ export const getUsersbyPermission = async (permission: string) => { export const updateUserPassword = async (userId: number, password: string) => { try { - const result = await db.update(userSchema) + const result = await db + .update(userSchema) .set({ - password: password + password: password, }) .where(eq(userSchema.id, userId)); return result.rows[0]; } catch (err) { - console.error('Erreur lors de la récupération et de l\'update de l\'utilisateur par email:', err); + console.error("Erreur lors de la récupération et de l'update de l'utilisateur par email:", err); throw new Error('Erreur de base de données'); } -} +}; -export const updateUserInfoByUserId = async ( - userId: number, - branch?: string, - contact?: string -) => { +export const updateUserInfoByUserId = async (userId: number, branch?: string, contact?: string) => { try { - const result = await db.update(userSchema) + const result = await db + .update(userSchema) .set({ branch: branch, - contact: contact + contact: contact, }) .where(eq(userSchema.id, userId)); @@ -246,33 +266,27 @@ export const updateUserInfoByUserId = async ( } }; -export const updateUserByAdmin = async ( - userId: number, - updates: Partial -) => { +export const updateUserByAdmin = async (userId: number, updates: Partial) => { try { - if (Object.keys(updates).length === 0) { throw new Error('Aucune donnée à mettre à jour'); } - const result = await db.update(userSchema) - .set( - updates - ) - .where(eq(userSchema.id, userId)); + const result = await db.update(userSchema).set(updates).where(eq(userSchema.id, userId)); return result; } catch (err) { - console.error('Erreur lors de la mise à jour par l\'admin:', err); + console.error("Erreur lors de la mise à jour par l'admin:", err); throw new Error('Erreur de base de données'); } }; export const deleteUserById = async (userId: number) => { try { - - const user_registration_token = await db.select({ user_id: registrationSchema.user_id }).from(registrationSchema).where(eq(registrationSchema.user_id, userId)); + const user_registration_token = await db + .select({ user_id: registrationSchema.user_id }) + .from(registrationSchema) + .where(eq(registrationSchema.user_id, userId)); if (user_registration_token.length > 0) { await db.delete(registrationSchema).where(eq(registrationSchema.user_id, userId)); @@ -281,7 +295,7 @@ export const deleteUserById = async (userId: number) => { const result = await db.delete(userSchema).where(eq(userSchema.id, userId)); return result; } catch (err) { - console.error('Erreur lors de la suppression de l\'utilisateur:', err); + console.error("Erreur lors de la suppression de l'utilisateur:", err); throw new Error('Erreur de base de données'); } }; diff --git a/backend/types/express.d.ts b/backend/types/express.d.ts index 7e446c6..c4e0efe 100644 --- a/backend/types/express.d.ts +++ b/backend/types/express.d.ts @@ -1,6 +1,6 @@ -import { type JwtPayload } from "jsonwebtoken"; +import { type JwtPayload } from 'jsonwebtoken'; -declare module "express-serve-static-core" { +declare module 'express-serve-static-core' { interface Request { user?: JwtPayload | string; permission?: JwtPayload | string; diff --git a/backend/types/user.d.ts b/backend/types/user.d.ts new file mode 100644 index 0000000..72089f3 --- /dev/null +++ b/backend/types/user.d.ts @@ -0,0 +1,5 @@ +export type UserContactInformation = { + ContactCE: string; + UrgencyContactName: string; + UrgencyContactPhone: number; +}; From 4e3e1a378b0e2e019aacf122ed915678b6f286b1 Mon Sep 17 00:00:00 2001 From: Antoine Date: Sun, 12 Jul 2026 13:09:11 +0200 Subject: [PATCH 07/27] feat: add form with answer sending --- backend/src/controllers/user.controller.ts | 13 +- .../database/migrations/0023_even_morg.sql | 8 + .../migrations/meta/0023_snapshot.json | 1335 +++++++++++++++++ .../database/migrations/meta/_journal.json | 7 + backend/src/routes/user.routes.ts | 1 + .../Relational/userinformation.schema.ts | 18 +- backend/src/services/user.service.ts | 6 +- backend/types/user.d.ts | 6 +- frontend/src/components/home/urgencyModal.tsx | 38 +- frontend/src/components/navbar.tsx | 1 + frontend/src/interfaces/user.interface.ts | 11 +- .../src/services/requests/user.service.ts | 39 +- 12 files changed, 1445 insertions(+), 38 deletions(-) create mode 100644 backend/src/database/migrations/0023_even_morg.sql create mode 100644 backend/src/database/migrations/meta/0023_snapshot.json diff --git a/backend/src/controllers/user.controller.ts b/backend/src/controllers/user.controller.ts index ff104cf..d78589e 100644 --- a/backend/src/controllers/user.controller.ts +++ b/backend/src/controllers/user.controller.ts @@ -99,9 +99,20 @@ export const getUserContactInformation = async (req: Request, res: Response) => } }; +export const getCurrentUserContactInformation = async (req: Request, res: Response) => { + const userId = req.user?.userId; + + try { + const userContactInfo = await user_service.getUserContactInformation(parseInt(userId)); + Ok(res, { data: userContactInfo }); + } catch { + Error(res, { msg: "Erreur lors de la récupération des informations de contact de l'utilisateur." }); + } +}; + export const createUserContactInformation = async (req: Request, res: Response) => { const userId = req.user?.userId; - const { contact }: { contact: UserContactInformation } = req.body; + const contact: UserContactInformation = req.body; try { const result = await user_service.createUserContactInformation(parseInt(userId), contact); diff --git a/backend/src/database/migrations/0023_even_morg.sql b/backend/src/database/migrations/0023_even_morg.sql new file mode 100644 index 0000000..94a1760 --- /dev/null +++ b/backend/src/database/migrations/0023_even_morg.sql @@ -0,0 +1,8 @@ +CREATE TABLE "user_informations" ( + "user_id" integer PRIMARY KEY NOT NULL, + "urgency_contact_name" text, + "urgency_contact_phone" text, + "contact_CE" text +); +--> statement-breakpoint +ALTER TABLE "user_informations" ADD CONSTRAINT "user_informations_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; \ No newline at end of file diff --git a/backend/src/database/migrations/meta/0023_snapshot.json b/backend/src/database/migrations/meta/0023_snapshot.json new file mode 100644 index 0000000..1cbadb9 --- /dev/null +++ b/backend/src/database/migrations/meta/0023_snapshot.json @@ -0,0 +1,1335 @@ +{ + "id": "77c4b2f6-c24d-4eb9-80a9-42fb8b9ef380", + "prevId": "93925edf-9622-4ce2-80bc-26050abbce0b", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.challenges": { + "name": "challenges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "challenges_created_by_users_id_fk": { + "name": "challenges_created_by_users_id_fk", + "tableFrom": "challenges", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "pre_registration_open": { + "name": "pre_registration_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "shotgun_open": { + "name": "shotgun_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "sdi_open": { + "name": "sdi_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "wei_open": { + "name": "wei_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "food_open": { + "name": "food_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "chall_open": { + "name": "chall_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.factions": { + "name": "factions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "factions_name_unique": { + "name": "factions_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.news": { + "name": "news", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "published": { + "name": "published", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "target": { + "name": "target", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permanences": { + "name": "permanences", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "end_at": { + "name": "end_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "capacity": { + "name": "capacity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_open": { + "name": "is_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "difficulty": { + "name": "difficulty", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.roles": { + "name": "roles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "roles_name_unique": { + "name": "roles_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.teams": { + "name": "teams", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "teams_name_unique": { + "name": "teams_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "majeur": { + "name": "majeur", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contact": { + "name": "contact", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'Nouveau'" + }, + "discord_id": { + "name": "discord_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bus_attribution": { + "name": "bus_attribution", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "bus": { + "name": "bus", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "departure_time": { + "name": "departure_time", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bus_attribution_user_id_users_id_fk": { + "name": "bus_attribution_user_id_users_id_fk", + "tableFrom": "bus_attribution", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.challenge_validation": { + "name": "challenge_validation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "challenge_id": { + "name": "challenge_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_by_admin_id": { + "name": "validated_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_at": { + "name": "validated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "target_user_id": { + "name": "target_user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_team_id": { + "name": "target_team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_faction_id": { + "name": "target_faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "added_by_admin_id": { + "name": "added_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "challenge_validation_challenge_id_challenges_id_fk": { + "name": "challenge_validation_challenge_id_challenges_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "challenges", + "columnsFrom": [ + "challenge_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_validated_by_admin_id_users_id_fk": { + "name": "challenge_validation_validated_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "validated_by_admin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_user_id_users_id_fk": { + "name": "challenge_validation_target_user_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "target_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_team_id_teams_id_fk": { + "name": "challenge_validation_target_team_id_teams_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "teams", + "columnsFrom": [ + "target_team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_faction_id_factions_id_fk": { + "name": "challenge_validation_target_faction_id_factions_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "factions", + "columnsFrom": [ + "target_faction_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_added_by_admin_id_users_id_fk": { + "name": "challenge_validation_added_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "added_by_admin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registration_tokens": { + "name": "registration_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_tokens_user_id_users_id_fk": { + "name": "registration_tokens_user_id_users_id_fk", + "tableFrom": "registration_tokens", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "registration_tokens_token_unique": { + "name": "registration_tokens_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.role_points": { + "name": "role_points", + "schema": "", + "columns": { + "role_points": { + "name": "role_points", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "role_points_role_points_roles_id_fk": { + "name": "role_points_role_points_roles_id_fk", + "tableFrom": "role_points", + "tableTo": "roles", + "columnsFrom": [ + "role_points" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "role_points_role_points_pk": { + "name": "role_points_role_points_pk", + "columns": [ + "role_points" + ] + } + }, + "uniqueConstraints": { + "role_points_role_points_unique": { + "name": "role_points_role_points_unique", + "nullsNotDistinct": false, + "columns": [ + "role_points" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_faction": { + "name": "team_faction", + "schema": "", + "columns": { + "faction_id": { + "name": "faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "team_faction_faction_id_factions_id_fk": { + "name": "team_faction_faction_id_factions_id_fk", + "tableFrom": "team_faction", + "tableTo": "factions", + "columnsFrom": [ + "faction_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "team_faction_team_id_teams_id_fk": { + "name": "team_faction_team_id_teams_id_fk", + "tableFrom": "team_faction", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "team_faction_faction_id_team_id_pk": { + "name": "team_faction_faction_id_team_id_pk", + "columns": [ + "faction_id", + "team_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_shotgun": { + "name": "team_shotgun", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "team_shotgun_team_id_teams_id_fk": { + "name": "team_shotgun_team_id_teams_id_fk", + "tableFrom": "team_shotgun", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_informations": { + "name": "user_informations", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "urgency_contact_name": { + "name": "urgency_contact_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "urgency_contact_phone": { + "name": "urgency_contact_phone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contact_CE": { + "name": "contact_CE", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_informations_user_id_users_id_fk": { + "name": "user_informations_user_id_users_id_fk", + "tableFrom": "user_informations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.respo_permanences": { + "name": "respo_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "respo_permanences_user_id_users_id_fk": { + "name": "respo_permanences_user_id_users_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "respo_permanences_permanence_id_permanences_id_fk": { + "name": "respo_permanences_permanence_id_permanences_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "permanences", + "columnsFrom": [ + "permanence_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "respo_permanences_user_id_permanence_id_pk": { + "name": "respo_permanences_user_id_permanence_id_pk", + "columns": [ + "user_id", + "permanence_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_permanences": { + "name": "user_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "registered_at": { + "name": "registered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "claimed": { + "name": "claimed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_permanences_user_id_users_id_fk": { + "name": "user_permanences_user_id_users_id_fk", + "tableFrom": "user_permanences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_permanences_permanence_id_permanences_id_fk": { + "name": "user_permanences_permanence_id_permanences_id_fk", + "tableFrom": "user_permanences", + "tableTo": "permanences", + "columnsFrom": [ + "permanence_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_permanences_user_id_permanence_id_pk": { + "name": "user_permanences_user_id_permanence_id_pk", + "columns": [ + "user_id", + "permanence_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_preferences": { + "name": "user_preferences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_preferences_user_id_users_id_fk": { + "name": "user_preferences_user_id_users_id_fk", + "tableFrom": "user_preferences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_preferences_role_id_roles_id_fk": { + "name": "user_preferences_role_id_roles_id_fk", + "tableFrom": "user_preferences", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_preferences_user_id_role_id_pk": { + "name": "user_preferences_user_id_role_id_pk", + "columns": [ + "user_id", + "role_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_roles": { + "name": "user_roles", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_roles_user_id_users_id_fk": { + "name": "user_roles_user_id_users_id_fk", + "tableFrom": "user_roles", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_roles_role_id_roles_id_fk": { + "name": "user_roles_role_id_roles_id_fk", + "tableFrom": "user_roles", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_teams": { + "name": "user_teams", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_teams_user_id_users_id_fk": { + "name": "user_teams_user_id_users_id_fk", + "tableFrom": "user_teams", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_teams_team_id_teams_id_fk": { + "name": "user_teams_team_id_teams_id_fk", + "tableFrom": "user_teams", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_teams_user_id_team_id_pk": { + "name": "user_teams_user_id_team_id_pk", + "columns": [ + "user_id", + "team_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_tent": { + "name": "user_tent", + "schema": "", + "columns": { + "user_id_1": { + "name": "user_id_1", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "user_id_2": { + "name": "user_id_2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "confirmed": { + "name": "confirmed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_tent_user_id_1_users_id_fk": { + "name": "user_tent_user_id_1_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": [ + "user_id_1" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_tent_user_id_2_users_id_fk": { + "name": "user_tent_user_id_2_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": [ + "user_id_2" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_tent_user_id_1_user_id_2_pk": { + "name": "user_tent_user_id_1_user_id_2_pk", + "columns": [ + "user_id_1", + "user_id_2" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/backend/src/database/migrations/meta/_journal.json b/backend/src/database/migrations/meta/_journal.json index 6924d8e..ea074cf 100644 --- a/backend/src/database/migrations/meta/_journal.json +++ b/backend/src/database/migrations/meta/_journal.json @@ -162,6 +162,13 @@ "when": 1757002717384, "tag": "0022_light_omega_red", "breakpoints": true + }, + { + "idx": 23, + "version": "7", + "when": 1783854058299, + "tag": "0023_even_morg", + "breakpoints": true } ] } \ No newline at end of file diff --git a/backend/src/routes/user.routes.ts b/backend/src/routes/user.routes.ts index 05f0bd0..56bade2 100644 --- a/backend/src/routes/user.routes.ts +++ b/backend/src/routes/user.routes.ts @@ -21,5 +21,6 @@ userRouter.patch('/user/me', userController.updateProfile); userRouter.get('/user/me', userController.getCurrentUser); userRouter.get('/user/getusers', userController.getUsers); userRouter.post('/user/usercontactinformation', userController.createUserContactInformation); +userRouter.get('/user/getusercontactinformation', userController.getCurrentUserContactInformation); export default userRouter; diff --git a/backend/src/schemas/Relational/userinformation.schema.ts b/backend/src/schemas/Relational/userinformation.schema.ts index bfdceea..feae1a7 100644 --- a/backend/src/schemas/Relational/userinformation.schema.ts +++ b/backend/src/schemas/Relational/userinformation.schema.ts @@ -1,11 +1,13 @@ -import { pgTable, integer, text } from "drizzle-orm/pg-core"; -import { userSchema } from "../Basic/user.schema"; +import { pgTable, integer, text } from 'drizzle-orm/pg-core'; +import { userSchema } from '../Basic/user.schema'; -export const userInformationSchema = pgTable("user_informations", { - user_id: integer("user_id").primaryKey().references(() => userSchema.id, { onDelete: "cascade" }), - urgency_contact_name: text("urgency_contact_name"), - urgency_contact_phone: integer("urgency_contact_phone"), - contact_CE: text("contact_CE"), +export const userInformationSchema = pgTable('user_informations', { + user_id: integer('user_id') + .primaryKey() + .references(() => userSchema.id, { onDelete: 'cascade' }), + urgency_contact_name: text('urgency_contact_name'), + urgency_contact_phone: text('urgency_contact_phone'), + contact_CE: text('contact_CE'), }); -export type UserInformation = typeof userInformationSchema.$inferSelect; \ No newline at end of file +export type UserInformation = typeof userInformationSchema.$inferSelect; diff --git a/backend/src/services/user.service.ts b/backend/src/services/user.service.ts index 2a80a9b..bbb1589 100644 --- a/backend/src/services/user.service.ts +++ b/backend/src/services/user.service.ts @@ -160,9 +160,9 @@ export const createUserContactInformation = async (userId: number, contact: User try { const newContactInfo = { user_id: userId, - urgency_contact_name: contact.UrgencyContactName, - urgency_contact_phone: contact.UrgencyContactPhone, - contact_CE: contact.ContactCE, + urgency_contact_name: contact.urgency_contact_name, + urgency_contact_phone: contact.urgency_contact_phone, + contact_CE: contact.contact_CE, }; const result = await db.insert(userInformationSchema).values(newContactInfo).returning(); diff --git a/backend/types/user.d.ts b/backend/types/user.d.ts index 72089f3..928f2e3 100644 --- a/backend/types/user.d.ts +++ b/backend/types/user.d.ts @@ -1,5 +1,5 @@ export type UserContactInformation = { - ContactCE: string; - UrgencyContactName: string; - UrgencyContactPhone: number; + urgency_contact_name: string; + urgency_contact_phone: string; + contact_CE: string; }; diff --git a/frontend/src/components/home/urgencyModal.tsx b/frontend/src/components/home/urgencyModal.tsx index 343fe2a..d0ac867 100644 --- a/frontend/src/components/home/urgencyModal.tsx +++ b/frontend/src/components/home/urgencyModal.tsx @@ -1,19 +1,45 @@ +import { useState } from 'react'; import { useSearchParams } from 'react-router-dom'; +import { createUserContactInformation } from '../../services/requests/user.service'; +import { Button } from '../ui/button'; +import { Input } from '../ui/input'; import Modal from '../ui/modal'; function UrgencyModal() { const [searchParams, setSearchParams] = useSearchParams(); + const [form, setForm] = useState({ contact_CE: '', urgency_contact_name: '', urgency_contact_phone: '' }); const isLogin = searchParams.get('login') === 'true'; return ( - setSearchParams({})} - buttons={null} - /> + setSearchParams({})} buttons={null}> +
    +

    Bienvenu sur le site de l'intégration, blablabla faut que tu completes le formulaire.

    + setForm({ ...form, contact_CE: e.target.value })} + /> + setForm({ ...form, urgency_contact_name: e.target.value })} + /> + setForm({ ...form, urgency_contact_phone: e.target.value })} + /> + +
    +
    ); } diff --git a/frontend/src/components/navbar.tsx b/frontend/src/components/navbar.tsx index 12a6e1c..a2e67c6 100644 --- a/frontend/src/components/navbar.tsx +++ b/frontend/src/components/navbar.tsx @@ -43,6 +43,7 @@ export const Navbar = () => { try { const contactInfo = await getCurrentUserContactInformation(); setHasContactInformation(contactInfo.urgency_contact_phone !== null); + console.log('Contact Information:', contactInfo); } catch (error) { console.error('Erreur lors de la récupération des informations de contact :', error); } diff --git a/frontend/src/interfaces/user.interface.ts b/frontend/src/interfaces/user.interface.ts index ea26891..775a65b 100644 --- a/frontend/src/interfaces/user.interface.ts +++ b/frontend/src/interfaces/user.interface.ts @@ -13,5 +13,12 @@ export interface User { export interface UserContactInformation { userId: number; urgency_contact_name: string; - urgency_contact_phone: number; -} \ No newline at end of file + urgency_contact_phone: string; + contact_CE: string; +} + +export interface CreateUserContactInformationRequest { + urgency_contact_name: string; + urgency_contact_phone: string; + contact_CE: string; +} diff --git a/frontend/src/services/requests/user.service.ts b/frontend/src/services/requests/user.service.ts index 1134c17..23d9428 100644 --- a/frontend/src/services/requests/user.service.ts +++ b/frontend/src/services/requests/user.service.ts @@ -1,4 +1,8 @@ -import { type User, type UserContactInformation } from '../../interfaces/user.interface'; +import { + type CreateUserContactInformationRequest, + type User, + type UserContactInformation, +} from '../../interfaces/user.interface'; import api from '../api'; export const getPermission = (): string | null => { @@ -24,22 +28,22 @@ export const isConnected = (): boolean => { }; export const getUsers = async () => { - const response = await api.get("/user/user/getusers"); + const response = await api.get('/user/user/getusers'); const users = response.data.data; return users; -} +}; export const getUsersAdmin = async () => { - const response = await api.get("/user/admin/getusers"); + const response = await api.get('/user/admin/getusers'); const users = response.data.data; return users; -} +}; export const getUsersByPermission = async () => { - const response = await api.get("/user/admin/getusersbypermission"); + const response = await api.get('/user/admin/getusersbypermission'); const users = response.data.data; return users; -} +}; export const getUserContactInformation = async (userId: number) => { const response = await api.get(`/user/admin/getusercontactinformation/${userId}`); @@ -47,8 +51,13 @@ export const getUserContactInformation = async (userId: number) => { return users; }; +export const createUserContactInformation = async (data: CreateUserContactInformationRequest) => { + const response = await api.post(`/user/user/usercontactinformation`, data); + return response.data; +}; + export const getCurrentUser = async () => { - const res = await api.get("/user/user/me"); + const res = await api.get('/user/user/me'); return res.data.data; }; @@ -59,26 +68,26 @@ export const getCurrentUserContactInformation = async () => { }; export const updateCurrentUser = async (data: Partial) => { - const response = await api.patch("/user/user/me", data); - return response.data + const response = await api.patch('/user/user/me', data); + return response.data; }; export const updateUserByAdmin = async (id: number, data: Partial) => { const response = await api.patch(`/user/admin/user/${id}`, data); - return response.data + return response.data; }; export const deleteUserByAdmin = async (id: number) => { const response = await api.delete(`/user/admin/user/${id}`); - return response.data + return response.data; }; export const syncnewStudent = async (date: string) => { const response = await api.post(`/user/admin/syncnewstudent/`, { date }); - return response.data + return response.data; }; export const syncDiscordUser = async (code: string) => { const response = await api.post(`/discord/user/callback/`, { code }); - return response.data -} + return response.data; +}; From f791d7db2904ee1f0bbacb5421d88f8150c72929 Mon Sep 17 00:00:00 2001 From: Arthur Dodin Date: Mon, 13 Jul 2026 11:44:25 +0200 Subject: [PATCH 08/27] feat(back): billetweb requests --- backend/.env.example | 12 +++++++ backend/src/utils/billetweb.ts | 54 +++++++++++++++++++++++++++++ backend/src/utils/secret.ts | 62 ++++++++++++++++++---------------- backend/types/billetweb.d.ts | 7 ++++ 4 files changed, 106 insertions(+), 29 deletions(-) create mode 100644 backend/src/utils/billetweb.ts create mode 100644 backend/types/billetweb.d.ts diff --git a/backend/.env.example b/backend/.env.example index e8a333d..13e19b8 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -1,6 +1,18 @@ DATABASE_URL=postgresql://admin:password@localhost:5432/integration-dev OUTSIDE_DATABASE_URL=postgresql://admin:password@localhost:5432/integration-dev +# Les variables Billetweb permettent d'autoriser l'achat de billets uniquement aux membres d'une liste d'adresses emails commandée par le site. +# En 2026, cette liste comprends automatiquement les Nouveaux et CE ayant remplis le formulaire "Contact de secours" et le questionnaire VSS. +# +# Le token se récupère sur la page https://www.billetweb.fr/bo/api.php#/, en étant préalablement connecté au compte billetweb de l'Intégration. +# +# L'ID de la liste d'accès se récupère sur la page Configuration > Offres Spréciales > Filtrage par liste > Cliquer sur la liste ; Il s'agit de largument "list_parent" dans l'URL. +# Exemple: https://www.billetweb.fr/bo/lists.php?list_parent=925 -> API_BILLETWEB_RESPONDENT_STUDENTS_LIST_ID=925 + +API_BILLETWEB_URL=https://www.billetweb.fr/api +API_BILLETWEB_TOKEN=Basic azerty +API_BILLETWEB_RESPONDENT_STUDENTS_LIST_ID= + POSTGRES_PASSWORD=password POSTGRES_USER=admin POSTGRES_DB=integration-dev diff --git a/backend/src/utils/billetweb.ts b/backend/src/utils/billetweb.ts new file mode 100644 index 0000000..13ba62d --- /dev/null +++ b/backend/src/utils/billetweb.ts @@ -0,0 +1,54 @@ +import axios from 'axios'; +import { api_billetweb_token, api_billetweb_url, api_billetweb_respondent_students_list_id } from './secret'; +import type { BilletwebUser, BilletwebMember } from '../../types/billetweb'; + +const headers = { + accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: api_billetweb_token, +}; + +const addUserToList = async (listId: string, user: BilletwebUser) => { + try { + if (!api_billetweb_url || !api_billetweb_token || !api_billetweb_respondent_students_list_id) return; + + await axios.post( + `${api_billetweb_url}/list/${listId}/push`, + { + data: [[user.email, user.firstName, user.lastName]], + }, + { headers }, + ); + } catch (error) { + console.error(`Error adding user ${user.email} to list ${listId}:`, error); + throw error; + } +}; + +const removeUserFromList = async (listId: string, email: string) => { + try { + if (!api_billetweb_url || !api_billetweb_token || !api_billetweb_respondent_students_list_id) return; + + const { data } = await axios.get(`${api_billetweb_url}/list/${listId}/data`, { headers }); + + const members = data.filter(([memberEmail]) => memberEmail !== email); + + // Ne rien faire si l'utilisateur n'était pas dans la liste + if (members.length === data.length) { + return; + } + + await axios.post(`${api_billetweb_url}/list/${listId}/replace`, { data: members }, { headers }); + } catch (error) { + console.error('Error removing user from list:', error); + throw error; + } +}; + +export const addUserToRespondentStudentsList = async (user: BilletwebUser) => { + addUserToList(api_billetweb_respondent_students_list_id, user); +}; + +export const removeUserFromRespondentStudentsList = async (email: string) => { + removeUserFromList(api_billetweb_respondent_students_list_id, email); +}; diff --git a/backend/src/utils/secret.ts b/backend/src/utils/secret.ts index f7c51fc..83db995 100644 --- a/backend/src/utils/secret.ts +++ b/backend/src/utils/secret.ts @@ -1,33 +1,37 @@ -import dotenv from "dotenv"; +import dotenv from 'dotenv'; dotenv.config(); -export const jwtSecret = process.env.JWT_SECRET || "default"; +export const jwtSecret = process.env.JWT_SECRET || 'default'; export const server_port = process.env.SERVER_PORT; -export const cas_login_url = process.env.CAS_LOGIN_URL || "default"; -export const cas_validate_url = process.env.CAS_VALIDATE_URL || "default"; -export const service_url = process.env.SERVICE_URL || "default"; -export const dev_db_url = process.env.DATABASE_URL || "default"; -export const postgres_password = process.env.POSTGRES_PASSWORD || "default"; -export const postgres_user = process.env.POSTGRES_USER || "default"; -export const postgres_port = process.env.POSTGRES_PORT || "default"; -export const postgres_db = process.env.POSTGRES_DB || "default"; -export const postgres_host = process.env.POSTGRES_HOST || "default"; -export const google_client_id = process.env.GOOGLE_CLIENT_ID || "default"; -export const google_client_secret = process.env.GOOGLE_CLIENT_SECRET || "default"; -export const google_client_uri = process.env.GOOGLE_REDIRECT_URI || "default"; -export const spreadsheet_id = process.env.SPREADSHEET_ID || "default"; -export const api_utt_username = process.env.API_UTT_USERNAME || "default"; -export const api_utt_password = process.env.API_UTT_PASSWORD || "default"; -export const api_utt_auth_url = process.env.API_UTT_AUTH_URL || "default"; -export const api_utt_admis_url = process.env.API_UTT_ADMIS_URL || "default"; -export const api_utt_admis_url_ismajor = process.env.API_UTT_ADMIS_URL_ISMAJOR || "default"; -export const email_host = process.env.EMAIL_HOST || "default"; -export const email_user = process.env.EMAIL_USER || "default"; -export const email_password = process.env.EMAIL_PASSWORD || "default"; -export const email_from = process.env.EMAIL_FROM || "default"; -export const discord_client_id = process.env.DISCORD_CLIENT_ID || "default"; -export const discord_client_secret = process.env.DISCORD_CLIENT_SECRET || "default"; -export const discord_redirect_uri = process.env.DISCORD_REDIRECT_URI || "default"; -export const shotgun_password = process.env.SHOTGUN_PASSWORD || ""; -export const automation_token = process.env.AUTOMATION_TOKEN || ""; +export const cas_login_url = process.env.CAS_LOGIN_URL || 'default'; +export const cas_validate_url = process.env.CAS_VALIDATE_URL || 'default'; +export const service_url = process.env.SERVICE_URL || 'default'; +export const dev_db_url = process.env.DATABASE_URL || 'default'; +export const postgres_password = process.env.POSTGRES_PASSWORD || 'default'; +export const postgres_user = process.env.POSTGRES_USER || 'default'; +export const postgres_port = process.env.POSTGRES_PORT || 'default'; +export const postgres_db = process.env.POSTGRES_DB || 'default'; +export const postgres_host = process.env.POSTGRES_HOST || 'default'; +export const google_client_id = process.env.GOOGLE_CLIENT_ID || 'default'; +export const google_client_secret = process.env.GOOGLE_CLIENT_SECRET || 'default'; +export const google_client_uri = process.env.GOOGLE_REDIRECT_URI || 'default'; +export const spreadsheet_id = process.env.SPREADSHEET_ID || 'default'; +export const api_billetweb_url = process.env.API_BILLETWEB_URL || 'default'; +export const api_billetweb_token = process.env.API_BILLETWEB_TOKEN || 'default'; +export const api_billetweb_respondent_students_list_id = + process.env.API_BILLETWEB_RESPONDENT_STUDENTS_LIST_ID || 'default'; +export const api_utt_username = process.env.API_UTT_USERNAME || 'default'; +export const api_utt_password = process.env.API_UTT_PASSWORD || 'default'; +export const api_utt_auth_url = process.env.API_UTT_AUTH_URL || 'default'; +export const api_utt_admis_url = process.env.API_UTT_ADMIS_URL || 'default'; +export const api_utt_admis_url_ismajor = process.env.API_UTT_ADMIS_URL_ISMAJOR || 'default'; +export const email_host = process.env.EMAIL_HOST || 'default'; +export const email_user = process.env.EMAIL_USER || 'default'; +export const email_password = process.env.EMAIL_PASSWORD || 'default'; +export const email_from = process.env.EMAIL_FROM || 'default'; +export const discord_client_id = process.env.DISCORD_CLIENT_ID || 'default'; +export const discord_client_secret = process.env.DISCORD_CLIENT_SECRET || 'default'; +export const discord_redirect_uri = process.env.DISCORD_REDIRECT_URI || 'default'; +export const shotgun_password = process.env.SHOTGUN_PASSWORD || ''; +export const automation_token = process.env.AUTOMATION_TOKEN || ''; diff --git a/backend/types/billetweb.d.ts b/backend/types/billetweb.d.ts new file mode 100644 index 0000000..11db5a9 --- /dev/null +++ b/backend/types/billetweb.d.ts @@ -0,0 +1,7 @@ +export interface BilletwebUser { + email: string; + firstName: string; + lastName: string; +} + +export type BilletwebMember = [string, ...string[]]; From db81338616fd5f01dc5557fb513637e4e15a2b60 Mon Sep 17 00:00:00 2001 From: Arthur Dodin Date: Mon, 13 Jul 2026 15:28:45 +0200 Subject: [PATCH 09/27] refactor(back): billetweb with API route created for us --- backend/src/utils/billetweb.ts | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/backend/src/utils/billetweb.ts b/backend/src/utils/billetweb.ts index 13ba62d..a5135d8 100644 --- a/backend/src/utils/billetweb.ts +++ b/backend/src/utils/billetweb.ts @@ -1,6 +1,6 @@ import axios from 'axios'; import { api_billetweb_token, api_billetweb_url, api_billetweb_respondent_students_list_id } from './secret'; -import type { BilletwebUser, BilletwebMember } from '../../types/billetweb'; +import type { BilletwebUser } from '../../types/billetweb'; const headers = { accept: 'application/json', @@ -29,18 +29,16 @@ const removeUserFromList = async (listId: string, email: string) => { try { if (!api_billetweb_url || !api_billetweb_token || !api_billetweb_respondent_students_list_id) return; - const { data } = await axios.get(`${api_billetweb_url}/list/${listId}/data`, { headers }); - - const members = data.filter(([memberEmail]) => memberEmail !== email); - - // Ne rien faire si l'utilisateur n'était pas dans la liste - if (members.length === data.length) { - return; - } - - await axios.post(`${api_billetweb_url}/list/${listId}/replace`, { data: members }, { headers }); + const response = await axios.post( + `${api_billetweb_url}/list/${listId}/remove`, + { + data: [[email]], + }, + { headers }, + ); + return response; } catch (error) { - console.error('Error removing user from list:', error); + console.error(`Error removing ${email} from list ${listId}:`, error); throw error; } }; From cb214ae6ab24117d302e0e94c944bcdde5ccf5ef Mon Sep 17 00:00:00 2001 From: Antoine Date: Fri, 17 Jul 2026 09:11:31 +0200 Subject: [PATCH 10/27] fix: delete contact_CE in form --- .../0024_natural_human_cannonball.sql | 1 + .../migrations/meta/0024_snapshot.json | 1329 +++++++++++++++++ .../database/migrations/meta/_journal.json | 7 + .../Relational/userinformation.schema.ts | 1 - backend/src/services/user.service.ts | 2 - backend/types/user.d.ts | 1 - frontend/eslint.config.js | 27 +- frontend/src/components/home/urgencyModal.tsx | 7 +- frontend/src/interfaces/user.interface.ts | 2 - 9 files changed, 1350 insertions(+), 27 deletions(-) create mode 100644 backend/src/database/migrations/0024_natural_human_cannonball.sql create mode 100644 backend/src/database/migrations/meta/0024_snapshot.json diff --git a/backend/src/database/migrations/0024_natural_human_cannonball.sql b/backend/src/database/migrations/0024_natural_human_cannonball.sql new file mode 100644 index 0000000..394fdcc --- /dev/null +++ b/backend/src/database/migrations/0024_natural_human_cannonball.sql @@ -0,0 +1 @@ +ALTER TABLE "user_informations" DROP COLUMN "contact_CE"; \ No newline at end of file diff --git a/backend/src/database/migrations/meta/0024_snapshot.json b/backend/src/database/migrations/meta/0024_snapshot.json new file mode 100644 index 0000000..c58070e --- /dev/null +++ b/backend/src/database/migrations/meta/0024_snapshot.json @@ -0,0 +1,1329 @@ +{ + "id": "f2813605-996e-4461-8e87-8b135d3eefd3", + "prevId": "77c4b2f6-c24d-4eb9-80a9-42fb8b9ef380", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.challenges": { + "name": "challenges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "challenges_created_by_users_id_fk": { + "name": "challenges_created_by_users_id_fk", + "tableFrom": "challenges", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "pre_registration_open": { + "name": "pre_registration_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "shotgun_open": { + "name": "shotgun_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "sdi_open": { + "name": "sdi_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "wei_open": { + "name": "wei_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "food_open": { + "name": "food_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "chall_open": { + "name": "chall_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.factions": { + "name": "factions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "factions_name_unique": { + "name": "factions_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.news": { + "name": "news", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "published": { + "name": "published", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "target": { + "name": "target", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permanences": { + "name": "permanences", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "end_at": { + "name": "end_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "capacity": { + "name": "capacity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_open": { + "name": "is_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "difficulty": { + "name": "difficulty", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.roles": { + "name": "roles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "roles_name_unique": { + "name": "roles_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.teams": { + "name": "teams", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "teams_name_unique": { + "name": "teams_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "majeur": { + "name": "majeur", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contact": { + "name": "contact", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'Nouveau'" + }, + "discord_id": { + "name": "discord_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bus_attribution": { + "name": "bus_attribution", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "bus": { + "name": "bus", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "departure_time": { + "name": "departure_time", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bus_attribution_user_id_users_id_fk": { + "name": "bus_attribution_user_id_users_id_fk", + "tableFrom": "bus_attribution", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.challenge_validation": { + "name": "challenge_validation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "challenge_id": { + "name": "challenge_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_by_admin_id": { + "name": "validated_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_at": { + "name": "validated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "target_user_id": { + "name": "target_user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_team_id": { + "name": "target_team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_faction_id": { + "name": "target_faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "added_by_admin_id": { + "name": "added_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "challenge_validation_challenge_id_challenges_id_fk": { + "name": "challenge_validation_challenge_id_challenges_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "challenges", + "columnsFrom": [ + "challenge_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_validated_by_admin_id_users_id_fk": { + "name": "challenge_validation_validated_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "validated_by_admin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_user_id_users_id_fk": { + "name": "challenge_validation_target_user_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "target_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_team_id_teams_id_fk": { + "name": "challenge_validation_target_team_id_teams_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "teams", + "columnsFrom": [ + "target_team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_faction_id_factions_id_fk": { + "name": "challenge_validation_target_faction_id_factions_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "factions", + "columnsFrom": [ + "target_faction_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_added_by_admin_id_users_id_fk": { + "name": "challenge_validation_added_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "added_by_admin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registration_tokens": { + "name": "registration_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_tokens_user_id_users_id_fk": { + "name": "registration_tokens_user_id_users_id_fk", + "tableFrom": "registration_tokens", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "registration_tokens_token_unique": { + "name": "registration_tokens_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.role_points": { + "name": "role_points", + "schema": "", + "columns": { + "role_points": { + "name": "role_points", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "role_points_role_points_roles_id_fk": { + "name": "role_points_role_points_roles_id_fk", + "tableFrom": "role_points", + "tableTo": "roles", + "columnsFrom": [ + "role_points" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "role_points_role_points_pk": { + "name": "role_points_role_points_pk", + "columns": [ + "role_points" + ] + } + }, + "uniqueConstraints": { + "role_points_role_points_unique": { + "name": "role_points_role_points_unique", + "nullsNotDistinct": false, + "columns": [ + "role_points" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_faction": { + "name": "team_faction", + "schema": "", + "columns": { + "faction_id": { + "name": "faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "team_faction_faction_id_factions_id_fk": { + "name": "team_faction_faction_id_factions_id_fk", + "tableFrom": "team_faction", + "tableTo": "factions", + "columnsFrom": [ + "faction_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "team_faction_team_id_teams_id_fk": { + "name": "team_faction_team_id_teams_id_fk", + "tableFrom": "team_faction", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "team_faction_faction_id_team_id_pk": { + "name": "team_faction_faction_id_team_id_pk", + "columns": [ + "faction_id", + "team_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_shotgun": { + "name": "team_shotgun", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "team_shotgun_team_id_teams_id_fk": { + "name": "team_shotgun_team_id_teams_id_fk", + "tableFrom": "team_shotgun", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_informations": { + "name": "user_informations", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "urgency_contact_name": { + "name": "urgency_contact_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "urgency_contact_phone": { + "name": "urgency_contact_phone", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_informations_user_id_users_id_fk": { + "name": "user_informations_user_id_users_id_fk", + "tableFrom": "user_informations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.respo_permanences": { + "name": "respo_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "respo_permanences_user_id_users_id_fk": { + "name": "respo_permanences_user_id_users_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "respo_permanences_permanence_id_permanences_id_fk": { + "name": "respo_permanences_permanence_id_permanences_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "permanences", + "columnsFrom": [ + "permanence_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "respo_permanences_user_id_permanence_id_pk": { + "name": "respo_permanences_user_id_permanence_id_pk", + "columns": [ + "user_id", + "permanence_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_permanences": { + "name": "user_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "registered_at": { + "name": "registered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "claimed": { + "name": "claimed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_permanences_user_id_users_id_fk": { + "name": "user_permanences_user_id_users_id_fk", + "tableFrom": "user_permanences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_permanences_permanence_id_permanences_id_fk": { + "name": "user_permanences_permanence_id_permanences_id_fk", + "tableFrom": "user_permanences", + "tableTo": "permanences", + "columnsFrom": [ + "permanence_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_permanences_user_id_permanence_id_pk": { + "name": "user_permanences_user_id_permanence_id_pk", + "columns": [ + "user_id", + "permanence_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_preferences": { + "name": "user_preferences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_preferences_user_id_users_id_fk": { + "name": "user_preferences_user_id_users_id_fk", + "tableFrom": "user_preferences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_preferences_role_id_roles_id_fk": { + "name": "user_preferences_role_id_roles_id_fk", + "tableFrom": "user_preferences", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_preferences_user_id_role_id_pk": { + "name": "user_preferences_user_id_role_id_pk", + "columns": [ + "user_id", + "role_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_roles": { + "name": "user_roles", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_roles_user_id_users_id_fk": { + "name": "user_roles_user_id_users_id_fk", + "tableFrom": "user_roles", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_roles_role_id_roles_id_fk": { + "name": "user_roles_role_id_roles_id_fk", + "tableFrom": "user_roles", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_teams": { + "name": "user_teams", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_teams_user_id_users_id_fk": { + "name": "user_teams_user_id_users_id_fk", + "tableFrom": "user_teams", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_teams_team_id_teams_id_fk": { + "name": "user_teams_team_id_teams_id_fk", + "tableFrom": "user_teams", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_teams_user_id_team_id_pk": { + "name": "user_teams_user_id_team_id_pk", + "columns": [ + "user_id", + "team_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_tent": { + "name": "user_tent", + "schema": "", + "columns": { + "user_id_1": { + "name": "user_id_1", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "user_id_2": { + "name": "user_id_2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "confirmed": { + "name": "confirmed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_tent_user_id_1_users_id_fk": { + "name": "user_tent_user_id_1_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": [ + "user_id_1" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_tent_user_id_2_users_id_fk": { + "name": "user_tent_user_id_2_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": [ + "user_id_2" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_tent_user_id_1_user_id_2_pk": { + "name": "user_tent_user_id_1_user_id_2_pk", + "columns": [ + "user_id_1", + "user_id_2" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/backend/src/database/migrations/meta/_journal.json b/backend/src/database/migrations/meta/_journal.json index ea074cf..bea96a9 100644 --- a/backend/src/database/migrations/meta/_journal.json +++ b/backend/src/database/migrations/meta/_journal.json @@ -169,6 +169,13 @@ "when": 1783854058299, "tag": "0023_even_morg", "breakpoints": true + }, + { + "idx": 24, + "version": "7", + "when": 1784272112439, + "tag": "0024_natural_human_cannonball", + "breakpoints": true } ] } \ No newline at end of file diff --git a/backend/src/schemas/Relational/userinformation.schema.ts b/backend/src/schemas/Relational/userinformation.schema.ts index feae1a7..71892ec 100644 --- a/backend/src/schemas/Relational/userinformation.schema.ts +++ b/backend/src/schemas/Relational/userinformation.schema.ts @@ -7,7 +7,6 @@ export const userInformationSchema = pgTable('user_informations', { .references(() => userSchema.id, { onDelete: 'cascade' }), urgency_contact_name: text('urgency_contact_name'), urgency_contact_phone: text('urgency_contact_phone'), - contact_CE: text('contact_CE'), }); export type UserInformation = typeof userInformationSchema.$inferSelect; diff --git a/backend/src/services/user.service.ts b/backend/src/services/user.service.ts index bbb1589..3721dde 100644 --- a/backend/src/services/user.service.ts +++ b/backend/src/services/user.service.ts @@ -145,7 +145,6 @@ export const getUserContactInformation = async (userId: number) => { userId: userInformationSchema.user_id, urgency_contact_name: userInformationSchema.urgency_contact_name, urgency_contact_phone: userInformationSchema.urgency_contact_phone, - contact_CE: userInformationSchema.contact_CE, }) .from(userInformationSchema) .where(eq(userInformationSchema.user_id, userId)); @@ -162,7 +161,6 @@ export const createUserContactInformation = async (userId: number, contact: User user_id: userId, urgency_contact_name: contact.urgency_contact_name, urgency_contact_phone: contact.urgency_contact_phone, - contact_CE: contact.contact_CE, }; const result = await db.insert(userInformationSchema).values(newContactInfo).returning(); diff --git a/backend/types/user.d.ts b/backend/types/user.d.ts index 928f2e3..6df16da 100644 --- a/backend/types/user.d.ts +++ b/backend/types/user.d.ts @@ -1,5 +1,4 @@ export type UserContactInformation = { urgency_contact_name: string; urgency_contact_phone: string; - contact_CE: string; }; diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js index 761cc9f..a6ada99 100644 --- a/frontend/eslint.config.js +++ b/frontend/eslint.config.js @@ -1,13 +1,13 @@ -import js from '@eslint/js' -import importPlugin from 'eslint-plugin-import' -import jsxA11y from 'eslint-plugin-jsx-a11y' -import reactPlugin from 'eslint-plugin-react' -import reactHooks from 'eslint-plugin-react-hooks' -import reactRefresh from 'eslint-plugin-react-refresh' -import simpleImportSort from 'eslint-plugin-simple-import-sort' -import unusedImports from 'eslint-plugin-unused-imports' -import globals from 'globals' -import tseslint from 'typescript-eslint' +import js from '@eslint/js'; +import importPlugin from 'eslint-plugin-import'; +import jsxA11y from 'eslint-plugin-jsx-a11y'; +import reactPlugin from 'eslint-plugin-react'; +import reactHooks from 'eslint-plugin-react-hooks'; +import reactRefresh from 'eslint-plugin-react-refresh'; +import simpleImportSort from 'eslint-plugin-simple-import-sort'; +import unusedImports from 'eslint-plugin-unused-imports'; +import globals from 'globals'; +import tseslint from 'typescript-eslint'; export default tseslint.config( { @@ -63,10 +63,7 @@ export default tseslint.config( argsIgnorePattern: '^_', }, ], - 'react-refresh/only-export-components': [ - 'warn', - { allowConstantExport: true }, - ], + 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }], }, }, -) +); diff --git a/frontend/src/components/home/urgencyModal.tsx b/frontend/src/components/home/urgencyModal.tsx index d0ac867..a26651e 100644 --- a/frontend/src/components/home/urgencyModal.tsx +++ b/frontend/src/components/home/urgencyModal.tsx @@ -8,7 +8,7 @@ import Modal from '../ui/modal'; function UrgencyModal() { const [searchParams, setSearchParams] = useSearchParams(); - const [form, setForm] = useState({ contact_CE: '', urgency_contact_name: '', urgency_contact_phone: '' }); + const [form, setForm] = useState({ urgency_contact_name: '', urgency_contact_phone: '' }); const isLogin = searchParams.get('login') === 'true'; @@ -16,11 +16,6 @@ function UrgencyModal() { setSearchParams({})} buttons={null}>

    Bienvenu sur le site de l'intégration, blablabla faut que tu completes le formulaire.

    - setForm({ ...form, contact_CE: e.target.value })} - /> Date: Fri, 17 Jul 2026 12:20:07 +0200 Subject: [PATCH 11/27] feat: add vssqcm schemas and seed --- backend/drizzle.config.ts | 16 +- backend/server.ts | 24 +- backend/src/database/initdb/initQcmvss.ts | 214 +++ .../migrations/0025_friendly_meltdown.sql | 16 + .../migrations/meta/0025_snapshot.json | 1426 +++++++++++++++++ .../database/migrations/meta/_journal.json | 7 + backend/src/schemas/Basic/user.schema.ts | 29 +- .../schemas/Basic/vssqcmquestion.schema.ts | 9 + .../schemas/Relational/vssqcmanswer.schema.ts | 13 + .../Relational/vssqcmquestion.schema.ts | 12 + 10 files changed, 1734 insertions(+), 32 deletions(-) create mode 100644 backend/src/database/initdb/initQcmvss.ts create mode 100644 backend/src/database/migrations/0025_friendly_meltdown.sql create mode 100644 backend/src/database/migrations/meta/0025_snapshot.json create mode 100644 backend/src/schemas/Basic/vssqcmquestion.schema.ts create mode 100644 backend/src/schemas/Relational/vssqcmanswer.schema.ts create mode 100644 backend/src/schemas/Relational/vssqcmquestion.schema.ts diff --git a/backend/drizzle.config.ts b/backend/drizzle.config.ts index 2b91af5..7eeadaa 100644 --- a/backend/drizzle.config.ts +++ b/backend/drizzle.config.ts @@ -1,13 +1,13 @@ -import { defineConfig } from 'drizzle-kit' -import * as dotenv from "dotenv"; +import { defineConfig } from 'drizzle-kit'; +import * as dotenv from 'dotenv'; dotenv.config(); export default defineConfig({ - schema: "./src/schemas/*", - out: "./src/database/migrations", - dialect: "postgresql", - dbCredentials: { - url: process.env.OUTSIDE_DATABASE_URL ?? "" - }, + schema: './src/schemas/*', + out: './src/database/migrations', + dialect: 'postgresql', + dbCredentials: { + url: process.env.OUTSIDE_DATABASE_URL ?? '', + }, }); diff --git a/backend/server.ts b/backend/server.ts index 02128c2..4984bd3 100644 --- a/backend/server.ts +++ b/backend/server.ts @@ -3,7 +3,7 @@ import cors from 'cors'; import express from 'express'; import dotenv from 'dotenv'; -import path from "path"; +import path from 'path'; import { initChallenge } from './src/database/initdb/initChallenge'; import { initUser } from './src/database/initdb/initUser'; @@ -28,6 +28,7 @@ import teamRoutes from './src/routes/team.routes'; import tentRoutes from './src/routes/tent.routes'; import userRoutes from './src/routes/user.routes'; import { server_port } from './src/utils/secret'; +import { initQcmvss } from './src/database/initdb/initQcmvss'; dotenv.config(); @@ -35,7 +36,7 @@ async function startServer() { const app = express(); // Configuration des middlewares - app.use(cors({ origin: "*" })); + app.use(cors({ origin: '*' })); app.use(bodyParser.json()); app.use(express.urlencoded({ extended: true })); @@ -45,10 +46,11 @@ async function startServer() { await initRoles(); await initEvent(); await initChallenge(); + await initQcmvss(); console.log('Base de données initialisée avec succès.'); // Utilisation des routes d'authentification - app.use('/api', defaultRoute) + app.use('/api', defaultRoute); app.use('/api/auth', authRoutes); app.use('/api/automation', authenticateAutomation, automationRoutes); app.use('/api/authadmin', authenticateUser, authRoutes); @@ -57,7 +59,7 @@ async function startServer() { app.use('/api/team', authenticateUser, teamRoutes); app.use('/api/event', authenticateUser, eventRoutes); app.use('/api/faction', authenticateUser, factionRoutes); - app.use('/api/imexport', authenticateUser, imexportRouter) + app.use('/api/imexport', authenticateUser, imexportRouter); app.use('/api/permanence', authenticateUser, permanenceRoutes); app.use('/api/challenge', authenticateUser, challengeRoutes); app.use('/api/email', authenticateUser, emailRoutes); @@ -65,19 +67,19 @@ async function startServer() { app.use('/api/discord', authenticateUser, discordRoutes); app.use('/api/tent', authenticateUser, tentRoutes); app.use('/api/bus', authenticateUser, busRoutes); - app.use("/api/uploads/news", express.static(path.join(__dirname, "/uploads/news"))); - app.use("/api/uploads/notebooks", express.static(path.join(__dirname, "/uploads/notebooks"))); - app.use("/api/uploads/foodmenu", express.static(path.join(__dirname, "/uploads/foodmenu"))); - app.use("/api/uploads/plannings", express.static(path.join(__dirname, "/uploads/plannings"))); - app.use("/api/exports/bus", express.static(path.join(__dirname, "/exports/bus"))); + app.use('/api/uploads/news', express.static(path.join(__dirname, '/uploads/news'))); + app.use('/api/uploads/notebooks', express.static(path.join(__dirname, '/uploads/notebooks'))); + app.use('/api/uploads/foodmenu', express.static(path.join(__dirname, '/uploads/foodmenu'))); + app.use('/api/uploads/plannings', express.static(path.join(__dirname, '/uploads/plannings'))); + app.use('/api/exports/bus', express.static(path.join(__dirname, '/exports/bus'))); // Démarrage du serveur app.listen(server_port, () => { console.log(`Server running on port ${server_port}`); }); } catch (err) { - console.error('Erreur lors de l\'initialisation de la base de données :', err); - process.exit(1); // Arrêter le serveur si l'initialisation échoue + console.error("Erreur lors de l'initialisation de la base de données :", err); + process.exit(1); // Arrêter le serveur si l'initialisation échoue } } diff --git a/backend/src/database/initdb/initQcmvss.ts b/backend/src/database/initdb/initQcmvss.ts new file mode 100644 index 0000000..ca18f57 --- /dev/null +++ b/backend/src/database/initdb/initQcmvss.ts @@ -0,0 +1,214 @@ +import { db } from '../db'; +import { vssqcmanswerSchema } from '../../schemas/Relational/vssqcmanswer.schema'; +import { vssqcmquestionSchema } from '../../schemas/Basic/vssqcmquestion.schema'; + +type SeedQuestion = { + question: string; + points: number; + type: 'single_choice' | 'multiple_choice'; + answers: { + answer: string; + is_correct: boolean; + }[]; +}; + +const qcmQuestions: SeedQuestion[] = [ + { + question: 'Oui = ', + points: 1, + type: 'single_choice', + answers: [ + { answer: 'Non', is_correct: false }, + { answer: 'Toujours oui', is_correct: false }, + { answer: 'Peut-être non plus tard', is_correct: true }, + ], + }, + { + question: 'Non = ', + points: 1, + type: 'single_choice', + answers: [ + { answer: 'Oui', is_correct: false }, + { answer: 'Non', is_correct: true }, + { answer: "Peut-être oui si j'insiste", is_correct: false }, + ], + }, + { + question: 'En résumé, le consentement', + points: 2, + type: 'multiple_choice', + answers: [ + { answer: 'concerne une action précise', is_correct: true }, + { answer: "ne peut-être considéré comme éclairé venant d'un personne en état d'ébriété", is_correct: true }, + { answer: 'doit être libre et éclairé', is_correct: true }, + { answer: 'peut être retiré à tout moment', is_correct: true }, + { + answer: "spécifique, enthousiaste; valable quand la personne chancèle sous l'effet de l'alcool", + is_correct: false, + }, + { answer: "peut s'obtenir en insistant", is_correct: false }, + { answer: 'est valable quand la personne est bourrée', is_correct: false }, + ], + }, + { + question: + "B a embrassé A de force pendant le bang. B était complètement bourré. Il s'agit d'une agression sexuelle. La prise d'alcool est alors une condition :", + points: 1, + type: 'single_choice', + answers: [ + { answer: 'Aggravante', is_correct: true }, + { answer: 'Atténuante', is_correct: false }, + ], + }, + { + question: 'Parmi les situations suivantes, lesquelles sont des agressions sexuelles :', + points: 1, + type: 'multiple_choice', + answers: [ + { answer: "Se frotter à quelqu'un•e", is_correct: true }, + { answer: 'Caresser les fesses de son•sa partenaire endormi•e', is_correct: true }, + { answer: "Embrasser quelqu'un•e de force", is_correct: true }, + { answer: "Embrasser par surprise quelqu'un•e qui danse au milieu de la foule", is_correct: true }, + { answer: "Embrasser quelqu'un•e tant alcoolisé•e qu'iel vient de vomir", is_correct: true }, + ], + }, + { + question: "Un.e de tes amis touche les fesses de B et l'enlace. B a un mouvement de recul. Que peux-tu faire ?", + points: 1, + type: 'multiple_choice', + answers: [ + { answer: "Rien de particulier. B ne s'en souviendra sûrement pas.", is_correct: false }, + { answer: 'Demander à B si elle•il va bien', is_correct: true }, + { + answer: "Prendre cet•te ami•e à part et lui faire comprendre qu'il•elle a mal agi, que B n'avait pas envie d'être touché•e.", + is_correct: true, + }, + { answer: 'Eloigner ton ami•e de B', is_correct: true }, + { answer: "Le signaler à un tiers si tu penses que B peut avoir besoin d'aide", is_correct: true }, + ], + }, + { + question: "A qui et où peux-tu demander de l'aide si tu en as besoin ?", + points: 1, + type: 'multiple_choice', + answers: [ + { answer: 'Dans la Safe Zone', is_correct: true }, + { answer: 'Aux personnes des confiance', is_correct: true }, + { answer: 'Au stand de prévention', is_correct: true }, + { answer: 'A la team prévention', is_correct: true }, + { answer: 'Aux super orgas', is_correct: true }, + { answer: "A tes chefs d'équipe", is_correct: true }, + { answer: 'A ta marraine / A ton parrain', is_correct: true }, + { answer: 'À un•e ami•e', is_correct: true }, + ], + }, + { + question: + 'En cas de VSS, quelles sont les peines maximales légalement encourue par une personne ayant commis une agression sexuelle ?', + points: 1, + type: 'single_choice', + answers: [ + { answer: "75 000 € d'amende et 5 ans d'emprisonnemen", is_correct: true }, + { answer: "10 000€ d'amende", is_correct: false }, + { answer: '15 ans de prison', is_correct: false }, + ], + }, + { + question: 'Quelles sont les conséquences possibles pour la victime de VSS ?', + points: 1, + type: 'multiple_choice', + answers: [ + { answer: 'Aucun effet particulier', is_correct: false }, + { answer: 'Problèmes somatiques (nausées, migraines, fatigue)', is_correct: true }, + { answer: 'Dysfonction sexuelle', is_correct: true }, + { answer: "Crainte de l'intimité", is_correct: true }, + { answer: 'Dépression majeure', is_correct: true }, + { answer: 'Détresse psychologique', is_correct: true }, + ], + }, + { + question: 'Que puis-je faire si je suis témoins de VSS ?', + points: 1, + type: 'multiple_choice', + answers: [ + { answer: "Dire à la victime de faire attention à elle et de mieux s'habiller", is_correct: false }, + { answer: 'Aller voir la team prévention ou les super-orgas', is_correct: true }, + { answer: 'Appeler France Victime (01 80 52 33 86)', is_correct: true }, + { answer: "Appeler le numéro d'astreinte", is_correct: true }, + ], + }, + { + question: + "A quelle sentence s'expose une personne commettant un viol ? \`n Article 222-23 Version en vigueur depuis le 23 avril 2021 \n Tout acte de pénétration sexuelle, de quelque nature qu'il soit, ou tout acte bucco-génital commis sur la personne d'autrui ou sur la personne de l'auteur par violence, contrainte, menace ou surprise est un viol. \n Le viol est puni de quinze ans de réclusion criminelle.", + points: 1, + type: 'multiple_choice', + answers: [ + { answer: '15 ans de réclusion criminelle', is_correct: true }, + { answer: "100 000€ d'amence et 20 ans de réclusion criminelle", is_correct: false }, + { answer: "100 000€ d'amence et 10 ans de réclusion criminelle", is_correct: false }, + ], + }, + { + question: "Qu'est-ce qui est considéré comme un acte de bizutage (et qui est donc interdit) ? ", + points: 1, + type: 'multiple_choice', + answers: [ + { answer: "Se dénuder ou inciter quelqu'un à se dénuder (Limousin, Maréchal...)", is_correct: true }, + { answer: "Obliger quelqu'un à boire de l'alcool de force lors d'une soirée", is_correct: true }, + { + answer: 'Organiser une chasse au trésor géante à travers toute la ville pour les nouveaux', + is_correct: false, + }, + { answer: 'Humilier publiquement un nouveau devant le groupe', is_correct: true }, + { answer: 'Forcer une personne à effectuer des tâches dégradantes ou dangereuses', is_correct: true }, + { answer: "Défier un nouveau à réciter l'annuaire téléphonique en dansant la macarena", is_correct: false }, + { answer: 'Motiver les nouveaux à se déguiser en canard', is_correct: false }, + { answer: 'Forcer les nouveaux à porter un déguisement obscène', is_correct: true }, + ], + }, + { + question: "A quelles sanctions s'expose l'auteur du bizutage ?", + points: 1, + type: 'multiple_choice', + answers: [ + { answer: "Une exclusion de l'intégration", is_correct: true }, + { answer: 'Rien du tout', is_correct: false }, + { + answer: "Le bizutage est un délit. Il est puni de 6 mois d'emprisonnement et de 7 500 € d'amende.", + is_correct: true, + }, + { answer: 'Si la victime est une personne vulnérable, les peines sont doublées', is_correct: true }, + { answer: 'Une mauvaise note', is_correct: false }, + ], + }, +]; + +export const initQcmvss = async () => { + const existingQuestion = await db.select().from(vssqcmquestionSchema).limit(1); + + if (existingQuestion.length > 0) { + return; + } + + for (const seedQuestion of qcmQuestions) { + const [createdQuestion] = await db + .insert(vssqcmquestionSchema) + .values({ + question: seedQuestion.question, + points: seedQuestion.points, + }) + .returning({ id: vssqcmquestionSchema.id }); + + if (!createdQuestion) { + throw new Error(`Question not inserted: ${seedQuestion.question}`); + } + + await db.insert(vssqcmanswerSchema).values( + seedQuestion.answers.map((seedAnswer) => ({ + questionid: createdQuestion.id, + answer: seedAnswer.answer, + is_correct: seedAnswer.is_correct, + })), + ); + } +}; diff --git a/backend/src/database/migrations/0025_friendly_meltdown.sql b/backend/src/database/migrations/0025_friendly_meltdown.sql new file mode 100644 index 0000000..454c6e2 --- /dev/null +++ b/backend/src/database/migrations/0025_friendly_meltdown.sql @@ -0,0 +1,16 @@ +CREATE TABLE "vssqcmquestion" ( + "id" serial PRIMARY KEY NOT NULL, + "question" text NOT NULL, + "points" integer NOT NULL, + "type" "question_type" NOT NULL +); +--> statement-breakpoint +CREATE TABLE "vssqcmanswer" ( + "id" serial PRIMARY KEY NOT NULL, + "questionid" integer NOT NULL, + "answer" text NOT NULL, + "is_correct" boolean NOT NULL +); +--> statement-breakpoint +ALTER TABLE "users" ADD COLUMN "vss_form" "vss_form" DEFAULT 'pending';--> statement-breakpoint +ALTER TABLE "vssqcmanswer" ADD CONSTRAINT "vssqcmanswer_questionid_vssqcmquestion_id_fk" FOREIGN KEY ("questionid") REFERENCES "public"."vssqcmquestion"("id") ON DELETE cascade ON UPDATE no action; \ No newline at end of file diff --git a/backend/src/database/migrations/meta/0025_snapshot.json b/backend/src/database/migrations/meta/0025_snapshot.json new file mode 100644 index 0000000..9ab71cd --- /dev/null +++ b/backend/src/database/migrations/meta/0025_snapshot.json @@ -0,0 +1,1426 @@ +{ + "id": "222234ea-1f97-4c76-bf24-29c5da01972e", + "prevId": "f2813605-996e-4461-8e87-8b135d3eefd3", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.challenges": { + "name": "challenges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "challenges_created_by_users_id_fk": { + "name": "challenges_created_by_users_id_fk", + "tableFrom": "challenges", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "pre_registration_open": { + "name": "pre_registration_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "shotgun_open": { + "name": "shotgun_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "sdi_open": { + "name": "sdi_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "wei_open": { + "name": "wei_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "food_open": { + "name": "food_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "chall_open": { + "name": "chall_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.factions": { + "name": "factions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "factions_name_unique": { + "name": "factions_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.news": { + "name": "news", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "published": { + "name": "published", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "target": { + "name": "target", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permanences": { + "name": "permanences", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "end_at": { + "name": "end_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "capacity": { + "name": "capacity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_open": { + "name": "is_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "difficulty": { + "name": "difficulty", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.roles": { + "name": "roles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "roles_name_unique": { + "name": "roles_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.teams": { + "name": "teams", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "teams_name_unique": { + "name": "teams_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "majeur": { + "name": "majeur", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contact": { + "name": "contact", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'Nouveau'" + }, + "discord_id": { + "name": "discord_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "vss_form": { + "name": "vss_form", + "type": "vss_form", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'pending'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.vssqcmquestion": { + "name": "vssqcmquestion", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "question": { + "name": "question", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "question_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bus_attribution": { + "name": "bus_attribution", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "bus": { + "name": "bus", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "departure_time": { + "name": "departure_time", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bus_attribution_user_id_users_id_fk": { + "name": "bus_attribution_user_id_users_id_fk", + "tableFrom": "bus_attribution", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.challenge_validation": { + "name": "challenge_validation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "challenge_id": { + "name": "challenge_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_by_admin_id": { + "name": "validated_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_at": { + "name": "validated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "target_user_id": { + "name": "target_user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_team_id": { + "name": "target_team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_faction_id": { + "name": "target_faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "added_by_admin_id": { + "name": "added_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "challenge_validation_challenge_id_challenges_id_fk": { + "name": "challenge_validation_challenge_id_challenges_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "challenges", + "columnsFrom": [ + "challenge_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_validated_by_admin_id_users_id_fk": { + "name": "challenge_validation_validated_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "validated_by_admin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_user_id_users_id_fk": { + "name": "challenge_validation_target_user_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "target_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_team_id_teams_id_fk": { + "name": "challenge_validation_target_team_id_teams_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "teams", + "columnsFrom": [ + "target_team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_faction_id_factions_id_fk": { + "name": "challenge_validation_target_faction_id_factions_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "factions", + "columnsFrom": [ + "target_faction_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_added_by_admin_id_users_id_fk": { + "name": "challenge_validation_added_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "added_by_admin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registration_tokens": { + "name": "registration_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_tokens_user_id_users_id_fk": { + "name": "registration_tokens_user_id_users_id_fk", + "tableFrom": "registration_tokens", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "registration_tokens_token_unique": { + "name": "registration_tokens_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.role_points": { + "name": "role_points", + "schema": "", + "columns": { + "role_points": { + "name": "role_points", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "role_points_role_points_roles_id_fk": { + "name": "role_points_role_points_roles_id_fk", + "tableFrom": "role_points", + "tableTo": "roles", + "columnsFrom": [ + "role_points" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "role_points_role_points_pk": { + "name": "role_points_role_points_pk", + "columns": [ + "role_points" + ] + } + }, + "uniqueConstraints": { + "role_points_role_points_unique": { + "name": "role_points_role_points_unique", + "nullsNotDistinct": false, + "columns": [ + "role_points" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_faction": { + "name": "team_faction", + "schema": "", + "columns": { + "faction_id": { + "name": "faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "team_faction_faction_id_factions_id_fk": { + "name": "team_faction_faction_id_factions_id_fk", + "tableFrom": "team_faction", + "tableTo": "factions", + "columnsFrom": [ + "faction_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "team_faction_team_id_teams_id_fk": { + "name": "team_faction_team_id_teams_id_fk", + "tableFrom": "team_faction", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "team_faction_faction_id_team_id_pk": { + "name": "team_faction_faction_id_team_id_pk", + "columns": [ + "faction_id", + "team_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_shotgun": { + "name": "team_shotgun", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "team_shotgun_team_id_teams_id_fk": { + "name": "team_shotgun_team_id_teams_id_fk", + "tableFrom": "team_shotgun", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_informations": { + "name": "user_informations", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "urgency_contact_name": { + "name": "urgency_contact_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "urgency_contact_phone": { + "name": "urgency_contact_phone", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_informations_user_id_users_id_fk": { + "name": "user_informations_user_id_users_id_fk", + "tableFrom": "user_informations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.respo_permanences": { + "name": "respo_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "respo_permanences_user_id_users_id_fk": { + "name": "respo_permanences_user_id_users_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "respo_permanences_permanence_id_permanences_id_fk": { + "name": "respo_permanences_permanence_id_permanences_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "permanences", + "columnsFrom": [ + "permanence_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "respo_permanences_user_id_permanence_id_pk": { + "name": "respo_permanences_user_id_permanence_id_pk", + "columns": [ + "user_id", + "permanence_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_permanences": { + "name": "user_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "registered_at": { + "name": "registered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "claimed": { + "name": "claimed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_permanences_user_id_users_id_fk": { + "name": "user_permanences_user_id_users_id_fk", + "tableFrom": "user_permanences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_permanences_permanence_id_permanences_id_fk": { + "name": "user_permanences_permanence_id_permanences_id_fk", + "tableFrom": "user_permanences", + "tableTo": "permanences", + "columnsFrom": [ + "permanence_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_permanences_user_id_permanence_id_pk": { + "name": "user_permanences_user_id_permanence_id_pk", + "columns": [ + "user_id", + "permanence_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_preferences": { + "name": "user_preferences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_preferences_user_id_users_id_fk": { + "name": "user_preferences_user_id_users_id_fk", + "tableFrom": "user_preferences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_preferences_role_id_roles_id_fk": { + "name": "user_preferences_role_id_roles_id_fk", + "tableFrom": "user_preferences", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_preferences_user_id_role_id_pk": { + "name": "user_preferences_user_id_role_id_pk", + "columns": [ + "user_id", + "role_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_roles": { + "name": "user_roles", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_roles_user_id_users_id_fk": { + "name": "user_roles_user_id_users_id_fk", + "tableFrom": "user_roles", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_roles_role_id_roles_id_fk": { + "name": "user_roles_role_id_roles_id_fk", + "tableFrom": "user_roles", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_teams": { + "name": "user_teams", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_teams_user_id_users_id_fk": { + "name": "user_teams_user_id_users_id_fk", + "tableFrom": "user_teams", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_teams_team_id_teams_id_fk": { + "name": "user_teams_team_id_teams_id_fk", + "tableFrom": "user_teams", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_teams_user_id_team_id_pk": { + "name": "user_teams_user_id_team_id_pk", + "columns": [ + "user_id", + "team_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_tent": { + "name": "user_tent", + "schema": "", + "columns": { + "user_id_1": { + "name": "user_id_1", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "user_id_2": { + "name": "user_id_2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "confirmed": { + "name": "confirmed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_tent_user_id_1_users_id_fk": { + "name": "user_tent_user_id_1_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": [ + "user_id_1" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_tent_user_id_2_users_id_fk": { + "name": "user_tent_user_id_2_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": [ + "user_id_2" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_tent_user_id_1_user_id_2_pk": { + "name": "user_tent_user_id_1_user_id_2_pk", + "columns": [ + "user_id_1", + "user_id_2" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.vssqcmanswer": { + "name": "vssqcmanswer", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "questionid": { + "name": "questionid", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "answer": { + "name": "answer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_correct": { + "name": "is_correct", + "type": "boolean", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "vssqcmanswer_questionid_vssqcmquestion_id_fk": { + "name": "vssqcmanswer_questionid_vssqcmquestion_id_fk", + "tableFrom": "vssqcmanswer", + "tableTo": "vssqcmquestion", + "columnsFrom": [ + "questionid" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/backend/src/database/migrations/meta/_journal.json b/backend/src/database/migrations/meta/_journal.json index bea96a9..88dbb0e 100644 --- a/backend/src/database/migrations/meta/_journal.json +++ b/backend/src/database/migrations/meta/_journal.json @@ -176,6 +176,13 @@ "when": 1784272112439, "tag": "0024_natural_human_cannonball", "breakpoints": true + }, + { + "idx": 25, + "version": "7", + "when": 1784283040878, + "tag": "0025_friendly_meltdown", + "breakpoints": true } ] } \ No newline at end of file diff --git a/backend/src/schemas/Basic/user.schema.ts b/backend/src/schemas/Basic/user.schema.ts index 8ada041..a442968 100644 --- a/backend/src/schemas/Basic/user.schema.ts +++ b/backend/src/schemas/Basic/user.schema.ts @@ -1,17 +1,20 @@ -import { boolean, pgTable, serial, text, timestamp } from "drizzle-orm/pg-core"; +import { boolean, pgEnum, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'; -export const userSchema = pgTable("users", { - id: serial("id").primaryKey(), - first_name: text("first_name"), - last_name: text("last_name"), - email: text("email").unique(), - majeur: boolean("majeur"), - branch: text("branch"), - contact: text("contact"), - password: text("password"), - permission: text("permission").default("Nouveau"), // Par défaut, le rôle sera "Nouveau" - discord_id: text("discord_id"), - created_at: timestamp("created_at").defaultNow(), +const vssFormEnum = pgEnum('vss_form', ['pending', 'validated', 'rejected']); + +export const userSchema = pgTable('users', { + id: serial('id').primaryKey(), + first_name: text('first_name'), + last_name: text('last_name'), + email: text('email').unique(), + majeur: boolean('majeur'), + branch: text('branch'), + contact: text('contact'), + password: text('password'), + permission: text('permission').default('Nouveau'), // Par défaut, le rôle sera "Nouveau" + discord_id: text('discord_id'), + created_at: timestamp('created_at').defaultNow(), + vss_form: vssFormEnum('vss_form').default('pending'), }); export type User = typeof userSchema.$inferSelect; diff --git a/backend/src/schemas/Basic/vssqcmquestion.schema.ts b/backend/src/schemas/Basic/vssqcmquestion.schema.ts new file mode 100644 index 0000000..64d403f --- /dev/null +++ b/backend/src/schemas/Basic/vssqcmquestion.schema.ts @@ -0,0 +1,9 @@ +import { integer, pgTable, serial, text } from 'drizzle-orm/pg-core'; + +export const vssqcmquestionSchema = pgTable('vssqcmquestion', { + id: serial('id').primaryKey(), + question: text('question').notNull(), + points: integer('points').notNull(), +}); + +export type VssQcmQuestion = typeof vssqcmquestionSchema.$inferSelect; diff --git a/backend/src/schemas/Relational/vssqcmanswer.schema.ts b/backend/src/schemas/Relational/vssqcmanswer.schema.ts new file mode 100644 index 0000000..008c14b --- /dev/null +++ b/backend/src/schemas/Relational/vssqcmanswer.schema.ts @@ -0,0 +1,13 @@ +import { boolean, integer, pgTable, serial, text } from 'drizzle-orm/pg-core'; +import { vssqcmquestionSchema } from '../Basic/vssqcmquestion.schema'; + +export const vssqcmanswerSchema = pgTable('vssqcmanswer', { + id: serial('id').primaryKey(), + questionid: integer('questionid') + .references(() => vssqcmquestionSchema.id, { onDelete: 'cascade' }) + .notNull(), + answer: text('answer').notNull(), + is_correct: boolean('is_correct').notNull(), +}); + +export type VssQcmAnswer = typeof vssqcmanswerSchema.$inferSelect; diff --git a/backend/src/schemas/Relational/vssqcmquestion.schema.ts b/backend/src/schemas/Relational/vssqcmquestion.schema.ts new file mode 100644 index 0000000..703c632 --- /dev/null +++ b/backend/src/schemas/Relational/vssqcmquestion.schema.ts @@ -0,0 +1,12 @@ +import { integer, pgEnum, pgTable, serial, text } from 'drizzle-orm/pg-core'; + +const questionTypeEnum = pgEnum('question_type', ['single_choice', 'multiple_choice']); + +export const vssqcmquestionSchema = pgTable('vssqcmquestion', { + id: serial('id').primaryKey(), + question: text('question').notNull(), + points: integer('points').notNull(), + type: questionTypeEnum('type').notNull(), +}); + +export type VssQcmQuestion = typeof vssqcmquestionSchema.$inferSelect; From c086704a3b2491527d0801fc762a86095582dab3 Mon Sep 17 00:00:00 2001 From: Antoine Date: Fri, 17 Jul 2026 16:31:25 +0200 Subject: [PATCH 12/27] fix: database works --- ...endly_meltdown.sql => 0025_black_quasimodo.sql} | 1 + .../database/migrations/meta/0025_snapshot.json | 14 ++++++++++++-- backend/src/database/migrations/meta/_journal.json | 4 ++-- backend/src/schemas/Basic/user.schema.ts | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) rename backend/src/database/migrations/{0025_friendly_meltdown.sql => 0025_black_quasimodo.sql} (86%) diff --git a/backend/src/database/migrations/0025_friendly_meltdown.sql b/backend/src/database/migrations/0025_black_quasimodo.sql similarity index 86% rename from backend/src/database/migrations/0025_friendly_meltdown.sql rename to backend/src/database/migrations/0025_black_quasimodo.sql index 454c6e2..b06f288 100644 --- a/backend/src/database/migrations/0025_friendly_meltdown.sql +++ b/backend/src/database/migrations/0025_black_quasimodo.sql @@ -1,3 +1,4 @@ +CREATE TYPE "public"."vss_form" AS ENUM('pending', 'validated', 'rejected');--> statement-breakpoint CREATE TABLE "vssqcmquestion" ( "id" serial PRIMARY KEY NOT NULL, "question" text NOT NULL, diff --git a/backend/src/database/migrations/meta/0025_snapshot.json b/backend/src/database/migrations/meta/0025_snapshot.json index 9ab71cd..0664849 100644 --- a/backend/src/database/migrations/meta/0025_snapshot.json +++ b/backend/src/database/migrations/meta/0025_snapshot.json @@ -1,5 +1,5 @@ { - "id": "222234ea-1f97-4c76-bf24-29c5da01972e", + "id": "4f5bad5b-1906-43f1-bcbc-6f5123811ee0", "prevId": "f2813605-996e-4461-8e87-8b135d3eefd3", "version": "7", "dialect": "postgresql", @@ -1412,7 +1412,17 @@ "isRLSEnabled": false } }, - "enums": {}, + "enums": { + "public.vss_form": { + "name": "vss_form", + "schema": "public", + "values": [ + "pending", + "validated", + "rejected" + ] + } + }, "schemas": {}, "sequences": {}, "roles": {}, diff --git a/backend/src/database/migrations/meta/_journal.json b/backend/src/database/migrations/meta/_journal.json index 88dbb0e..6981274 100644 --- a/backend/src/database/migrations/meta/_journal.json +++ b/backend/src/database/migrations/meta/_journal.json @@ -180,8 +180,8 @@ { "idx": 25, "version": "7", - "when": 1784283040878, - "tag": "0025_friendly_meltdown", + "when": 1784298273943, + "tag": "0025_black_quasimodo", "breakpoints": true } ] diff --git a/backend/src/schemas/Basic/user.schema.ts b/backend/src/schemas/Basic/user.schema.ts index a442968..df31a13 100644 --- a/backend/src/schemas/Basic/user.schema.ts +++ b/backend/src/schemas/Basic/user.schema.ts @@ -1,6 +1,6 @@ import { boolean, pgEnum, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'; -const vssFormEnum = pgEnum('vss_form', ['pending', 'validated', 'rejected']); +export const vssFormEnum = pgEnum('vss_form', ['pending', 'validated', 'rejected']); export const userSchema = pgTable('users', { id: serial('id').primaryKey(), From 4523e4f6fc302a3b607c7695889789bedde3c5cd Mon Sep 17 00:00:00 2001 From: Antoine Date: Fri, 17 Jul 2026 16:45:57 +0200 Subject: [PATCH 13/27] fix: made a lot of shit but seems good --- backend/src/database/initdb/initQcmvss.ts | 1 + ...black_quasimodo.sql => 0025_high_wind_dancer.sql} | 3 ++- .../src/database/migrations/meta/0025_snapshot.json | 10 +++++++++- backend/src/database/migrations/meta/_journal.json | 4 ++-- backend/src/schemas/Basic/vssqcmquestion.schema.ts | 5 ++++- .../src/schemas/Relational/vssqcmquestion.schema.ts | 12 ------------ 6 files changed, 18 insertions(+), 17 deletions(-) rename backend/src/database/migrations/{0025_black_quasimodo.sql => 0025_high_wind_dancer.sql} (87%) delete mode 100644 backend/src/schemas/Relational/vssqcmquestion.schema.ts diff --git a/backend/src/database/initdb/initQcmvss.ts b/backend/src/database/initdb/initQcmvss.ts index ca18f57..4f826bb 100644 --- a/backend/src/database/initdb/initQcmvss.ts +++ b/backend/src/database/initdb/initQcmvss.ts @@ -196,6 +196,7 @@ export const initQcmvss = async () => { .values({ question: seedQuestion.question, points: seedQuestion.points, + type: seedQuestion.type, }) .returning({ id: vssqcmquestionSchema.id }); diff --git a/backend/src/database/migrations/0025_black_quasimodo.sql b/backend/src/database/migrations/0025_high_wind_dancer.sql similarity index 87% rename from backend/src/database/migrations/0025_black_quasimodo.sql rename to backend/src/database/migrations/0025_high_wind_dancer.sql index b06f288..91cbbd8 100644 --- a/backend/src/database/migrations/0025_black_quasimodo.sql +++ b/backend/src/database/migrations/0025_high_wind_dancer.sql @@ -1,4 +1,5 @@ CREATE TYPE "public"."vss_form" AS ENUM('pending', 'validated', 'rejected');--> statement-breakpoint +CREATE TYPE "public"."question_type" AS ENUM('single_choice', 'multiple_choice');--> statement-breakpoint CREATE TABLE "vssqcmquestion" ( "id" serial PRIMARY KEY NOT NULL, "question" text NOT NULL, @@ -14,4 +15,4 @@ CREATE TABLE "vssqcmanswer" ( ); --> statement-breakpoint ALTER TABLE "users" ADD COLUMN "vss_form" "vss_form" DEFAULT 'pending';--> statement-breakpoint -ALTER TABLE "vssqcmanswer" ADD CONSTRAINT "vssqcmanswer_questionid_vssqcmquestion_id_fk" FOREIGN KEY ("questionid") REFERENCES "public"."vssqcmquestion"("id") ON DELETE cascade ON UPDATE no action; \ No newline at end of file +ALTER TABLE "vssqcmanswer" ADD CONSTRAINT "vssqcmanswer_questionid_vssqcmquestion_id_fk" FOREIGN KEY ("questionid") REFERENCES "public"."vssqcmquestion"("id") ON DELETE cascade ON UPDATE no action; diff --git a/backend/src/database/migrations/meta/0025_snapshot.json b/backend/src/database/migrations/meta/0025_snapshot.json index 0664849..3e69f00 100644 --- a/backend/src/database/migrations/meta/0025_snapshot.json +++ b/backend/src/database/migrations/meta/0025_snapshot.json @@ -1,5 +1,5 @@ { - "id": "4f5bad5b-1906-43f1-bcbc-6f5123811ee0", + "id": "c76925a0-a42e-42c9-8f72-0d914fe74da9", "prevId": "f2813605-996e-4461-8e87-8b135d3eefd3", "version": "7", "dialect": "postgresql", @@ -1421,6 +1421,14 @@ "validated", "rejected" ] + }, + "public.question_type": { + "name": "question_type", + "schema": "public", + "values": [ + "single_choice", + "multiple_choice" + ] } }, "schemas": {}, diff --git a/backend/src/database/migrations/meta/_journal.json b/backend/src/database/migrations/meta/_journal.json index 6981274..6700d9f 100644 --- a/backend/src/database/migrations/meta/_journal.json +++ b/backend/src/database/migrations/meta/_journal.json @@ -180,8 +180,8 @@ { "idx": 25, "version": "7", - "when": 1784298273943, - "tag": "0025_black_quasimodo", + "when": 1784298990793, + "tag": "0025_high_wind_dancer", "breakpoints": true } ] diff --git a/backend/src/schemas/Basic/vssqcmquestion.schema.ts b/backend/src/schemas/Basic/vssqcmquestion.schema.ts index 64d403f..cc9c3c1 100644 --- a/backend/src/schemas/Basic/vssqcmquestion.schema.ts +++ b/backend/src/schemas/Basic/vssqcmquestion.schema.ts @@ -1,9 +1,12 @@ -import { integer, pgTable, serial, text } from 'drizzle-orm/pg-core'; +import { integer, pgEnum, pgTable, serial, text } from 'drizzle-orm/pg-core'; + +export const questionTypeEnum = pgEnum('question_type', ['single_choice', 'multiple_choice']); export const vssqcmquestionSchema = pgTable('vssqcmquestion', { id: serial('id').primaryKey(), question: text('question').notNull(), points: integer('points').notNull(), + type: questionTypeEnum('type').notNull(), }); export type VssQcmQuestion = typeof vssqcmquestionSchema.$inferSelect; diff --git a/backend/src/schemas/Relational/vssqcmquestion.schema.ts b/backend/src/schemas/Relational/vssqcmquestion.schema.ts deleted file mode 100644 index 703c632..0000000 --- a/backend/src/schemas/Relational/vssqcmquestion.schema.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { integer, pgEnum, pgTable, serial, text } from 'drizzle-orm/pg-core'; - -const questionTypeEnum = pgEnum('question_type', ['single_choice', 'multiple_choice']); - -export const vssqcmquestionSchema = pgTable('vssqcmquestion', { - id: serial('id').primaryKey(), - question: text('question').notNull(), - points: integer('points').notNull(), - type: questionTypeEnum('type').notNull(), -}); - -export type VssQcmQuestion = typeof vssqcmquestionSchema.$inferSelect; From fa6cadfbeeb6901a8b0441608240d3dfa4629aa6 Mon Sep 17 00:00:00 2001 From: Antoine Date: Sat, 18 Jul 2026 13:47:05 +0200 Subject: [PATCH 14/27] feat: implement vss form --- backend/src/controllers/user.controller.ts | 56 +- .../database/migrations/0026_good_unus.sql | 1 + .../migrations/meta/0026_snapshot.json | 1445 +++++++++++++++++ .../database/migrations/meta/_journal.json | 7 + backend/src/routes/user.routes.ts | 4 +- backend/src/schemas/Basic/user.schema.ts | 2 +- backend/src/services/user.service.ts | 171 +- frontend/src/components/home/urgencyModal.tsx | 150 +- frontend/src/components/home/vssModal.tsx | 270 +++ frontend/src/components/navbar.tsx | 59 +- frontend/src/interfaces/user.interface.ts | 35 + .../src/services/requests/user.service.ts | 28 +- 12 files changed, 2159 insertions(+), 69 deletions(-) create mode 100644 backend/src/database/migrations/0026_good_unus.sql create mode 100644 backend/src/database/migrations/meta/0026_snapshot.json create mode 100644 frontend/src/components/home/vssModal.tsx diff --git a/backend/src/controllers/user.controller.ts b/backend/src/controllers/user.controller.ts index d78589e..eb8b5b1 100644 --- a/backend/src/controllers/user.controller.ts +++ b/backend/src/controllers/user.controller.ts @@ -46,13 +46,22 @@ export const getUsersByPermission = async (req: Request, res: Response) => { } }; -export const syncNewstudent = async (req: Request, res: Response) => { +export const syncNewstudent = async (req: Request, unknown, { date: string }>, res: Response) => { const { date } = req.body; + type SiepStudent = { + email: string; + prenom: string; + nom: string; + Majeur: boolean; + diplome: string; + specialite: string; + }; + try { const token = await SIEP_Utils.getTokenUTTAPI(); - const newStudents = await SIEP_Utils.getNewStudentsFromUTTAPI_NOPAGE(token, date); - const newStudentfiltered = newStudents.filter((student: any) => !noSyncEmails.includes(student.email)); //Nouveau à ne pas sync (Démissionnaires, etc) + const newStudents: SiepStudent[] = await SIEP_Utils.getNewStudentsFromUTTAPI_NOPAGE(token, date); + const newStudentfiltered = newStudents.filter((student: SiepStudent) => !noSyncEmails.includes(student.email)); //Nouveau à ne pas sync (Démissionnaires, etc) for (const element of newStudentfiltered) { const userInDb = await user_service.getUserByEmail(element.email.toLowerCase()); @@ -72,7 +81,7 @@ export const syncNewstudent = async (req: Request, res: Response) => { } } Ok(res, { msg: 'All NewStudent created and synced' }); - } catch (error) { + } catch (error: unknown) { Error(res, { error }); } }; @@ -99,26 +108,47 @@ export const getUserContactInformation = async (req: Request, res: Response) => } }; -export const getCurrentUserContactInformation = async (req: Request, res: Response) => { +export const createUserContactInformation = async (req: Request, res: Response) => { const userId = req.user?.userId; + const contact: UserContactInformation = req.body; try { - const userContactInfo = await user_service.getUserContactInformation(parseInt(userId)); - Ok(res, { data: userContactInfo }); + const result = await user_service.createUserContactInformation(parseInt(userId), contact); + Ok(res, { msg: 'Informations de contact créées', data: result }); } catch { - Error(res, { msg: "Erreur lors de la récupération des informations de contact de l'utilisateur." }); + Error(res, { msg: 'Erreur lors de la création des informations de contact.' }); } }; -export const createUserContactInformation = async (req: Request, res: Response) => { +export const getCurrentUserOnboardingStatus = async (req: Request, res: Response) => { const userId = req.user?.userId; - const contact: UserContactInformation = req.body; try { - const result = await user_service.createUserContactInformation(parseInt(userId), contact); - Ok(res, { msg: 'Informations de contact créées', data: result }); + const status = await user_service.getCurrentUserOnboardingStatus(parseInt(userId)); + Ok(res, { data: status }); } catch { - Error(res, { msg: 'Erreur lors de la création des informations de contact.' }); + Error(res, { msg: "Erreur lors de la récupération du statut d'onboarding." }); + } +}; + +export const getVssQuestionnaire = async (_req: Request, res: Response) => { + try { + const questionnaire = await user_service.getVssQuestionnaire(); + Ok(res, { data: questionnaire }); + } catch { + Error(res, { msg: 'Erreur lors de la récupération du questionnaire VSS.' }); + } +}; + +export const submitVssQuestionnaire = async (req: Request, res: Response) => { + const userId = req.user?.userId; + const payload = req.body; + + try { + const result = await user_service.submitVssQuestionnaire(parseInt(userId), payload); + Ok(res, { data: result }); + } catch { + Error(res, { msg: 'Erreur lors de la soumission du questionnaire VSS.' }); } }; diff --git a/backend/src/database/migrations/0026_good_unus.sql b/backend/src/database/migrations/0026_good_unus.sql new file mode 100644 index 0000000..cab44f7 --- /dev/null +++ b/backend/src/database/migrations/0026_good_unus.sql @@ -0,0 +1 @@ +ALTER TYPE "public"."vss_form" ADD VALUE 'toretry' BEFORE 'validated'; \ No newline at end of file diff --git a/backend/src/database/migrations/meta/0026_snapshot.json b/backend/src/database/migrations/meta/0026_snapshot.json new file mode 100644 index 0000000..82f221c --- /dev/null +++ b/backend/src/database/migrations/meta/0026_snapshot.json @@ -0,0 +1,1445 @@ +{ + "id": "8ceeb5a4-a02f-426a-9b8f-5a15ac8d26cd", + "prevId": "c76925a0-a42e-42c9-8f72-0d914fe74da9", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.challenges": { + "name": "challenges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "challenges_created_by_users_id_fk": { + "name": "challenges_created_by_users_id_fk", + "tableFrom": "challenges", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "pre_registration_open": { + "name": "pre_registration_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "shotgun_open": { + "name": "shotgun_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "sdi_open": { + "name": "sdi_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "wei_open": { + "name": "wei_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "food_open": { + "name": "food_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "chall_open": { + "name": "chall_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.factions": { + "name": "factions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "factions_name_unique": { + "name": "factions_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.news": { + "name": "news", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "published": { + "name": "published", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "target": { + "name": "target", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permanences": { + "name": "permanences", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "end_at": { + "name": "end_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "capacity": { + "name": "capacity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_open": { + "name": "is_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "difficulty": { + "name": "difficulty", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.roles": { + "name": "roles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "roles_name_unique": { + "name": "roles_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.teams": { + "name": "teams", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "teams_name_unique": { + "name": "teams_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "majeur": { + "name": "majeur", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contact": { + "name": "contact", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'Nouveau'" + }, + "discord_id": { + "name": "discord_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "vss_form": { + "name": "vss_form", + "type": "vss_form", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'pending'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.vssqcmquestion": { + "name": "vssqcmquestion", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "question": { + "name": "question", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "question_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bus_attribution": { + "name": "bus_attribution", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "bus": { + "name": "bus", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "departure_time": { + "name": "departure_time", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bus_attribution_user_id_users_id_fk": { + "name": "bus_attribution_user_id_users_id_fk", + "tableFrom": "bus_attribution", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.challenge_validation": { + "name": "challenge_validation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "challenge_id": { + "name": "challenge_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_by_admin_id": { + "name": "validated_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_at": { + "name": "validated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "target_user_id": { + "name": "target_user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_team_id": { + "name": "target_team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_faction_id": { + "name": "target_faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "added_by_admin_id": { + "name": "added_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "challenge_validation_challenge_id_challenges_id_fk": { + "name": "challenge_validation_challenge_id_challenges_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "challenges", + "columnsFrom": [ + "challenge_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_validated_by_admin_id_users_id_fk": { + "name": "challenge_validation_validated_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "validated_by_admin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_user_id_users_id_fk": { + "name": "challenge_validation_target_user_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "target_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_team_id_teams_id_fk": { + "name": "challenge_validation_target_team_id_teams_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "teams", + "columnsFrom": [ + "target_team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_faction_id_factions_id_fk": { + "name": "challenge_validation_target_faction_id_factions_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "factions", + "columnsFrom": [ + "target_faction_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_added_by_admin_id_users_id_fk": { + "name": "challenge_validation_added_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "added_by_admin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registration_tokens": { + "name": "registration_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_tokens_user_id_users_id_fk": { + "name": "registration_tokens_user_id_users_id_fk", + "tableFrom": "registration_tokens", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "registration_tokens_token_unique": { + "name": "registration_tokens_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.role_points": { + "name": "role_points", + "schema": "", + "columns": { + "role_points": { + "name": "role_points", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "role_points_role_points_roles_id_fk": { + "name": "role_points_role_points_roles_id_fk", + "tableFrom": "role_points", + "tableTo": "roles", + "columnsFrom": [ + "role_points" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "role_points_role_points_pk": { + "name": "role_points_role_points_pk", + "columns": [ + "role_points" + ] + } + }, + "uniqueConstraints": { + "role_points_role_points_unique": { + "name": "role_points_role_points_unique", + "nullsNotDistinct": false, + "columns": [ + "role_points" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_faction": { + "name": "team_faction", + "schema": "", + "columns": { + "faction_id": { + "name": "faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "team_faction_faction_id_factions_id_fk": { + "name": "team_faction_faction_id_factions_id_fk", + "tableFrom": "team_faction", + "tableTo": "factions", + "columnsFrom": [ + "faction_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "team_faction_team_id_teams_id_fk": { + "name": "team_faction_team_id_teams_id_fk", + "tableFrom": "team_faction", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "team_faction_faction_id_team_id_pk": { + "name": "team_faction_faction_id_team_id_pk", + "columns": [ + "faction_id", + "team_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_shotgun": { + "name": "team_shotgun", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "team_shotgun_team_id_teams_id_fk": { + "name": "team_shotgun_team_id_teams_id_fk", + "tableFrom": "team_shotgun", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_informations": { + "name": "user_informations", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "urgency_contact_name": { + "name": "urgency_contact_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "urgency_contact_phone": { + "name": "urgency_contact_phone", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_informations_user_id_users_id_fk": { + "name": "user_informations_user_id_users_id_fk", + "tableFrom": "user_informations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.respo_permanences": { + "name": "respo_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "respo_permanences_user_id_users_id_fk": { + "name": "respo_permanences_user_id_users_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "respo_permanences_permanence_id_permanences_id_fk": { + "name": "respo_permanences_permanence_id_permanences_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "permanences", + "columnsFrom": [ + "permanence_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "respo_permanences_user_id_permanence_id_pk": { + "name": "respo_permanences_user_id_permanence_id_pk", + "columns": [ + "user_id", + "permanence_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_permanences": { + "name": "user_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "registered_at": { + "name": "registered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "claimed": { + "name": "claimed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_permanences_user_id_users_id_fk": { + "name": "user_permanences_user_id_users_id_fk", + "tableFrom": "user_permanences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_permanences_permanence_id_permanences_id_fk": { + "name": "user_permanences_permanence_id_permanences_id_fk", + "tableFrom": "user_permanences", + "tableTo": "permanences", + "columnsFrom": [ + "permanence_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_permanences_user_id_permanence_id_pk": { + "name": "user_permanences_user_id_permanence_id_pk", + "columns": [ + "user_id", + "permanence_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_preferences": { + "name": "user_preferences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_preferences_user_id_users_id_fk": { + "name": "user_preferences_user_id_users_id_fk", + "tableFrom": "user_preferences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_preferences_role_id_roles_id_fk": { + "name": "user_preferences_role_id_roles_id_fk", + "tableFrom": "user_preferences", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_preferences_user_id_role_id_pk": { + "name": "user_preferences_user_id_role_id_pk", + "columns": [ + "user_id", + "role_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_roles": { + "name": "user_roles", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_roles_user_id_users_id_fk": { + "name": "user_roles_user_id_users_id_fk", + "tableFrom": "user_roles", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_roles_role_id_roles_id_fk": { + "name": "user_roles_role_id_roles_id_fk", + "tableFrom": "user_roles", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_teams": { + "name": "user_teams", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_teams_user_id_users_id_fk": { + "name": "user_teams_user_id_users_id_fk", + "tableFrom": "user_teams", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_teams_team_id_teams_id_fk": { + "name": "user_teams_team_id_teams_id_fk", + "tableFrom": "user_teams", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_teams_user_id_team_id_pk": { + "name": "user_teams_user_id_team_id_pk", + "columns": [ + "user_id", + "team_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_tent": { + "name": "user_tent", + "schema": "", + "columns": { + "user_id_1": { + "name": "user_id_1", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "user_id_2": { + "name": "user_id_2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "confirmed": { + "name": "confirmed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_tent_user_id_1_users_id_fk": { + "name": "user_tent_user_id_1_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": [ + "user_id_1" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_tent_user_id_2_users_id_fk": { + "name": "user_tent_user_id_2_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": [ + "user_id_2" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_tent_user_id_1_user_id_2_pk": { + "name": "user_tent_user_id_1_user_id_2_pk", + "columns": [ + "user_id_1", + "user_id_2" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.vssqcmanswer": { + "name": "vssqcmanswer", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "questionid": { + "name": "questionid", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "answer": { + "name": "answer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_correct": { + "name": "is_correct", + "type": "boolean", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "vssqcmanswer_questionid_vssqcmquestion_id_fk": { + "name": "vssqcmanswer_questionid_vssqcmquestion_id_fk", + "tableFrom": "vssqcmanswer", + "tableTo": "vssqcmquestion", + "columnsFrom": [ + "questionid" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.vss_form": { + "name": "vss_form", + "schema": "public", + "values": [ + "pending", + "toretry", + "validated", + "rejected" + ] + }, + "public.question_type": { + "name": "question_type", + "schema": "public", + "values": [ + "single_choice", + "multiple_choice" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/backend/src/database/migrations/meta/_journal.json b/backend/src/database/migrations/meta/_journal.json index 6700d9f..64717b9 100644 --- a/backend/src/database/migrations/meta/_journal.json +++ b/backend/src/database/migrations/meta/_journal.json @@ -183,6 +183,13 @@ "when": 1784298990793, "tag": "0025_high_wind_dancer", "breakpoints": true + }, + { + "idx": 26, + "version": "7", + "when": 1784372155559, + "tag": "0026_good_unus", + "breakpoints": true } ] } \ No newline at end of file diff --git a/backend/src/routes/user.routes.ts b/backend/src/routes/user.routes.ts index 56bade2..37579d1 100644 --- a/backend/src/routes/user.routes.ts +++ b/backend/src/routes/user.routes.ts @@ -21,6 +21,8 @@ userRouter.patch('/user/me', userController.updateProfile); userRouter.get('/user/me', userController.getCurrentUser); userRouter.get('/user/getusers', userController.getUsers); userRouter.post('/user/usercontactinformation', userController.createUserContactInformation); -userRouter.get('/user/getusercontactinformation', userController.getCurrentUserContactInformation); +userRouter.get('/onboarding-status', userController.getCurrentUserOnboardingStatus); +userRouter.get('/vss/questionnaire', userController.getVssQuestionnaire); +userRouter.post('/vss/questionnaire', userController.submitVssQuestionnaire); export default userRouter; diff --git a/backend/src/schemas/Basic/user.schema.ts b/backend/src/schemas/Basic/user.schema.ts index df31a13..c08ae93 100644 --- a/backend/src/schemas/Basic/user.schema.ts +++ b/backend/src/schemas/Basic/user.schema.ts @@ -1,6 +1,6 @@ import { boolean, pgEnum, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'; -export const vssFormEnum = pgEnum('vss_form', ['pending', 'validated', 'rejected']); +export const vssFormEnum = pgEnum('vss_form', ['pending', 'toretry', 'validated', 'rejected']); export const userSchema = pgTable('users', { id: serial('id').primaryKey(), diff --git a/backend/src/services/user.service.ts b/backend/src/services/user.service.ts index 3721dde..de4e28c 100644 --- a/backend/src/services/user.service.ts +++ b/backend/src/services/user.service.ts @@ -2,6 +2,8 @@ import bcrypt from 'bcryptjs'; import { eq } from 'drizzle-orm'; import { db } from '../database/db'; // Import de la connexion PostgreSQL import { type User, userSchema } from '../schemas/Basic/user.schema'; +import { vssqcmquestionSchema } from '../schemas/Basic/vssqcmquestion.schema'; +import { vssqcmanswerSchema } from '../schemas/Relational/vssqcmanswer.schema'; import { registrationSchema } from '../schemas/Relational/registration.schema'; import { getFaction } from './faction.service'; import { getUserRoles } from './role.service'; @@ -9,6 +11,28 @@ import { getTeam, getTeamFaction, getUserTeam } from './team.service'; import { userInformationSchema } from '../schemas/Relational/userinformation.schema'; import { type UserContactInformation } from '../../types/user'; +export type VssQuestionnaireAnswer = { + id: number; + answer: string; +}; + +export type VssQuestionnaireQuestion = { + id: number; + question: string; + points: number; + type: 'single_choice' | 'multiple_choice'; + answers: VssQuestionnaireAnswer[]; +}; + +export type VssSubmissionAnswer = { + questionId: number; + answerIds: number[]; +}; + +export type VssSubmissionPayload = { + answers: VssSubmissionAnswer[]; +}; + // Fonction pour récupérer un utilisateur par email export const getUserByEmail = async (email: string) => { try { @@ -33,6 +57,7 @@ export const getUserById = async (userId: number) => { contact: userSchema.contact, permission: userSchema.permission, discord_id: userSchema.discord_id, + vss_form: userSchema.vss_form, }) .from(userSchema) .where(eq(userSchema.id, userId)); @@ -163,7 +188,17 @@ export const createUserContactInformation = async (userId: number, contact: User urgency_contact_phone: contact.urgency_contact_phone, }; - const result = await db.insert(userInformationSchema).values(newContactInfo).returning(); + const result = await db + .insert(userInformationSchema) + .values(newContactInfo) + .onConflictDoUpdate({ + target: userInformationSchema.user_id, + set: { + urgency_contact_name: contact.urgency_contact_name, + urgency_contact_phone: contact.urgency_contact_phone, + }, + }) + .returning(); return result[0]; } catch (err) { console.error("Erreur lors de la création des informations de contact de l'utilisateur:", err); @@ -171,6 +206,140 @@ export const createUserContactInformation = async (userId: number, contact: User } }; +export const getCurrentUserOnboardingStatus = async (userId: number) => { + try { + const [contactInformation] = await db + .select({ + userId: userInformationSchema.user_id, + }) + .from(userInformationSchema) + .where(eq(userInformationSchema.user_id, userId)); + + const [user] = await db + .select({ + vss_form: userSchema.vss_form, + }) + .from(userSchema) + .where(eq(userSchema.id, userId)); + + const vssForm = user?.vss_form ?? 'pending'; + + return { + hasUrgencyContactInformation: Boolean(contactInformation), + vss_form: vssForm, + needsVssForm: vssForm === 'pending' || vssForm === 'toretry', + }; + } catch (err) { + console.error("Erreur lors de la récupération du statut d'onboarding:", err); + throw new Error('Erreur de base de données'); + } +}; + +export const getVssQuestionnaire = async () => { + try { + const questions = await db.select().from(vssqcmquestionSchema); + const answers = await db.select().from(vssqcmanswerSchema); + + return questions.map((question) => ({ + id: question.id, + question: question.question, + points: question.points, + type: question.type, + answers: answers + .filter((answer) => answer.questionid === question.id) + .map((answer) => ({ + id: answer.id, + answer: answer.answer, + })), + })); + } catch (err) { + console.error('Erreur lors de la récupération du questionnaire VSS:', err); + throw new Error('Erreur de base de données'); + } +}; + +export const submitVssQuestionnaire = async (userId: number, payload: VssSubmissionPayload) => { + try { + const [user] = await db + .select({ + vss_form: userSchema.vss_form, + }) + .from(userSchema) + .where(eq(userSchema.id, userId)); + + if (!user) { + throw new Error('Utilisateur introuvable'); + } + + if (user.vss_form === 'validated' || user.vss_form === 'rejected') { + return { + score: 0, + maxScore: 0, + status: user.vss_form, + }; + } + + const questions = await db.select().from(vssqcmquestionSchema); + const answers = await db.select().from(vssqcmanswerSchema); + + const answersByQuestion = new Map(); + for (const answer of answers) { + const currentAnswers = answersByQuestion.get(answer.questionid) ?? []; + currentAnswers.push(answer); + answersByQuestion.set(answer.questionid, currentAnswers); + } + + const responsesByQuestion = new Map>(); + for (const response of payload.answers ?? []) { + responsesByQuestion.set(response.questionId, new Set(response.answerIds)); + } + + for (const question of questions) { + const response = responsesByQuestion.get(question.id); + if (!response || response.size === 0) { + throw new Error('Toutes les questions doivent recevoir une réponse.'); + } + } + + let score = 0; + const maxScore = questions.reduce((total, question) => total + question.points, 0); + + for (const question of questions) { + const questionAnswers = answersByQuestion.get(question.id) ?? []; + const correctAnswerIds = questionAnswers.filter((answer) => answer.is_correct).map((answer) => answer.id); + const selectedAnswerIds = Array.from(responsesByQuestion.get(question.id) ?? []); + + const isCorrect = + selectedAnswerIds.length === correctAnswerIds.length && + selectedAnswerIds.every((answerId) => correctAnswerIds.includes(answerId)); + + if (isCorrect) { + score += question.points; + } + } + + let status: 'pending' | 'toretry' | 'validated' | 'rejected' = 'validated'; + if (score < Math.ceil(maxScore / 2)) { + status = user.vss_form === 'toretry' ? 'rejected' : 'toretry'; + } + + const [updatedUser] = await db + .update(userSchema) + .set({ vss_form: status }) + .where(eq(userSchema.id, userId)) + .returning({ vss_form: userSchema.vss_form }); + + return { + score, + maxScore, + status: updatedUser?.vss_form ?? status, + }; + } catch (err) { + console.error('Erreur lors de la soumission du questionnaire VSS:', err); + throw new Error('Erreur de base de données'); + } +}; + export const getUsersAll = async () => { try { const users = await db.select().from(userSchema); diff --git a/frontend/src/components/home/urgencyModal.tsx b/frontend/src/components/home/urgencyModal.tsx index a26651e..9b76b4d 100644 --- a/frontend/src/components/home/urgencyModal.tsx +++ b/frontend/src/components/home/urgencyModal.tsx @@ -1,40 +1,142 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; -import { createUserContactInformation } from '../../services/requests/user.service'; +import { createUserContactInformation, getCurrentUserOnboardingStatus } from '../../services/requests/user.service'; import { Button } from '../ui/button'; import { Input } from '../ui/input'; import Modal from '../ui/modal'; +import VssModal from './vssModal'; + +type FlowStep = 'idle' | 'loading' | 'urgency' | 'vss'; function UrgencyModal() { const [searchParams, setSearchParams] = useSearchParams(); const [form, setForm] = useState({ urgency_contact_name: '', urgency_contact_phone: '' }); + const [flowStep, setFlowStep] = useState('idle'); + const [error, setError] = useState(null); const isLogin = searchParams.get('login') === 'true'; + useEffect(() => { + if (!isLogin) { + setFlowStep('idle'); + setForm({ urgency_contact_name: '', urgency_contact_phone: '' }); + setError(null); + return; + } + + let cancelled = false; + + const loadOnboardingStatus = async () => { + setFlowStep('loading'); + setError(null); + + try { + const status = await getCurrentUserOnboardingStatus(); + + if (cancelled) { + return; + } + + if (!status.hasUrgencyContactInformation) { + setFlowStep('urgency'); + return; + } + + if (status.needsVssForm) { + setFlowStep('vss'); + return; + } + + setFlowStep('idle'); + setSearchParams({}); + } catch { + if (!cancelled) { + setFlowStep('urgency'); + setError('Impossible de récupérer le statut du formulaire.'); + } + } + }; + + loadOnboardingStatus(); + + return () => { + cancelled = true; + }; + }, [isLogin, setSearchParams]); + + const closeFlow = () => { + setSearchParams({}); + setFlowStep('idle'); + setForm({ urgency_contact_name: '', urgency_contact_phone: '' }); + setError(null); + }; + + const handleContactSubmit = async () => { + setError(null); + + try { + await createUserContactInformation(form); + window.dispatchEvent(new Event('user-onboarding-updated')); + setFlowStep('vss'); + } catch { + setError("Impossible d'enregistrer les informations d'urgence."); + } + }; + return ( - setSearchParams({})} buttons={null}> -
    -

    Bienvenu sur le site de l'intégration, blablabla faut que tu completes le formulaire.

    - setForm({ ...form, urgency_contact_name: e.target.value })} - /> - setForm({ ...form, urgency_contact_phone: e.target.value })} - /> - -
    -
    + <> + +
    +

    Chargement du statut du formulaire...

    +
    +
    + + +
    +

    Bienvenu sur le site de l'intégration, blablabla faut que tu completes le formulaire.

    + + {error && ( +

    + {error} +

    + )} + + setForm({ ...form, urgency_contact_name: e.target.value })} + /> + setForm({ ...form, urgency_contact_phone: e.target.value })} + /> +
    + + +
    +
    +
    + + { + window.dispatchEvent(new Event('user-onboarding-updated')); + }} + /> + ); } diff --git a/frontend/src/components/home/vssModal.tsx b/frontend/src/components/home/vssModal.tsx new file mode 100644 index 0000000..a12aebd --- /dev/null +++ b/frontend/src/components/home/vssModal.tsx @@ -0,0 +1,270 @@ +import { useEffect, useState } from 'react'; + +import { type VssQuestionnaireQuestion, type VssSubmissionResponse } from '../../interfaces/user.interface'; +import { getVssQuestionnaire, submitVssQuestionnaire } from '../../services/requests/user.service'; +import { Button } from '../ui/button'; +import Modal from '../ui/modal'; + +interface VssModalProps { + visible: boolean; + onCancel: () => void; + onSubmitted?: (result: VssSubmissionResponse) => void; +} + +const getAnswerClassName = (selected: boolean) => + `rounded-xl border px-4 py-3 text-left transition ${ + selected + ? 'border-blue-500 bg-blue-50 text-blue-900 shadow-sm dark:border-blue-400 dark:bg-blue-950/40 dark:text-blue-100' + : 'border-border/60 bg-white hover:border-blue-300 hover:bg-blue-50/60 dark:border-white/10 dark:bg-neutral-900 dark:hover:border-blue-500/60 dark:hover:bg-blue-950/20' + }`; + +const VssQuestionBlock = ({ + question, + selectedAnswerIds, + onSelect, +}: { + question: VssQuestionnaireQuestion; + selectedAnswerIds: number[]; + onSelect: (questionId: number, answerId: number, type: VssQuestionnaireQuestion['type']) => void; +}) => { + return ( +
    +
    +
    +

    Question {question.id}

    +

    + {question.question} +

    +
    + + {question.points} point{question.points > 1 ? 's' : ''} + +
    + +
    + {question.answers.map((answer) => { + const isSelected = selectedAnswerIds.includes(answer.id); + + return ( + + ); + })} +
    +

    + {question.type === 'single_choice' + ? 'Choisis une seule réponse.' + : 'Tu peux sélectionner plusieurs réponses.'} +

    +
    + ); +}; + +function VssModal({ visible, onCancel, onSubmitted }: VssModalProps) { + const [questions, setQuestions] = useState([]); + const [selectedAnswers, setSelectedAnswers] = useState>({}); + const [loading, setLoading] = useState(false); + const [submitting, setSubmitting] = useState(false); + const [error, setError] = useState(null); + const [result, setResult] = useState(null); + + useEffect(() => { + if (!visible) { + setQuestions([]); + setSelectedAnswers({}); + setError(null); + setResult(null); + setLoading(false); + setSubmitting(false); + return; + } + + let cancelled = false; + + const loadQuestionnaire = async () => { + setLoading(true); + setError(null); + setResult(null); + + try { + const questionnaire = await getVssQuestionnaire(); + + if (cancelled) { + return; + } + + setQuestions(questionnaire); + setSelectedAnswers({}); + } catch { + if (!cancelled) { + setError('Impossible de charger le questionnaire VSS.'); + } + } finally { + if (!cancelled) { + setLoading(false); + } + } + }; + + loadQuestionnaire(); + + return () => { + cancelled = true; + }; + }, [visible]); + + const handleSelectAnswer = (questionId: number, answerId: number, type: VssQuestionnaireQuestion['type']) => { + setSelectedAnswers((currentAnswers) => { + const existingAnswers = currentAnswers[questionId] ?? []; + + if (type === 'single_choice') { + return { + ...currentAnswers, + [questionId]: [answerId], + }; + } + + const hasAnswer = existingAnswers.includes(answerId); + return { + ...currentAnswers, + [questionId]: hasAnswer + ? existingAnswers.filter((currentAnswerId) => currentAnswerId !== answerId) + : [...existingAnswers, answerId], + }; + }); + }; + + const handleSubmit = async () => { + setError(null); + setSubmitting(true); + + try { + const unansweredQuestions = questions.filter((question) => { + const currentAnswers = selectedAnswers[question.id] ?? []; + return currentAnswers.length === 0; + }); + + if (unansweredQuestions.length > 0) { + setError('Réponds à toutes les questions avant d’envoyer le questionnaire.'); + return; + } + + const result = await submitVssQuestionnaire({ + answers: questions.map((question) => ({ + questionId: question.id, + answerIds: selectedAnswers[question.id] ?? [], + })), + }); + + setResult(result); + onSubmitted?.(result); + } catch { + setError('Impossible d’envoyer le questionnaire VSS.'); + } finally { + setSubmitting(false); + } + }; + + const answeredCount = questions.filter((question) => (selectedAnswers[question.id] ?? []).length > 0).length; + const totalQuestions = questions.length; + + const statusMessage = + result?.status === 'validated' + ? 'Questionnaire validé. Tu peux fermer cette fenêtre.' + : result?.status === 'toretry' + ? 'Le résultat nécessite une seconde tentative. Tu pourras retenter plus tard.' + : result?.status === 'rejected' + ? 'Le nombre de tentatives autorisées est atteint.' + : null; + + return ( + +
    +

    + {loading + ? 'Chargement du questionnaire...' + : 'Réponds au questionnaire VSS avant de fermer cette fenêtre.'} +

    + + {error && ( +
    + {error} +
    + )} + + {result && ( +
    +

    {statusMessage}

    + {result.maxScore > 0 && ( +

    + Score obtenu : {result.score}/{result.maxScore} +

    + )} +
    + )} + + {!loading && questions.length > 0 && ( +
    +
    + + {answeredCount}/{totalQuestions} questions répondues + + + {questions.reduce((total, question) => total + question.points, 0)} points possibles + +
    + + {questions.map((question) => ( + + ))} +
    + )} + + {!loading && questions.length === 0 && !error && ( +
    + Aucun questionnaire disponible pour le moment. +
    + )} + +
    + {result ? ( + + ) : ( + <> + + + + )} +
    +
    +
    + ); +} + +export default VssModal; diff --git a/frontend/src/components/navbar.tsx b/frontend/src/components/navbar.tsx index a2e67c6..44323bb 100644 --- a/frontend/src/components/navbar.tsx +++ b/frontend/src/components/navbar.tsx @@ -5,7 +5,7 @@ import { Fragment, useEffect, useState } from 'react'; import { NavLink, useLocation, useSearchParams } from 'react-router-dom'; import { decodeToken, getToken } from '../services/requests/auth.service'; -import { getCurrentUserContactInformation } from '../services/requests/user.service'; +import { getCurrentUserOnboardingStatus } from '../services/requests/user.service'; import { Button } from './ui/button'; interface NavItem { @@ -30,6 +30,7 @@ export const Navbar = () => { : { userPermission: undefined, userRoles: [] }; const roles = [userPermission, ...userRoles.map((r) => r.roleName)].filter(Boolean) as string[]; const [hasContactInformation, setHasContactInformation] = useState(false); + const [needsVssForm, setNeedsVssForm] = useState(false); const [, setSearchParams] = useSearchParams(); const handleLogout = () => { @@ -39,20 +40,33 @@ export const Navbar = () => { useEffect(() => { setMenuOpen(false); - const fetchContactInformation = async () => { + + const fetchOnboardingStatus = async () => { try { - const contactInfo = await getCurrentUserContactInformation(); - setHasContactInformation(contactInfo.urgency_contact_phone !== null); - console.log('Contact Information:', contactInfo); + const onboardingStatus = await getCurrentUserOnboardingStatus(); + setHasContactInformation(onboardingStatus.hasUrgencyContactInformation); + setNeedsVssForm(onboardingStatus.needsVssForm); } catch (error) { - console.error('Erreur lors de la récupération des informations de contact :', error); + console.error("Erreur lors de la récupération du statut d'onboarding :", error); } }; if (isAuthenticated) { - fetchContactInformation(); + fetchOnboardingStatus(); } - }, [pathname]); + + const handleOnboardingUpdate = () => { + if (isAuthenticated) { + fetchOnboardingStatus(); + } + }; + + window.addEventListener('user-onboarding-updated', handleOnboardingUpdate); + + return () => { + window.removeEventListener('user-onboarding-updated', handleOnboardingUpdate); + }; + }, [isAuthenticated, pathname]); const navItems: NavItem[] = [ { label: 'Home', to: '/home', icon: HomeIcon }, @@ -205,21 +219,20 @@ export const Navbar = () => { - { - /* Contact Information Warning */ hasContactInformation === false && isAuthenticated && ( -
    -

    - ATTENTION : Tu n'as pas complété le formulaire VSS ainsi que tes informations d'urgence. - Merci de le faire au plus vite ! -

    - -
    - ) - } + {isAuthenticated && (hasContactInformation === false || needsVssForm) && ( +
    +

    + {hasContactInformation === false + ? "ATTENTION : Tu n'as pas complété le formulaire VSS ainsi que tes informations d'urgence. Merci de le faire au plus vite !" + : "ATTENTION : Tu n'as pas encore complété le questionnaire VSS. Merci de le faire au plus vite !"} +

    + +
    + )}
    ); }; diff --git a/frontend/src/interfaces/user.interface.ts b/frontend/src/interfaces/user.interface.ts index ff25b12..f0ff7fc 100644 --- a/frontend/src/interfaces/user.interface.ts +++ b/frontend/src/interfaces/user.interface.ts @@ -8,6 +8,7 @@ export interface User { branch: string; contact: string; discord_id: string; + vss_form?: 'pending' | 'toretry' | 'validated' | 'rejected'; } export interface UserContactInformation { @@ -20,3 +21,37 @@ export interface CreateUserContactInformationRequest { urgency_contact_name: string; urgency_contact_phone: string; } + +export interface UserOnboardingStatus { + hasUrgencyContactInformation: boolean; + vss_form: 'pending' | 'toretry' | 'validated' | 'rejected'; + needsVssForm: boolean; +} + +export interface VssQuestionnaireAnswer { + id: number; + answer: string; +} + +export interface VssQuestionnaireQuestion { + id: number; + question: string; + points: number; + type: 'single_choice' | 'multiple_choice'; + answers: VssQuestionnaireAnswer[]; +} + +export interface VssSubmissionAnswer { + questionId: number; + answerIds: number[]; +} + +export interface VssSubmissionRequest { + answers: VssSubmissionAnswer[]; +} + +export interface VssSubmissionResponse { + score: number; + maxScore: number; + status: 'pending' | 'toretry' | 'validated' | 'rejected'; +} diff --git a/frontend/src/services/requests/user.service.ts b/frontend/src/services/requests/user.service.ts index 23d9428..09d9fd4 100644 --- a/frontend/src/services/requests/user.service.ts +++ b/frontend/src/services/requests/user.service.ts @@ -2,6 +2,10 @@ import { type CreateUserContactInformationRequest, type User, type UserContactInformation, + type UserOnboardingStatus, + type VssQuestionnaireQuestion, + type VssSubmissionRequest, + type VssSubmissionResponse, } from '../../interfaces/user.interface'; import api from '../api'; @@ -56,17 +60,29 @@ export const createUserContactInformation = async (data: CreateUserContactInform return response.data; }; +export const getCurrentUserOnboardingStatus = async () => { + const response = await api.get('/user/onboarding-status'); + const status: UserOnboardingStatus = response.data.data; + return status; +}; + +export const getVssQuestionnaire = async () => { + const response = await api.get('/user/vss/questionnaire'); + const questionnaire: VssQuestionnaireQuestion[] = response.data.data; + return questionnaire; +}; + +export const submitVssQuestionnaire = async (data: VssSubmissionRequest) => { + const response = await api.post('/user/vss/questionnaire', data); + const result: VssSubmissionResponse = response.data.data; + return result; +}; + export const getCurrentUser = async () => { const res = await api.get('/user/user/me'); return res.data.data; }; -export const getCurrentUserContactInformation = async () => { - const response = await api.get(`/user/user/getusercontactinformation`); - const users: UserContactInformation = response.data.data; - return users; -}; - export const updateCurrentUser = async (data: Partial) => { const response = await api.patch('/user/user/me', data); return response.data; From 8358ceb1d6e9fea5cc128dffc11131f8eceb90d3 Mon Sep 17 00:00:00 2001 From: Antoine Date: Sat, 18 Jul 2026 15:35:22 +0200 Subject: [PATCH 15/27] feat: can't access to billetweb iframe if form not submissed or vss danger --- .../components/WEI_SDI_Food/sdiSection.tsx | 59 ++++++++++++++++--- .../components/WEI_SDI_Food/weiSection.tsx | 59 ++++++++++++++++--- 2 files changed, 100 insertions(+), 18 deletions(-) diff --git a/frontend/src/components/WEI_SDI_Food/sdiSection.tsx b/frontend/src/components/WEI_SDI_Food/sdiSection.tsx index b03b479..181ec88 100644 --- a/frontend/src/components/WEI_SDI_Food/sdiSection.tsx +++ b/frontend/src/components/WEI_SDI_Food/sdiSection.tsx @@ -1,26 +1,42 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState } from 'react'; -import { checkSDIStatus } from "../../services/requests/event.service"; -import { Card, CardContent, CardHeader, CardTitle } from "../ui/card"; +import { checkSDIStatus } from '../../services/requests/event.service'; +import { getCurrentUserOnboardingStatus } from '../../services/requests/user.service'; +import { Card, CardContent, CardHeader, CardTitle } from '../ui/card'; export const SdiSection = () => { const [isSDIOpen, setIsSDIOpen] = useState(false); + const [hasContactInformation, setHasContactInformation] = useState(false); + const [hasVssForm, setHasVssForm] = useState(false); + const [needVssForm, setNeedsVssForm] = useState(false); useEffect(() => { - const script = document.createElement("script"); - script.src = "https://www.billetweb.fr/js/export.js"; + const script = document.createElement('script'); + script.src = 'https://www.billetweb.fr/js/export.js'; script.async = true; document.body.appendChild(script); fetchStatus(); + fetchOnboardingStatus(); }, []); + const fetchOnboardingStatus = async () => { + try { + const onboardingStatus = await getCurrentUserOnboardingStatus(); + setHasContactInformation(onboardingStatus.hasUrgencyContactInformation); + setHasVssForm(onboardingStatus.vss_form == 'validated'); + setNeedsVssForm(onboardingStatus.needsVssForm); + } catch (error) { + console.error("Erreur lors de la récupération du statut d'onboarding :", error); + } + }; + const fetchStatus = async () => { try { const status = await checkSDIStatus(); setIsSDIOpen(status); } catch { - alert("Erreur lors de la récupération du statut de SDI."); + alert('Erreur lors de la récupération du statut de SDI.'); } }; @@ -31,7 +47,8 @@ export const SdiSection = () => { 🎉 Participe à la Soirée d'Intégration (SDI) !

    - Un événement incroyable t'attend… Inscris-toi dès maintenant pour ne rien rater de cette Soirée d'Intégration ! + Un événement incroyable t'attend… Inscris-toi dès maintenant pour ne rien rater de cette Soirée + d'Intégration !

    @@ -40,8 +57,32 @@ export const SdiSection = () => {

    🚫 La billetterie de la Soirée d'intégration (SDI) n'est pas encore disponible.

    +

    Reste connecté, elle ouvrira bientôt !

    + + ) : !hasContactInformation ? ( +
    +

    + 🚫 Tu n'as pas rempli le questionnaire avec tes contacts d'urgence. Tant que ce n'est pas + fait, tu ne peux pas accéder à la billetterie de la Soirée d'intégration (SDI). +

    +

    Va vite le compléter !

    +
    + ) : needVssForm ? ( +
    +

    + 🚫 Tu n'as pas rempli le questionnaire de sensibilisation aux VSS. Tant que ce n'est pas + fait, tu ne peux pas accéder à la billetterie de la Soirée d'intégration (SDI). +

    +

    Va vite le compléter !

    +
    + ) : !hasVssForm ? ( +
    +

    + 🚫 Tu as fait trop d'erreur sur le questionnaire de sensibilisation aux VSS. Tu ne peux par + conséquent pas accéder à la billeterie de la Soirée d'intégration (SDI). +

    - Reste connecté, elle ouvrira bientôt ! + Si tu penses qu'il s'agit d'une erreur, tu peux te rapprocher de la team prévention.

    ) : ( @@ -54,6 +95,6 @@ export const SdiSection = () => { )}
    - + ); }; diff --git a/frontend/src/components/WEI_SDI_Food/weiSection.tsx b/frontend/src/components/WEI_SDI_Food/weiSection.tsx index b304371..2e5eb51 100644 --- a/frontend/src/components/WEI_SDI_Food/weiSection.tsx +++ b/frontend/src/components/WEI_SDI_Food/weiSection.tsx @@ -1,26 +1,42 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState } from 'react'; -import { checkWEIStatus } from "../../services/requests/event.service"; -import { Card, CardContent, CardHeader, CardTitle } from "../ui/card"; +import { checkWEIStatus } from '../../services/requests/event.service'; +import { getCurrentUserOnboardingStatus } from '../../services/requests/user.service'; +import { Card, CardContent, CardHeader, CardTitle } from '../ui/card'; export const WeiSection = () => { const [isWEIOpen, setIsWEIOpen] = useState(false); + const [hasContactInformation, setHasContactInformation] = useState(false); + const [hasVssForm, setHasVssForm] = useState(false); + const [needVssForm, setNeedsVssForm] = useState(false); useEffect(() => { - const script = document.createElement("script"); - script.src = "https://www.billetweb.fr/js/export.js"; + const script = document.createElement('script'); + script.src = 'https://www.billetweb.fr/js/export.js'; script.async = true; document.body.appendChild(script); fetchStatus(); + fetchOnboardingStatus(); }, []); + const fetchOnboardingStatus = async () => { + try { + const onboardingStatus = await getCurrentUserOnboardingStatus(); + setHasContactInformation(onboardingStatus.hasUrgencyContactInformation); + setHasVssForm(onboardingStatus.vss_form == 'validated'); + setNeedsVssForm(onboardingStatus.needsVssForm); + } catch (error) { + console.error("Erreur lors de la récupération du statut d'onboarding :", error); + } + }; + const fetchStatus = async () => { try { const status = await checkWEIStatus(); setIsWEIOpen(status); } catch { - alert("Erreur lors de la récupération du statut de WEI."); + alert('Erreur lors de la récupération du statut de WEI.'); } }; @@ -31,7 +47,8 @@ export const WeiSection = () => { 🎉 Tu es nouveau ? Participe au WEI !

    - Un événement incroyable t'attend… Inscris-toi dès maintenant pour ne rien rater du Week-End d'Intégration 2025 ! + Un événement incroyable t'attend… Inscris-toi dès maintenant pour ne rien rater du Week-End + d'Intégration 2025 !

    @@ -40,8 +57,32 @@ export const WeiSection = () => {

    🚫 La billetterie du WEI n'est pas encore disponible.

    +

    Reste connecté, elle ouvrira bientôt !

    + + ) : !hasContactInformation ? ( +
    +

    + 🚫 Tu n'as pas rempli le questionnaire avec tes contacts d'urgence. Tant que ce n'est pas + fait, tu ne peux pas accéder à la billetterie du Week-End d'Intégration (WEI). +

    +

    Va vite le compléter !

    +
    + ) : needVssForm ? ( +
    +

    + 🚫 Tu n'as pas rempli le questionnaire de sensibilisation aux VSS. Tant que ce n'est pas + fait, tu ne peux pas accéder à la billetterie du Week-End d'Intégration (WEI). +

    +

    Va vite le compléter !

    +
    + ) : !hasVssForm ? ( +
    +

    + 🚫 Tu as fait trop d'erreur sur le questionnaire de sensibilisation aux VSS. Tu ne peux par + conséquent pas accéder à la billeterie du Week-End d'Intégration (WEI). +

    - Reste connecté, elle ouvrira bientôt ! + Si tu penses qu'il s'agit d'une erreur, tu peux te rapprocher de la team prévention.

    ) : ( @@ -54,6 +95,6 @@ export const WeiSection = () => { )}
    - + ); }; From 8e9c9f2810d5d5e6cf3ef4ebb790f301160627bd Mon Sep 17 00:00:00 2001 From: Antoine Date: Sat, 18 Jul 2026 19:41:05 +0200 Subject: [PATCH 16/27] refactor: introduction text in urgency and vss modal --- frontend/src/components/home/urgencyModal.tsx | 18 ++++++++-- frontend/src/components/home/vssModal.tsx | 34 +++++++++++-------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/frontend/src/components/home/urgencyModal.tsx b/frontend/src/components/home/urgencyModal.tsx index 9b76b4d..39842b4 100644 --- a/frontend/src/components/home/urgencyModal.tsx +++ b/frontend/src/components/home/urgencyModal.tsx @@ -102,14 +102,26 @@ function UrgencyModal() { onCancel={closeFlow} buttons={null}>
    -

    Bienvenu sur le site de l'intégration, blablabla faut que tu completes le formulaire.

    - +

    Bienvenue sur le site de l'intégration !

    +

    Nous sommes ravis de t'accueillir parmi nous à l'UTT.

    +

    + Durant ta première semaine à l'UTT, tu pourras participer aux activités d'intégration. Afin que + celle-ci se déroule dans les meilleures conditions, nous avons besoin que tu répondes à deux + formulaires. +

    +

    + Dans ce premier formulaire, nous te demandons simplement de renseigner un contact d'urgence, au + cas où le moindre problème surviendrait durant cette semaine. +

    +

    + Tu peux quitter ce formulaire à tout moment et le compléter plus tard. Cependant, il est + obligatoire pour participer à certaines activités. +

    {error && (

    {error}

    )} - ([]); const [selectedAnswers, setSelectedAnswers] = useState>({}); - const [loading, setLoading] = useState(false); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); const [result, setResult] = useState(null); @@ -79,7 +78,6 @@ function VssModal({ visible, onCancel, onSubmitted }: VssModalProps) { setSelectedAnswers({}); setError(null); setResult(null); - setLoading(false); setSubmitting(false); return; } @@ -87,7 +85,6 @@ function VssModal({ visible, onCancel, onSubmitted }: VssModalProps) { let cancelled = false; const loadQuestionnaire = async () => { - setLoading(true); setError(null); setResult(null); @@ -104,10 +101,6 @@ function VssModal({ visible, onCancel, onSubmitted }: VssModalProps) { if (!cancelled) { setError('Impossible de charger le questionnaire VSS.'); } - } finally { - if (!cancelled) { - setLoading(false); - } } }; @@ -190,10 +183,23 @@ function VssModal({ visible, onCancel, onSubmitted }: VssModalProps) { buttons={null} containerClassName="max-w-4xl">
    -

    - {loading - ? 'Chargement du questionnaire...' - : 'Réponds au questionnaire VSS avant de fermer cette fenêtre.'} +

    + Dans ce questionnaire, tu devras répondre aux questions ci-dessous à propos des Violences Sexistes + et Sexuelles (VSS). +

    +

    + La note est sur 14 et tu disposes de deux essais pour obtenir au moins 7 points. Cette + sensibilisation est très importante pour nous afin de nous assurer que l'intégration se déroule dans + les meilleures conditions pour tout le monde. +

    +

    + Si tu n'arrives pas à obtenir la moyenne après deux tentatives, nous serons malheureusement + contraints de te refuser l'accès à la Soirée et au Week-end d'intégration, car ce sont les moments + où la majorité des situations de VSS se produisent. +

    +

    + Tu peux quitter ce questionnaire à tout moment et le compléter plus tard. Cependant, il est + obligatoire pour participer à certaines activités.

    {error && ( @@ -220,7 +226,7 @@ function VssModal({ visible, onCancel, onSubmitted }: VssModalProps) {
    )} - {!loading && questions.length > 0 && ( + {questions.length > 0 && (
    @@ -242,7 +248,7 @@ function VssModal({ visible, onCancel, onSubmitted }: VssModalProps) {
    )} - {!loading && questions.length === 0 && !error && ( + {questions.length === 0 && !error && (
    Aucun questionnaire disponible pour le moment.
    @@ -256,7 +262,7 @@ function VssModal({ visible, onCancel, onSubmitted }: VssModalProps) { - From 3518f398ea1d871befd3f718d3a9374005488447 Mon Sep 17 00:00:00 2001 From: Antoine Date: Sat, 18 Jul 2026 19:48:02 +0200 Subject: [PATCH 17/27] feat: add to billetweb if VSS accepted --- backend/src/services/user.service.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/backend/src/services/user.service.ts b/backend/src/services/user.service.ts index de4e28c..0953857 100644 --- a/backend/src/services/user.service.ts +++ b/backend/src/services/user.service.ts @@ -10,6 +10,7 @@ import { getUserRoles } from './role.service'; import { getTeam, getTeamFaction, getUserTeam } from './team.service'; import { userInformationSchema } from '../schemas/Relational/userinformation.schema'; import { type UserContactInformation } from '../../types/user'; +import { addUserToRespondentStudentsList } from '../utils/billetweb'; export type VssQuestionnaireAnswer = { id: number; @@ -327,8 +328,18 @@ export const submitVssQuestionnaire = async (userId: number, payload: VssSubmiss .update(userSchema) .set({ vss_form: status }) .where(eq(userSchema.id, userId)) - .returning({ vss_form: userSchema.vss_form }); + .returning({ + vss_form: userSchema.vss_form, + email: userSchema.email, + firstName: userSchema.first_name, + lastName: userSchema.last_name, + }); + if (status == 'validated') { + addUserToRespondentStudentsList({ + ...updatedUser, + }); + } return { score, maxScore, From 282c6b43021a47ca472ddfdc1764ac2f87bfbb8d Mon Sep 17 00:00:00 2001 From: Antoine Date: Sat, 18 Jul 2026 19:59:08 +0200 Subject: [PATCH 18/27] feat: only student can now see form and be impacted --- frontend/src/components/WEI_SDI_Food/sdiSection.tsx | 12 +++++++++--- frontend/src/components/navbar.tsx | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/WEI_SDI_Food/sdiSection.tsx b/frontend/src/components/WEI_SDI_Food/sdiSection.tsx index 181ec88..bb9cc3b 100644 --- a/frontend/src/components/WEI_SDI_Food/sdiSection.tsx +++ b/frontend/src/components/WEI_SDI_Food/sdiSection.tsx @@ -1,5 +1,6 @@ import { useEffect, useState } from 'react'; +import { decodeToken, getToken } from '../../services/requests/auth.service'; import { checkSDIStatus } from '../../services/requests/event.service'; import { getCurrentUserOnboardingStatus } from '../../services/requests/user.service'; import { Card, CardContent, CardHeader, CardTitle } from '../ui/card'; @@ -9,6 +10,11 @@ export const SdiSection = () => { const [hasContactInformation, setHasContactInformation] = useState(false); const [hasVssForm, setHasVssForm] = useState(false); const [needVssForm, setNeedsVssForm] = useState(false); + const token = getToken(); + const { userPermission, userRoles = [] } = token + ? decodeToken(token) + : { userPermission: undefined, userRoles: [] }; + const roles = [userPermission, ...userRoles.map((r) => r.roleName)].filter(Boolean) as string[]; useEffect(() => { const script = document.createElement('script'); @@ -59,7 +65,7 @@ export const SdiSection = () => {

    Reste connecté, elle ouvrira bientôt !

    - ) : !hasContactInformation ? ( + ) : !hasContactInformation && roles.includes('Student') ? (

    🚫 Tu n'as pas rempli le questionnaire avec tes contacts d'urgence. Tant que ce n'est pas @@ -67,7 +73,7 @@ export const SdiSection = () => {

    Va vite le compléter !

    - ) : needVssForm ? ( + ) : needVssForm && roles.includes('Student') ? (

    🚫 Tu n'as pas rempli le questionnaire de sensibilisation aux VSS. Tant que ce n'est pas @@ -75,7 +81,7 @@ export const SdiSection = () => {

    Va vite le compléter !

    - ) : !hasVssForm ? ( + ) : !hasVssForm && roles.includes('Student') ? (

    🚫 Tu as fait trop d'erreur sur le questionnaire de sensibilisation aux VSS. Tu ne peux par diff --git a/frontend/src/components/navbar.tsx b/frontend/src/components/navbar.tsx index 44323bb..b7e90d3 100644 --- a/frontend/src/components/navbar.tsx +++ b/frontend/src/components/navbar.tsx @@ -219,7 +219,7 @@ export const Navbar = () => { - {isAuthenticated && (hasContactInformation === false || needsVssForm) && ( + {isAuthenticated && (hasContactInformation === false || needsVssForm) && roles.includes('Student') && (

    {hasContactInformation === false From bee4ea73c09a5fe21bafa82cdb170952477732ca Mon Sep 17 00:00:00 2001 From: Antoine Date: Sat, 18 Jul 2026 20:16:45 +0200 Subject: [PATCH 19/27] fix: resolve conflict in database (hope don't break everything) --- .../migrations/0023_zippy_colonel_america.sql | 5 + ...{0023_even_morg.sql => 0024_even_morg.sql} | 0 ....sql => 0025_natural_human_cannonball.sql} | 0 ...d_dancer.sql => 0026_high_wind_dancer.sql} | 0 ...{0026_good_unus.sql => 0027_good_unus.sql} | 0 .../migrations/meta/0023_snapshot.json | 2510 ++++++++-------- .../migrations/meta/0024_snapshot.json | 2520 ++++++++--------- .../migrations/meta/0025_snapshot.json | 121 +- .../migrations/meta/0026_snapshot.json | 5 +- .../migrations/meta/0027_snapshot.json | 1445 ++++++++++ .../database/migrations/meta/_journal.json | 395 +-- 11 files changed, 4030 insertions(+), 2971 deletions(-) create mode 100644 backend/src/database/migrations/0023_zippy_colonel_america.sql rename backend/src/database/migrations/{0023_even_morg.sql => 0024_even_morg.sql} (100%) rename backend/src/database/migrations/{0024_natural_human_cannonball.sql => 0025_natural_human_cannonball.sql} (100%) rename backend/src/database/migrations/{0025_high_wind_dancer.sql => 0026_high_wind_dancer.sql} (100%) rename backend/src/database/migrations/{0026_good_unus.sql => 0027_good_unus.sql} (100%) create mode 100644 backend/src/database/migrations/meta/0027_snapshot.json diff --git a/backend/src/database/migrations/0023_zippy_colonel_america.sql b/backend/src/database/migrations/0023_zippy_colonel_america.sql new file mode 100644 index 0000000..f4254d5 --- /dev/null +++ b/backend/src/database/migrations/0023_zippy_colonel_america.sql @@ -0,0 +1,5 @@ +CREATE TABLE "banned_addresses" ( + "id" serial PRIMARY KEY NOT NULL, + "email" text, + CONSTRAINT "banned_addresses_email_unique" UNIQUE("email") +); diff --git a/backend/src/database/migrations/0023_even_morg.sql b/backend/src/database/migrations/0024_even_morg.sql similarity index 100% rename from backend/src/database/migrations/0023_even_morg.sql rename to backend/src/database/migrations/0024_even_morg.sql diff --git a/backend/src/database/migrations/0024_natural_human_cannonball.sql b/backend/src/database/migrations/0025_natural_human_cannonball.sql similarity index 100% rename from backend/src/database/migrations/0024_natural_human_cannonball.sql rename to backend/src/database/migrations/0025_natural_human_cannonball.sql diff --git a/backend/src/database/migrations/0025_high_wind_dancer.sql b/backend/src/database/migrations/0026_high_wind_dancer.sql similarity index 100% rename from backend/src/database/migrations/0025_high_wind_dancer.sql rename to backend/src/database/migrations/0026_high_wind_dancer.sql diff --git a/backend/src/database/migrations/0026_good_unus.sql b/backend/src/database/migrations/0027_good_unus.sql similarity index 100% rename from backend/src/database/migrations/0026_good_unus.sql rename to backend/src/database/migrations/0027_good_unus.sql diff --git a/backend/src/database/migrations/meta/0023_snapshot.json b/backend/src/database/migrations/meta/0023_snapshot.json index 1cbadb9..3d53326 100644 --- a/backend/src/database/migrations/meta/0023_snapshot.json +++ b/backend/src/database/migrations/meta/0023_snapshot.json @@ -1,1335 +1,1183 @@ { - "id": "77c4b2f6-c24d-4eb9-80a9-42fb8b9ef380", - "prevId": "93925edf-9622-4ce2-80bc-26050abbce0b", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.challenges": { - "name": "challenges", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "category": { - "name": "category", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "points": { - "name": "points", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "created_by": { - "name": "created_by", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "challenges_created_by_users_id_fk": { - "name": "challenges_created_by_users_id_fk", - "tableFrom": "challenges", - "tableTo": "users", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.events": { - "name": "events", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "pre_registration_open": { - "name": "pre_registration_open", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "shotgun_open": { - "name": "shotgun_open", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "sdi_open": { - "name": "sdi_open", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "wei_open": { - "name": "wei_open", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "food_open": { - "name": "food_open", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "chall_open": { - "name": "chall_open", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.factions": { - "name": "factions", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "factions_name_unique": { - "name": "factions_name_unique", - "nullsNotDistinct": false, - "columns": [ - "name" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.news": { - "name": "news", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "published": { - "name": "published", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "target": { - "name": "target", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "image_url": { - "name": "image_url", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.permanences": { - "name": "permanences", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "location": { - "name": "location", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "start_at": { - "name": "start_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "end_at": { - "name": "end_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "capacity": { - "name": "capacity", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "is_open": { - "name": "is_open", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "difficulty": { - "name": "difficulty", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.roles": { - "name": "roles", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "roles_name_unique": { - "name": "roles_name_unique", - "nullsNotDistinct": false, - "columns": [ - "name" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.teams": { - "name": "teams", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "teams_name_unique": { - "name": "teams_name_unique", - "nullsNotDistinct": false, - "columns": [ - "name" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.users": { - "name": "users", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "first_name": { - "name": "first_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "last_name": { - "name": "last_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "majeur": { - "name": "majeur", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "branch": { - "name": "branch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "contact": { - "name": "contact", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "permission": { - "name": "permission", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'Nouveau'" - }, - "discord_id": { - "name": "discord_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "users_email_unique": { - "name": "users_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.bus_attribution": { - "name": "bus_attribution", - "schema": "", - "columns": { - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": true, - "notNull": true - }, - "bus": { - "name": "bus", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "departure_time": { - "name": "departure_time", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "bus_attribution_user_id_users_id_fk": { - "name": "bus_attribution_user_id_users_id_fk", - "tableFrom": "bus_attribution", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.challenge_validation": { - "name": "challenge_validation", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "challenge_id": { - "name": "challenge_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "validated_by_admin_id": { - "name": "validated_by_admin_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "validated_at": { - "name": "validated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "target_user_id": { - "name": "target_user_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "target_team_id": { - "name": "target_team_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "target_faction_id": { - "name": "target_faction_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "points": { - "name": "points", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "added_by_admin_id": { - "name": "added_by_admin_id", - "type": "integer", - "primaryKey": false, - "notNull": true + "id": "128e2d49-22e7-477d-a202-ae518c2e21ed", + "prevId": "93925edf-9622-4ce2-80bc-26050abbce0b", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.banned_addresses": { + "name": "banned_addresses", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "banned_addresses_email_unique": { + "name": "banned_addresses_email_unique", + "nullsNotDistinct": false, + "columns": ["email"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.challenges": { + "name": "challenges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "challenges_created_by_users_id_fk": { + "name": "challenges_created_by_users_id_fk", + "tableFrom": "challenges", + "tableTo": "users", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "pre_registration_open": { + "name": "pre_registration_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "shotgun_open": { + "name": "shotgun_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "sdi_open": { + "name": "sdi_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "wei_open": { + "name": "wei_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "food_open": { + "name": "food_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "chall_open": { + "name": "chall_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.factions": { + "name": "factions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "factions_name_unique": { + "name": "factions_name_unique", + "nullsNotDistinct": false, + "columns": ["name"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.news": { + "name": "news", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "published": { + "name": "published", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "target": { + "name": "target", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permanences": { + "name": "permanences", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "end_at": { + "name": "end_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "capacity": { + "name": "capacity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_open": { + "name": "is_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "difficulty": { + "name": "difficulty", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.roles": { + "name": "roles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "roles_name_unique": { + "name": "roles_name_unique", + "nullsNotDistinct": false, + "columns": ["name"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.teams": { + "name": "teams", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "teams_name_unique": { + "name": "teams_name_unique", + "nullsNotDistinct": false, + "columns": ["name"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "majeur": { + "name": "majeur", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contact": { + "name": "contact", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'Nouveau'" + }, + "discord_id": { + "name": "discord_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": ["email"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bus_attribution": { + "name": "bus_attribution", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "bus": { + "name": "bus", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "departure_time": { + "name": "departure_time", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bus_attribution_user_id_users_id_fk": { + "name": "bus_attribution_user_id_users_id_fk", + "tableFrom": "bus_attribution", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.challenge_validation": { + "name": "challenge_validation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "challenge_id": { + "name": "challenge_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_by_admin_id": { + "name": "validated_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_at": { + "name": "validated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "target_user_id": { + "name": "target_user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_team_id": { + "name": "target_team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_faction_id": { + "name": "target_faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "added_by_admin_id": { + "name": "added_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "challenge_validation_challenge_id_challenges_id_fk": { + "name": "challenge_validation_challenge_id_challenges_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "challenges", + "columnsFrom": ["challenge_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_validated_by_admin_id_users_id_fk": { + "name": "challenge_validation_validated_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": ["validated_by_admin_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_user_id_users_id_fk": { + "name": "challenge_validation_target_user_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": ["target_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_team_id_teams_id_fk": { + "name": "challenge_validation_target_team_id_teams_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "teams", + "columnsFrom": ["target_team_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_faction_id_factions_id_fk": { + "name": "challenge_validation_target_faction_id_factions_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "factions", + "columnsFrom": ["target_faction_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_added_by_admin_id_users_id_fk": { + "name": "challenge_validation_added_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": ["added_by_admin_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registration_tokens": { + "name": "registration_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_tokens_user_id_users_id_fk": { + "name": "registration_tokens_user_id_users_id_fk", + "tableFrom": "registration_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "registration_tokens_token_unique": { + "name": "registration_tokens_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.role_points": { + "name": "role_points", + "schema": "", + "columns": { + "role_points": { + "name": "role_points", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "role_points_role_points_roles_id_fk": { + "name": "role_points_role_points_roles_id_fk", + "tableFrom": "role_points", + "tableTo": "roles", + "columnsFrom": ["role_points"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "role_points_role_points_pk": { + "name": "role_points_role_points_pk", + "columns": ["role_points"] + } + }, + "uniqueConstraints": { + "role_points_role_points_unique": { + "name": "role_points_role_points_unique", + "nullsNotDistinct": false, + "columns": ["role_points"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_faction": { + "name": "team_faction", + "schema": "", + "columns": { + "faction_id": { + "name": "faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "team_faction_faction_id_factions_id_fk": { + "name": "team_faction_faction_id_factions_id_fk", + "tableFrom": "team_faction", + "tableTo": "factions", + "columnsFrom": ["faction_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "team_faction_team_id_teams_id_fk": { + "name": "team_faction_team_id_teams_id_fk", + "tableFrom": "team_faction", + "tableTo": "teams", + "columnsFrom": ["team_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "team_faction_faction_id_team_id_pk": { + "name": "team_faction_faction_id_team_id_pk", + "columns": ["faction_id", "team_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_shotgun": { + "name": "team_shotgun", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "team_shotgun_team_id_teams_id_fk": { + "name": "team_shotgun_team_id_teams_id_fk", + "tableFrom": "team_shotgun", + "tableTo": "teams", + "columnsFrom": ["team_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.respo_permanences": { + "name": "respo_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "respo_permanences_user_id_users_id_fk": { + "name": "respo_permanences_user_id_users_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "respo_permanences_permanence_id_permanences_id_fk": { + "name": "respo_permanences_permanence_id_permanences_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "permanences", + "columnsFrom": ["permanence_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "respo_permanences_user_id_permanence_id_pk": { + "name": "respo_permanences_user_id_permanence_id_pk", + "columns": ["user_id", "permanence_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_permanences": { + "name": "user_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "registered_at": { + "name": "registered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "claimed": { + "name": "claimed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_permanences_user_id_users_id_fk": { + "name": "user_permanences_user_id_users_id_fk", + "tableFrom": "user_permanences", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_permanences_permanence_id_permanences_id_fk": { + "name": "user_permanences_permanence_id_permanences_id_fk", + "tableFrom": "user_permanences", + "tableTo": "permanences", + "columnsFrom": ["permanence_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_permanences_user_id_permanence_id_pk": { + "name": "user_permanences_user_id_permanence_id_pk", + "columns": ["user_id", "permanence_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_preferences": { + "name": "user_preferences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_preferences_user_id_users_id_fk": { + "name": "user_preferences_user_id_users_id_fk", + "tableFrom": "user_preferences", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_preferences_role_id_roles_id_fk": { + "name": "user_preferences_role_id_roles_id_fk", + "tableFrom": "user_preferences", + "tableTo": "roles", + "columnsFrom": ["role_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_preferences_user_id_role_id_pk": { + "name": "user_preferences_user_id_role_id_pk", + "columns": ["user_id", "role_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_roles": { + "name": "user_roles", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_roles_user_id_users_id_fk": { + "name": "user_roles_user_id_users_id_fk", + "tableFrom": "user_roles", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_roles_role_id_roles_id_fk": { + "name": "user_roles_role_id_roles_id_fk", + "tableFrom": "user_roles", + "tableTo": "roles", + "columnsFrom": ["role_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_teams": { + "name": "user_teams", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_teams_user_id_users_id_fk": { + "name": "user_teams_user_id_users_id_fk", + "tableFrom": "user_teams", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_teams_team_id_teams_id_fk": { + "name": "user_teams_team_id_teams_id_fk", + "tableFrom": "user_teams", + "tableTo": "teams", + "columnsFrom": ["team_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_teams_user_id_team_id_pk": { + "name": "user_teams_user_id_team_id_pk", + "columns": ["user_id", "team_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_tent": { + "name": "user_tent", + "schema": "", + "columns": { + "user_id_1": { + "name": "user_id_1", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "user_id_2": { + "name": "user_id_2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "confirmed": { + "name": "confirmed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_tent_user_id_1_users_id_fk": { + "name": "user_tent_user_id_1_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": ["user_id_1"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_tent_user_id_2_users_id_fk": { + "name": "user_tent_user_id_2_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": ["user_id_2"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_tent_user_id_1_user_id_2_pk": { + "name": "user_tent_user_id_1_user_id_2_pk", + "columns": ["user_id_1", "user_id_2"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false } - }, - "indexes": {}, - "foreignKeys": { - "challenge_validation_challenge_id_challenges_id_fk": { - "name": "challenge_validation_challenge_id_challenges_id_fk", - "tableFrom": "challenge_validation", - "tableTo": "challenges", - "columnsFrom": [ - "challenge_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "challenge_validation_validated_by_admin_id_users_id_fk": { - "name": "challenge_validation_validated_by_admin_id_users_id_fk", - "tableFrom": "challenge_validation", - "tableTo": "users", - "columnsFrom": [ - "validated_by_admin_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "challenge_validation_target_user_id_users_id_fk": { - "name": "challenge_validation_target_user_id_users_id_fk", - "tableFrom": "challenge_validation", - "tableTo": "users", - "columnsFrom": [ - "target_user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "challenge_validation_target_team_id_teams_id_fk": { - "name": "challenge_validation_target_team_id_teams_id_fk", - "tableFrom": "challenge_validation", - "tableTo": "teams", - "columnsFrom": [ - "target_team_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "challenge_validation_target_faction_id_factions_id_fk": { - "name": "challenge_validation_target_faction_id_factions_id_fk", - "tableFrom": "challenge_validation", - "tableTo": "factions", - "columnsFrom": [ - "target_faction_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "challenge_validation_added_by_admin_id_users_id_fk": { - "name": "challenge_validation_added_by_admin_id_users_id_fk", - "tableFrom": "challenge_validation", - "tableTo": "users", - "columnsFrom": [ - "added_by_admin_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.registration_tokens": { - "name": "registration_tokens", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "registration_tokens_user_id_users_id_fk": { - "name": "registration_tokens_user_id_users_id_fk", - "tableFrom": "registration_tokens", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "registration_tokens_token_unique": { - "name": "registration_tokens_token_unique", - "nullsNotDistinct": false, - "columns": [ - "token" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.role_points": { - "name": "role_points", - "schema": "", - "columns": { - "role_points": { - "name": "role_points", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "points": { - "name": "points", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "role_points_role_points_roles_id_fk": { - "name": "role_points_role_points_roles_id_fk", - "tableFrom": "role_points", - "tableTo": "roles", - "columnsFrom": [ - "role_points" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "role_points_role_points_pk": { - "name": "role_points_role_points_pk", - "columns": [ - "role_points" - ] - } - }, - "uniqueConstraints": { - "role_points_role_points_unique": { - "name": "role_points_role_points_unique", - "nullsNotDistinct": false, - "columns": [ - "role_points" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false }, - "public.team_faction": { - "name": "team_faction", - "schema": "", - "columns": { - "faction_id": { - "name": "faction_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "team_id": { - "name": "team_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "team_faction_faction_id_factions_id_fk": { - "name": "team_faction_faction_id_factions_id_fk", - "tableFrom": "team_faction", - "tableTo": "factions", - "columnsFrom": [ - "faction_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "team_faction_team_id_teams_id_fk": { - "name": "team_faction_team_id_teams_id_fk", - "tableFrom": "team_faction", - "tableTo": "teams", - "columnsFrom": [ - "team_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "team_faction_faction_id_team_id_pk": { - "name": "team_faction_faction_id_team_id_pk", - "columns": [ - "faction_id", - "team_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.team_shotgun": { - "name": "team_shotgun", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "team_id": { - "name": "team_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "timestamp": { - "name": "timestamp", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "team_shotgun_team_id_teams_id_fk": { - "name": "team_shotgun_team_id_teams_id_fk", - "tableFrom": "team_shotgun", - "tableTo": "teams", - "columnsFrom": [ - "team_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_informations": { - "name": "user_informations", - "schema": "", - "columns": { - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": true, - "notNull": true - }, - "urgency_contact_name": { - "name": "urgency_contact_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "urgency_contact_phone": { - "name": "urgency_contact_phone", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "contact_CE": { - "name": "contact_CE", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "user_informations_user_id_users_id_fk": { - "name": "user_informations_user_id_users_id_fk", - "tableFrom": "user_informations", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.respo_permanences": { - "name": "respo_permanences", - "schema": "", - "columns": { - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "permanence_id": { - "name": "permanence_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "respo_permanences_user_id_users_id_fk": { - "name": "respo_permanences_user_id_users_id_fk", - "tableFrom": "respo_permanences", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "respo_permanences_permanence_id_permanences_id_fk": { - "name": "respo_permanences_permanence_id_permanences_id_fk", - "tableFrom": "respo_permanences", - "tableTo": "permanences", - "columnsFrom": [ - "permanence_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "respo_permanences_user_id_permanence_id_pk": { - "name": "respo_permanences_user_id_permanence_id_pk", - "columns": [ - "user_id", - "permanence_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_permanences": { - "name": "user_permanences", - "schema": "", - "columns": { - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "permanence_id": { - "name": "permanence_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "registered_at": { - "name": "registered_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "claimed": { - "name": "claimed", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - } - }, - "indexes": {}, - "foreignKeys": { - "user_permanences_user_id_users_id_fk": { - "name": "user_permanences_user_id_users_id_fk", - "tableFrom": "user_permanences", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "user_permanences_permanence_id_permanences_id_fk": { - "name": "user_permanences_permanence_id_permanences_id_fk", - "tableFrom": "user_permanences", - "tableTo": "permanences", - "columnsFrom": [ - "permanence_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "user_permanences_user_id_permanence_id_pk": { - "name": "user_permanences_user_id_permanence_id_pk", - "columns": [ - "user_id", - "permanence_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_preferences": { - "name": "user_preferences", - "schema": "", - "columns": { - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "role_id": { - "name": "role_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "user_preferences_user_id_users_id_fk": { - "name": "user_preferences_user_id_users_id_fk", - "tableFrom": "user_preferences", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "user_preferences_role_id_roles_id_fk": { - "name": "user_preferences_role_id_roles_id_fk", - "tableFrom": "user_preferences", - "tableTo": "roles", - "columnsFrom": [ - "role_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "user_preferences_user_id_role_id_pk": { - "name": "user_preferences_user_id_role_id_pk", - "columns": [ - "user_id", - "role_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_roles": { - "name": "user_roles", - "schema": "", - "columns": { - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "role_id": { - "name": "role_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "user_roles_user_id_users_id_fk": { - "name": "user_roles_user_id_users_id_fk", - "tableFrom": "user_roles", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "user_roles_role_id_roles_id_fk": { - "name": "user_roles_role_id_roles_id_fk", - "tableFrom": "user_roles", - "tableTo": "roles", - "columnsFrom": [ - "role_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_teams": { - "name": "user_teams", - "schema": "", - "columns": { - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "team_id": { - "name": "team_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "user_teams_user_id_users_id_fk": { - "name": "user_teams_user_id_users_id_fk", - "tableFrom": "user_teams", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "user_teams_team_id_teams_id_fk": { - "name": "user_teams_team_id_teams_id_fk", - "tableFrom": "user_teams", - "tableTo": "teams", - "columnsFrom": [ - "team_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "user_teams_user_id_team_id_pk": { - "name": "user_teams_user_id_team_id_pk", - "columns": [ - "user_id", - "team_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_tent": { - "name": "user_tent", - "schema": "", - "columns": { - "user_id_1": { - "name": "user_id_1", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "user_id_2": { - "name": "user_id_2", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "confirmed": { - "name": "confirmed", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "user_tent_user_id_1_users_id_fk": { - "name": "user_tent_user_id_1_users_id_fk", - "tableFrom": "user_tent", - "tableTo": "users", - "columnsFrom": [ - "user_id_1" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "user_tent_user_id_2_users_id_fk": { - "name": "user_tent_user_id_2_users_id_fk", - "tableFrom": "user_tent", - "tableTo": "users", - "columnsFrom": [ - "user_id_2" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "user_tent_user_id_1_user_id_2_pk": { - "name": "user_tent_user_id_1_user_id_2_pk", - "columns": [ - "user_id_1", - "user_id_2" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": {}, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, + "enums": {}, "schemas": {}, - "tables": {} - } -} \ No newline at end of file + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/backend/src/database/migrations/meta/0024_snapshot.json b/backend/src/database/migrations/meta/0024_snapshot.json index c58070e..1a2b4f8 100644 --- a/backend/src/database/migrations/meta/0024_snapshot.json +++ b/backend/src/database/migrations/meta/0024_snapshot.json @@ -1,1329 +1,1199 @@ { - "id": "f2813605-996e-4461-8e87-8b135d3eefd3", - "prevId": "77c4b2f6-c24d-4eb9-80a9-42fb8b9ef380", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.challenges": { - "name": "challenges", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "category": { - "name": "category", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "points": { - "name": "points", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "created_by": { - "name": "created_by", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "challenges_created_by_users_id_fk": { - "name": "challenges_created_by_users_id_fk", - "tableFrom": "challenges", - "tableTo": "users", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.events": { - "name": "events", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "pre_registration_open": { - "name": "pre_registration_open", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "shotgun_open": { - "name": "shotgun_open", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "sdi_open": { - "name": "sdi_open", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "wei_open": { - "name": "wei_open", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "food_open": { - "name": "food_open", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "chall_open": { - "name": "chall_open", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.factions": { - "name": "factions", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false + "id": "77c4b2f6-c24d-4eb9-80a9-42fb8b9ef380", + "prevId": "77c4b2f6-c24d-4eb9-80a9-42fb8b9ef380", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.challenges": { + "name": "challenges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "challenges_created_by_users_id_fk": { + "name": "challenges_created_by_users_id_fk", + "tableFrom": "challenges", + "tableTo": "users", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "pre_registration_open": { + "name": "pre_registration_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "shotgun_open": { + "name": "shotgun_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "sdi_open": { + "name": "sdi_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "wei_open": { + "name": "wei_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "food_open": { + "name": "food_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "chall_open": { + "name": "chall_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.factions": { + "name": "factions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "factions_name_unique": { + "name": "factions_name_unique", + "nullsNotDistinct": false, + "columns": ["name"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.news": { + "name": "news", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "published": { + "name": "published", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "target": { + "name": "target", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permanences": { + "name": "permanences", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "end_at": { + "name": "end_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "capacity": { + "name": "capacity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_open": { + "name": "is_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "difficulty": { + "name": "difficulty", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.roles": { + "name": "roles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "roles_name_unique": { + "name": "roles_name_unique", + "nullsNotDistinct": false, + "columns": ["name"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.teams": { + "name": "teams", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "teams_name_unique": { + "name": "teams_name_unique", + "nullsNotDistinct": false, + "columns": ["name"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "majeur": { + "name": "majeur", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contact": { + "name": "contact", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'Nouveau'" + }, + "discord_id": { + "name": "discord_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": ["email"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bus_attribution": { + "name": "bus_attribution", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "bus": { + "name": "bus", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "departure_time": { + "name": "departure_time", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bus_attribution_user_id_users_id_fk": { + "name": "bus_attribution_user_id_users_id_fk", + "tableFrom": "bus_attribution", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.challenge_validation": { + "name": "challenge_validation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "challenge_id": { + "name": "challenge_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_by_admin_id": { + "name": "validated_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_at": { + "name": "validated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "target_user_id": { + "name": "target_user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_team_id": { + "name": "target_team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_faction_id": { + "name": "target_faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "added_by_admin_id": { + "name": "added_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "challenge_validation_challenge_id_challenges_id_fk": { + "name": "challenge_validation_challenge_id_challenges_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "challenges", + "columnsFrom": ["challenge_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_validated_by_admin_id_users_id_fk": { + "name": "challenge_validation_validated_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": ["validated_by_admin_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_user_id_users_id_fk": { + "name": "challenge_validation_target_user_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": ["target_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_team_id_teams_id_fk": { + "name": "challenge_validation_target_team_id_teams_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "teams", + "columnsFrom": ["target_team_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_faction_id_factions_id_fk": { + "name": "challenge_validation_target_faction_id_factions_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "factions", + "columnsFrom": ["target_faction_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_added_by_admin_id_users_id_fk": { + "name": "challenge_validation_added_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": ["added_by_admin_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registration_tokens": { + "name": "registration_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_tokens_user_id_users_id_fk": { + "name": "registration_tokens_user_id_users_id_fk", + "tableFrom": "registration_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "registration_tokens_token_unique": { + "name": "registration_tokens_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.role_points": { + "name": "role_points", + "schema": "", + "columns": { + "role_points": { + "name": "role_points", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "role_points_role_points_roles_id_fk": { + "name": "role_points_role_points_roles_id_fk", + "tableFrom": "role_points", + "tableTo": "roles", + "columnsFrom": ["role_points"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "role_points_role_points_pk": { + "name": "role_points_role_points_pk", + "columns": ["role_points"] + } + }, + "uniqueConstraints": { + "role_points_role_points_unique": { + "name": "role_points_role_points_unique", + "nullsNotDistinct": false, + "columns": ["role_points"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_faction": { + "name": "team_faction", + "schema": "", + "columns": { + "faction_id": { + "name": "faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "team_faction_faction_id_factions_id_fk": { + "name": "team_faction_faction_id_factions_id_fk", + "tableFrom": "team_faction", + "tableTo": "factions", + "columnsFrom": ["faction_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "team_faction_team_id_teams_id_fk": { + "name": "team_faction_team_id_teams_id_fk", + "tableFrom": "team_faction", + "tableTo": "teams", + "columnsFrom": ["team_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "team_faction_faction_id_team_id_pk": { + "name": "team_faction_faction_id_team_id_pk", + "columns": ["faction_id", "team_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_shotgun": { + "name": "team_shotgun", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "team_shotgun_team_id_teams_id_fk": { + "name": "team_shotgun_team_id_teams_id_fk", + "tableFrom": "team_shotgun", + "tableTo": "teams", + "columnsFrom": ["team_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_informations": { + "name": "user_informations", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "urgency_contact_name": { + "name": "urgency_contact_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "urgency_contact_phone": { + "name": "urgency_contact_phone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contact_CE": { + "name": "contact_CE", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_informations_user_id_users_id_fk": { + "name": "user_informations_user_id_users_id_fk", + "tableFrom": "user_informations", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.respo_permanences": { + "name": "respo_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "respo_permanences_user_id_users_id_fk": { + "name": "respo_permanences_user_id_users_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "respo_permanences_permanence_id_permanences_id_fk": { + "name": "respo_permanences_permanence_id_permanences_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "permanences", + "columnsFrom": ["permanence_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "respo_permanences_user_id_permanence_id_pk": { + "name": "respo_permanences_user_id_permanence_id_pk", + "columns": ["user_id", "permanence_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_permanences": { + "name": "user_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "registered_at": { + "name": "registered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "claimed": { + "name": "claimed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_permanences_user_id_users_id_fk": { + "name": "user_permanences_user_id_users_id_fk", + "tableFrom": "user_permanences", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_permanences_permanence_id_permanences_id_fk": { + "name": "user_permanences_permanence_id_permanences_id_fk", + "tableFrom": "user_permanences", + "tableTo": "permanences", + "columnsFrom": ["permanence_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_permanences_user_id_permanence_id_pk": { + "name": "user_permanences_user_id_permanence_id_pk", + "columns": ["user_id", "permanence_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_preferences": { + "name": "user_preferences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_preferences_user_id_users_id_fk": { + "name": "user_preferences_user_id_users_id_fk", + "tableFrom": "user_preferences", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_preferences_role_id_roles_id_fk": { + "name": "user_preferences_role_id_roles_id_fk", + "tableFrom": "user_preferences", + "tableTo": "roles", + "columnsFrom": ["role_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_preferences_user_id_role_id_pk": { + "name": "user_preferences_user_id_role_id_pk", + "columns": ["user_id", "role_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_roles": { + "name": "user_roles", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_roles_user_id_users_id_fk": { + "name": "user_roles_user_id_users_id_fk", + "tableFrom": "user_roles", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_roles_role_id_roles_id_fk": { + "name": "user_roles_role_id_roles_id_fk", + "tableFrom": "user_roles", + "tableTo": "roles", + "columnsFrom": ["role_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_teams": { + "name": "user_teams", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_teams_user_id_users_id_fk": { + "name": "user_teams_user_id_users_id_fk", + "tableFrom": "user_teams", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_teams_team_id_teams_id_fk": { + "name": "user_teams_team_id_teams_id_fk", + "tableFrom": "user_teams", + "tableTo": "teams", + "columnsFrom": ["team_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_teams_user_id_team_id_pk": { + "name": "user_teams_user_id_team_id_pk", + "columns": ["user_id", "team_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_tent": { + "name": "user_tent", + "schema": "", + "columns": { + "user_id_1": { + "name": "user_id_1", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "user_id_2": { + "name": "user_id_2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "confirmed": { + "name": "confirmed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_tent_user_id_1_users_id_fk": { + "name": "user_tent_user_id_1_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": ["user_id_1"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_tent_user_id_2_users_id_fk": { + "name": "user_tent_user_id_2_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": ["user_id_2"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_tent_user_id_1_user_id_2_pk": { + "name": "user_tent_user_id_1_user_id_2_pk", + "columns": ["user_id_1", "user_id_2"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "factions_name_unique": { - "name": "factions_name_unique", - "nullsNotDistinct": false, - "columns": [ - "name" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false }, - "public.news": { - "name": "news", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "published": { - "name": "published", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "target": { - "name": "target", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "image_url": { - "name": "image_url", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.permanences": { - "name": "permanences", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "location": { - "name": "location", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "start_at": { - "name": "start_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "end_at": { - "name": "end_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "capacity": { - "name": "capacity", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "is_open": { - "name": "is_open", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "difficulty": { - "name": "difficulty", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.roles": { - "name": "roles", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "roles_name_unique": { - "name": "roles_name_unique", - "nullsNotDistinct": false, - "columns": [ - "name" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.teams": { - "name": "teams", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "teams_name_unique": { - "name": "teams_name_unique", - "nullsNotDistinct": false, - "columns": [ - "name" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.users": { - "name": "users", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "first_name": { - "name": "first_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "last_name": { - "name": "last_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "majeur": { - "name": "majeur", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "branch": { - "name": "branch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "contact": { - "name": "contact", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "permission": { - "name": "permission", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'Nouveau'" - }, - "discord_id": { - "name": "discord_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "users_email_unique": { - "name": "users_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.bus_attribution": { - "name": "bus_attribution", - "schema": "", - "columns": { - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": true, - "notNull": true - }, - "bus": { - "name": "bus", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "departure_time": { - "name": "departure_time", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "bus_attribution_user_id_users_id_fk": { - "name": "bus_attribution_user_id_users_id_fk", - "tableFrom": "bus_attribution", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.challenge_validation": { - "name": "challenge_validation", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "challenge_id": { - "name": "challenge_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "validated_by_admin_id": { - "name": "validated_by_admin_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "validated_at": { - "name": "validated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "target_user_id": { - "name": "target_user_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "target_team_id": { - "name": "target_team_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "target_faction_id": { - "name": "target_faction_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "points": { - "name": "points", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "added_by_admin_id": { - "name": "added_by_admin_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "challenge_validation_challenge_id_challenges_id_fk": { - "name": "challenge_validation_challenge_id_challenges_id_fk", - "tableFrom": "challenge_validation", - "tableTo": "challenges", - "columnsFrom": [ - "challenge_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "challenge_validation_validated_by_admin_id_users_id_fk": { - "name": "challenge_validation_validated_by_admin_id_users_id_fk", - "tableFrom": "challenge_validation", - "tableTo": "users", - "columnsFrom": [ - "validated_by_admin_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "challenge_validation_target_user_id_users_id_fk": { - "name": "challenge_validation_target_user_id_users_id_fk", - "tableFrom": "challenge_validation", - "tableTo": "users", - "columnsFrom": [ - "target_user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "challenge_validation_target_team_id_teams_id_fk": { - "name": "challenge_validation_target_team_id_teams_id_fk", - "tableFrom": "challenge_validation", - "tableTo": "teams", - "columnsFrom": [ - "target_team_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "challenge_validation_target_faction_id_factions_id_fk": { - "name": "challenge_validation_target_faction_id_factions_id_fk", - "tableFrom": "challenge_validation", - "tableTo": "factions", - "columnsFrom": [ - "target_faction_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "challenge_validation_added_by_admin_id_users_id_fk": { - "name": "challenge_validation_added_by_admin_id_users_id_fk", - "tableFrom": "challenge_validation", - "tableTo": "users", - "columnsFrom": [ - "added_by_admin_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.registration_tokens": { - "name": "registration_tokens", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "registration_tokens_user_id_users_id_fk": { - "name": "registration_tokens_user_id_users_id_fk", - "tableFrom": "registration_tokens", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "registration_tokens_token_unique": { - "name": "registration_tokens_token_unique", - "nullsNotDistinct": false, - "columns": [ - "token" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.role_points": { - "name": "role_points", - "schema": "", - "columns": { - "role_points": { - "name": "role_points", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "points": { - "name": "points", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "role_points_role_points_roles_id_fk": { - "name": "role_points_role_points_roles_id_fk", - "tableFrom": "role_points", - "tableTo": "roles", - "columnsFrom": [ - "role_points" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "role_points_role_points_pk": { - "name": "role_points_role_points_pk", - "columns": [ - "role_points" - ] - } - }, - "uniqueConstraints": { - "role_points_role_points_unique": { - "name": "role_points_role_points_unique", - "nullsNotDistinct": false, - "columns": [ - "role_points" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.team_faction": { - "name": "team_faction", - "schema": "", - "columns": { - "faction_id": { - "name": "faction_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "team_id": { - "name": "team_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "team_faction_faction_id_factions_id_fk": { - "name": "team_faction_faction_id_factions_id_fk", - "tableFrom": "team_faction", - "tableTo": "factions", - "columnsFrom": [ - "faction_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "team_faction_team_id_teams_id_fk": { - "name": "team_faction_team_id_teams_id_fk", - "tableFrom": "team_faction", - "tableTo": "teams", - "columnsFrom": [ - "team_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "team_faction_faction_id_team_id_pk": { - "name": "team_faction_faction_id_team_id_pk", - "columns": [ - "faction_id", - "team_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.team_shotgun": { - "name": "team_shotgun", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "team_id": { - "name": "team_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "timestamp": { - "name": "timestamp", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "team_shotgun_team_id_teams_id_fk": { - "name": "team_shotgun_team_id_teams_id_fk", - "tableFrom": "team_shotgun", - "tableTo": "teams", - "columnsFrom": [ - "team_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_informations": { - "name": "user_informations", - "schema": "", - "columns": { - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": true, - "notNull": true - }, - "urgency_contact_name": { - "name": "urgency_contact_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "urgency_contact_phone": { - "name": "urgency_contact_phone", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "user_informations_user_id_users_id_fk": { - "name": "user_informations_user_id_users_id_fk", - "tableFrom": "user_informations", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.respo_permanences": { - "name": "respo_permanences", - "schema": "", - "columns": { - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "permanence_id": { - "name": "permanence_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "respo_permanences_user_id_users_id_fk": { - "name": "respo_permanences_user_id_users_id_fk", - "tableFrom": "respo_permanences", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "respo_permanences_permanence_id_permanences_id_fk": { - "name": "respo_permanences_permanence_id_permanences_id_fk", - "tableFrom": "respo_permanences", - "tableTo": "permanences", - "columnsFrom": [ - "permanence_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "respo_permanences_user_id_permanence_id_pk": { - "name": "respo_permanences_user_id_permanence_id_pk", - "columns": [ - "user_id", - "permanence_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_permanences": { - "name": "user_permanences", - "schema": "", - "columns": { - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "permanence_id": { - "name": "permanence_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "registered_at": { - "name": "registered_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "claimed": { - "name": "claimed", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - } - }, - "indexes": {}, - "foreignKeys": { - "user_permanences_user_id_users_id_fk": { - "name": "user_permanences_user_id_users_id_fk", - "tableFrom": "user_permanences", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "user_permanences_permanence_id_permanences_id_fk": { - "name": "user_permanences_permanence_id_permanences_id_fk", - "tableFrom": "user_permanences", - "tableTo": "permanences", - "columnsFrom": [ - "permanence_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "user_permanences_user_id_permanence_id_pk": { - "name": "user_permanences_user_id_permanence_id_pk", - "columns": [ - "user_id", - "permanence_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_preferences": { - "name": "user_preferences", - "schema": "", - "columns": { - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "role_id": { - "name": "role_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "user_preferences_user_id_users_id_fk": { - "name": "user_preferences_user_id_users_id_fk", - "tableFrom": "user_preferences", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "user_preferences_role_id_roles_id_fk": { - "name": "user_preferences_role_id_roles_id_fk", - "tableFrom": "user_preferences", - "tableTo": "roles", - "columnsFrom": [ - "role_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "user_preferences_user_id_role_id_pk": { - "name": "user_preferences_user_id_role_id_pk", - "columns": [ - "user_id", - "role_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_roles": { - "name": "user_roles", - "schema": "", - "columns": { - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "role_id": { - "name": "role_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "user_roles_user_id_users_id_fk": { - "name": "user_roles_user_id_users_id_fk", - "tableFrom": "user_roles", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "user_roles_role_id_roles_id_fk": { - "name": "user_roles_role_id_roles_id_fk", - "tableFrom": "user_roles", - "tableTo": "roles", - "columnsFrom": [ - "role_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_teams": { - "name": "user_teams", - "schema": "", - "columns": { - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "team_id": { - "name": "team_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "user_teams_user_id_users_id_fk": { - "name": "user_teams_user_id_users_id_fk", - "tableFrom": "user_teams", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "user_teams_team_id_teams_id_fk": { - "name": "user_teams_team_id_teams_id_fk", - "tableFrom": "user_teams", - "tableTo": "teams", - "columnsFrom": [ - "team_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "user_teams_user_id_team_id_pk": { - "name": "user_teams_user_id_team_id_pk", - "columns": [ - "user_id", - "team_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_tent": { - "name": "user_tent", - "schema": "", - "columns": { - "user_id_1": { - "name": "user_id_1", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "user_id_2": { - "name": "user_id_2", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "confirmed": { - "name": "confirmed", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "user_tent_user_id_1_users_id_fk": { - "name": "user_tent_user_id_1_users_id_fk", - "tableFrom": "user_tent", - "tableTo": "users", - "columnsFrom": [ - "user_id_1" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "user_tent_user_id_2_users_id_fk": { - "name": "user_tent_user_id_2_users_id_fk", - "tableFrom": "user_tent", - "tableTo": "users", - "columnsFrom": [ - "user_id_2" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "user_tent_user_id_1_user_id_2_pk": { - "name": "user_tent_user_id_1_user_id_2_pk", - "columns": [ - "user_id_1", - "user_id_2" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": {}, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, + "enums": {}, "schemas": {}, - "tables": {} - } -} \ No newline at end of file + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/backend/src/database/migrations/meta/0025_snapshot.json b/backend/src/database/migrations/meta/0025_snapshot.json index 3e69f00..c58070e 100644 --- a/backend/src/database/migrations/meta/0025_snapshot.json +++ b/backend/src/database/migrations/meta/0025_snapshot.json @@ -1,6 +1,6 @@ { - "id": "c76925a0-a42e-42c9-8f72-0d914fe74da9", - "prevId": "f2813605-996e-4461-8e87-8b135d3eefd3", + "id": "f2813605-996e-4461-8e87-8b135d3eefd3", + "prevId": "77c4b2f6-c24d-4eb9-80a9-42fb8b9ef380", "version": "7", "dialect": "postgresql", "tables": { @@ -453,14 +453,6 @@ "primaryKey": false, "notNull": false, "default": "now()" - }, - "vss_form": { - "name": "vss_form", - "type": "vss_form", - "typeSchema": "public", - "primaryKey": false, - "notNull": false, - "default": "'pending'" } }, "indexes": {}, @@ -479,44 +471,6 @@ "checkConstraints": {}, "isRLSEnabled": false }, - "public.vssqcmquestion": { - "name": "vssqcmquestion", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "question": { - "name": "question", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "points": { - "name": "points", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "type": { - "name": "type", - "type": "question_type", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, "public.bus_attribution": { "name": "bus_attribution", "schema": "", @@ -1359,78 +1313,9 @@ "policies": {}, "checkConstraints": {}, "isRLSEnabled": false - }, - "public.vssqcmanswer": { - "name": "vssqcmanswer", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "questionid": { - "name": "questionid", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "answer": { - "name": "answer", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "is_correct": { - "name": "is_correct", - "type": "boolean", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "vssqcmanswer_questionid_vssqcmquestion_id_fk": { - "name": "vssqcmanswer_questionid_vssqcmquestion_id_fk", - "tableFrom": "vssqcmanswer", - "tableTo": "vssqcmquestion", - "columnsFrom": [ - "questionid" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": { - "public.vss_form": { - "name": "vss_form", - "schema": "public", - "values": [ - "pending", - "validated", - "rejected" - ] - }, - "public.question_type": { - "name": "question_type", - "schema": "public", - "values": [ - "single_choice", - "multiple_choice" - ] } }, + "enums": {}, "schemas": {}, "sequences": {}, "roles": {}, diff --git a/backend/src/database/migrations/meta/0026_snapshot.json b/backend/src/database/migrations/meta/0026_snapshot.json index 82f221c..3e69f00 100644 --- a/backend/src/database/migrations/meta/0026_snapshot.json +++ b/backend/src/database/migrations/meta/0026_snapshot.json @@ -1,6 +1,6 @@ { - "id": "8ceeb5a4-a02f-426a-9b8f-5a15ac8d26cd", - "prevId": "c76925a0-a42e-42c9-8f72-0d914fe74da9", + "id": "c76925a0-a42e-42c9-8f72-0d914fe74da9", + "prevId": "f2813605-996e-4461-8e87-8b135d3eefd3", "version": "7", "dialect": "postgresql", "tables": { @@ -1418,7 +1418,6 @@ "schema": "public", "values": [ "pending", - "toretry", "validated", "rejected" ] diff --git a/backend/src/database/migrations/meta/0027_snapshot.json b/backend/src/database/migrations/meta/0027_snapshot.json new file mode 100644 index 0000000..82f221c --- /dev/null +++ b/backend/src/database/migrations/meta/0027_snapshot.json @@ -0,0 +1,1445 @@ +{ + "id": "8ceeb5a4-a02f-426a-9b8f-5a15ac8d26cd", + "prevId": "c76925a0-a42e-42c9-8f72-0d914fe74da9", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.challenges": { + "name": "challenges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "challenges_created_by_users_id_fk": { + "name": "challenges_created_by_users_id_fk", + "tableFrom": "challenges", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "pre_registration_open": { + "name": "pre_registration_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "shotgun_open": { + "name": "shotgun_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "sdi_open": { + "name": "sdi_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "wei_open": { + "name": "wei_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "food_open": { + "name": "food_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "chall_open": { + "name": "chall_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.factions": { + "name": "factions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "factions_name_unique": { + "name": "factions_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.news": { + "name": "news", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "published": { + "name": "published", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "target": { + "name": "target", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permanences": { + "name": "permanences", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "end_at": { + "name": "end_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "capacity": { + "name": "capacity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_open": { + "name": "is_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "difficulty": { + "name": "difficulty", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.roles": { + "name": "roles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "roles_name_unique": { + "name": "roles_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.teams": { + "name": "teams", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "teams_name_unique": { + "name": "teams_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "majeur": { + "name": "majeur", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contact": { + "name": "contact", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'Nouveau'" + }, + "discord_id": { + "name": "discord_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "vss_form": { + "name": "vss_form", + "type": "vss_form", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'pending'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.vssqcmquestion": { + "name": "vssqcmquestion", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "question": { + "name": "question", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "question_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bus_attribution": { + "name": "bus_attribution", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "bus": { + "name": "bus", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "departure_time": { + "name": "departure_time", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bus_attribution_user_id_users_id_fk": { + "name": "bus_attribution_user_id_users_id_fk", + "tableFrom": "bus_attribution", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.challenge_validation": { + "name": "challenge_validation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "challenge_id": { + "name": "challenge_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_by_admin_id": { + "name": "validated_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_at": { + "name": "validated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "target_user_id": { + "name": "target_user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_team_id": { + "name": "target_team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_faction_id": { + "name": "target_faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "added_by_admin_id": { + "name": "added_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "challenge_validation_challenge_id_challenges_id_fk": { + "name": "challenge_validation_challenge_id_challenges_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "challenges", + "columnsFrom": [ + "challenge_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_validated_by_admin_id_users_id_fk": { + "name": "challenge_validation_validated_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "validated_by_admin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_user_id_users_id_fk": { + "name": "challenge_validation_target_user_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "target_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_team_id_teams_id_fk": { + "name": "challenge_validation_target_team_id_teams_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "teams", + "columnsFrom": [ + "target_team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_faction_id_factions_id_fk": { + "name": "challenge_validation_target_faction_id_factions_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "factions", + "columnsFrom": [ + "target_faction_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_added_by_admin_id_users_id_fk": { + "name": "challenge_validation_added_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "added_by_admin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registration_tokens": { + "name": "registration_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_tokens_user_id_users_id_fk": { + "name": "registration_tokens_user_id_users_id_fk", + "tableFrom": "registration_tokens", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "registration_tokens_token_unique": { + "name": "registration_tokens_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.role_points": { + "name": "role_points", + "schema": "", + "columns": { + "role_points": { + "name": "role_points", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "role_points_role_points_roles_id_fk": { + "name": "role_points_role_points_roles_id_fk", + "tableFrom": "role_points", + "tableTo": "roles", + "columnsFrom": [ + "role_points" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "role_points_role_points_pk": { + "name": "role_points_role_points_pk", + "columns": [ + "role_points" + ] + } + }, + "uniqueConstraints": { + "role_points_role_points_unique": { + "name": "role_points_role_points_unique", + "nullsNotDistinct": false, + "columns": [ + "role_points" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_faction": { + "name": "team_faction", + "schema": "", + "columns": { + "faction_id": { + "name": "faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "team_faction_faction_id_factions_id_fk": { + "name": "team_faction_faction_id_factions_id_fk", + "tableFrom": "team_faction", + "tableTo": "factions", + "columnsFrom": [ + "faction_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "team_faction_team_id_teams_id_fk": { + "name": "team_faction_team_id_teams_id_fk", + "tableFrom": "team_faction", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "team_faction_faction_id_team_id_pk": { + "name": "team_faction_faction_id_team_id_pk", + "columns": [ + "faction_id", + "team_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_shotgun": { + "name": "team_shotgun", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "team_shotgun_team_id_teams_id_fk": { + "name": "team_shotgun_team_id_teams_id_fk", + "tableFrom": "team_shotgun", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_informations": { + "name": "user_informations", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "urgency_contact_name": { + "name": "urgency_contact_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "urgency_contact_phone": { + "name": "urgency_contact_phone", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_informations_user_id_users_id_fk": { + "name": "user_informations_user_id_users_id_fk", + "tableFrom": "user_informations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.respo_permanences": { + "name": "respo_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "respo_permanences_user_id_users_id_fk": { + "name": "respo_permanences_user_id_users_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "respo_permanences_permanence_id_permanences_id_fk": { + "name": "respo_permanences_permanence_id_permanences_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "permanences", + "columnsFrom": [ + "permanence_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "respo_permanences_user_id_permanence_id_pk": { + "name": "respo_permanences_user_id_permanence_id_pk", + "columns": [ + "user_id", + "permanence_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_permanences": { + "name": "user_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "registered_at": { + "name": "registered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "claimed": { + "name": "claimed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_permanences_user_id_users_id_fk": { + "name": "user_permanences_user_id_users_id_fk", + "tableFrom": "user_permanences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_permanences_permanence_id_permanences_id_fk": { + "name": "user_permanences_permanence_id_permanences_id_fk", + "tableFrom": "user_permanences", + "tableTo": "permanences", + "columnsFrom": [ + "permanence_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_permanences_user_id_permanence_id_pk": { + "name": "user_permanences_user_id_permanence_id_pk", + "columns": [ + "user_id", + "permanence_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_preferences": { + "name": "user_preferences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_preferences_user_id_users_id_fk": { + "name": "user_preferences_user_id_users_id_fk", + "tableFrom": "user_preferences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_preferences_role_id_roles_id_fk": { + "name": "user_preferences_role_id_roles_id_fk", + "tableFrom": "user_preferences", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_preferences_user_id_role_id_pk": { + "name": "user_preferences_user_id_role_id_pk", + "columns": [ + "user_id", + "role_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_roles": { + "name": "user_roles", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_roles_user_id_users_id_fk": { + "name": "user_roles_user_id_users_id_fk", + "tableFrom": "user_roles", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_roles_role_id_roles_id_fk": { + "name": "user_roles_role_id_roles_id_fk", + "tableFrom": "user_roles", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_teams": { + "name": "user_teams", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_teams_user_id_users_id_fk": { + "name": "user_teams_user_id_users_id_fk", + "tableFrom": "user_teams", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_teams_team_id_teams_id_fk": { + "name": "user_teams_team_id_teams_id_fk", + "tableFrom": "user_teams", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_teams_user_id_team_id_pk": { + "name": "user_teams_user_id_team_id_pk", + "columns": [ + "user_id", + "team_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_tent": { + "name": "user_tent", + "schema": "", + "columns": { + "user_id_1": { + "name": "user_id_1", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "user_id_2": { + "name": "user_id_2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "confirmed": { + "name": "confirmed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_tent_user_id_1_users_id_fk": { + "name": "user_tent_user_id_1_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": [ + "user_id_1" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_tent_user_id_2_users_id_fk": { + "name": "user_tent_user_id_2_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": [ + "user_id_2" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_tent_user_id_1_user_id_2_pk": { + "name": "user_tent_user_id_1_user_id_2_pk", + "columns": [ + "user_id_1", + "user_id_2" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.vssqcmanswer": { + "name": "vssqcmanswer", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "questionid": { + "name": "questionid", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "answer": { + "name": "answer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_correct": { + "name": "is_correct", + "type": "boolean", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "vssqcmanswer_questionid_vssqcmquestion_id_fk": { + "name": "vssqcmanswer_questionid_vssqcmquestion_id_fk", + "tableFrom": "vssqcmanswer", + "tableTo": "vssqcmquestion", + "columnsFrom": [ + "questionid" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.vss_form": { + "name": "vss_form", + "schema": "public", + "values": [ + "pending", + "toretry", + "validated", + "rejected" + ] + }, + "public.question_type": { + "name": "question_type", + "schema": "public", + "values": [ + "single_choice", + "multiple_choice" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/backend/src/database/migrations/meta/_journal.json b/backend/src/database/migrations/meta/_journal.json index 64717b9..6bdde63 100644 --- a/backend/src/database/migrations/meta/_journal.json +++ b/backend/src/database/migrations/meta/_journal.json @@ -1,195 +1,202 @@ { - "version": "7", - "dialect": "postgresql", - "entries": [ - { - "idx": 0, - "version": "7", - "when": 1743857362115, - "tag": "0000_workable_rafael_vega", - "breakpoints": true - }, - { - "idx": 1, - "version": "7", - "when": 1743868246465, - "tag": "0001_stormy_quicksilver", - "breakpoints": true - }, - { - "idx": 2, - "version": "7", - "when": 1743897931065, - "tag": "0002_luxuriant_lockjaw", - "breakpoints": true - }, - { - "idx": 3, - "version": "7", - "when": 1743979532382, - "tag": "0003_material_lorna_dane", - "breakpoints": true - }, - { - "idx": 4, - "version": "7", - "when": 1744064732443, - "tag": "0004_careless_misty_knight", - "breakpoints": true - }, - { - "idx": 5, - "version": "7", - "when": 1744118020611, - "tag": "0005_needy_darwin", - "breakpoints": true - }, - { - "idx": 6, - "version": "7", - "when": 1744126517418, - "tag": "0006_bright_boomerang", - "breakpoints": true - }, - { - "idx": 7, - "version": "7", - "when": 1744212319949, - "tag": "0007_striped_mulholland_black", - "breakpoints": true - }, - { - "idx": 8, - "version": "7", - "when": 1744215076184, - "tag": "0008_striped_bushwacker", - "breakpoints": true - }, - { - "idx": 9, - "version": "7", - "when": 1744241202940, - "tag": "0009_previous_mystique", - "breakpoints": true - }, - { - "idx": 10, - "version": "7", - "when": 1744241242502, - "tag": "0010_fair_mulholland_black", - "breakpoints": true - }, - { - "idx": 11, - "version": "7", - "when": 1744241259194, - "tag": "0011_fearless_nextwave", - "breakpoints": true - }, - { - "idx": 12, - "version": "7", - "when": 1746040673007, - "tag": "0012_productive_giant_man", - "breakpoints": true - }, - { - "idx": 13, - "version": "7", - "when": 1752757642698, - "tag": "0013_curly_angel", - "breakpoints": true - }, - { - "idx": 14, - "version": "7", - "when": 1753638076374, - "tag": "0014_special_reaper", - "breakpoints": true - }, - { - "idx": 15, - "version": "7", - "when": 1753744481956, - "tag": "0015_greedy_genesis", - "breakpoints": true - }, - { - "idx": 16, - "version": "7", - "when": 1754903172897, - "tag": "0016_sudden_ultimatum", - "breakpoints": true - }, - { - "idx": 17, - "version": "7", - "when": 1755637642205, - "tag": "0017_melted_meggan", - "breakpoints": true - }, - { - "idx": 18, - "version": "7", - "when": 1755858317109, - "tag": "0018_puzzling_arachne", - "breakpoints": true - }, - { - "idx": 19, - "version": "7", - "when": 1755906116757, - "tag": "0019_complete_moondragon", - "breakpoints": true - }, - { - "idx": 20, - "version": "7", - "when": 1755907709198, - "tag": "0020_strange_colonel_america", - "breakpoints": true - }, - { - "idx": 21, - "version": "7", - "when": 1756063134903, - "tag": "0021_colossal_madame_web", - "breakpoints": true - }, - { - "idx": 22, - "version": "7", - "when": 1757002717384, - "tag": "0022_light_omega_red", - "breakpoints": true - }, - { - "idx": 23, - "version": "7", - "when": 1783854058299, - "tag": "0023_even_morg", - "breakpoints": true - }, - { - "idx": 24, - "version": "7", - "when": 1784272112439, - "tag": "0024_natural_human_cannonball", - "breakpoints": true - }, - { - "idx": 25, - "version": "7", - "when": 1784298990793, - "tag": "0025_high_wind_dancer", - "breakpoints": true - }, - { - "idx": 26, - "version": "7", - "when": 1784372155559, - "tag": "0026_good_unus", - "breakpoints": true - } - ] -} \ No newline at end of file + "version": "7", + "dialect": "postgresql", + "entries": [ + { + "idx": 0, + "version": "7", + "when": 1743857362115, + "tag": "0000_workable_rafael_vega", + "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1743868246465, + "tag": "0001_stormy_quicksilver", + "breakpoints": true + }, + { + "idx": 2, + "version": "7", + "when": 1743897931065, + "tag": "0002_luxuriant_lockjaw", + "breakpoints": true + }, + { + "idx": 3, + "version": "7", + "when": 1743979532382, + "tag": "0003_material_lorna_dane", + "breakpoints": true + }, + { + "idx": 4, + "version": "7", + "when": 1744064732443, + "tag": "0004_careless_misty_knight", + "breakpoints": true + }, + { + "idx": 5, + "version": "7", + "when": 1744118020611, + "tag": "0005_needy_darwin", + "breakpoints": true + }, + { + "idx": 6, + "version": "7", + "when": 1744126517418, + "tag": "0006_bright_boomerang", + "breakpoints": true + }, + { + "idx": 7, + "version": "7", + "when": 1744212319949, + "tag": "0007_striped_mulholland_black", + "breakpoints": true + }, + { + "idx": 8, + "version": "7", + "when": 1744215076184, + "tag": "0008_striped_bushwacker", + "breakpoints": true + }, + { + "idx": 9, + "version": "7", + "when": 1744241202940, + "tag": "0009_previous_mystique", + "breakpoints": true + }, + { + "idx": 10, + "version": "7", + "when": 1744241242502, + "tag": "0010_fair_mulholland_black", + "breakpoints": true + }, + { + "idx": 11, + "version": "7", + "when": 1744241259194, + "tag": "0011_fearless_nextwave", + "breakpoints": true + }, + { + "idx": 12, + "version": "7", + "when": 1746040673007, + "tag": "0012_productive_giant_man", + "breakpoints": true + }, + { + "idx": 13, + "version": "7", + "when": 1752757642698, + "tag": "0013_curly_angel", + "breakpoints": true + }, + { + "idx": 14, + "version": "7", + "when": 1753638076374, + "tag": "0014_special_reaper", + "breakpoints": true + }, + { + "idx": 15, + "version": "7", + "when": 1753744481956, + "tag": "0015_greedy_genesis", + "breakpoints": true + }, + { + "idx": 16, + "version": "7", + "when": 1754903172897, + "tag": "0016_sudden_ultimatum", + "breakpoints": true + }, + { + "idx": 17, + "version": "7", + "when": 1755637642205, + "tag": "0017_melted_meggan", + "breakpoints": true + }, + { + "idx": 18, + "version": "7", + "when": 1755858317109, + "tag": "0018_puzzling_arachne", + "breakpoints": true + }, + { + "idx": 19, + "version": "7", + "when": 1755906116757, + "tag": "0019_complete_moondragon", + "breakpoints": true + }, + { + "idx": 20, + "version": "7", + "when": 1755907709198, + "tag": "0020_strange_colonel_america", + "breakpoints": true + }, + { + "idx": 21, + "version": "7", + "when": 1756063134903, + "tag": "0021_colossal_madame_web", + "breakpoints": true + }, + { + "idx": 22, + "version": "7", + "when": 1757002717384, + "tag": "0022_light_omega_red", + "breakpoints": true + }, + { + "idx": 23, + "version": "7", + "when": 1782943789540, + "tag": "0023_zippy_colonel_america", + "breakpoints": true + }, + { + "idx": 24, + "version": "7", + "when": 1783854058299, + "tag": "0024_even_morg", + "breakpoints": true + }, + { + "idx": 25, + "version": "7", + "when": 1784272112439, + "tag": "0025_natural_human_cannonball", + "breakpoints": true + }, + { + "idx": 26, + "version": "7", + "when": 1784298990793, + "tag": "0026_high_wind_dancer", + "breakpoints": true + }, + { + "idx": 27, + "version": "7", + "when": 1784372155559, + "tag": "0027_good_unus", + "breakpoints": true + } + ] +} From 2ed250be3f7ad5da62fad0468df9c2eb86280efc Mon Sep 17 00:00:00 2001 From: Antoine Date: Sat, 18 Jul 2026 20:28:38 +0200 Subject: [PATCH 20/27] fix: pointing to right prev migration --- backend/src/database/migrations/meta/0024_snapshot.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/database/migrations/meta/0024_snapshot.json b/backend/src/database/migrations/meta/0024_snapshot.json index 1a2b4f8..9961248 100644 --- a/backend/src/database/migrations/meta/0024_snapshot.json +++ b/backend/src/database/migrations/meta/0024_snapshot.json @@ -1,6 +1,6 @@ { "id": "77c4b2f6-c24d-4eb9-80a9-42fb8b9ef380", - "prevId": "77c4b2f6-c24d-4eb9-80a9-42fb8b9ef380", + "prevId": "128e2d49-22e7-477d-a202-ae518c2e21ed", "version": "7", "dialect": "postgresql", "tables": { From 810169cfb0b5dcabf2da9822f357f884de3e1f24 Mon Sep 17 00:00:00 2001 From: Antoine Date: Sat, 18 Jul 2026 20:32:14 +0200 Subject: [PATCH 21/27] fix(lint) --- backend/src/controllers/user.controller.ts | 10 --- backend/src/services/user.service.ts | 4 +- frontend/src/components/navbar.tsx | 83 ++++++++++--------- .../src/services/requests/user.service.ts | 1 - 4 files changed, 44 insertions(+), 54 deletions(-) diff --git a/backend/src/controllers/user.controller.ts b/backend/src/controllers/user.controller.ts index 2d472f6..0e5c0d3 100644 --- a/backend/src/controllers/user.controller.ts +++ b/backend/src/controllers/user.controller.ts @@ -45,15 +45,6 @@ export const getUsersByPermission: AppRequestHandler = async (req, res) => { const { date } = req.body; - type SiepStudent = { - email: string; - prenom: string; - nom: string; - Majeur: boolean; - diplome: string; - specialite: string; - }; - try { await user_service.syncNewStudents(date); @@ -132,7 +123,6 @@ export const submitVssQuestionnaire = async (req: Request, res: Response) => { }; export const updateProfile: AppRequestHandler = async (req, res) => { - const userId = req.user?.userId; const { branch, contact } = req.body; diff --git a/backend/src/services/user.service.ts b/backend/src/services/user.service.ts index 718cf5f..6d9d65e 100644 --- a/backend/src/services/user.service.ts +++ b/backend/src/services/user.service.ts @@ -17,6 +17,8 @@ import { getTeam, getTeamFaction, getUserTeam } from './team.service'; import { userInformationSchema } from '../schemas/Relational/userinformation.schema'; import { type UserContactInformation } from '../../types/user'; import { addUserToRespondentStudentsList } from '../utils/billetweb'; +import { generateEmailHtml, sendEmail } from './email.service'; +import { email_from } from '../utils/secret'; export type VssQuestionnaireAnswer = { id: number; @@ -39,8 +41,6 @@ export type VssSubmissionAnswer = { export type VssSubmissionPayload = { answers: VssSubmissionAnswer[]; }; -import { generateEmailHtml, sendEmail } from './email.service'; -import { email_from } from '../utils/secret'; // Fonction pour récupérer un utilisateur par email export const getUserByEmail = async (email: string) => { diff --git a/frontend/src/components/navbar.tsx b/frontend/src/components/navbar.tsx index 2bb8f6c..eefab42 100644 --- a/frontend/src/components/navbar.tsx +++ b/frontend/src/components/navbar.tsx @@ -166,58 +166,59 @@ export const Navbar = () => { UTT Integration - {/* Hamburger mobile */} - + {/* Hamburger mobile */} + - {/* Menu desktop */} -

      - {navItems.map((item) => - canShowItem(item) ? ( -
    • - {item.children ? ( - - ) : item.kind === 'action' ? ( - - ) : ( - - )} -
    • - ) : null, - )} -
    -
    - - {/* Menu mobile */} - - {menuOpen && ( - + {/* Menu desktop */} +
      {navItems.map((item) => canShowItem(item) ? ( - - {!item.children ? ( - item.kind === 'action' ? ( - - ) : ( - - ) +
    • + {item.children ? ( + + ) : item.kind === 'action' ? ( + ) : ( )} - +
    • ) : null, )}
    + {/* Menu mobile */} + + {menuOpen && ( + + {navItems.map((item) => + canShowItem(item) ? ( + + {!item.children ? ( + item.kind === 'action' ? ( + + ) : ( + + ) + ) : ( + + )} + + ) : null, + )} + + )} + + {/* Menu mobile */} {menuOpen && ( diff --git a/frontend/src/services/requests/user.service.ts b/frontend/src/services/requests/user.service.ts index eb29891..38b7fbe 100644 --- a/frontend/src/services/requests/user.service.ts +++ b/frontend/src/services/requests/user.service.ts @@ -8,7 +8,6 @@ import { type VssSubmissionRequest, type VssSubmissionResponse, } from '../../interfaces/user.interface'; - import api from '../api'; export const getPermission = (): string | null => { From 7cd3d238a2cb14ba3547f36d69417b958480f940 Mon Sep 17 00:00:00 2001 From: Antoine Date: Sat, 18 Jul 2026 20:39:42 +0200 Subject: [PATCH 22/27] refactor: update user controller methods to use AppRequestHandler type --- backend/src/controllers/user.controller.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/backend/src/controllers/user.controller.ts b/backend/src/controllers/user.controller.ts index 0e5c0d3..92f1a6b 100644 --- a/backend/src/controllers/user.controller.ts +++ b/backend/src/controllers/user.controller.ts @@ -67,7 +67,7 @@ export const getCurrentUser: AppRequestHandler = async (req, res) => { } }; -export const getUserContactInformation = async (req: Request, res: Response) => { +export const getUserContactInformation: AppRequestHandler = async (req, res) => { const { userId } = req.params; try { @@ -78,30 +78,30 @@ export const getUserContactInformation = async (req: Request, res: Response) => } }; -export const createUserContactInformation = async (req: Request, res: Response) => { +export const createUserContactInformation: AppRequestHandler = async (req, res) => { const userId = req.user?.userId; - const contact: UserContactInformation = req.body; + const contact = req.body; try { - const result = await user_service.createUserContactInformation(parseInt(userId), contact); + const result = await user_service.createUserContactInformation(userId, contact); Ok(res, { msg: 'Informations de contact créées', data: result }); } catch { Error(res, { msg: 'Erreur lors de la création des informations de contact.' }); } }; -export const getCurrentUserOnboardingStatus = async (req: Request, res: Response) => { +export const getCurrentUserOnboardingStatus: AppRequestHandler = async (req, res) => { const userId = req.user?.userId; try { - const status = await user_service.getCurrentUserOnboardingStatus(parseInt(userId)); + const status = await user_service.getCurrentUserOnboardingStatus(userId); Ok(res, { data: status }); } catch { Error(res, { msg: "Erreur lors de la récupération du statut d'onboarding." }); } }; -export const getVssQuestionnaire = async (_req: Request, res: Response) => { +export const getVssQuestionnaire: AppRequestHandler = async (req, res) => { try { const questionnaire = await user_service.getVssQuestionnaire(); Ok(res, { data: questionnaire }); @@ -110,12 +110,12 @@ export const getVssQuestionnaire = async (_req: Request, res: Response) => { } }; -export const submitVssQuestionnaire = async (req: Request, res: Response) => { +export const submitVssQuestionnaire: AppRequestHandler = async (req, res) => { const userId = req.user?.userId; const payload = req.body; try { - const result = await user_service.submitVssQuestionnaire(parseInt(userId), payload); + const result = await user_service.submitVssQuestionnaire(userId, payload); Ok(res, { data: result }); } catch { Error(res, { msg: 'Erreur lors de la soumission du questionnaire VSS.' }); From 5b78707d389da72b959fae1eaa2888be00e4da15 Mon Sep 17 00:00:00 2001 From: Antoine D <106921102+Suboyyy@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:15:21 +0200 Subject: [PATCH 23/27] Update frontend/src/components/Admin/adminUser.tsx Co-authored-by: Arthur Dodin <52950784+tuturd@users.noreply.github.com> --- frontend/src/components/Admin/adminUser.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/Admin/adminUser.tsx b/frontend/src/components/Admin/adminUser.tsx index 1708a17..0b0e773 100644 --- a/frontend/src/components/Admin/adminUser.tsx +++ b/frontend/src/components/Admin/adminUser.tsx @@ -3,7 +3,7 @@ import Select from 'react-select'; import { type SingleValue } from 'react-select'; import Swal from 'sweetalert2'; -import { type User,type UserContactInformation } from '../../interfaces/user.interface'; +import type { User, UserContactInformation } from '../../interfaces/user.interface'; import { renewTokenUser, requestPasswordUser } from '../../services/requests/auth.service'; import { createUserByAdmin, From 7a2f629727ddd1ead838b6cc5d7d2b006a4f503e Mon Sep 17 00:00:00 2001 From: Antoine D <106921102+Suboyyy@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:15:53 +0200 Subject: [PATCH 24/27] Update frontend/src/services/requests/user.service.ts Co-authored-by: Arthur Dodin <52950784+tuturd@users.noreply.github.com> --- frontend/src/services/requests/user.service.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/frontend/src/services/requests/user.service.ts b/frontend/src/services/requests/user.service.ts index 38b7fbe..1493432 100644 --- a/frontend/src/services/requests/user.service.ts +++ b/frontend/src/services/requests/user.service.ts @@ -1,4 +1,13 @@ -import { +import type { + CreateUserContactInformationRequest, + NewUser, + User, + UserContactInformation, + UserOnboardingStatus, + VssQuestionnaireQuestion, + VssSubmissionRequest, + VssSubmissionResponse, +} from '../../interfaces/user.interface'; type CreateUserContactInformationRequest, type NewUser, type User, From d3c945d76b5f9a54cbfaa375f6e89986cee3ec61 Mon Sep 17 00:00:00 2001 From: Antoine D <106921102+Suboyyy@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:16:07 +0200 Subject: [PATCH 25/27] Update frontend/src/components/home/vssModal.tsx Co-authored-by: Arthur Dodin <52950784+tuturd@users.noreply.github.com> --- frontend/src/components/home/vssModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/home/vssModal.tsx b/frontend/src/components/home/vssModal.tsx index 3f0b922..64cd3fa 100644 --- a/frontend/src/components/home/vssModal.tsx +++ b/frontend/src/components/home/vssModal.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; -import { type VssQuestionnaireQuestion, type VssSubmissionResponse } from '../../interfaces/user.interface'; +import type { VssQuestionnaireQuestion, VssSubmissionResponse } from '../../interfaces/user.interface'; import { getVssQuestionnaire, submitVssQuestionnaire } from '../../services/requests/user.service'; import { Button } from '../ui/button'; import Modal from '../ui/modal'; From 09beecb20c7e3165ed628d3f59c92b2c724f93ba Mon Sep 17 00:00:00 2001 From: Antoine Date: Thu, 23 Jul 2026 18:14:40 +0200 Subject: [PATCH 26/27] fix: all github comment --- backend/src/controllers/user.controller.ts | 15 +- .../migrations/0028_special_black_cat.sql | 8 + .../migrations/meta/0028_snapshot.json | 1478 +++++++++++++++++ .../database/migrations/meta/_journal.json | 409 ++--- backend/src/dto/user.dto.ts | 11 + .../Relational/userinformation.schema.ts | 4 +- backend/src/services/user.service.ts | 23 +- backend/types/user.d.ts | 4 - frontend/src/components/Admin/adminUser.tsx | 21 +- .../components/WEI_SDI_Food/sdiSection.tsx | 2 +- .../components/WEI_SDI_Food/weiSection.tsx | 2 +- .../{urgencyModal.tsx => emergencyModal.tsx} | 28 +- frontend/src/components/navbar.tsx | 2 +- frontend/src/interfaces/user.interface.ts | 10 +- frontend/src/pages/home.tsx | 4 +- .../src/services/requests/user.service.ts | 9 - 16 files changed, 1761 insertions(+), 269 deletions(-) create mode 100644 backend/src/database/migrations/0028_special_black_cat.sql create mode 100644 backend/src/database/migrations/meta/0028_snapshot.json delete mode 100644 backend/types/user.d.ts rename frontend/src/components/home/{urgencyModal.tsx => emergencyModal.tsx} (84%) diff --git a/backend/src/controllers/user.controller.ts b/backend/src/controllers/user.controller.ts index 92f1a6b..f10ef74 100644 --- a/backend/src/controllers/user.controller.ts +++ b/backend/src/controllers/user.controller.ts @@ -1,7 +1,14 @@ -import type { AdminCreateUserDto, PermissionParams, ProfileBody, SyncBody, UserIdParams } from '../dto/user.dto'; +import type { + AdminCreateUserDto, + CreateUserContactInformationDto, + PermissionParams, + ProfileBody, + SyncBody, + UserIdParams, + VssSubmissionPayload, +} from '../dto/user.dto'; import * as user_service from '../services/user.service'; import { Error, Ok } from '../utils/responses'; -import { type UserContactInformation } from '../../types/user'; import type { AppRequestHandler } from '../types/http'; export const getUsersAdmin: AppRequestHandler = async (_req, res) => { @@ -78,7 +85,7 @@ export const getUserContactInformation: AppRequestHandler = async (req, res) => } }; -export const createUserContactInformation: AppRequestHandler = async (req, res) => { +export const createUserContactInformation: AppRequestHandler = async (req, res) => { const userId = req.user?.userId; const contact = req.body; @@ -110,7 +117,7 @@ export const getVssQuestionnaire: AppRequestHandler = async (req, res) => { } }; -export const submitVssQuestionnaire: AppRequestHandler = async (req, res) => { +export const submitVssQuestionnaire: AppRequestHandler = async (req, res) => { const userId = req.user?.userId; const payload = req.body; diff --git a/backend/src/database/migrations/0028_special_black_cat.sql b/backend/src/database/migrations/0028_special_black_cat.sql new file mode 100644 index 0000000..a3219ea --- /dev/null +++ b/backend/src/database/migrations/0028_special_black_cat.sql @@ -0,0 +1,8 @@ +CREATE TABLE "banned_addresses" ( + "id" serial PRIMARY KEY NOT NULL, + "email" text, + CONSTRAINT "banned_addresses_email_unique" UNIQUE("email") +); +--> statement-breakpoint +ALTER TABLE "user_informations" RENAME COLUMN "urgency_contact_name" TO "emergency_contact_name";--> statement-breakpoint +ALTER TABLE "user_informations" RENAME COLUMN "urgency_contact_phone" TO "emergency_contact_phone"; \ No newline at end of file diff --git a/backend/src/database/migrations/meta/0028_snapshot.json b/backend/src/database/migrations/meta/0028_snapshot.json new file mode 100644 index 0000000..af9b564 --- /dev/null +++ b/backend/src/database/migrations/meta/0028_snapshot.json @@ -0,0 +1,1478 @@ +{ + "id": "fca8b812-3f6c-4644-92a6-e8f43c18387f", + "prevId": "8ceeb5a4-a02f-426a-9b8f-5a15ac8d26cd", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.banned_addresses": { + "name": "banned_addresses", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "banned_addresses_email_unique": { + "name": "banned_addresses_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.challenges": { + "name": "challenges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "challenges_created_by_users_id_fk": { + "name": "challenges_created_by_users_id_fk", + "tableFrom": "challenges", + "tableTo": "users", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "pre_registration_open": { + "name": "pre_registration_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "shotgun_open": { + "name": "shotgun_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "sdi_open": { + "name": "sdi_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "wei_open": { + "name": "wei_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "food_open": { + "name": "food_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "chall_open": { + "name": "chall_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.factions": { + "name": "factions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "factions_name_unique": { + "name": "factions_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.news": { + "name": "news", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "published": { + "name": "published", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "target": { + "name": "target", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permanences": { + "name": "permanences", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "end_at": { + "name": "end_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "capacity": { + "name": "capacity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_open": { + "name": "is_open", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "difficulty": { + "name": "difficulty", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.roles": { + "name": "roles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "roles_name_unique": { + "name": "roles_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.teams": { + "name": "teams", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "teams_name_unique": { + "name": "teams_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "majeur": { + "name": "majeur", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contact": { + "name": "contact", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'Nouveau'" + }, + "discord_id": { + "name": "discord_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "vss_form": { + "name": "vss_form", + "type": "vss_form", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'pending'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.vssqcmquestion": { + "name": "vssqcmquestion", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "question": { + "name": "question", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "question_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bus_attribution": { + "name": "bus_attribution", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "bus": { + "name": "bus", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "departure_time": { + "name": "departure_time", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bus_attribution_user_id_users_id_fk": { + "name": "bus_attribution_user_id_users_id_fk", + "tableFrom": "bus_attribution", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.challenge_validation": { + "name": "challenge_validation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "challenge_id": { + "name": "challenge_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_by_admin_id": { + "name": "validated_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "validated_at": { + "name": "validated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "target_user_id": { + "name": "target_user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_team_id": { + "name": "target_team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "target_faction_id": { + "name": "target_faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "added_by_admin_id": { + "name": "added_by_admin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "challenge_validation_challenge_id_challenges_id_fk": { + "name": "challenge_validation_challenge_id_challenges_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "challenges", + "columnsFrom": [ + "challenge_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_validated_by_admin_id_users_id_fk": { + "name": "challenge_validation_validated_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "validated_by_admin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_user_id_users_id_fk": { + "name": "challenge_validation_target_user_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "target_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_team_id_teams_id_fk": { + "name": "challenge_validation_target_team_id_teams_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "teams", + "columnsFrom": [ + "target_team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_target_faction_id_factions_id_fk": { + "name": "challenge_validation_target_faction_id_factions_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "factions", + "columnsFrom": [ + "target_faction_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "challenge_validation_added_by_admin_id_users_id_fk": { + "name": "challenge_validation_added_by_admin_id_users_id_fk", + "tableFrom": "challenge_validation", + "tableTo": "users", + "columnsFrom": [ + "added_by_admin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registration_tokens": { + "name": "registration_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_tokens_user_id_users_id_fk": { + "name": "registration_tokens_user_id_users_id_fk", + "tableFrom": "registration_tokens", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "registration_tokens_token_unique": { + "name": "registration_tokens_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.role_points": { + "name": "role_points", + "schema": "", + "columns": { + "role_points": { + "name": "role_points", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "points": { + "name": "points", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "role_points_role_points_roles_id_fk": { + "name": "role_points_role_points_roles_id_fk", + "tableFrom": "role_points", + "tableTo": "roles", + "columnsFrom": [ + "role_points" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "role_points_role_points_pk": { + "name": "role_points_role_points_pk", + "columns": [ + "role_points" + ] + } + }, + "uniqueConstraints": { + "role_points_role_points_unique": { + "name": "role_points_role_points_unique", + "nullsNotDistinct": false, + "columns": [ + "role_points" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_faction": { + "name": "team_faction", + "schema": "", + "columns": { + "faction_id": { + "name": "faction_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "team_faction_faction_id_factions_id_fk": { + "name": "team_faction_faction_id_factions_id_fk", + "tableFrom": "team_faction", + "tableTo": "factions", + "columnsFrom": [ + "faction_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "team_faction_team_id_teams_id_fk": { + "name": "team_faction_team_id_teams_id_fk", + "tableFrom": "team_faction", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "team_faction_faction_id_team_id_pk": { + "name": "team_faction_faction_id_team_id_pk", + "columns": [ + "faction_id", + "team_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_shotgun": { + "name": "team_shotgun", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "team_shotgun_team_id_teams_id_fk": { + "name": "team_shotgun_team_id_teams_id_fk", + "tableFrom": "team_shotgun", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_informations": { + "name": "user_informations", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "emergency_contact_name": { + "name": "emergency_contact_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "emergency_contact_phone": { + "name": "emergency_contact_phone", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_informations_user_id_users_id_fk": { + "name": "user_informations_user_id_users_id_fk", + "tableFrom": "user_informations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.respo_permanences": { + "name": "respo_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "respo_permanences_user_id_users_id_fk": { + "name": "respo_permanences_user_id_users_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "respo_permanences_permanence_id_permanences_id_fk": { + "name": "respo_permanences_permanence_id_permanences_id_fk", + "tableFrom": "respo_permanences", + "tableTo": "permanences", + "columnsFrom": [ + "permanence_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "respo_permanences_user_id_permanence_id_pk": { + "name": "respo_permanences_user_id_permanence_id_pk", + "columns": [ + "user_id", + "permanence_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_permanences": { + "name": "user_permanences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permanence_id": { + "name": "permanence_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "registered_at": { + "name": "registered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "claimed": { + "name": "claimed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_permanences_user_id_users_id_fk": { + "name": "user_permanences_user_id_users_id_fk", + "tableFrom": "user_permanences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_permanences_permanence_id_permanences_id_fk": { + "name": "user_permanences_permanence_id_permanences_id_fk", + "tableFrom": "user_permanences", + "tableTo": "permanences", + "columnsFrom": [ + "permanence_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_permanences_user_id_permanence_id_pk": { + "name": "user_permanences_user_id_permanence_id_pk", + "columns": [ + "user_id", + "permanence_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_preferences": { + "name": "user_preferences", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_preferences_user_id_users_id_fk": { + "name": "user_preferences_user_id_users_id_fk", + "tableFrom": "user_preferences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_preferences_role_id_roles_id_fk": { + "name": "user_preferences_role_id_roles_id_fk", + "tableFrom": "user_preferences", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_preferences_user_id_role_id_pk": { + "name": "user_preferences_user_id_role_id_pk", + "columns": [ + "user_id", + "role_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_roles": { + "name": "user_roles", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_roles_user_id_users_id_fk": { + "name": "user_roles_user_id_users_id_fk", + "tableFrom": "user_roles", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_roles_role_id_roles_id_fk": { + "name": "user_roles_role_id_roles_id_fk", + "tableFrom": "user_roles", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_teams": { + "name": "user_teams", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_teams_user_id_users_id_fk": { + "name": "user_teams_user_id_users_id_fk", + "tableFrom": "user_teams", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_teams_team_id_teams_id_fk": { + "name": "user_teams_team_id_teams_id_fk", + "tableFrom": "user_teams", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_teams_user_id_team_id_pk": { + "name": "user_teams_user_id_team_id_pk", + "columns": [ + "user_id", + "team_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_tent": { + "name": "user_tent", + "schema": "", + "columns": { + "user_id_1": { + "name": "user_id_1", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "user_id_2": { + "name": "user_id_2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "confirmed": { + "name": "confirmed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_tent_user_id_1_users_id_fk": { + "name": "user_tent_user_id_1_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": [ + "user_id_1" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_tent_user_id_2_users_id_fk": { + "name": "user_tent_user_id_2_users_id_fk", + "tableFrom": "user_tent", + "tableTo": "users", + "columnsFrom": [ + "user_id_2" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_tent_user_id_1_user_id_2_pk": { + "name": "user_tent_user_id_1_user_id_2_pk", + "columns": [ + "user_id_1", + "user_id_2" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.vssqcmanswer": { + "name": "vssqcmanswer", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "questionid": { + "name": "questionid", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "answer": { + "name": "answer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_correct": { + "name": "is_correct", + "type": "boolean", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "vssqcmanswer_questionid_vssqcmquestion_id_fk": { + "name": "vssqcmanswer_questionid_vssqcmquestion_id_fk", + "tableFrom": "vssqcmanswer", + "tableTo": "vssqcmquestion", + "columnsFrom": [ + "questionid" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.vss_form": { + "name": "vss_form", + "schema": "public", + "values": [ + "pending", + "toretry", + "validated", + "rejected" + ] + }, + "public.question_type": { + "name": "question_type", + "schema": "public", + "values": [ + "single_choice", + "multiple_choice" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/backend/src/database/migrations/meta/_journal.json b/backend/src/database/migrations/meta/_journal.json index 6bdde63..2598f16 100644 --- a/backend/src/database/migrations/meta/_journal.json +++ b/backend/src/database/migrations/meta/_journal.json @@ -1,202 +1,209 @@ { - "version": "7", - "dialect": "postgresql", - "entries": [ - { - "idx": 0, - "version": "7", - "when": 1743857362115, - "tag": "0000_workable_rafael_vega", - "breakpoints": true - }, - { - "idx": 1, - "version": "7", - "when": 1743868246465, - "tag": "0001_stormy_quicksilver", - "breakpoints": true - }, - { - "idx": 2, - "version": "7", - "when": 1743897931065, - "tag": "0002_luxuriant_lockjaw", - "breakpoints": true - }, - { - "idx": 3, - "version": "7", - "when": 1743979532382, - "tag": "0003_material_lorna_dane", - "breakpoints": true - }, - { - "idx": 4, - "version": "7", - "when": 1744064732443, - "tag": "0004_careless_misty_knight", - "breakpoints": true - }, - { - "idx": 5, - "version": "7", - "when": 1744118020611, - "tag": "0005_needy_darwin", - "breakpoints": true - }, - { - "idx": 6, - "version": "7", - "when": 1744126517418, - "tag": "0006_bright_boomerang", - "breakpoints": true - }, - { - "idx": 7, - "version": "7", - "when": 1744212319949, - "tag": "0007_striped_mulholland_black", - "breakpoints": true - }, - { - "idx": 8, - "version": "7", - "when": 1744215076184, - "tag": "0008_striped_bushwacker", - "breakpoints": true - }, - { - "idx": 9, - "version": "7", - "when": 1744241202940, - "tag": "0009_previous_mystique", - "breakpoints": true - }, - { - "idx": 10, - "version": "7", - "when": 1744241242502, - "tag": "0010_fair_mulholland_black", - "breakpoints": true - }, - { - "idx": 11, - "version": "7", - "when": 1744241259194, - "tag": "0011_fearless_nextwave", - "breakpoints": true - }, - { - "idx": 12, - "version": "7", - "when": 1746040673007, - "tag": "0012_productive_giant_man", - "breakpoints": true - }, - { - "idx": 13, - "version": "7", - "when": 1752757642698, - "tag": "0013_curly_angel", - "breakpoints": true - }, - { - "idx": 14, - "version": "7", - "when": 1753638076374, - "tag": "0014_special_reaper", - "breakpoints": true - }, - { - "idx": 15, - "version": "7", - "when": 1753744481956, - "tag": "0015_greedy_genesis", - "breakpoints": true - }, - { - "idx": 16, - "version": "7", - "when": 1754903172897, - "tag": "0016_sudden_ultimatum", - "breakpoints": true - }, - { - "idx": 17, - "version": "7", - "when": 1755637642205, - "tag": "0017_melted_meggan", - "breakpoints": true - }, - { - "idx": 18, - "version": "7", - "when": 1755858317109, - "tag": "0018_puzzling_arachne", - "breakpoints": true - }, - { - "idx": 19, - "version": "7", - "when": 1755906116757, - "tag": "0019_complete_moondragon", - "breakpoints": true - }, - { - "idx": 20, - "version": "7", - "when": 1755907709198, - "tag": "0020_strange_colonel_america", - "breakpoints": true - }, - { - "idx": 21, - "version": "7", - "when": 1756063134903, - "tag": "0021_colossal_madame_web", - "breakpoints": true - }, - { - "idx": 22, - "version": "7", - "when": 1757002717384, - "tag": "0022_light_omega_red", - "breakpoints": true - }, - { - "idx": 23, - "version": "7", - "when": 1782943789540, - "tag": "0023_zippy_colonel_america", - "breakpoints": true - }, - { - "idx": 24, - "version": "7", - "when": 1783854058299, - "tag": "0024_even_morg", - "breakpoints": true - }, - { - "idx": 25, - "version": "7", - "when": 1784272112439, - "tag": "0025_natural_human_cannonball", - "breakpoints": true - }, - { - "idx": 26, - "version": "7", - "when": 1784298990793, - "tag": "0026_high_wind_dancer", - "breakpoints": true - }, - { - "idx": 27, - "version": "7", - "when": 1784372155559, - "tag": "0027_good_unus", - "breakpoints": true - } - ] -} + "version": "7", + "dialect": "postgresql", + "entries": [ + { + "idx": 0, + "version": "7", + "when": 1743857362115, + "tag": "0000_workable_rafael_vega", + "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1743868246465, + "tag": "0001_stormy_quicksilver", + "breakpoints": true + }, + { + "idx": 2, + "version": "7", + "when": 1743897931065, + "tag": "0002_luxuriant_lockjaw", + "breakpoints": true + }, + { + "idx": 3, + "version": "7", + "when": 1743979532382, + "tag": "0003_material_lorna_dane", + "breakpoints": true + }, + { + "idx": 4, + "version": "7", + "when": 1744064732443, + "tag": "0004_careless_misty_knight", + "breakpoints": true + }, + { + "idx": 5, + "version": "7", + "when": 1744118020611, + "tag": "0005_needy_darwin", + "breakpoints": true + }, + { + "idx": 6, + "version": "7", + "when": 1744126517418, + "tag": "0006_bright_boomerang", + "breakpoints": true + }, + { + "idx": 7, + "version": "7", + "when": 1744212319949, + "tag": "0007_striped_mulholland_black", + "breakpoints": true + }, + { + "idx": 8, + "version": "7", + "when": 1744215076184, + "tag": "0008_striped_bushwacker", + "breakpoints": true + }, + { + "idx": 9, + "version": "7", + "when": 1744241202940, + "tag": "0009_previous_mystique", + "breakpoints": true + }, + { + "idx": 10, + "version": "7", + "when": 1744241242502, + "tag": "0010_fair_mulholland_black", + "breakpoints": true + }, + { + "idx": 11, + "version": "7", + "when": 1744241259194, + "tag": "0011_fearless_nextwave", + "breakpoints": true + }, + { + "idx": 12, + "version": "7", + "when": 1746040673007, + "tag": "0012_productive_giant_man", + "breakpoints": true + }, + { + "idx": 13, + "version": "7", + "when": 1752757642698, + "tag": "0013_curly_angel", + "breakpoints": true + }, + { + "idx": 14, + "version": "7", + "when": 1753638076374, + "tag": "0014_special_reaper", + "breakpoints": true + }, + { + "idx": 15, + "version": "7", + "when": 1753744481956, + "tag": "0015_greedy_genesis", + "breakpoints": true + }, + { + "idx": 16, + "version": "7", + "when": 1754903172897, + "tag": "0016_sudden_ultimatum", + "breakpoints": true + }, + { + "idx": 17, + "version": "7", + "when": 1755637642205, + "tag": "0017_melted_meggan", + "breakpoints": true + }, + { + "idx": 18, + "version": "7", + "when": 1755858317109, + "tag": "0018_puzzling_arachne", + "breakpoints": true + }, + { + "idx": 19, + "version": "7", + "when": 1755906116757, + "tag": "0019_complete_moondragon", + "breakpoints": true + }, + { + "idx": 20, + "version": "7", + "when": 1755907709198, + "tag": "0020_strange_colonel_america", + "breakpoints": true + }, + { + "idx": 21, + "version": "7", + "when": 1756063134903, + "tag": "0021_colossal_madame_web", + "breakpoints": true + }, + { + "idx": 22, + "version": "7", + "when": 1757002717384, + "tag": "0022_light_omega_red", + "breakpoints": true + }, + { + "idx": 23, + "version": "7", + "when": 1782943789540, + "tag": "0023_zippy_colonel_america", + "breakpoints": true + }, + { + "idx": 24, + "version": "7", + "when": 1783854058299, + "tag": "0024_even_morg", + "breakpoints": true + }, + { + "idx": 25, + "version": "7", + "when": 1784272112439, + "tag": "0025_natural_human_cannonball", + "breakpoints": true + }, + { + "idx": 26, + "version": "7", + "when": 1784298990793, + "tag": "0026_high_wind_dancer", + "breakpoints": true + }, + { + "idx": 27, + "version": "7", + "when": 1784372155559, + "tag": "0027_good_unus", + "breakpoints": true + }, + { + "idx": 28, + "version": "7", + "when": 1784823075781, + "tag": "0028_special_black_cat", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/backend/src/dto/user.dto.ts b/backend/src/dto/user.dto.ts index 41c11de..7e0107a 100644 --- a/backend/src/dto/user.dto.ts +++ b/backend/src/dto/user.dto.ts @@ -1,3 +1,5 @@ +import { type VssSubmissionAnswer } from '../services/user.service'; + export interface AdminCreateUserDto { firstName: string; lastName: string; @@ -23,3 +25,12 @@ export type ProfileBody = { branch: string; contact: string; }; + +export type CreateUserContactInformationDto = { + emergency_contact_name: string; + emergency_contact_phone: string; +}; + +export type VssSubmissionPayload = { + answers: VssSubmissionAnswer[]; +}; diff --git a/backend/src/schemas/Relational/userinformation.schema.ts b/backend/src/schemas/Relational/userinformation.schema.ts index 71892ec..a2707f1 100644 --- a/backend/src/schemas/Relational/userinformation.schema.ts +++ b/backend/src/schemas/Relational/userinformation.schema.ts @@ -5,8 +5,8 @@ export const userInformationSchema = pgTable('user_informations', { user_id: integer('user_id') .primaryKey() .references(() => userSchema.id, { onDelete: 'cascade' }), - urgency_contact_name: text('urgency_contact_name'), - urgency_contact_phone: text('urgency_contact_phone'), + emergency_contact_name: text('emergency_contact_name'), + emergency_contact_phone: text('emergency_contact_phone'), }); export type UserInformation = typeof userInformationSchema.$inferSelect; diff --git a/backend/src/services/user.service.ts b/backend/src/services/user.service.ts index 6d9d65e..f764a0e 100644 --- a/backend/src/services/user.service.ts +++ b/backend/src/services/user.service.ts @@ -2,7 +2,7 @@ import bcrypt from 'bcryptjs'; import { eq } from 'drizzle-orm'; import * as randomstring from 'randomstring'; import { db } from '../database/db'; // Import de la connexion PostgreSQL -import type { AdminCreateUserDto } from '../dto/user.dto'; +import type { AdminCreateUserDto, CreateUserContactInformationDto, VssSubmissionPayload } from '../dto/user.dto'; import { type User, userSchema } from '../schemas/Basic/user.schema'; import { vssqcmquestionSchema } from '../schemas/Basic/vssqcmquestion.schema'; import { vssqcmanswerSchema } from '../schemas/Relational/vssqcmanswer.schema'; @@ -15,7 +15,6 @@ import { getFaction } from './faction.service'; import { getUserRoles } from './role.service'; import { getTeam, getTeamFaction, getUserTeam } from './team.service'; import { userInformationSchema } from '../schemas/Relational/userinformation.schema'; -import { type UserContactInformation } from '../../types/user'; import { addUserToRespondentStudentsList } from '../utils/billetweb'; import { generateEmailHtml, sendEmail } from './email.service'; import { email_from } from '../utils/secret'; @@ -38,10 +37,6 @@ export type VssSubmissionAnswer = { answerIds: number[]; }; -export type VssSubmissionPayload = { - answers: VssSubmissionAnswer[]; -}; - // Fonction pour récupérer un utilisateur par email export const getUserByEmail = async (email: string) => { try { @@ -261,8 +256,8 @@ export const getUserContactInformation = async (userId: number) => { const user = await db .select({ userId: userInformationSchema.user_id, - urgency_contact_name: userInformationSchema.urgency_contact_name, - urgency_contact_phone: userInformationSchema.urgency_contact_phone, + emergency_contact_name: userInformationSchema.emergency_contact_name, + emergency_contact_phone: userInformationSchema.emergency_contact_phone, }) .from(userInformationSchema) .where(eq(userInformationSchema.user_id, userId)); @@ -273,12 +268,12 @@ export const getUserContactInformation = async (userId: number) => { } }; -export const createUserContactInformation = async (userId: number, contact: UserContactInformation) => { +export const createUserContactInformation = async (userId: number, contact: CreateUserContactInformationDto) => { try { const newContactInfo = { user_id: userId, - urgency_contact_name: contact.urgency_contact_name, - urgency_contact_phone: contact.urgency_contact_phone, + emergency_contact_name: contact.emergency_contact_name, + emergency_contact_phone: contact.emergency_contact_phone, }; const result = await db @@ -287,8 +282,8 @@ export const createUserContactInformation = async (userId: number, contact: User .onConflictDoUpdate({ target: userInformationSchema.user_id, set: { - urgency_contact_name: contact.urgency_contact_name, - urgency_contact_phone: contact.urgency_contact_phone, + emergency_contact_name: contact.emergency_contact_name, + emergency_contact_phone: contact.emergency_contact_phone, }, }) .returning(); @@ -318,7 +313,7 @@ export const getCurrentUserOnboardingStatus = async (userId: number) => { const vssForm = user?.vss_form ?? 'pending'; return { - hasUrgencyContactInformation: Boolean(contactInformation), + hasemergencyContactInformation: Boolean(contactInformation), vss_form: vssForm, needsVssForm: vssForm === 'pending' || vssForm === 'toretry', }; diff --git a/backend/types/user.d.ts b/backend/types/user.d.ts deleted file mode 100644 index 6df16da..0000000 --- a/backend/types/user.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type UserContactInformation = { - urgency_contact_name: string; - urgency_contact_phone: string; -}; diff --git a/frontend/src/components/Admin/adminUser.tsx b/frontend/src/components/Admin/adminUser.tsx index 0b0e773..f0b632b 100644 --- a/frontend/src/components/Admin/adminUser.tsx +++ b/frontend/src/components/Admin/adminUser.tsx @@ -282,20 +282,19 @@ export const AdminUser = () => {
    - -
    - )} diff --git a/frontend/src/components/WEI_SDI_Food/sdiSection.tsx b/frontend/src/components/WEI_SDI_Food/sdiSection.tsx index bb9cc3b..38f8e59 100644 --- a/frontend/src/components/WEI_SDI_Food/sdiSection.tsx +++ b/frontend/src/components/WEI_SDI_Food/sdiSection.tsx @@ -29,7 +29,7 @@ export const SdiSection = () => { const fetchOnboardingStatus = async () => { try { const onboardingStatus = await getCurrentUserOnboardingStatus(); - setHasContactInformation(onboardingStatus.hasUrgencyContactInformation); + setHasContactInformation(onboardingStatus.hasemergencyContactInformation); setHasVssForm(onboardingStatus.vss_form == 'validated'); setNeedsVssForm(onboardingStatus.needsVssForm); } catch (error) { diff --git a/frontend/src/components/WEI_SDI_Food/weiSection.tsx b/frontend/src/components/WEI_SDI_Food/weiSection.tsx index 2e5eb51..57a888a 100644 --- a/frontend/src/components/WEI_SDI_Food/weiSection.tsx +++ b/frontend/src/components/WEI_SDI_Food/weiSection.tsx @@ -23,7 +23,7 @@ export const WeiSection = () => { const fetchOnboardingStatus = async () => { try { const onboardingStatus = await getCurrentUserOnboardingStatus(); - setHasContactInformation(onboardingStatus.hasUrgencyContactInformation); + setHasContactInformation(onboardingStatus.hasemergencyContactInformation); setHasVssForm(onboardingStatus.vss_form == 'validated'); setNeedsVssForm(onboardingStatus.needsVssForm); } catch (error) { diff --git a/frontend/src/components/home/urgencyModal.tsx b/frontend/src/components/home/emergencyModal.tsx similarity index 84% rename from frontend/src/components/home/urgencyModal.tsx rename to frontend/src/components/home/emergencyModal.tsx index 39842b4..1543fbc 100644 --- a/frontend/src/components/home/urgencyModal.tsx +++ b/frontend/src/components/home/emergencyModal.tsx @@ -7,11 +7,11 @@ import { Input } from '../ui/input'; import Modal from '../ui/modal'; import VssModal from './vssModal'; -type FlowStep = 'idle' | 'loading' | 'urgency' | 'vss'; +type FlowStep = 'idle' | 'loading' | 'emergency' | 'vss'; -function UrgencyModal() { +function EmergencyModal() { const [searchParams, setSearchParams] = useSearchParams(); - const [form, setForm] = useState({ urgency_contact_name: '', urgency_contact_phone: '' }); + const [form, setForm] = useState({ emergency_contact_name: '', emergency_contact_phone: '' }); const [flowStep, setFlowStep] = useState('idle'); const [error, setError] = useState(null); @@ -20,7 +20,7 @@ function UrgencyModal() { useEffect(() => { if (!isLogin) { setFlowStep('idle'); - setForm({ urgency_contact_name: '', urgency_contact_phone: '' }); + setForm({ emergency_contact_name: '', emergency_contact_phone: '' }); setError(null); return; } @@ -38,8 +38,8 @@ function UrgencyModal() { return; } - if (!status.hasUrgencyContactInformation) { - setFlowStep('urgency'); + if (!status.hasemergencyContactInformation) { + setFlowStep('emergency'); return; } @@ -52,7 +52,7 @@ function UrgencyModal() { setSearchParams({}); } catch { if (!cancelled) { - setFlowStep('urgency'); + setFlowStep('emergency'); setError('Impossible de récupérer le statut du formulaire.'); } } @@ -68,7 +68,7 @@ function UrgencyModal() { const closeFlow = () => { setSearchParams({}); setFlowStep('idle'); - setForm({ urgency_contact_name: '', urgency_contact_phone: '' }); + setForm({ emergency_contact_name: '', emergency_contact_phone: '' }); setError(null); }; @@ -98,7 +98,7 @@ function UrgencyModal() {
    @@ -124,13 +124,13 @@ function UrgencyModal() { )} setForm({ ...form, urgency_contact_name: e.target.value })} + value={form.emergency_contact_name} + onChange={(e) => setForm({ ...form, emergency_contact_name: e.target.value })} /> setForm({ ...form, urgency_contact_phone: e.target.value })} + value={form.emergency_contact_phone} + onChange={(e) => setForm({ ...form, emergency_contact_phone: e.target.value })} />