diff --git a/.gitignore b/.gitignore index 4314885..2da2c94 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ __pycache__ .vscode advLab.db server_setup.md -db_backups \ No newline at end of file +db_backups +import_files \ No newline at end of file diff --git a/advlabdb/adminModelViews.py b/advlabdb/adminModelViews.py index bcce772..f0e9643 100644 --- a/advlabdb/adminModelViews.py +++ b/advlabdb/adminModelViews.py @@ -1,18 +1,23 @@ -from flask import flash, request, url_for +from flask import flash, request, url_for, redirect from flask_admin.contrib.sqla.fields import QuerySelectField, QuerySelectMultipleField from flask_admin.contrib.sqla.filters import BaseSQLAFilter from flask_admin.helpers import get_form_data from flask_admin.menu import MenuLink from flask_admin.model.template import EndpointLinkRowAction +from flask_admin import expose from flask_security import admin_change_password, current_user, hash_password from sqlalchemy import func, or_, and_ from wtforms import BooleanField, Form, RadioField, SelectField, TextField from wtforms.fields.html5 import DateField, IntegerField from wtforms.validators import URL, DataRequired, Email, NumberRange, Optional +from flask_wtf import FlaskForm +from flask_wtf.file import FileField, FileRequired, FileAllowed +from werkzeug.utils import secure_filename +from pathlib import Path from advlabdb import adminSpace, app, assistantSpace, db, user_datastore from advlabdb.configUtils import getConfig -from advlabdb.customClasses import SecureAdminModelView +from advlabdb.customClasses import SecureAdminModelView, SecureAdminBaseView from advlabdb.exceptions import DataBaseException, ModelViewException from advlabdb.models import ( Appointment, @@ -36,6 +41,7 @@ from advlabdb.utils import ( setUserActiveSemester, userActiveSemester, ) +from advlabdb.database_import import importFromFile def semesterExperimentQueryFactory(): @@ -775,6 +781,38 @@ class ProgramView(SecureAdminModelView): column_details_list = column_list + form_excluded_columns +class ImportView(SecureAdminBaseView): + class FileForm(FlaskForm): + file = FileField( + label="Import file", + validators=[FileRequired(), FileAllowed(["txt"], "Only txt files are allowed!")], + description="The import file has to be a text file (with .txt at the end) encoded in UTF-8. It has to strictly follow the required format.", + ) + + @expose("/", methods=["GET", "POST"]) + def index(self): + form = ImportView.FileForm() + + if form.validate_on_submit(): + f = form.file.data + filename = secure_filename(f.filename) + + directory = "import_files" + Path(directory).mkdir(exist_ok=True) + + filePath = directory + f"/{filename}" + f.save(filePath) + + try: + importFromFile(filePath) + except Exception as exc: + flash(str(exc), "error") + + return redirect(url_for("index")) + + return self.render("import.html", form=form) + + adminSpace.add_view(StudentView(Student, db.session)) adminSpace.add_view(PartStudentView(PartStudent, db.session)) adminSpace.add_view(GroupView(Group, db.session)) @@ -789,5 +827,6 @@ adminSpace.add_view(AssistantView(Assistant, db.session)) adminSpace.add_view(UserView(User, db.session)) adminSpace.add_view(RoleView(Role, db.session)) adminSpace.add_view(ProgramView(Program, db.session)) +adminSpace.add_view(ImportView(name="Import")) initActiveSemesterMenuLinks(adminSpace) diff --git a/advlabdb/templates/import.html b/advlabdb/templates/import.html new file mode 100644 index 0000000..8e2a89b --- /dev/null +++ b/advlabdb/templates/import.html @@ -0,0 +1,9 @@ +{% extends "admin/master.html" %} + +{% block body %} +
+ {{ form.csrf_token }} + {{ form.file }} + +
+{% endblock body %} \ No newline at end of file