import Colle from '#models/colle'
import Examiner from '#models/examiner'
import Room from '#models/room'
import Subject from '#models/subject'
import User from '#models/user'
export class ColleService {
async getStudent(studentName: string, className: string) {
// Find or create a student by name
const { firstName, lastName } = this.splitNames(studentName)
const student = await User.query()
.where('first_name', firstName)
.where('last_name', lastName)
.where('class_name', className)
.first()
if (!student) {
return User.create({ firstName, lastName, className })
}
return student
}
splitNames(fullName: string): { firstName: string; lastName: string } {
const words = fullName.trim().split(/\s+/)
let lastNameParts: string[] = []
let i = 0
// Collect all uppercase words at the start
while (i < words.length && words[i] === words[i].toUpperCase()) {
lastNameParts.push(words[i])
i++
}
const lastName = lastNameParts.join(' ')
const firstName = words.slice(i).join(' ')
return { firstName, lastName }
}
async getExaminer(examinerName: string) {
// Find or create an examiner by name
const examiner = await Examiner.query().where('name', examinerName).first()
if (!examiner) return Examiner.create({ name: examinerName })
return examiner
}
async getSubject(subjectName: string) {
// Find or create a subject by name
const subject = await Subject.query().where('name', subjectName).first()
if (!subject) return Subject.create({ name: subjectName })
return subject
}
async getRoom(roomName: string) {
// Find or create a room by name
const room = await Room.query().where('name', roomName).first()
if (!room) return Room.create({ name: roomName })
return room
}
async getColles(student: User, startDate: string, endDate: string) {
const classColles = await Colle.query()
.preload('student')
.preload('examiner')
.preload('subject')
.preload('room')
.where('date', '>=', startDate)
.where('date', '<=', endDate)
.whereHas('student', (query) => {
query.where('className', student.className)
})
// Filter only colles that have been graded
.whereNotNull('grade')
.orderBy('date', 'asc')
const studentColles = await Colle.query()
.preload('examiner')
.preload('subject')
.preload('room')
.preload('student')
.where('date', '>=', startDate)
.where('date', '<=', endDate)
.where('studentId', student.id)
.orderBy('date', 'asc')
// TODO: Favorite colles
const favoriteColles = [] as Colle[]
return {
classColles,
studentColles,
favoriteColles,
}
}
// Pre-process HTML content to render LaTeX
private removeTrailingLines(htmlString: string) {
return htmlString.replace(/(
\s*)+$/gi, '').trim()
}
private extractLatexImages(html: string) {
const imgRegex = /
]+src="(https:\/\/latex\.codecogs\.com\/gif\.latex\?(=?.*?))"[^>]*>/g
let parts = []
let latexMatches: string[] = []
let lastIndex = 0
html.replace(imgRegex, (match, _, latex, index) => {
parts.push(html.slice(lastIndex, index)) // Add HTML before image
latexMatches.push(decodeURIComponent(latex)) // Extract and decode LaTeX
lastIndex = index + match.length
return ''
})
parts.push(html.slice(lastIndex)) // Add remaining HTML after last image
return { parts, latexMatches }
}
prepareHtmlForRendering(html: string) {
const strippedHtml = this.removeTrailingLines(html)
const { parts, latexMatches } = this.extractLatexImages(strippedHtml)
const outputHtml = parts
.map((part, i) => {
if (!latexMatches[i]) {
return part
}
return `${part}$$${latexMatches[i]}$$`
})
.join('')
// Remove all "\," from string
const regex = /\\,/g
return outputHtml.replace(regex, ' ')
}
}