2021-09-11 18:47:48 +00:00
from datetime import datetime
2022-09-07 22:33:00 +00:00
from pathlib import Path
2021-09-11 18:47:48 +00:00
2022-08-09 13:50:59 +00:00
from flask import flash
2022-05-16 17:14:55 +00:00
from sqlalchemy import select
2022-02-13 18:58:05 +00:00
2023-11-01 22:18:47 +00:00
from . actions import backup
2023-11-02 17:47:52 +00:00
from . exceptions import DatabaseImportException
2022-05-08 19:26:25 +00:00
from . models import (
2022-02-13 18:58:05 +00:00
Appointment ,
Assistant ,
2021-09-11 18:47:48 +00:00
Experiment ,
2022-02-13 18:58:05 +00:00
Group ,
2021-09-11 18:47:48 +00:00
GroupExperiment ,
2022-02-13 18:58:05 +00:00
Part ,
PartStudent ,
2021-09-11 18:47:48 +00:00
Program ,
2022-02-13 18:58:05 +00:00
Semester ,
2021-09-11 18:47:48 +00:00
SemesterExperiment ,
2022-02-13 18:58:05 +00:00
Student ,
2021-09-11 18:47:48 +00:00
User ,
2022-08-09 12:46:48 +00:00
db ,
get_first ,
2021-09-11 18:47:48 +00:00
)
2022-05-07 14:48:28 +00:00
2022-05-17 23:08:07 +00:00
def is_null ( entry ) :
2023-11-02 19:04:09 +00:00
return entry in { " NULL " , " " }
2022-05-17 23:08:07 +00:00
def nullable ( entry ) :
if is_null ( entry ) :
return None
2022-09-12 17:08:02 +00:00
return entry . strip ( )
2022-05-17 23:08:07 +00:00
def not_nullable ( entry ) :
if is_null ( entry ) :
2022-09-12 17:20:01 +00:00
raise DatabaseImportException ( " Unnullable entry is NULL! " )
2022-05-17 23:08:07 +00:00
2022-09-12 17:08:02 +00:00
return entry . strip ( )
2022-05-17 23:08:07 +00:00
2022-09-07 22:33:00 +00:00
def importFromFile ( filePath : Path ) :
if filePath . name [ - 4 : ] != " .txt " :
2022-09-12 17:20:01 +00:00
raise DatabaseImportException (
2022-03-19 21:22:23 +00:00
" The import file has to be a text file with txt extension (.txt at the end of the filename)! "
2021-09-11 18:47:48 +00:00
)
semesters = { }
parts = { }
students = { }
groups = { }
partStudents = { }
experiments = { }
groupExperiments = { }
appointments = { }
2023-11-02 18:44:24 +00:00
with filePath . open ( ) as f :
2022-08-08 20:51:52 +00:00
flash ( " Reading file... " )
2021-09-11 18:47:48 +00:00
expectingTable = True
readHeader = False
for line in f :
line = line [ : - 1 ]
2022-05-17 23:08:07 +00:00
if line == " " :
2021-09-11 18:47:48 +00:00
expectingTable = True
continue
if expectingTable :
2022-05-17 23:08:07 +00:00
if line [ 0 ] != " # " :
2022-09-12 17:20:01 +00:00
raise DatabaseImportException ( f " Expected a Table name starting with # but got this line: { line } " )
2021-09-11 18:47:48 +00:00
2022-05-17 23:08:07 +00:00
expectingTable = False
tableName = line [ 1 : ]
if tableName == " Semester " :
activeDict = semesters
elif tableName == " Part " :
activeDict = parts
elif tableName == " Student " :
activeDict = students
elif tableName == " Group " :
activeDict = groups
elif tableName == " PartStudent " :
activeDict = partStudents
elif tableName == " Experiment " :
activeDict = experiments
elif tableName == " GroupExperiment " :
activeDict = groupExperiments
elif tableName == " Appointment " :
activeDict = appointments
else :
2022-09-12 17:20:01 +00:00
raise DatabaseImportException ( f " { tableName } is not a valid table name! " )
2022-05-17 23:08:07 +00:00
readHeader = True
continue
2021-09-11 18:47:48 +00:00
cells = line . split ( " \t " )
if readHeader :
readHeader = False
activeDict [ " _header " ] = cells
for cell in cells :
activeDict [ cell ] = [ ]
continue
cellsLen = len ( cells )
2022-05-17 23:08:07 +00:00
if cellsLen != len ( activeDict [ " _header " ] ) :
2022-09-12 17:20:01 +00:00
raise DatabaseImportException (
2021-09-11 18:47:48 +00:00
f " The number of header cells is not equal to the number of row cells in row { cells } ! "
)
2022-05-17 23:08:07 +00:00
for i in range ( cellsLen ) :
activeDict [ activeDict [ " _header " ] [ i ] ] . append ( cells [ i ] )
try :
2021-09-11 18:47:48 +00:00
# Semester
2022-08-08 20:51:52 +00:00
flash ( " Semester... " )
2021-09-11 18:47:48 +00:00
2022-05-17 23:08:07 +00:00
if len ( semesters [ " label " ] ) != 1 :
2022-09-12 17:20:01 +00:00
raise DatabaseImportException ( " Only one semester is allowed in an import file! " )
2021-09-11 18:47:48 +00:00
2022-05-17 23:08:07 +00:00
semesterLabel = not_nullable ( semesters [ " label " ] [ 0 ] )
semesterYear = int ( not_nullable ( semesters [ " year " ] [ 0 ] ) )
2022-05-16 20:28:09 +00:00
dbSemester = get_first ( select ( Semester ) . where ( Semester . label == semesterLabel , Semester . year == semesterYear ) )
2021-09-11 18:47:48 +00:00
2022-05-16 17:14:55 +00:00
if dbSemester is None :
2022-09-12 17:20:01 +00:00
raise DatabaseImportException (
2021-09-11 18:47:48 +00:00
f " { semesterLabel } { semesterYear } does not exist in the database! Please make sure that you create the semester from the web interface first. "
)
# Part
2022-08-08 20:51:52 +00:00
flash ( " Part... " )
2021-09-11 18:47:48 +00:00
dbParts = { }
for i , id in enumerate ( parts [ " id " ] ) :
2022-05-17 23:08:07 +00:00
id = int ( not_nullable ( id ) )
partNumber = int ( not_nullable ( parts [ " number " ] [ i ] ) )
partProgramLabel = not_nullable ( parts [ " program_label " ] [ i ] )
2022-05-16 20:28:09 +00:00
dbPart = get_first (
select ( Part )
. join ( Program )
. where (
Part . number == partNumber ,
Program . label == partProgramLabel ,
Part . semester == dbSemester ,
2022-05-16 17:14:55 +00:00
)
)
2021-09-11 18:47:48 +00:00
2022-05-16 17:14:55 +00:00
if dbPart is None :
2022-09-12 17:20:01 +00:00
raise DatabaseImportException (
2022-05-17 23:25:51 +00:00
f " Part with number { partNumber } and program label { partProgramLabel } does not exist in the database! Please make sure that you create parts from the web interface first. "
2021-09-11 18:47:48 +00:00
)
dbParts [ id ] = dbPart
# Student
2022-08-08 20:51:52 +00:00
flash ( " Student... " )
2021-09-11 18:47:48 +00:00
dbStudents = { }
2022-09-07 23:37:06 +00:00
for i , student_number in enumerate ( students [ " student_number " ] ) :
student_number = int ( not_nullable ( student_number ) )
first_name = not_nullable ( students [ " first_name " ] [ i ] )
last_name = not_nullable ( students [ " last_name " ] [ i ] )
2022-09-12 17:08:02 +00:00
uni_email = not_nullable ( students [ " uni_email " ] [ i ] ) . lower ( )
2022-09-12 17:20:01 +00:00
contact_email = nullable ( students [ " contact_email " ] [ i ] )
if contact_email is not None :
contact_email = contact_email . lower ( )
2022-09-07 23:37:06 +00:00
bachelor_thesis = nullable ( students [ " bachelor_thesis " ] [ i ] )
bachelor_thesis_work_group = nullable ( students [ " bachelor_thesis_work_group " ] [ i ] )
note = nullable ( students [ " note " ] [ i ] )
dbStudent = get_first ( select ( Student ) . where ( Student . student_number == student_number ) )
2021-09-11 18:47:48 +00:00
2022-05-16 17:14:55 +00:00
if dbStudent is None :
2021-09-11 18:47:48 +00:00
dbStudent = Student (
2022-09-07 23:37:06 +00:00
student_number = student_number ,
first_name = first_name ,
last_name = last_name ,
uni_email = uni_email ,
contact_email = contact_email ,
bachelor_thesis = bachelor_thesis ,
bachelor_thesis_work_group = bachelor_thesis_work_group ,
note = note ,
2021-09-11 18:47:48 +00:00
)
db . session . add ( dbStudent )
else :
2022-09-07 23:37:06 +00:00
# Check if columns that should not change match
if dbStudent . first_name != first_name :
2022-09-10 16:26:46 +00:00
flash (
f ' First name " { dbStudent . first_name } " in the database does not match with the first name " { first_name } " provided in the import file for the student number { student_number } . ' ,
" warning " ,
2022-09-07 23:37:06 +00:00
)
if dbStudent . last_name != last_name :
2022-09-10 16:26:46 +00:00
flash (
f ' Last name " { dbStudent . last_name } " in the database does not match with the last name " { last_name } " provided in the import file for the student number { student_number } . ' ,
" warning " ,
2022-09-07 23:37:06 +00:00
)
if dbStudent . uni_email != uni_email :
2022-09-10 16:26:46 +00:00
flash (
f ' University email " { dbStudent . uni_email } " in the database does not match with the university email " { last_name } " provided in the import file for the student number { student_number } . ' ,
" warning " ,
2022-09-07 23:37:06 +00:00
)
dbStudent . contact_email = contact_email
# Only overwrite if set
if bachelor_thesis is not None :
dbStudent . bachelor_thesis = bachelor_thesis
if bachelor_thesis_work_group is not None :
dbStudent . bachelor_thesis_work_group = bachelor_thesis_work_group
# Append to note instead of overwriting
if note is not None :
if dbStudent . note is None :
dbStudent . note = note
dbStudent . note + = " \n " + note
dbStudents [ student_number ] = dbStudent
2021-09-11 18:47:48 +00:00
# Group
2022-08-08 20:51:52 +00:00
flash ( " Group... " )
2021-09-11 18:47:48 +00:00
dbGroups = { }
for i , id in enumerate ( groups [ " id " ] ) :
2022-05-17 23:08:07 +00:00
id = int ( not_nullable ( id ) )
2022-05-16 20:28:09 +00:00
program = get_first ( select ( Program ) . where ( Program . label == not_nullable ( groups [ " program_label " ] [ i ] ) ) )
2021-09-11 18:47:48 +00:00
dbGroup = Group (
2022-05-17 23:08:07 +00:00
number = int ( not_nullable ( groups [ " number " ] [ i ] ) ) ,
2022-05-16 17:14:55 +00:00
program = program ,
2021-09-11 18:47:48 +00:00
semester = dbSemester ,
)
db . session . add ( dbGroup )
dbGroups [ id ] = dbGroup
# PartStudent
2022-08-08 20:51:52 +00:00
flash ( " PartStudent... " )
2021-09-11 18:47:48 +00:00
2022-09-07 23:37:06 +00:00
for i , student_number in enumerate ( partStudents [ " student_number " ] ) :
student_number = int ( not_nullable ( student_number ) )
2022-05-15 18:05:00 +00:00
dbPartStudent = PartStudent (
2022-09-07 23:37:06 +00:00
student = dbStudents [ student_number ] ,
2022-05-17 23:08:07 +00:00
part = dbParts [ int ( not_nullable ( partStudents [ " part_id " ] [ i ] ) ) ] ,
group = dbGroups [ int ( not_nullable ( partStudents [ " group_id " ] [ i ] ) ) ] ,
2021-09-11 18:47:48 +00:00
)
db . session . add ( dbPartStudent )
# Experiment
2022-08-08 20:51:52 +00:00
flash ( " Experiment... " )
2021-09-11 18:47:48 +00:00
dbSemesterExperiments = { }
for i , id in enumerate ( experiments [ " id " ] ) :
2022-05-17 23:08:07 +00:00
id = int ( not_nullable ( id ) )
experimentNumber = int ( not_nullable ( experiments [ " number " ] [ i ] ) )
2022-05-16 17:14:55 +00:00
2022-05-16 20:28:09 +00:00
experimentProgram = get_first (
select ( Program ) . where ( Program . label == not_nullable ( experiments [ " program_label " ] [ i ] ) )
2022-05-16 17:14:55 +00:00
)
2022-05-16 20:28:09 +00:00
dbExperiment = get_first (
select ( Experiment ) . where ( Experiment . number == experimentNumber , Experiment . program == experimentProgram )
2022-05-16 17:14:55 +00:00
)
if dbExperiment is None :
2022-05-17 23:08:07 +00:00
# TODO: Check if experimentProgram is None
2022-09-12 17:20:01 +00:00
raise DatabaseImportException (
2022-06-01 21:02:17 +00:00
f " Experiment with number { experimentNumber } and program { experimentProgram } does not exist in the database. Please make sure that experiments are created from the web interface. "
2021-09-11 18:47:48 +00:00
)
2022-05-16 20:28:09 +00:00
dbSemesterExperiment = get_first (
select ( SemesterExperiment ) . where (
SemesterExperiment . experiment == dbExperiment , SemesterExperiment . semester == dbSemester
2022-05-16 17:14:55 +00:00
)
)
2021-09-11 18:47:48 +00:00
2022-05-16 17:14:55 +00:00
if dbSemesterExperiment is None :
2022-09-12 17:20:01 +00:00
raise DatabaseImportException (
2022-06-01 21:02:17 +00:00
f " No semester experiment exists in the database to the experiment with number { experimentNumber } and program { experimentProgram } . Please make sure that semester experiments are created in the web interface. The problem might be that the experiment was not active while creating a new semester "
2021-09-11 18:47:48 +00:00
)
dbSemesterExperiments [ id ] = dbSemesterExperiment
# GroupExperiment
2022-08-08 20:51:52 +00:00
flash ( " GroupExperiment... " )
2021-09-11 18:47:48 +00:00
dbGroupExperiments = { }
for i , id in enumerate ( groupExperiments [ " id " ] ) :
2022-05-17 23:08:07 +00:00
id = int ( not_nullable ( id ) )
2022-05-15 18:59:57 +00:00
dbGroupExperiment = GroupExperiment (
2022-05-17 23:08:07 +00:00
semester_experiment = dbSemesterExperiments [ int ( not_nullable ( groupExperiments [ " experiment_id " ] [ i ] ) ) ] ,
group = dbGroups [ int ( not_nullable ( groupExperiments [ " group_id " ] [ i ] ) ) ] ,
2021-09-11 18:47:48 +00:00
)
db . session . add ( dbGroupExperiment )
dbGroupExperiments [ id ] = dbGroupExperiment
# Appointment
2022-08-08 20:51:52 +00:00
flash ( " Appointment... " )
2021-09-11 18:47:48 +00:00
for i , date in enumerate ( appointments [ " date " ] ) :
2022-05-17 23:08:07 +00:00
date = not_nullable ( date )
2022-09-12 17:08:02 +00:00
assistantEmail = not_nullable ( appointments [ " assistant_email " ] [ i ] ) . lower ( )
2022-05-16 20:28:09 +00:00
assistant = get_first ( select ( Assistant ) . join ( User ) . where ( User . email == assistantEmail ) )
2021-09-11 18:47:48 +00:00
2022-05-15 20:24:49 +00:00
if assistant is None :
2022-09-12 17:20:01 +00:00
raise DatabaseImportException (
2022-05-17 23:08:07 +00:00
f " Assistant with email { assistantEmail } does not exist in the database! Please make sure that you create assistants in the web interface. "
2021-09-11 18:47:48 +00:00
)
2022-05-15 20:24:49 +00:00
dbAppointment = Appointment (
2021-09-11 18:47:48 +00:00
date = datetime . strptime ( date , " %d . % m. % Y " ) . date ( ) ,
2022-05-17 23:08:07 +00:00
special = bool ( int ( not_nullable ( appointments [ " special " ] [ i ] ) ) ) ,
group_experiment = dbGroupExperiments [ int ( not_nullable ( appointments [ " group_experiment_id " ] [ i ] ) ) ] ,
2021-09-11 18:47:48 +00:00
assistant = assistant ,
)
db . session . add ( dbAppointment )
2023-11-01 22:18:47 +00:00
backup ( f " before_ { dbSemester } _import " )
2022-05-17 23:08:07 +00:00
db . session . commit ( )
except Exception as ex :
db . session . rollback ( )
2021-09-11 18:47:48 +00:00
2022-05-17 23:08:07 +00:00
raise ex
2022-02-13 18:58:05 +00:00
2023-11-01 22:18:47 +00:00
backup ( f " after_ { dbSemester } _import " )
2021-09-11 18:47:48 +00:00
2022-09-12 17:20:01 +00:00
flash ( " \n Import done! " , " success " )
flash ( " Please check that everything worked as expected. Restore the database backup otherwise! " , " warning " )