2021-09-11 18:47:48 +00:00
from datetime import datetime
2022-05-07 14:48:28 +00:00
from os import environ
from pathlib import Path
2021-09-11 18:47:48 +00:00
from shutil import copy2
2022-02-13 18:58:05 +00:00
from flask import flash , has_request_context
2022-05-16 17:14:55 +00:00
from sqlalchemy import select
2022-02-13 18:58:05 +00:00
2022-05-08 19:26:25 +00:00
from . import db
from . exceptions import DataBaseImportException
2022-05-16 20:28:09 +00:00
from . model_independent_funs import get_first
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-05-07 14:48:28 +00:00
relative_db_dir = Path ( environ [ " RELATIVE_DB_DIR " ] )
2022-05-17 23:08:07 +00:00
relative_db_path = relative_db_dir / " advlab.db "
2022-05-07 14:48:28 +00:00
relative_db_bk_dir = relative_db_dir / " backups "
relative_db_bk_dir . mkdir ( exist_ok = True )
def now ( ) :
return datetime . now ( ) . strftime ( " %d _ % m_ % Y_ % H_ % M_ % S " )
2021-09-11 18:47:48 +00:00
2022-05-17 23:08:07 +00:00
def is_null ( entry ) :
return entry == " NULL " or entry == " "
def nullable ( entry ) :
if is_null ( entry ) :
return None
return entry
def not_nullable ( entry ) :
if is_null ( entry ) :
raise DataBaseImportException ( " Unnullable entry is NULL! " )
return entry
2021-09-11 18:47:48 +00:00
def importFromFile ( filePath ) :
if filePath [ - 4 : ] != " .txt " :
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
)
2022-05-17 23:08:07 +00:00
if has_request_context ( ) :
show = flash
else :
show = print
2021-09-11 18:47:48 +00:00
semesters = { }
parts = { }
students = { }
groups = { }
partStudents = { }
experiments = { }
groupExperiments = { }
appointments = { }
2022-05-17 23:08:07 +00:00
with open ( filePath , " r " ) as f :
2021-09-11 18:47:48 +00:00
show ( " Reading file... " )
expectingTable = True
readHeader = False
activeDict = None
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 ] != " # " :
2021-09-11 18:47:48 +00:00
raise DataBaseImportException ( f " Expected a Table name starting with # but got this line: { line } " )
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 :
raise DataBaseImportException ( f " { tableName } is not a valid table name! " )
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 " ] ) :
2021-09-11 18:47:48 +00:00
raise DataBaseImportException (
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
show ( " Semester... " )
2022-05-17 23:08:07 +00:00
if len ( semesters [ " label " ] ) != 1 :
2021-09-11 18:47:48 +00:00
raise DataBaseImportException ( " Only one semester is allowed in an import file! " )
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 :
2021-09-11 18:47:48 +00:00
raise DataBaseImportException (
f " { semesterLabel } { semesterYear } does not exist in the database! Please make sure that you create the semester from the web interface first. "
)
# Part
show ( " Part... " )
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 :
2021-09-11 18:47:48 +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
show ( " Student... " )
dbStudents = { }
for i , studentNumber in enumerate ( students [ " student_number " ] ) :
2022-05-17 23:08:07 +00:00
studentNumber = int ( not_nullable ( studentNumber ) )
2022-05-16 20:28:09 +00:00
dbStudent = get_first ( select ( Student ) . where ( Student . student_number == studentNumber ) )
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 (
student_number = studentNumber ,
2022-05-17 23:08:07 +00:00
first_name = not_nullable ( students [ " first_name " ] [ i ] ) ,
last_name = not_nullable ( students [ " last_name " ] [ i ] ) ,
uni_email = not_nullable ( students [ " uni_email " ] [ i ] ) ,
contact_email = nullable ( students [ " contact_email " ] [ i ] ) ,
bachelor_thesis = nullable ( students [ " bachelor_thesis " ] [ i ] ) ,
bachelor_thesis_work_group = nullable ( students [ " bachelor_thesis_work_group " ] [ i ] ) ,
note = nullable ( students [ " note " ] [ i ] ) ,
2021-09-11 18:47:48 +00:00
)
db . session . add ( dbStudent )
else :
2022-05-17 23:08:07 +00:00
dbStudent . contact_email = nullable ( students [ " contact_email " ] [ i ] )
dbStudent . bachelor_thesis = nullable ( students [ " bachelor_thesis " ] [ i ] )
dbStudent . bachelor_thesis_work_group = nullable ( students [ " bachelor_thesis_work_group " ] [ i ] )
dbStudent . note = nullable ( students [ " note " ] [ i ] )
2021-09-11 18:47:48 +00:00
dbStudents [ studentNumber ] = dbStudent
# Group
show ( " Group... " )
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
show ( " PartStudent... " )
for i , studentNumber in enumerate ( partStudents [ " student_number " ] ) :
2022-05-17 23:08:07 +00:00
studentNumber = int ( not_nullable ( studentNumber ) )
2022-05-15 18:05:00 +00:00
dbPartStudent = PartStudent (
2021-09-11 18:47:48 +00:00
student = dbStudents [ studentNumber ] ,
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
show ( " Experiment... " )
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
2021-09-11 18:47:48 +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 :
2021-09-11 18:47:48 +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
show ( " GroupExperiment... " )
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
show ( " Appointment... " )
for i , date in enumerate ( appointments [ " date " ] ) :
2022-05-17 23:08:07 +00:00
date = not_nullable ( date )
assistantEmail = not_nullable ( appointments [ " assistant_email " ] [ i ] )
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 :
2021-09-11 18:47:48 +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 )
# Backup
2022-06-01 21:02:17 +00:00
dest = relative_db_bk_dir / f " before_ { dbSemester } _import_ { now ( ) } .db "
2022-05-07 14:48:28 +00:00
copy2 ( relative_db_path , dest )
2021-09-11 18:47:48 +00:00
2022-05-17 23:08:07 +00:00
show ( f " Made a backup of the database before commiting the import at { dest } " )
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
2022-06-01 21:02:17 +00:00
dest = relative_db_bk_dir / f " after_ { dbSemester } _import_ { now ( ) } .db "
2022-05-07 14:48:28 +00:00
copy2 ( relative_db_path , dest )
2021-09-11 18:47:48 +00:00
show ( f " Made a backup of the database after the import at { dest } " )
show ( " \n Import done! " )
show ( " Please check that everything worked as expected. Restore the database backup otherwise! " )