This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

1generator goprisma { 2 provider = "go run github.com/steebchen/prisma-client-go" 3 previewFeatures = ["fullTextSearchPostgres", "postgresqlExtensions"] 4} 5 6// See https://pothos-graphql.dev/docs/plugins/prisma#setup 7 8datasource db { 9 provider = "postgresql" 10 url = env("DATABASE_URL") 11 extensions = [fuzzystrmatch, pgcrypto, unaccent, pg_trgm] 12} 13 14/// Users are the people who use the app 15model User { 16 id String @id @default(dbgenerated("nanoid('u:'::text)")) 17 uid String @unique @db.VarChar(255) 18 createdAt DateTime @default(now()) 19 lastSeenAt DateTime @default(now()) 20 21 // School details 22 schoolServer String? @db.VarChar(255) 23 schoolUid String? @db.VarChar(255) 24 // email of the user from the school's LDAP 25 schoolEmail String? @db.VarChar(255) 26 27 email String @unique @db.VarChar(255) 28 otherEmails String[] @db.VarChar(255) 29 firstName String @db.VarChar(255) 30 lastName String @db.VarChar(255) 31 majorId String? 32 major Major? @relation(fields: [majorId], references: [id], onUpdate: Cascade, onDelete: Restrict) 33 minor Minor? @relation(fields: [minorId], references: [id]) 34 minorId String? 35 graduationYear Int 36 apprentice Boolean @default(false) 37 address String @default("") @db.VarChar(255) 38 birthday DateTime? 39 description String @default("") @db.Text 40 nickname String @default("") @db.VarChar(255) 41 pronouns String @default("") @db.VarChar(255) 42 phone String @default("") @db.VarChar(255) 43 pictureFile String @default("") @db.VarChar(255) 44 links Link[] 45 godparentId String? 46 cededImageRightsToTVn7 Boolean @default(false) 47 enabledNotificationChannels NotificationChannel[] @default([Articles, Shotguns, Permissions, GroupBoard, GodparentRequests, Comments, Other]) 48 latestVersionSeenInChangelog String @default("0.0.0") 49 bot Boolean @default(false) 50 // Not shown on profile, used to autofill Lydia payment request forms 51 lydiaPhone String @default("") @db.VarChar(255) 52 // Prevent these themes from being auto-deployed to the user 53 blockedThemes Theme[] 54 55 // Permissions 56 admin Boolean @default(false) 57 canEditGroups StudentAssociation[] @relation("studentAssociationGroupsEditor") 58 canAccessDocuments Boolean @default(false) 59 60 // Relationships 61 articles Article[] 62 groups GroupMember[] 63 credentials Credential[] 64 Reservation Registration[] @relation("author") 65 managedEvents EventManager[] 66 logs LogEntry[] 67 events Event[] 68 notificationSubscriptions NotificationSubscription[] 69 notifications Notification[] 70 godparent User? @relation("mentorship", fields: [godparentId], references: [id], onDelete: SetNull) // Le parrain ou la marraine 71 godchildren User[] @relation("mentorship") // Les filleul(e)s 72 incomingGodparentRequests GodparentRequest[] @relation("godparent") 73 outgoingGodparentRequests GodparentRequest[] @relation("godchild") 74 passwordResets PasswordReset[] 75 emailChanges EmailChange[] 76 Announcement Announcement[] 77 contributions Contribution[] 78 verifications Registration[] @relation("verifiedBy") 79 oppositions Registration[] @relation("opposedBy") 80 cancellations Registration[] @relation("cancelledBy") 81 receivedBookings Registration[] @relation("beneficiaryOf") 82 documents Document[] 83 bannedFromEvents Event[] @relation("bannedFromEvents") 84 reactions Reaction[] 85 formAnswers Answer[] 86 createdForms Form[] 87 completedForms Form[] @relation("completedForms") 88 partiallyCompletedForms Form[] @relation("partiallyCompletedForms") 89 adminOfStudentAssociations StudentAssociation[] @relation("studentAssociationAdmins") 90 bookmarks Bookmark[] 91 sharedPosts Article[] @relation("articleShares") 92 sharedEvents Event[] @relation("eventShares") 93 seenBookings Registration[] @relation("seenBy") 94 eventManagerInvites EventManagerInvite[] @relation("eventManagerInviteUses") 95 invitedToTickets Ticket[] @relation("invitedTo") 96 97 // For full-text search 98 search Unsupported("tsvector") @default(dbgenerated("''::tsvector")) 99 claimedPromotions PromotionCode[] 100 formsWithMarkedCheckboxes Form[] @relation("formsWithMarkedCheckbox") 101 createdPages Page[] 102 pointOfContactFor Registration[] @relation("pointOfContactFor") 103 104 @@unique([schoolServer, schoolUid]) 105 @@index([search], type: Gin) 106} 107 108/// A bookmarked page, used to make personal quick access links 109model Bookmark { 110 id String @id @default(dbgenerated("nanoid('bookmark:'::text)")) 111 createdAt DateTime @default(now()) 112 updatedAt DateTime @updatedAt 113 user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade) 114 userId String 115 // The path to the bookmarked page. Up to the frontend's interpretation 116 path String 117 118 @@unique([userId, path]) 119} 120 121/// Requests to become someone's godchild. Gets deleted once the request has been accepted (or denied). godchild is the requester, godparent is the requested. 122model GodparentRequest { 123 id String @id @default(dbgenerated("nanoid('godparentreq:'::text)")) 124 createdAt DateTime @default(now()) 125 updatedAt DateTime @updatedAt 126 127 godchild User @relation("godchild", fields: [godchildId], references: [id], onDelete: Cascade) 128 godchildId String 129 godparent User @relation("godparent", fields: [godparentId], references: [id], onDelete: Cascade) 130 godparentId String 131 132 @@unique([godchildId, godparentId]) 133} 134 135/// UserCandidates are users in the registration process 136model UserCandidate { 137 id String @id @default(dbgenerated("nanoid('candidate:'::text)")) 138 token String @unique 139 createdAt DateTime @default(now()) 140 141 email String @unique @db.VarChar(255) 142 emailValidated Boolean @default(false) 143 uid String @default("") @db.VarChar(255) 144 firstName String @default("") @db.VarChar(255) 145 lastName String @default("") @db.VarChar(255) 146 147 churrosPassword String @db.VarChar(255) 148 ldapPassword String @db.VarChar(255) 149 150 majorId String? 151 major Major? @relation(fields: [majorId], references: [id], onUpdate: Cascade, onDelete: Restrict) 152 graduationYear Int? 153 apprentice Boolean @default(false) 154 155 birthday DateTime? 156 cededImageRightsToTVn7 Boolean @default(false) 157 158 usingQuickSignup QuickSignup? @relation(fields: [quickSignupId], references: [id]) 159 quickSignupId String? 160} 161 162/// A password reset token 163model PasswordReset { 164 id String @id @default(dbgenerated("nanoid('passreset:'::text)")) 165 createdAt DateTime @default(now()) 166 updatedAt DateTime @updatedAt 167 user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade) 168 userId String 169 expiresAt DateTime? 170} 171 172/// A email validation request 173model EmailChange { 174 id String @id @default(dbgenerated("nanoid('emailchange:'::text)")) 175 createdAt DateTime @default(now()) 176 updatedAt DateTime @updatedAt 177 email String 178 expiresAt DateTime? 179 user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade) 180 userId String 181 pending Boolean @default(true) 182 // token is not exposed to the API, whereas id has to be 183 token String @unique @default(dbgenerated("nanoid(''::text, 30)")) 184} 185 186model QuickSignup { 187 id String @id @default(dbgenerated("nanoid('quicksignup:'::text, 6)")) 188 createdAt DateTime @default(now()) 189 updatedAt DateTime @updatedAt 190 validUntil DateTime 191 school School @relation(fields: [schoolId], references: [id], onDelete: Cascade, onUpdate: Cascade) 192 schoolId String 193 candidates UserCandidate[] 194} 195 196// Enum for the different kinds of logos 197enum LogoSourceType { 198 InternalLink 199 ExternalLink 200 GroupLogo 201 Icon 202} 203 204/// A service 205model Service { 206 id String @id @default(dbgenerated("nanoid('service:'::text)")) 207 name String @db.VarChar(255) 208 url String @default("") @db.VarChar(255) 209 description String @default("") @db.VarChar(255) 210 logo String @db.VarChar(255) 211 logoSourceType LogoSourceType 212 schoolId String? 213 school School? @relation(fields: [schoolId], references: [id], onUpdate: Cascade, onDelete: SetNull) 214 studentAssociationId String? 215 studentAssociation StudentAssociation? @relation(fields: [studentAssociationId], references: [id], onUpdate: Cascade, onDelete: SetNull) 216 groupId String? 217 group Group? @relation(fields: [groupId], references: [id], onUpdate: Cascade, onDelete: SetNull) 218 importance Int @default(0) 219 hidden Boolean @default(false) 220 221 @@unique([schoolId, studentAssociationId, groupId, url]) 222 @@unique([schoolId, studentAssociationId, groupId, name]) 223} 224 225/// A single external link 226model Link { 227 id String @id @default(dbgenerated("nanoid('link:'::text)")) 228 name String @db.VarChar(255) 229 value String @db.VarChar(255) 230 createdAt DateTime @default(now()) 231 232 // All resources that can have links 233 User User? @relation(fields: [userId], references: [id], onDelete: SetNull) 234 userId String? 235 StudentAssociation StudentAssociation? @relation(fields: [studentAssociationId], references: [id]) 236 studentAssociationId String? 237 Group Group? @relation(fields: [groupId], references: [id]) 238 groupId String? 239 Article Article? @relation(fields: [articleId], references: [id]) 240 articleId String? 241 Event Event? @relation(fields: [eventId], references: [id]) 242 eventId String? 243 Ticket Ticket? @relation(fields: [ticketId], references: [id]) 244 ticketId String? 245 Notification Notification? @relation(fields: [notificationId], references: [id]) 246 notificationId String? 247 Subject Subject? @relation(fields: [subjectId], references: [id]) 248 subjectId String? 249 250 @@unique([name, userId, studentAssociationId, groupId, articleId, eventId, ticketId, notificationId, subjectId]) 251 @@unique([userId, value]) 252 @@unique([studentAssociationId, value]) 253 @@unique([groupId, value]) 254 @@unique([articleId, value]) 255 @@unique([eventId, value]) 256 @@unique([ticketId, value]) 257 @@unique([notificationId, value]) 258 @@unique([subjectId, value]) 259} 260 261/// A school syllabus 262model Major { 263 id String @id @default(dbgenerated("nanoid('major:'::text)")) 264 uid String @unique @db.VarChar(255) 265 name String @db.VarChar(255) 266 shortName String @default("") @db.VarChar(255) 267 ldapSchoolUid String? @db.VarChar(255) 268 pictureFile String @default("") @db.VarChar(255) 269 createdAt DateTime @default(now()) 270 updatedAt DateTime @default(now()) @updatedAt 271 discontinued Boolean @default(false) 272 273 schools School[] @relation("MajorToSchool") 274 ldapSchool School? @relation("ldapSchool", fields: [ldapSchoolUid], references: [uid], onUpdate: Cascade, onDelete: SetNull) 275 students User[] 276 userCandidates UserCandidate[] 277 accessibleTickets Ticket[] 278 subjects Subject[] 279 minors Minor[] 280} 281 282model Minor { 283 id String @id @default(dbgenerated("nanoid('minor:'::text)")) 284 name String 285 shortName String @default("") 286 slug String 287 majors Major[] 288 yearTier Int 289 subjects Subject[] 290 users User[] 291 292 @@unique([slug, yearTier]) 293} 294 295model School { 296 id String @id @default(dbgenerated("nanoid('school:'::text)")) 297 uid String @unique @db.VarChar(255) 298 name String @db.VarChar(255) 299 color String @db.VarChar(7) 300 studentMailDomain String @default("") @db.VarChar(255) 301 aliasMailDomains String[] @default([]) 302 description String @default("") @db.Text 303 address String @default("") @db.VarChar(255) 304 pictureFile String @default("") @db.VarChar(255) 305 306 majors Major[] @relation("MajorToSchool") 307 majorsLdapSchool Major[] @relation("ldapSchool") 308 studentAssociations StudentAssociation[] 309 accessibleTickets Ticket[] 310 contributionOptions ContributionOption[] 311 services Service[] 312 quickSignups QuickSignup[] 313} 314 315enum CredentialType { 316 Password 317 Token 318 GroupAccessToken 319 Google // External token, used for google sheets integration (and possibly more in the future) 320} 321 322/// A credential is a way to authenticate a user 323model Credential { 324 id String @id @default(dbgenerated("nanoid('credential:'::text)")) 325 userId String? 326 groupId String? 327 name String @default("") @db.VarChar(255) 328 type CredentialType 329 value String @db.VarChar(255) 330 userAgent String @default("") @db.VarChar(255) 331 createdAt DateTime @default(now()) 332 expiresAt DateTime? 333 refresh String? @db.VarChar(255) 334 335 user User? @relation(fields: [userId], references: [id], onUpdate: Cascade, onDelete: Cascade) 336 group Group? @relation(fields: [groupId], references: [id], onUpdate: Cascade, onDelete: Cascade) 337} 338 339/// There is one student association per school 340model StudentAssociation { 341 id String @id @default(dbgenerated("nanoid('ae:'::text)")) 342 uid String @unique @db.VarChar(255) 343 description String @default("") @db.Text 344 schoolId String 345 name String @unique @db.VarChar(255) 346 links Link[] 347 pictureFile String @default("") @db.VarChar(255) 348 heroBackgroundFile String @default("") @db.VarChar(255) /// Used for the student association's homepage 349 allPrezMailingList String @default("") @db.VarChar(255) 350 allTrezMailingList String @default("") @db.VarChar(255) 351 allBoardMailingList String @default("") @db.VarChar(255) 352 internalMailDomain String @default("") @db.VarChar(255) 353 354 createdAt DateTime @default(now()) 355 updatedAt DateTime @updatedAt 356 357 school School @relation(fields: [schoolId], references: [id], onUpdate: Cascade, onDelete: Restrict) 358 groups Group[] 359 board Group? @relation("studentAssociationBoard", fields: [boardId], references: [id], onDelete: SetNull, onUpdate: Cascade) 360 boardId String? @unique 361 lydiaAccounts LydiaAccount[] 362 contributionOptions ContributionOption[] 363 services Service[] 364 admins User[] @relation("studentAssociationAdmins") 365 groupsEditors User[] @relation("studentAssociationGroupsEditor") 366 pages Page[] 367} 368 369model Contribution { 370 id String @id @default(dbgenerated("nanoid('contribution:'::text)")) 371 option ContributionOption @relation(fields: [optionId], references: [id], onDelete: Cascade, onUpdate: Cascade) 372 optionId String 373 transaction LydiaTransaction? 374 transactionId String? 375 user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade) 376 paid Boolean @default(false) 377 userId String 378 379 @@unique([optionId, userId]) 380} 381 382model ContributionOption { 383 id String @id @default(dbgenerated("nanoid('contributionoption:'::text)")) 384 offeredIn School @relation(fields: [offeredInId], references: [id], onDelete: Cascade, onUpdate: Cascade) 385 offeredInId String 386 paysFor StudentAssociation[] 387 beneficiary LydiaAccount? @relation(fields: [lydiaAccountId], references: [id], onDelete: SetNull, onUpdate: Cascade) 388 lydiaAccountId String? 389 name String 390 price Float 391 description String @default("") @db.Text 392 contributions Contribution[] 393} 394 395/// The different kinds of groups 396enum GroupType { 397 StudentAssociationSection 398 Association 399 Club 400 List 401 Integration 402 Group 403} 404 405/// A group is a collection of users 406model Group { 407 id String @id @default(dbgenerated("nanoid('g:'::text)")) 408 uid String @unique @db.VarChar(255) 409 parentId String? 410 /// Helper field to get a whole tree without processing all groups 411 /// To be set to the group's id itself for root groups. 412 familyId String? 413 studentAssociationId String 414 pictureFile String @default("") @db.VarChar(255) 415 pictureFileDark String @default("") @db.VarChar(255) 416 name String @db.VarChar(255) 417 type GroupType 418 color String @db.VarChar(7) 419 selfJoinable Boolean @default(false) 420 roomIsOpen Boolean @default(false) 421 createdAt DateTime @default(now()) 422 updatedAt DateTime @default(now()) @updatedAt 423 unlisted Boolean @default(false) 424 425 address String @default("") @db.VarChar(255) 426 description String @default("") @db.VarChar(255) 427 email String @default("") @db.VarChar(255) 428 mailingList String @default("") @db.VarChar(255) 429 longDescription String @default("") 430 website String @default("") @db.VarChar(255) 431 ldapUid String @default("") @db.VarChar(255) 432 links Link[] 433 pages Page[] 434 435 /// Parent group, from which this group inherits its permissions 436 parent Group? @relation("parent", fields: [parentId], references: [id], onUpdate: Cascade, onDelete: Restrict) 437 children Group[] @relation("parent") 438 439 /// Family root, only created for performance reasons 440 familyRoot Group? @relation("root", fields: [familyId], references: [id], onUpdate: Cascade, onDelete: Restrict) 441 familyChildren Group[] @relation("root") 442 443 /// Related clubs 444 related Group[] @relation("related") 445 relatedTo Group[] @relation("related") 446 447 articles Article[] 448 members GroupMember[] 449 studentAssociation StudentAssociation @relation(fields: [studentAssociationId], references: [id], onUpdate: Cascade, onDelete: Restrict) 450 events Event[] 451 coOrganizedEvents Event[] @relation("coOrganizer") 452 lyiaAccounts LydiaAccount[] 453 tickets Ticket[] @relation("openTo") 454 services Service[] 455 restrictedFormSections FormSection[] @relation("restrictedTo") 456 457 notifications Notification[] 458 groupId String? 459 ticketGroupId String? 460 joinedByBookingTickets Ticket[] @relation("autojoin") 461 themes Theme[] 462 defaultApplicableOffers Promotion[] @relation("defaultApplicableOffers") 463 464 // For ldap 465 ldapGidNumber Int @unique @default(autoincrement()) 466 467 // For full-text search 468 search Unsupported("tsvector") @default(dbgenerated("''::tsvector")) 469 forms Form[] 470 boardOf StudentAssociation? @relation("studentAssociationBoard") 471 boardOfId String? 472 tokens Credential[] 473 474 @@index([search], type: Gin) 475} 476 477/// The intermediate model between users 478model GroupMember { 479 groupId String 480 memberId String 481 title String @default("") @db.VarChar(255) 482 president Boolean @default(false) 483 treasurer Boolean @default(false) 484 vicePresident Boolean @default(false) 485 secretary Boolean @default(false) 486 canEditMembers Boolean @default(false) 487 canEditArticles Boolean @default(false) 488 canScanEvents Boolean @default(false) 489 isDeveloper Boolean @default(false) 490 createdAt DateTime @default(now()) 491 492 group Group @relation(fields: [groupId], references: [id], onUpdate: Cascade, onDelete: Cascade) 493 member User @relation(fields: [memberId], references: [id], onUpdate: Cascade, onDelete: Cascade) 494 495 @@id([groupId, memberId]) 496} 497 498/// An article is a post in a group 499model Article { 500 id String @id @default(dbgenerated("nanoid('a:'::text)")) 501 authorId String? 502 groupId String 503 slug String @db.VarChar(255) // TODO remove 504 title String @db.VarChar(255) 505 body String @db.Text 506 published Boolean @default(false) 507 visibility Visibility @default(Private) 508 createdAt DateTime @default(now()) 509 notifiedAt DateTime? @default(now()) // to prevent old notifications before this was added. Another migration will remove this default value. 510 publishedAt DateTime @default(now()) 511 pictureFile String @default("") @db.VarChar(255) 512 links Link[] 513 514 author User? @relation(fields: [authorId], references: [id], onUpdate: Cascade, onDelete: SetNull) 515 group Group @relation(fields: [groupId], references: [id], onUpdate: Cascade, onDelete: Cascade) 516 event Event? @relation(fields: [eventId], references: [id]) 517 eventId String? 518 reactions Reaction[] 519 sharedBy User[] @relation("articleShares") 520 521 // For full-text search 522 search Unsupported("tsvector") @default(dbgenerated("''::tsvector")) 523 524 @@index([search], type: Gin) 525} 526 527enum EventFrequency { 528 Once 529 Weekly 530 Monthly 531 Biweekly 532} 533 534/// An event is a date, time and place, as well as an optional ticket 535model Event { 536 id String @id @default(dbgenerated("nanoid('e:'::text)")) 537 createdAt DateTime @default(now()) 538 updatedAt DateTime @default(now()) @updatedAt 539 authorId String? 540 groupId String 541 contactMail String 542 beneficiary LydiaAccount? @relation(fields: [lydiaAccountId], references: [id]) 543 description String @db.Text 544 slug String @db.VarChar(255) 545 title String @db.VarChar(255) 546 // events without dates are useful when they're "drafts", but they' can't appear in the calendar - thus they're only visible by link 547 startsAt DateTime? 548 endsAt DateTime? 549 globalCapacity Int? 550 notifiedAt DateTime? @default(now()) // to prevent old notifications before this was added. Another migration will remove this default value. 551 location String @default("") @db.VarChar(255) 552 visibility Visibility 553 frequency EventFrequency @default(Once) 554 recurringUntil DateTime? 555 pictureFile String @default("") @db.VarChar(255) 556 showPlacesLeft Boolean @default(true) 557 showCapacity Boolean @default(true) 558 managers EventManager[] 559 author User? @relation(fields: [authorId], references: [id], onUpdate: Cascade, onDelete: SetNull) 560 includeInKiosk Boolean @default(false) 561 group Group @relation(fields: [groupId], references: [id]) 562 coOrganizers Group[] @relation("coOrganizer") 563 tickets Ticket[] 564 ticketGroups TicketGroup[] 565 articles Article[] 566 lydiaAccountId String? 567 links Link[] 568 bannedUsers User[] @relation("bannedFromEvents") 569 reactions Reaction[] 570 forms Form[] 571 sharedBy User[] @relation("eventShares") 572 applicableOffers Promotion[] 573 managerInvites EventManagerInvite[] 574 // enfore providing a point of contact for external bookings 575 enforcePointOfContact Boolean @default(false) 576 577 // For full-text search 578 search Unsupported("tsvector") @default(dbgenerated("''::tsvector")) 579 580 @@index([search], type: Gin) 581} 582 583enum Visibility { 584 Private 585 Unlisted 586 GroupRestricted 587 SchoolRestricted 588 Public 589} 590 591/// Used to make invite links to invite people as managers of an event 592model EventManagerInvite { 593 id String @id @default(dbgenerated("nanoid('eminvite:'::text)")) 594 createdAt DateTime @default(now()) 595 updatedAt DateTime @updatedAt 596 597 /// Maximum number of uses 598 capacity Int? 599 code String @unique 600 /// If null, should expire at the event's end date, not never expire 601 expiresAt DateTime? 602 603 eventId String 604 event Event @relation(fields: [eventId], references: [id], onDelete: Cascade) 605 606 canVerifyRegistrations Boolean @default(true) // Can scan tickets 607 canEdit Boolean @default(false) 608 canEditPermissions Boolean @default(false) 609 610 usedBy User[] @relation("eventManagerInviteUses") 611} 612 613/// An event manager is a user that can scan tickets, and may be able to manage the event 614model EventManager { 615 id String @id @default(dbgenerated("nanoid('em:'::text)")) 616 eventId String 617 userId String 618 canVerifyRegistrations Boolean @default(true) // Can scan tickets 619 canEdit Boolean @default(false) 620 canEditPermissions Boolean @default(false) 621 622 event Event @relation(fields: [eventId], references: [id], onUpdate: Cascade, onDelete: Cascade) 623 user User @relation(fields: [userId], references: [id], onUpdate: Cascade, onDelete: Cascade) 624 625 @@unique([eventId, userId]) 626} 627 628/// A ticket group allows for conditions on multiple tickets, such as an upper limit on the sum of registrations in the sub-tickets 629model TicketGroup { 630 id String @id @default(dbgenerated("nanoid('tg:'::text)")) 631 eventId String 632 name String @db.VarChar(255) 633 634 capacity Int @default(0) // 0 means unlimited, capacity is on the sum of sub-tickets registrations 635 tickets Ticket[] 636 event Event @relation(fields: [eventId], references: [id]) 637 638 @@unique([eventId, name]) 639} 640 641/// Decide when to count a ticket as counting towards the capacity 642enum TicketCountingPolicy { 643 OnBooked // Count when the ticket is booked 644 OnPaid // Count when the ticket is paid 645} 646 647/// A ticket is a way to register for an event. May include a price and conditions. 648model Ticket { 649 id String @id @default(dbgenerated("nanoid('t:'::text)")) 650 slug String 651 eventId String 652 ticketGroupId String? 653 name String @db.VarChar(255) 654 description String @db.VarChar(255) 655 opensAt DateTime? 656 closesAt DateTime? 657 minimumPrice Float 658 maximumPrice Float 659 capacity Int? 660 registrations Registration[] 661 links Link[] 662 allowedPaymentMethods PaymentMethod[] @default([]) // empty means all 663 countingPolicy TicketCountingPolicy @default(OnBooked) 664 inviteCode String? @unique 665 666 // Conditions for that ticket. 667 openToPromotions Int[] @default([]) 668 openToAlumni Boolean? @default(false) // false means only non-alumni, true means only alumni, null means both 669 openToExternal Boolean? @default(false) // same thing 670 openToContributors Boolean? // same thing 671 openToApprentices Boolean? // same thing 672 openToSchools School[] 673 openToMajors Major[] 674 openToGroups Group[] @relation("openTo") 675 godsonLimit Int @default(0) // 0 means unlimited 676 autojoinGroups Group[] @relation("autojoin") 677 678 onlyManagersCanProvide Boolean @default(false) 679 680 event Event @relation(fields: [eventId], references: [id], onUpdate: Cascade, onDelete: Cascade) 681 group TicketGroup? @relation(fields: [ticketGroupId], references: [id], onDelete: SetNull, onUpdate: Cascade) 682 Promotion Promotion? @relation(fields: [promotionId], references: [id]) 683 promotionId String? 684 invited User[] @relation("invitedTo") 685} 686 687/// A reservation is a user's registration for a ticket 688model Registration { 689 id String @id @default(dbgenerated("nanoid('r:'::text)")) 690 ticketId String 691 externalBeneficiary String? 692 internalBeneficiary User? @relation(fields: [internalBeneficiaryId], references: [id], onUpdate: Cascade, onDelete: SetNull, name: "beneficiaryOf") 693 internalBeneficiaryId String? 694 authorId String? 695 authorEmail String @default("") 696 authorName String @default("") 697 verifiedById String? 698 opposedById String? 699 cancelledById String? 700 createdAt DateTime @default(now()) 701 updatedAt DateTime @updatedAt 702 paymentMethod PaymentMethod? 703 paid Boolean @default(false) 704 wantsToPay Float? 705 // Person to refer to, especially for external beneficiaries, to handle misconducts at the event 706 pointOfContactId String? 707 pointOfContact User? @relation(fields: [pointOfContactId], references: [id], onDelete: SetNull, name: "pointOfContactFor") 708 709 lydiaTransaction LydiaTransaction? 710 paypalTransaction PaypalTransaction? 711 ticket Ticket @relation(fields: [ticketId], references: [id], onUpdate: Cascade, onDelete: Cascade) 712 author User? @relation(name: "author", fields: [authorId], references: [id], onUpdate: Cascade, onDelete: SetNull) 713 verifiedBy User? @relation(name: "verifiedBy", fields: [verifiedById], references: [id], onUpdate: Cascade, onDelete: SetNull) 714 verifiedAt DateTime? 715 opposedBy User? @relation(name: "opposedBy", fields: [opposedById], references: [id], onUpdate: Cascade, onDelete: SetNull) 716 opposedAt DateTime? 717 cancelledBy User? @relation(name: "cancelledBy", fields: [cancelledById], references: [id], onUpdate: Cascade, onDelete: SetNull) 718 cancelledAt DateTime? 719 seenBy User[] @relation(name: "seenBy") 720 formAnswer Answer? 721 722 // Those are kept in sync by a trigger, and are used for fuzzy-matching in a full text search 723 authorFullName String? @default("") @db.VarChar(255) 724 internalBeneficiaryFullName String? @default("") @db.VarChar(255) 725 search Unsupported("tsvector") @default(dbgenerated("''::tsvector")) 726 727 @@index([search], type: Gin) 728} 729 730enum PaymentMethod { 731 Lydia 732 PayPal 733 Card 734 Transfer 735 Check 736 Cash 737 External 738 Other 739} 740 741/// A log entry is a log of an action that happened on the website 742model LogEntry { 743 id String @id @default(dbgenerated("nanoid('log:'::text)")) 744 happenedAt DateTime @default(now()) 745 userId String? 746 area String @db.VarChar(255) // billeterie, gestion clubs, etc. à typer, mais pas dans la DB (pour être plus flexible) 747 action String @db.VarChar(255) 748 target String? @db.VarChar(255) 749 message String @db.Text 750 751 user User? @relation(fields: [userId], references: [id], onUpdate: Cascade, onDelete: SetNull) 752} 753 754/// A Lydia account 755model LydiaAccount { 756 id String @id @default(dbgenerated("nanoid('lydia:'::text)")) 757 groupId String? 758 group Group? @relation(fields: [groupId], references: [id], onUpdate: Cascade, onDelete: Cascade) 759 name String @default("") @db.VarChar(255) 760 privateToken String @default("") @db.VarChar(255) 761 vendorToken String @default("") @db.VarChar(255) 762 studentAssociationId String? 763 events Event[] 764 studentAssociation StudentAssociation? @relation(fields: [studentAssociationId], references: [id]) 765 ContributionOption ContributionOption[] 766 767 @@unique([privateToken, vendorToken, groupId]) 768} 769 770// Lydia payment 771model LydiaTransaction { 772 id String @id @default(dbgenerated("nanoid('lydiapayment:'::text)")) 773 phoneNumber String @default("") @db.VarChar(255) 774 registrationId String? @unique 775 registration Registration? @relation(fields: [registrationId], references: [id], onUpdate: Cascade, onDelete: Cascade) 776 shopPaymentId String? @unique 777 requestId String? 778 requestUuid String? 779 transactionId String? 780 createdAt DateTime @default(now()) 781 updatedAt DateTime @updatedAt 782 contribution Contribution? @relation(fields: [studentAssociationContributionId], references: [id], onDelete: Cascade, onUpdate: Cascade) 783 studentAssociationContributionId String? @unique 784 paidCallback String? 785} 786 787enum PayPalTransactionStatus { 788 Created 789 Saved 790 Approved 791 Voided 792 Completed 793 PayerActionRequired 794} 795 796/// Paypal payment 797model PaypalTransaction { 798 id String @id @default(dbgenerated("nanoid('paypalpayment:'::text)")) 799 emailAddress String @default("") @db.VarChar(255) 800 registrationId String? @unique 801 registration Registration? @relation(fields: [registrationId], references: [id], onUpdate: Cascade, onDelete: Cascade) 802 status PayPalTransactionStatus? 803 804 /// PayPal's order ID. 805 orderId String? 806 createdAt DateTime @default(now()) 807 updatedAt DateTime @updatedAt 808} 809 810/// A NotificationSubscription stores a user's subscription to push notifications on a user agent 811model NotificationSubscription { 812 id String @id @default(dbgenerated("nanoid('notifsub:'::text)")) 813 name String @default("") @db.VarChar(255) 814 createdAt DateTime @default(now()) 815 updatedAt DateTime @updatedAt 816 owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade, onUpdate: Cascade) 817 ownerId String 818 endpoint String @unique 819 expiresAt DateTime? 820 authKey String 821 p256dhKey String 822 notifications Notification[] 823} 824 825/// A notification is a push notification that was sent to a user 826model Notification { 827 id String @id @default(dbgenerated("nanoid('notif:'::text)")) 828 createdAt DateTime @default(now()) 829 updatedAt DateTime @updatedAt 830 timestamp DateTime? 831 subscription NotificationSubscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade, onUpdate: Cascade) 832 subscriptionId String 833 image String @default("") 834 actions Link[] 835 title String @db.VarChar(255) 836 imageFile String @default("") 837 body String @db.Text 838 vibrate Int[] @default([]) 839 group Group? @relation(fields: [groupId], references: [id], onDelete: SetNull, onUpdate: Cascade) 840 groupId String? 841 channel NotificationChannel @default(Other) 842 user User? @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade) 843 userId String? 844 goto String @default("") 845} 846 847/// A NotificationChannel represents the different kinds of reasons why you might receive a notification: a shotgun just opened, etc. 848enum NotificationChannel { 849 Articles 850 Shotguns 851 Permissions 852 GroupBoard 853 GodparentRequests 854 Comments 855 Mandatory 856 Other // should't be used too much 857} 858 859/// Announcement is a way to get a message accross the entire site, such as for maintenance announcements. 860model Announcement { 861 id String @id @default(dbgenerated("nanoid('ann:'::text)")) 862 by User? @relation(fields: [userId], references: [id], onDelete: SetNull, onUpdate: Cascade) 863 userId String? 864 title String @db.VarChar(255) 865 body String @db.Text 866 warning Boolean 867 createdAt DateTime @default(now()) 868 updatedAt DateTime @updatedAt 869 startsAt DateTime 870 endsAt DateTime 871} 872 873model TeachingUnit { 874 id String @id @default(dbgenerated("nanoid('ue:'::text)")) 875 name String @db.VarChar(255) 876 shortName String @default("") @db.VarChar(255) 877 apogeeCode String? @db.VarChar(255) 878 subjects Subject[] 879} 880 881model Subject { 882 id String @id @default(dbgenerated("nanoid('subj:'::text)")) 883 name String 884 slug String 885 shortName String @default("") @db.VarChar(255) 886 yearTier Int? 887 forApprentices Boolean @default(false) 888 links Link[] 889 apogeeCode String? @db.VarChar(255) 890 unitId String? 891 unit TeachingUnit? @relation(fields: [unitId], references: [id], onDelete: SetNull, onUpdate: Cascade) 892 nextExamAt DateTime? 893 majors Major[] 894 minors Minor[] 895 documents Document[] 896 // 1 for the first semester, 2 for the second one. Null means both 897 semester Int? 898 emoji String @default("") @db.VarChar(4) 899 900 @@unique([slug, yearTier, forApprentices]) 901} 902 903enum DocumentType { 904 // Graded 905 Exam // Partiel 906 PracticalExam // BE 907 GradedExercises // DM 908 909 // Ungraded 910 Exercises // TD 911 Practical // TP 912 CourseNotes // CM 913 CourseSlides // Diapos 914 Summary // Fiche de rev, Fiche 915 916 Miscellaneous // Divers 917} 918 919model Document { 920 id String @id @default(dbgenerated("nanoid('doc:'::text)")) 921 slug String 922 createdAt DateTime @default(now()) 923 updatedAt DateTime @updatedAt 924 schoolYear Int // stored using the school year start's year 925 926 title String 927 description String @db.Text 928 // Null subject means the document needs to be sorted 929 subject Subject? @relation(fields: [subjectId], references: [id], onDelete: Cascade, onUpdate: Cascade) 930 subjectId String? 931 type DocumentType 932 paperPaths String[] // le sujet 933 solutionPaths String[] // la correction 934 935 uploader User? @relation(fields: [uploaderId], references: [id], onDelete: SetNull, onUpdate: Cascade) 936 uploaderId String? 937 938 reactions Reaction[] 939 940 search Unsupported("tsvector") @default(dbgenerated("''::tsvector")) 941 942 @@unique([subjectId, slug]) 943 @@index([search], type: Gin) 944} 945 946model Reaction { 947 id String @id @default(dbgenerated("nanoid('reac:'::text)")) 948 emoji String 949 950 createdAt DateTime @default(now()) 951 updatedAt DateTime @updatedAt 952 author User? @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade) 953 authorId String? 954 955 document Document? @relation(fields: [documentId], references: [id], onDelete: Cascade, onUpdate: Cascade) 956 documentId String? 957 article Article? @relation(fields: [articleId], references: [id], onDelete: Cascade, onUpdate: Cascade) 958 articleId String? 959 event Event? @relation(fields: [eventId], references: [id], onDelete: Cascade, onUpdate: Cascade) 960 eventId String? 961 962 @@unique([emoji, authorId, documentId]) 963 @@unique([emoji, authorId, articleId]) 964 @@unique([emoji, authorId, eventId]) 965} 966 967enum PromotionType { 968 SIMPPS 969 // More to come... 970} 971 972model PromotionCode { 973 id String @id @default(dbgenerated("nanoid('promocode:'::text)")) 974 createdAt DateTime @default(now()) 975 updatedAt DateTime @updatedAt 976 claimedAt DateTime? 977 code String @unique 978 claimedBy User? @relation(fields: [claimedById], references: [id], onDelete: Cascade) 979 claimedById String? 980 promotion Promotion @relation(fields: [promotionId], references: [id], onDelete: Cascade) 981 promotionId String 982} 983 984model Promotion { 985 id String @id @default(dbgenerated("nanoid('promo:'::text)")) 986 createdAt DateTime @default(now()) 987 updatedAt DateTime @updatedAt 988 validUntil DateTime? 989 type PromotionType 990 codes PromotionCode[] 991 validOn Ticket[] 992 validByDefaultOn Group[] @relation("defaultApplicableOffers") 993 994 priceOverride Int 995 events Event[] 996} 997 998model Form { 999 id String @id @default(dbgenerated("nanoid('form:'::text)")) 1000 createdAt DateTime @default(now()) 1001 updatedAt DateTime @updatedAt 1002 createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull, onUpdate: Cascade) 1003 createdById String? 1004 visibility Visibility 1005 groupId String? 1006 group Group? @relation(fields: [groupId], references: [id], onDelete: Cascade, onUpdate: Cascade) 1007 1008 event Event? @relation(fields: [eventId], references: [id], onDelete: SetNull, onUpdate: Cascade) 1009 eventId String? 1010 1011 opensAt DateTime? 1012 closesAt DateTime? 1013 title String @db.VarChar(255) 1014 description String @db.Text 1015 sections FormSection[] 1016 answeredBy User[] @relation("completedForms") 1017 partiallyAnsweredBy User[] @relation("partiallyCompletedForms") 1018 allowEditingAnswers Boolean @default(true) 1019 // Pretty specific use-case: manually marking or un-marking answers from the answer list for each user. Used for votes that can be both online and offline. 1020 enableAnswersCompletionCheckbox Boolean @default(false) 1021 markedCheckboxes User[] @relation("formsWithMarkedCheckbox") 1022 restrictToPromotions Int[] 1023 contributorsOnly Boolean @default(false) 1024 1025 // For full-text search 1026 search Unsupported("tsvector") @default(dbgenerated("''::tsvector")) 1027 linkedGoogleSheetId String? 1028 1029 @@index([search], type: Gin) 1030} 1031 1032model FormSection { 1033 id String @id @default(dbgenerated("nanoid('formsection:'::text)")) 1034 order Int 1035 form Form @relation(fields: [formId], references: [id], onDelete: Cascade) 1036 formId String 1037 title String @db.VarChar(255) 1038 description String @db.Text 1039 questions Question[] 1040 1041 /// Conditions 1042 1043 restrictedToGroups Group[] @relation("restrictedTo") 1044 jumps FormJump[] 1045 1046 @@unique([formId, order]) 1047} 1048 1049/// Represent a jump condition: answering a certain value of a certain question changes what section of the form is shown next 1050model FormJump { 1051 id String @id @default(dbgenerated("nanoid('formjump:'::text)")) 1052 question Question @relation(fields: [questionId], references: [id], onDelete: Cascade) 1053 questionId String 1054 value String 1055 target FormSection @relation(fields: [targetId], references: [id], onDelete: Cascade, onUpdate: Cascade) 1056 targetId String 1057} 1058 1059model Question { 1060 id String @id @default(dbgenerated("nanoid('question:'::text)")) 1061 section FormSection @relation(fields: [sectionId], references: [id], onDelete: Cascade, onUpdate: Cascade) 1062 sectionId String 1063 order Int 1064 1065 title String @db.VarChar(255) 1066 description String @db.Text 1067 type QuestionKind 1068 mandatory Boolean @default(false) 1069 anonymous Boolean @default(false) 1070 1071 options String[] @default([]) 1072 scaleStart Int? 1073 scaleEnd Int? 1074 allowOptionOther Boolean @default(false) 1075 allowedFiletypes String[] @default([]) // empty means all 1076 1077 // See Answer 1078 defaultAnswer String[] 1079 1080 answers Answer[] 1081 jumps FormJump[] 1082 1083 @@unique([sectionId, order]) 1084} 1085 1086enum QuestionKind { 1087 Text 1088 LongText 1089 SelectOne 1090 SelectMultiple 1091 FileUpload 1092 // In scale, options has two values, the labels of the start and end of the scale 1093 Scale 1094 Number 1095 Date 1096 Time 1097} 1098 1099model Answer { 1100 id String @id @default(dbgenerated("nanoid('answer:'::text)")) 1101 question Question @relation(fields: [questionId], references: [id], onDelete: Cascade) 1102 questionId String 1103 1104 createdAt DateTime @default(now()) 1105 updatedAt DateTime @updatedAt 1106 1107 createdBy User? @relation(fields: [createdById], references: [id], onDelete: Cascade, onUpdate: Cascade) 1108 createdById String? 1109 1110 /// Only the first value is considered for all types except SelectMultiple. 1111 /// Can be empty if the user didn't answer the question (when it wasn't mandatory, for example) 1112 answer String[] 1113 1114 /// Data to link back to an event booking 1115 booking Registration? @relation(fields: [bookingId], references: [id], onDelete: SetNull, onUpdate: Cascade) 1116 bookingId String? @unique 1117 1118 // For full-text search 1119 search Unsupported("tsvector") @default(dbgenerated("''::tsvector")) 1120 1121 // For now, users can answer only once to every question 1122 @@unique([questionId, createdById]) 1123 @@index([search], type: Gin) 1124} 1125 1126/// A user-defined markdown page, useful for custom pages, only liked to student associations for now. 1127model Page { 1128 id String @id @default(dbgenerated("nanoid('page:'::text)")) 1129 1130 // Paths are unique per linked resource, final URL of the page should therefore be namespaced 1131 path String @db.VarChar(255) 1132 title String @db.VarChar(255) 1133 body String @db.Text 1134 createdAt DateTime @default(now()) 1135 updatedAt DateTime @updatedAt 1136 lastAuthor User? @relation(fields: [lastAuthorId], references: [id], onDelete: SetNull, onUpdate: Cascade) 1137 lastAuthorId String? 1138 studentAssociation StudentAssociation? @relation(fields: [studentAssociationId], references: [id], onDelete: Cascade, onUpdate: Cascade) 1139 studentAssociationId String? 1140 group Group? @relation(fields: [groupId], references: [id], onDelete: SetNull, onUpdate: Cascade) 1141 groupId String? 1142 /// Paths to files that are included on that page (relative to the storage root as always) 1143 files String[] 1144 // For full-text search 1145 search Unsupported("tsvector") @default(dbgenerated("''::tsvector")) 1146 1147 @@unique([studentAssociationId, path]) 1148 @@unique([groupId, path]) 1149 @@index([search], type: Gin) 1150} 1151 1152// UIDs that should never be considered free 1153model BlockedUid { 1154 uid String @id 1155} 1156 1157model Theme { 1158 id String @id @default(dbgenerated("nanoid('theme:'::text)")) 1159 name String @db.VarChar(255) 1160 values ThemeValue[] 1161 createdAt DateTime @default(now()) 1162 updatedAt DateTime @updatedAt 1163 visibility Visibility @default(Private) 1164 startsAt DateTime? @default(now()) 1165 endsAt DateTime? 1166 author Group? @relation(fields: [authorId], references: [id], onDelete: SetNull, onUpdate: Cascade) 1167 authorId String? 1168 1169 // Auto-change people's theme to this one when it's visible to them 1170 autodeploy Boolean @default(false) 1171 blockedBy User[] 1172} 1173 1174enum ThemeVariant { 1175 Light 1176 Dark 1177 // Might add more stuff, like "High contrast light, high contrast dark", etc 1178} 1179 1180enum ThemeVariable { 1181 ColorBackground 1182 ColorBackground2 1183 ColorBackground3 1184 ColorBackground4 1185 ColorShy 1186 ColorMuted 1187 ColorForeground 1188 ColorPrimary 1189 ColorSuccess 1190 ColorDanger 1191 ColorWarning 1192 ColorPrimaryBackground 1193 ColorSuccessBackground 1194 ColorDangerBackground 1195 ColorWarningBackground 1196 ImageLogoNavbarTop 1197 ImageLogoNavbarSide 1198 ImageBackgroundNavbarBottom 1199 ImageBackgroundNavbarTop 1200 PatternBackground 1201} 1202 1203model ThemeValue { 1204 id String @id @default(dbgenerated("nanoid('themeval:'::text)")) 1205 variable ThemeVariable 1206 value String @db.VarChar(500) 1207 theme Theme @relation(fields: [themeId], references: [id], onDelete: Cascade, onUpdate: Cascade) 1208 themeId String 1209 variant ThemeVariant @default(Light) 1210 1211 @@unique([themeId, variant, variable]) 1212}