|
|
|
//
|
|
|
|
// Common
|
|
|
|
//
|
|
|
|
|
|
|
|
export type MetadataProps = 'id' | 'createdAt' | 'deleted'
|
|
|
|
|
|
|
|
export type Opaque<T, K, L extends string = 'opaque'> = T & { _: K; __: L }
|
|
|
|
export type Id<T> = Opaque<string, T, 'id'>
|
|
|
|
|
|
|
|
//
|
|
|
|
// Users
|
|
|
|
//
|
|
|
|
|
|
|
|
export type AdministratorRole = 'admin' | 'moderator'
|
|
|
|
export type StudentRole = 'student'
|
|
|
|
|
|
|
|
export type UserRole = AdministratorRole | StudentRole
|
|
|
|
|
|
|
|
export type UserId = Id<User>
|
|
|
|
|
|
|
|
export type User = {
|
|
|
|
id: UserId
|
|
|
|
fullName: string
|
|
|
|
|
|
|
|
role: UserRole
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isAdministrator(role: UserRole): role is AdministratorRole {
|
|
|
|
return role !== 'student'
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isStudent(role: UserRole): role is StudentRole {
|
|
|
|
return role === 'student'
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Problems
|
|
|
|
//
|
|
|
|
|
|
|
|
export type ProblemId = Id<Problem>
|
|
|
|
|
|
|
|
export type Problem = {
|
|
|
|
id: ProblemId
|
|
|
|
createdAt: string
|
|
|
|
deleted: boolean
|
|
|
|
|
|
|
|
title: string
|
|
|
|
content: string
|
|
|
|
createdBy: UserId
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Solutions
|
|
|
|
//
|
|
|
|
|
|
|
|
export type SolutionStatus = 'pending' | 'correct' | 'wrong'
|
|
|
|
|
|
|
|
export type SolutionId = Id<Solution>
|
|
|
|
|
|
|
|
export type SolutionStatMap = Record<string, SolutionStat | undefined>
|
|
|
|
|
|
|
|
export type SolutionStat = {
|
|
|
|
sentSolutionsCount: number
|
|
|
|
correctSolutionsCount: number
|
|
|
|
}
|
|
|
|
|
|
|
|
export type Solution = {
|
|
|
|
id: SolutionId
|
|
|
|
createdAt: string
|
|
|
|
deleted: boolean
|
|
|
|
|
|
|
|
sentBy: UserId
|
|
|
|
forProblem: ProblemId
|
|
|
|
content: string
|
|
|
|
status: SolutionStatus
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The _visibility status_ only applies when `status` is not "pending"
|
|
|
|
*/
|
|
|
|
visible: boolean
|
|
|
|
}
|