add black, isort and flake8 package, format code, fix examination schedule and enrollments functionality, add chairman of committee field for TermOfDefence entity
This commit is contained in:
parent
038f9da93d
commit
40274dc8d7
@ -25,8 +25,24 @@ Run tests
|
||||
```bash
|
||||
pytest
|
||||
```
|
||||
|
||||
Run all tests in specific python module
|
||||
```bash
|
||||
pytest ./tests/unit_tests/test_file.py
|
||||
```
|
||||
|
||||
Run one test inside of python module
|
||||
```bash
|
||||
pytest ./tests/unit_tests/test_file.py::test_function_name
|
||||
```
|
||||
***
|
||||
|
||||
### Format code:
|
||||
```bash
|
||||
black path/to/file.py
|
||||
isort path/to/file.py
|
||||
flake8
|
||||
```
|
||||
### Useful commands:
|
||||
Add new package
|
||||
```bash
|
||||
@ -45,15 +61,19 @@ flask startapp NAME_OF_APP
|
||||
```
|
||||
Above command create package structure:
|
||||
\
|
||||
Create serializer in `__schemas__.py` file:
|
||||
Create serializer in `schemas.py` file:
|
||||
```python3
|
||||
class ExampleSchema(ma.SQLAlchemyAutoSchema):
|
||||
class Meta:
|
||||
model = MODEL_NAME
|
||||
from marshmallow import Schema, fields
|
||||
|
||||
class ExampleSchema(Schema):
|
||||
id = fields.Integer()
|
||||
name = fields.Str()
|
||||
```
|
||||
\
|
||||
Create models in `__models__.py` file:
|
||||
Create models in `models.py` file:
|
||||
```python3
|
||||
from ..dependencies import db
|
||||
|
||||
class Example(db.Model):
|
||||
__tablename__ = "examples"
|
||||
|
||||
@ -61,7 +81,7 @@ class Example(db.Model):
|
||||
title = db.Column(db.String(255), unique=True)
|
||||
```
|
||||
\
|
||||
Create api routes in ```__routes__.py``` file. You only have to register blueprint in `app/__init__.py`.
|
||||
Create api routes in ```routes.py``` file. You only have to register blueprint in `app/__init__.py`.
|
||||
```python3
|
||||
from flask import Blueprint, make_response, jsonify, Response
|
||||
|
||||
|
@ -1,26 +1,26 @@
|
||||
import os
|
||||
|
||||
from apiflask import APIFlask
|
||||
from flask_migrate import Migrate
|
||||
from flask_cors import CORS
|
||||
from flask_migrate import Migrate
|
||||
|
||||
from .api import api_bp
|
||||
from .commands.clear_db import clear_db
|
||||
from .commands.startapp import startapp
|
||||
from .config import config
|
||||
from .dependencies import db, ma
|
||||
from .commands.startapp import startapp
|
||||
from .commands.clear_db import clear_db
|
||||
from .utils import import_models
|
||||
from .api import api_bp
|
||||
from .errors import register_error_handlers
|
||||
from .utils import import_models
|
||||
|
||||
|
||||
def create_app(config_name: str = '') -> APIFlask:
|
||||
def create_app(config_name: str = "") -> APIFlask:
|
||||
if config_name is None:
|
||||
config_name = os.environ.get("FLASK_ENV")
|
||||
|
||||
app = APIFlask(__name__, docs_path='/')
|
||||
app = APIFlask(__name__, docs_path="/")
|
||||
app.config.from_object(config.get(config_name) or config.get("development"))
|
||||
|
||||
if app.config['ENABLE_CORS']:
|
||||
if app.config["ENABLE_CORS"]:
|
||||
CORS(app)
|
||||
|
||||
db.init_app(app)
|
||||
|
@ -1,10 +1,11 @@
|
||||
from flask import Blueprint
|
||||
|
||||
from .coordinator.routes import bp as coordinator_bp
|
||||
from .examination_schedule.routes import bp as examination_schedules_bp
|
||||
from .project_supervisor.routes import bp as project_supervisor_bp
|
||||
from .students.routes import bp as students_bp
|
||||
from .examination_schedule.routes import bp as examination_schedules_bp
|
||||
|
||||
api_bp = Blueprint('api', __name__, url_prefix='/api')
|
||||
api_bp = Blueprint("api", __name__, url_prefix="/api")
|
||||
|
||||
# register blueprints here
|
||||
api_bp.register_blueprint(coordinator_bp)
|
||||
|
@ -2,6 +2,21 @@ from enum import Enum
|
||||
|
||||
|
||||
class ModeGroups(str, Enum):
|
||||
STATIONARY = 's'
|
||||
NON_STATIONARY = 'n'
|
||||
ENGLISH_SPEAKING_STATIONARY = 'e'
|
||||
STATIONARY = "s"
|
||||
NON_STATIONARY = "n"
|
||||
ENGLISH_SPEAKING_STATIONARY = "e"
|
||||
|
||||
|
||||
class EnrollmentsMode(str, Enum):
|
||||
"""
|
||||
What means specific values?:
|
||||
INIT - project supervisor set your availability time for this examination
|
||||
schedule, students cannot use examination schedule
|
||||
OPEN - students can assign to term of defence, project supervisor cannot
|
||||
use examination schedule
|
||||
CLOSE - students and project supervisor cannot use examination schedule
|
||||
"""
|
||||
|
||||
INIT = "i"
|
||||
OPEN = "o"
|
||||
CLOSE = "c"
|
||||
|
@ -1,4 +1,4 @@
|
||||
from marshmallow import fields, Schema
|
||||
from marshmallow import Schema, fields
|
||||
|
||||
|
||||
class MessageSchema(Schema):
|
||||
|
@ -10,11 +10,13 @@ class PaginationResponse(TypedDict):
|
||||
max_pages: int
|
||||
|
||||
|
||||
def order_by_column_name(query: BaseQuery, model_field: str, order_by_col_name: Union[str, None]) -> BaseQuery:
|
||||
def order_by_column_name(
|
||||
query: BaseQuery, model_field: str, order_by_col_name: Union[str, None]
|
||||
) -> BaseQuery:
|
||||
if order_by_col_name is not None:
|
||||
if order_by_col_name == 'asc':
|
||||
if order_by_col_name == "asc":
|
||||
query = query.order_by(model_field)
|
||||
elif order_by_col_name == 'desc':
|
||||
elif order_by_col_name == "desc":
|
||||
query = query.order_by(desc(model_field))
|
||||
|
||||
return query
|
||||
@ -27,12 +29,12 @@ def paginate_models(page: int, query: BaseQuery, per_page=10) -> PaginationRespo
|
||||
else:
|
||||
query = query.paginate(page=default_page, per_page=per_page, error_out=False)
|
||||
|
||||
return {
|
||||
'items': query.items,
|
||||
'max_pages': query.pages
|
||||
}
|
||||
return {"items": query.items, "max_pages": query.pages}
|
||||
|
||||
|
||||
def is_allowed_extensions(filename: str):
|
||||
return '.' in filename and \
|
||||
filename.rsplit('.', 1)[1].lower() in current_app.config['ALLOWED_EXTENSIONS']
|
||||
return (
|
||||
"." in filename
|
||||
and filename.rsplit(".", 1)[1].lower()
|
||||
in current_app.config["ALLOWED_EXTENSIONS"]
|
||||
)
|
||||
|
@ -1,10 +1,10 @@
|
||||
from flask.cli import with_appcontext
|
||||
from click import command
|
||||
from flask.cli import with_appcontext
|
||||
|
||||
from ..dependencies import db
|
||||
|
||||
|
||||
@command('clear_db')
|
||||
@command("clear_db")
|
||||
@with_appcontext
|
||||
def clear_db() -> None:
|
||||
"""Clear database"""
|
||||
|
@ -1,9 +1,9 @@
|
||||
import os
|
||||
import re
|
||||
|
||||
from flask import current_app
|
||||
from click import command, argument
|
||||
from click import argument, command
|
||||
from click.exceptions import ClickException
|
||||
from flask import current_app
|
||||
from flask.cli import with_appcontext
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ def startapp(name: str) -> None:
|
||||
"""Create the application structure"""
|
||||
|
||||
if not re.match("^[a-zA-Z].*$", name):
|
||||
raise ClickException(f"The name argument must be type of string!")
|
||||
raise ClickException("The name argument must be type of string!")
|
||||
|
||||
app_dir = current_app.config["SRC_DIR"] / name
|
||||
if os.path.exists(app_dir):
|
||||
@ -26,12 +26,14 @@ def startapp(name: str) -> None:
|
||||
Below you write a schema of model
|
||||
Example:
|
||||
|
||||
from marshmallow import Schema
|
||||
|
||||
class ExampleSchema(ma.SQLAlchemyAutoSchema):
|
||||
class Meta:
|
||||
model = MODEL_NAME
|
||||
\'\'\'
|
||||
|
||||
from ..dependencies import ma
|
||||
from marshmallow import Schema
|
||||
"""
|
||||
|
||||
model_content = """\'\'\'
|
||||
@ -43,7 +45,6 @@ class Example(db.Model):
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||
title = db.Column(db.String(255), unique=True)
|
||||
|
||||
\'\'\'
|
||||
|
||||
from ..dependencies import db
|
||||
|
@ -8,11 +8,11 @@ class Config:
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
SRC_DIR = BASE_DIR / "app"
|
||||
EXCLUDED_DIRS = ["__pycache__", "commands"]
|
||||
TIMEZONE = 'Europe/Warsaw'
|
||||
TIMEZONE = "Europe/Warsaw"
|
||||
|
||||
ENABLE_CORS = os.environ.get('ENABLE_CORS') or False
|
||||
ENABLE_CORS = os.environ.get("ENABLE_CORS") or False
|
||||
|
||||
ALLOWED_EXTENSIONS = {'csv'}
|
||||
ALLOWED_EXTENSIONS = {"csv"}
|
||||
MAX_CONTENT_LENGTH = 10 * 1024 * 1024 # 10 MB
|
||||
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
@ -20,8 +20,8 @@ class Config:
|
||||
LIMIT_STUDENTS_PER_GROUP = 5
|
||||
LIMIT_MEMBERS_PER_COMMITTEE = 3
|
||||
|
||||
DESCRIPTION = 'System PRI'
|
||||
OPENAPI_VERSION = '3.0.2'
|
||||
DESCRIPTION = "System PRI"
|
||||
OPENAPI_VERSION = "3.0.2"
|
||||
|
||||
# Weights for project grade sheet
|
||||
PRESENTATION_WEIGHT_FIRST_TERM = 1.5
|
||||
|
@ -1,8 +1,6 @@
|
||||
class CSVException(Exception):
|
||||
"""Main csv exception"""
|
||||
pass
|
||||
|
||||
|
||||
class InvalidNameOrTypeHeaderException(CSVException):
|
||||
"""Throw if csv file has invalid name or type of header"""
|
||||
pass
|
||||
|
@ -1,13 +1,23 @@
|
||||
from flask import abort
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
|
||||
from flask import abort
|
||||
from sqlalchemy import and_, or_
|
||||
|
||||
from ...base.mode import EnrollmentsMode
|
||||
from ...dependencies import db
|
||||
from ...examination_schedule.models import ExaminationSchedule, TermOfDefence
|
||||
from ...project_supervisor.models import ProjectSupervisor
|
||||
from ...students.models import Group
|
||||
|
||||
|
||||
def get_term_of_defence_by_id_and_examination_schedule_id(examination_schedule_id: int,
|
||||
term_of_defence_id: int) -> ExaminationSchedule:
|
||||
td = TermOfDefence.query.filter(TermOfDefence.id == term_of_defence_id,
|
||||
TermOfDefence.examination_schedule_id == examination_schedule_id).first()
|
||||
def get_term_of_defence_by_id_and_examination_schedule_id(
|
||||
examination_schedule_id: int, term_of_defence_id: int
|
||||
) -> ExaminationSchedule:
|
||||
td = TermOfDefence.query.filter(
|
||||
TermOfDefence.id == term_of_defence_id,
|
||||
TermOfDefence.examination_schedule_id == examination_schedule_id,
|
||||
).first()
|
||||
if td is None:
|
||||
abort(404, "Not found examination schedule or term of defence!")
|
||||
return td
|
||||
@ -27,9 +37,12 @@ def check_the_group_has_assigned_to_term_of_defence(group_id: int) -> TermOfDefe
|
||||
return td
|
||||
|
||||
|
||||
def set_new_group_to_term_of_defence(examination_schedule_id: int, term_of_defence_id: int,
|
||||
group_id: int) -> TermOfDefence:
|
||||
td = get_term_of_defence_by_id_and_examination_schedule_id(examination_schedule_id, term_of_defence_id)
|
||||
def set_new_group_to_term_of_defence(
|
||||
examination_schedule_id: int, term_of_defence_id: int, group_id: int
|
||||
) -> TermOfDefence:
|
||||
td = get_term_of_defence_by_id_and_examination_schedule_id(
|
||||
examination_schedule_id, term_of_defence_id
|
||||
)
|
||||
get_group_by_id(group_id)
|
||||
check_the_group_has_assigned_to_term_of_defence(group_id)
|
||||
td.group_id = group_id
|
||||
@ -37,7 +50,95 @@ def set_new_group_to_term_of_defence(examination_schedule_id: int, term_of_defen
|
||||
|
||||
|
||||
def get_examination_schedule_by_id(examination_schedule_id: int) -> ExaminationSchedule:
|
||||
ex = ExaminationSchedule.query.filter(ExaminationSchedule.id == examination_schedule_id).first()
|
||||
ex = ExaminationSchedule.query.filter(
|
||||
ExaminationSchedule.id == examination_schedule_id
|
||||
).first()
|
||||
if ex is None:
|
||||
abort(404, "Not found examination schedule!")
|
||||
return ex
|
||||
|
||||
|
||||
def get_and_check_the_project_supervisors_exists_in_db(
|
||||
year_group_id: int, project_supervisors_ids: List[int]
|
||||
) -> List[ProjectSupervisor]:
|
||||
project_supervisors = (
|
||||
ProjectSupervisor.query.filter(
|
||||
or_(*[ProjectSupervisor.id == i for i in project_supervisors_ids])
|
||||
)
|
||||
.filter(ProjectSupervisor.year_group_id == year_group_id)
|
||||
.all()
|
||||
)
|
||||
|
||||
if len(project_supervisors) != len(project_supervisors_ids):
|
||||
abort(400, "Project Supervisors didn't exist!")
|
||||
|
||||
return project_supervisors
|
||||
|
||||
|
||||
def validate_enrollments_date(
|
||||
ex_start_date: datetime, ex_end_date: datetime, duration_time: int, data: dict
|
||||
) -> None:
|
||||
start_date = data.get("start_date")
|
||||
end_date = data.get("end_date")
|
||||
|
||||
if not (
|
||||
ex_start_date.timestamp() <= start_date.timestamp()
|
||||
and ex_end_date.timestamp() >= end_date.timestamp()
|
||||
):
|
||||
abort(400, "Invalid date range!")
|
||||
|
||||
if end_date <= start_date:
|
||||
abort(400, "End date must be greater than start date!")
|
||||
|
||||
delta_time = end_date - start_date
|
||||
delta_time_in_minutes = delta_time.total_seconds() / 60
|
||||
print(delta_time_in_minutes, duration_time, delta_time_in_minutes != duration_time)
|
||||
if delta_time_in_minutes % duration_time != 0:
|
||||
abort(400, "Invalid duration time!")
|
||||
|
||||
|
||||
def check_the_term_of_defence_not_exists_in_chosen_date_range(
|
||||
examination_schedule_id: int, data: dict
|
||||
) -> None:
|
||||
start_date = data.get("start_date")
|
||||
end_date = data.get("end_date")
|
||||
td = (
|
||||
TermOfDefence.query.filter(
|
||||
TermOfDefence.examination_schedule_id == examination_schedule_id
|
||||
)
|
||||
.filter(
|
||||
or_(
|
||||
and_(
|
||||
TermOfDefence.start_date >= start_date,
|
||||
TermOfDefence.start_date < end_date,
|
||||
TermOfDefence.end_date >= end_date,
|
||||
),
|
||||
and_(
|
||||
TermOfDefence.start_date <= start_date,
|
||||
TermOfDefence.end_date > start_date,
|
||||
TermOfDefence.end_date <= end_date,
|
||||
),
|
||||
)
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
if td is not None:
|
||||
abort(400, "This term of defence is taken! You choose other date!")
|
||||
|
||||
|
||||
def set_enrollments_mode(
|
||||
examination_schedule_id: int, mode: EnrollmentsMode, action_name: str
|
||||
) -> dict:
|
||||
examination_schedule = (
|
||||
db.session.query(ExaminationSchedule)
|
||||
.filter(ExaminationSchedule.id == examination_schedule_id)
|
||||
.first()
|
||||
)
|
||||
|
||||
if examination_schedule is None:
|
||||
abort(404, "Not found examination schedule!")
|
||||
|
||||
examination_schedule.open_enrollments = mode.value
|
||||
db.session.commit()
|
||||
return {"message": f"You {action_name} enrollments for this examination schedule!"}
|
||||
|
@ -1,12 +1,12 @@
|
||||
from flask import Blueprint
|
||||
|
||||
from .examination_schedule import bp as examination_schedule_bp
|
||||
from .enrollments import bp as enrollments_bp
|
||||
from .examination_schedule import bp as examination_schedule_bp
|
||||
from .groups import bp as groups_bp
|
||||
from .project_supervisor import bp as project_supervisor_bp
|
||||
from .students import bp as students_bp
|
||||
from .year_group import bp as year_group_bp
|
||||
from .workloads import bp as workloads_bp
|
||||
from .year_group import bp as year_group_bp
|
||||
|
||||
bp = Blueprint("coordinator", __name__, url_prefix="/coordinator")
|
||||
|
||||
|
@ -1,68 +1,53 @@
|
||||
import datetime
|
||||
|
||||
from apiflask import APIBlueprint
|
||||
from flask import abort, current_app
|
||||
from sqlalchemy import or_, and_
|
||||
from flask_sqlalchemy import get_debug_queries
|
||||
from flask import abort
|
||||
|
||||
from ..schemas import TermOfDefenceSchema, TemporaryAvailabilityListSchema, AssignedGroupToTermOfDefenceListSchema, \
|
||||
GroupIdSchema
|
||||
from ...examination_schedule.models import TermOfDefence, TemporaryAvailability
|
||||
from ...students.models import YearGroup
|
||||
from ...project_supervisor.models import ProjectSupervisor
|
||||
from ...dependencies import db
|
||||
from ...base.schemas import MessageSchema
|
||||
from ...dependencies import db
|
||||
from ...examination_schedule.models import TemporaryAvailability, TermOfDefence
|
||||
from ..query.enrollments import (
|
||||
check_the_term_of_defence_not_exists_in_chosen_date_range,
|
||||
get_and_check_the_project_supervisors_exists_in_db,
|
||||
get_examination_schedule_by_id,
|
||||
get_term_of_defence_by_id_and_examination_schedule_id,
|
||||
set_new_group_to_term_of_defence,
|
||||
validate_enrollments_date,
|
||||
)
|
||||
from ..schemas.enrollments import (
|
||||
AssignedGroupToTermOfDefenceListSchema,
|
||||
TemporaryAvailabilityListSchema,
|
||||
TermOfDefenceSchema,
|
||||
)
|
||||
from ..schemas.groups import GroupIdSchema
|
||||
from ..utils import generate_range_dates
|
||||
from ..query.enrollments import get_term_of_defence_by_id_and_examination_schedule_id, set_new_group_to_term_of_defence, \
|
||||
get_examination_schedule_by_id
|
||||
|
||||
bp = APIBlueprint("enrollments", __name__, url_prefix="/enrollments")
|
||||
|
||||
|
||||
@bp.post('/<int:examination_schedule_id>/add')
|
||||
@bp.post("/<int:examination_schedule_id>/add")
|
||||
@bp.input(TermOfDefenceSchema)
|
||||
@bp.output(MessageSchema)
|
||||
def create_term_of_defence(examination_schedule_id: int, data: dict) -> dict:
|
||||
if not data:
|
||||
abort(400, "You have passed empty data!")
|
||||
chairman_of_committee_id = data.pop("chairman_of_committee")
|
||||
project_supervisors_ids = data.pop("project_supervisors")
|
||||
if chairman_of_committee_id not in project_supervisors_ids:
|
||||
abort(400, "Invalid id of chairman committee!")
|
||||
|
||||
ex = get_examination_schedule_by_id(examination_schedule_id)
|
||||
|
||||
yg_id = ex.year_group_id
|
||||
project_supervisors_ids = data.pop('project_supervisors')
|
||||
project_supervisors = ProjectSupervisor.query.filter(
|
||||
or_(*[ProjectSupervisor.id == i for i in project_supervisors_ids])).filter(YearGroup.id == yg_id).all()
|
||||
|
||||
if len(project_supervisors) != len(project_supervisors_ids):
|
||||
abort(404, "Project Supervisors didn't exist!")
|
||||
|
||||
start_date = data['start_date']
|
||||
end_date = data['end_date']
|
||||
|
||||
if not (ex.start_date.timestamp() <= start_date.timestamp() and ex.end_date.timestamp() >= end_date.timestamp()):
|
||||
abort(400, "Invalid date range!")
|
||||
|
||||
if end_date <= start_date:
|
||||
abort(400, "End date must be greater than start date!")
|
||||
|
||||
delta_time = end_date - start_date
|
||||
delta_time_in_minutes = delta_time.total_seconds() / 60
|
||||
if delta_time_in_minutes != ex.duration_time:
|
||||
abort(400, "Invalid duration time!")
|
||||
|
||||
td = TermOfDefence.query.filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
|
||||
filter(
|
||||
or_(and_(TermOfDefence.start_date >= start_date,
|
||||
TermOfDefence.start_date < end_date,
|
||||
TermOfDefence.end_date >= end_date),
|
||||
and_(TermOfDefence.start_date <= start_date,
|
||||
TermOfDefence.end_date > start_date,
|
||||
TermOfDefence.end_date <= end_date))).first()
|
||||
|
||||
if td is not None:
|
||||
abort(400, "This term of defence is taken! You choose other date!")
|
||||
|
||||
td = TermOfDefence(**data, examination_schedule_id=examination_schedule_id)
|
||||
project_supervisors = get_and_check_the_project_supervisors_exists_in_db(
|
||||
ex.year_group_id, project_supervisors_ids
|
||||
)
|
||||
validate_enrollments_date(ex.start_date, ex.end_date, ex.duration_time, data)
|
||||
check_the_term_of_defence_not_exists_in_chosen_date_range(
|
||||
examination_schedule_id, data
|
||||
)
|
||||
td = TermOfDefence(
|
||||
**data,
|
||||
examination_schedule_id=examination_schedule_id,
|
||||
chairman_of_committee=chairman_of_committee_id
|
||||
)
|
||||
db.session.add(td)
|
||||
db.session.commit()
|
||||
for p in project_supervisors:
|
||||
@ -71,110 +56,76 @@ def create_term_of_defence(examination_schedule_id: int, data: dict) -> dict:
|
||||
return {"message": "Term of defence was created!"}
|
||||
|
||||
|
||||
@bp.post('/<int:examination_schedule_id>/add-term-of-defences/')
|
||||
@bp.post("/<int:examination_schedule_id>/add-term-of-defences/")
|
||||
@bp.input(TermOfDefenceSchema)
|
||||
@bp.output(MessageSchema)
|
||||
def create_many_term_of_defences(examination_schedule_id: int, data: dict) -> dict:
|
||||
if not data:
|
||||
abort(400, "You have passed empty data!")
|
||||
chairman_of_committee_id = data.pop("chairman_of_committee")
|
||||
project_supervisors_ids = data.pop("project_supervisors")
|
||||
if chairman_of_committee_id not in project_supervisors_ids:
|
||||
abort(400, "Invalid id of chairman committee!")
|
||||
|
||||
ex = get_examination_schedule_by_id(examination_schedule_id)
|
||||
|
||||
yg_id = ex.year_group_id
|
||||
project_supervisors_ids = data.pop('project_supervisors')
|
||||
project_supervisors = ProjectSupervisor.query.filter(
|
||||
or_(*[ProjectSupervisor.id == i for i in project_supervisors_ids])).filter(YearGroup.id == yg_id).all()
|
||||
|
||||
if len(project_supervisors) != len(project_supervisors_ids):
|
||||
abort(404, "Project Supervisors didn't exist!")
|
||||
|
||||
start_date = data['start_date']
|
||||
end_date = data['end_date']
|
||||
if not (ex.start_date.timestamp() <= start_date.timestamp() and ex.end_date.timestamp() >= end_date.timestamp()):
|
||||
abort(400, "Invalid date range!")
|
||||
|
||||
if end_date <= start_date:
|
||||
abort(400, "End date must be greater than start date!")
|
||||
|
||||
delta_time = end_date - start_date
|
||||
delta_time_in_minutes = delta_time.total_seconds() / 60
|
||||
if delta_time_in_minutes % ex.duration_time != 0:
|
||||
abort(400, "Invalid duration time!")
|
||||
|
||||
td = TermOfDefence.query.filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
|
||||
filter(
|
||||
or_(and_(TermOfDefence.start_date >= start_date,
|
||||
TermOfDefence.start_date < end_date,
|
||||
TermOfDefence.end_date >= end_date),
|
||||
and_(TermOfDefence.start_date <= start_date,
|
||||
TermOfDefence.end_date > start_date,
|
||||
TermOfDefence.end_date <= end_date))).first()
|
||||
|
||||
if td is not None:
|
||||
abort(400, "This term of defence is taken! You choose other date!")
|
||||
project_supervisors = get_and_check_the_project_supervisors_exists_in_db(
|
||||
ex.year_group_id, project_supervisors_ids
|
||||
)
|
||||
validate_enrollments_date(ex.start_date, ex.end_date, ex.duration_time, data)
|
||||
check_the_term_of_defence_not_exists_in_chosen_date_range(
|
||||
examination_schedule_id, data
|
||||
)
|
||||
|
||||
# create many here
|
||||
start_date = data.get("start_date")
|
||||
end_date = data.get("end_date")
|
||||
dates = generate_range_dates(start_date, end_date, ex.duration_time)
|
||||
for start_date in dates:
|
||||
end_date = start_date + datetime.timedelta(minutes=ex.duration_time)
|
||||
|
||||
td = TermOfDefence(start_date=start_date, end_date=end_date, examination_schedule_id=examination_schedule_id)
|
||||
td = TermOfDefence(
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
examination_schedule_id=examination_schedule_id,
|
||||
chairman_of_committee=chairman_of_committee_id,
|
||||
)
|
||||
td.members_of_committee = project_supervisors
|
||||
db.session.add(td)
|
||||
db.session.commit()
|
||||
return {"message": "Term of defences was created!"}
|
||||
|
||||
|
||||
@bp.put('/<int:examination_schedule_id>/update/<int:term_of_defence_id>/')
|
||||
@bp.put("/<int:examination_schedule_id>/update/<int:term_of_defence_id>/")
|
||||
@bp.input(TermOfDefenceSchema)
|
||||
@bp.output(MessageSchema)
|
||||
def update_term_of_defence(examination_schedule_id: int, term_of_defence_id: int, data: dict) -> dict:
|
||||
if not data:
|
||||
abort(400, "You have passed empty data!")
|
||||
def update_term_of_defence(
|
||||
examination_schedule_id: int, term_of_defence_id: int, data: dict
|
||||
) -> dict:
|
||||
chairman_of_committee_id = data.pop("chairman_of_committee")
|
||||
project_supervisors_ids = data.pop("project_supervisors")
|
||||
if chairman_of_committee_id not in project_supervisors_ids:
|
||||
abort(400, "Invalid id of chairman committee!")
|
||||
|
||||
td_query = TermOfDefence.query.filter(TermOfDefence.id == term_of_defence_id,
|
||||
TermOfDefence.examination_schedule_id == examination_schedule_id)
|
||||
td_query = TermOfDefence.query.filter(
|
||||
TermOfDefence.id == term_of_defence_id,
|
||||
TermOfDefence.examination_schedule_id == examination_schedule_id,
|
||||
)
|
||||
td = td_query.first()
|
||||
if td is None:
|
||||
abort(404, "Not found term of defence!")
|
||||
|
||||
ex = td.examination_schedule
|
||||
yg_id = ex.year_group_id
|
||||
project_supervisors_ids = data.pop('project_supervisors')
|
||||
project_supervisors = ProjectSupervisor.query.filter(
|
||||
or_(*[ProjectSupervisor.id == i for i in project_supervisors_ids])).filter(YearGroup.id == yg_id).all()
|
||||
ex = get_examination_schedule_by_id(examination_schedule_id)
|
||||
|
||||
if len(project_supervisors) != len(project_supervisors_ids):
|
||||
abort(404, "Project Supervisors didn't exist!")
|
||||
|
||||
start_date = data['start_date']
|
||||
end_date = data['end_date']
|
||||
if not (ex.start_date.timestamp() <= start_date.timestamp() and ex.end_date.timestamp() >= end_date.timestamp()):
|
||||
abort(400, "Invalid date range!")
|
||||
|
||||
if end_date <= start_date:
|
||||
abort(400, "End date must be greater than start date!")
|
||||
|
||||
delta_time = end_date - start_date
|
||||
delta_time_in_minutes = delta_time.total_seconds() / 60
|
||||
if delta_time_in_minutes != ex.duration_time:
|
||||
abort(400, "Invalid duration time!")
|
||||
|
||||
term_of_defence = TermOfDefence.query.filter(TermOfDefence.id != term_of_defence_id,
|
||||
TermOfDefence.examination_schedule_id == examination_schedule_id). \
|
||||
filter(
|
||||
or_(and_(TermOfDefence.start_date >= start_date,
|
||||
TermOfDefence.start_date < end_date,
|
||||
TermOfDefence.end_date >= end_date),
|
||||
and_(TermOfDefence.start_date <= start_date,
|
||||
TermOfDefence.end_date > start_date,
|
||||
TermOfDefence.end_date <= end_date))).first()
|
||||
|
||||
if term_of_defence is not None:
|
||||
abort(400, "This term of defence is taken! You choose other date!")
|
||||
project_supervisors = get_and_check_the_project_supervisors_exists_in_db(
|
||||
ex.year_group_id, project_supervisors_ids
|
||||
)
|
||||
validate_enrollments_date(ex.start_date, ex.end_date, ex.duration_time, data)
|
||||
check_the_term_of_defence_not_exists_in_chosen_date_range(
|
||||
examination_schedule_id, data
|
||||
)
|
||||
|
||||
td_query.update(data)
|
||||
td.members_of_committee = []
|
||||
td.chairman_of_committee = chairman_of_committee_id
|
||||
db.session.commit()
|
||||
for p in project_supervisors:
|
||||
td.members_of_committee.append(p)
|
||||
@ -183,75 +134,102 @@ def update_term_of_defence(examination_schedule_id: int, term_of_defence_id: int
|
||||
return {"message": "Term of defence was updated!"}
|
||||
|
||||
|
||||
@bp.delete('/<int:examination_schedule_id>/delete/<int:term_of_defence_id>/')
|
||||
@bp.delete("/<int:examination_schedule_id>/delete/<int:term_of_defence_id>/")
|
||||
@bp.output(MessageSchema)
|
||||
def delete_term_of_defence(examination_schedule_id: int, term_of_defence_id: int) -> dict:
|
||||
td = get_term_of_defence_by_id_and_examination_schedule_id(examination_schedule_id, term_of_defence_id)
|
||||
def delete_term_of_defence(
|
||||
examination_schedule_id: int, term_of_defence_id: int
|
||||
) -> dict:
|
||||
td = get_term_of_defence_by_id_and_examination_schedule_id(
|
||||
examination_schedule_id, term_of_defence_id
|
||||
)
|
||||
db.session.delete(td)
|
||||
db.session.commit()
|
||||
return {"message": "Term of defence was deleted!"}
|
||||
|
||||
|
||||
@bp.get('/<int:examination_schedule_id>/term-of-defences/')
|
||||
@bp.get("/<int:examination_schedule_id>/term-of-defences/")
|
||||
@bp.output(AssignedGroupToTermOfDefenceListSchema)
|
||||
def list_of_term_of_defences(examination_schedule_id: int) -> dict:
|
||||
get_examination_schedule_by_id(examination_schedule_id)
|
||||
|
||||
td = TermOfDefence.query. \
|
||||
join(TermOfDefence.members_of_committee, isouter=True). \
|
||||
filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
|
||||
all()
|
||||
td = (
|
||||
TermOfDefence.query.join(TermOfDefence.members_of_committee, isouter=True)
|
||||
.filter(TermOfDefence.examination_schedule_id == examination_schedule_id)
|
||||
.all()
|
||||
)
|
||||
return {"term_of_defences": td}
|
||||
|
||||
|
||||
@bp.get('/<int:examination_schedule_id>/temporary-availabilities/')
|
||||
@bp.get("/<int:examination_schedule_id>/temporary-availabilities/")
|
||||
@bp.output(TemporaryAvailabilityListSchema)
|
||||
def list_of_temporary_availability(examination_schedule_id: int) -> dict:
|
||||
get_examination_schedule_by_id(examination_schedule_id)
|
||||
|
||||
td = TemporaryAvailability.query. \
|
||||
filter(TemporaryAvailability.examination_schedule_id == examination_schedule_id). \
|
||||
join(TemporaryAvailability.project_supervisor). \
|
||||
all()
|
||||
td = (
|
||||
TemporaryAvailability.query.filter(
|
||||
TemporaryAvailability.examination_schedule_id == examination_schedule_id
|
||||
)
|
||||
.join(TemporaryAvailability.project_supervisor)
|
||||
.all()
|
||||
)
|
||||
return {"temporary_availabilities": td}
|
||||
|
||||
|
||||
@bp.get('/<int:examination_schedule_id>/assigned-group-to-term-of-defences/')
|
||||
@bp.get("/<int:examination_schedule_id>/assigned-group-to-term-of-defences/")
|
||||
@bp.output(AssignedGroupToTermOfDefenceListSchema)
|
||||
def list_of_assigned_group_to_term_of_defences(examination_schedule_id: int) -> dict:
|
||||
get_examination_schedule_by_id(examination_schedule_id)
|
||||
|
||||
td = TermOfDefence.query. \
|
||||
join(TermOfDefence.members_of_committee, isouter=True). \
|
||||
join(TermOfDefence.group). \
|
||||
filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
|
||||
filter(TermOfDefence.group_id.isnot(None)). \
|
||||
all()
|
||||
td = (
|
||||
TermOfDefence.query.join(TermOfDefence.members_of_committee, isouter=True)
|
||||
.join(TermOfDefence.group)
|
||||
.filter(TermOfDefence.examination_schedule_id == examination_schedule_id)
|
||||
.filter(TermOfDefence.group_id.isnot(None))
|
||||
.all()
|
||||
)
|
||||
return {"term_of_defences": td}
|
||||
|
||||
|
||||
@bp.post('/<int:examination_schedule_id>/term-of-defence/<int:term_of_defence_id>/group/')
|
||||
@bp.post(
|
||||
"/<int:examination_schedule_id>/term-of-defence/<int:term_of_defence_id>/group/"
|
||||
)
|
||||
@bp.input(GroupIdSchema)
|
||||
@bp.output(MessageSchema)
|
||||
def add_group_to_term_of_defence(examination_schedule_id: int, term_of_defence_id: int, data: dict) -> dict:
|
||||
set_new_group_to_term_of_defence(examination_schedule_id, term_of_defence_id, data.get("group_id"))
|
||||
def add_group_to_term_of_defence(
|
||||
examination_schedule_id: int, term_of_defence_id: int, data: dict
|
||||
) -> dict:
|
||||
set_new_group_to_term_of_defence(
|
||||
examination_schedule_id, term_of_defence_id, data.get("group_id")
|
||||
)
|
||||
db.session.commit()
|
||||
return {"message": "Group was added to term of defences!"}
|
||||
|
||||
|
||||
@bp.delete('/<int:examination_schedule_id>/term-of-defence/<int:term_of_defence_id>/group/')
|
||||
@bp.delete(
|
||||
"/<int:examination_schedule_id>/term-of-defence/<int:term_of_defence_id>/group/"
|
||||
)
|
||||
@bp.output(MessageSchema)
|
||||
def delete_group_to_term_of_defence(examination_schedule_id: int, term_of_defence_id: int) -> dict:
|
||||
td = get_term_of_defence_by_id_and_examination_schedule_id(examination_schedule_id, term_of_defence_id)
|
||||
def delete_group_to_term_of_defence(
|
||||
examination_schedule_id: int, term_of_defence_id: int
|
||||
) -> dict:
|
||||
td = get_term_of_defence_by_id_and_examination_schedule_id(
|
||||
examination_schedule_id, term_of_defence_id
|
||||
)
|
||||
td.group_id = None
|
||||
db.session.commit()
|
||||
return {"message": "Group was deleted from term of defences!"}
|
||||
|
||||
|
||||
@bp.put('/<int:examination_schedule_id>/term-of-defence/<int:term_of_defence_id>/group/')
|
||||
@bp.put(
|
||||
"/<int:examination_schedule_id>/term-of-defence/<int:term_of_defence_id>/group/"
|
||||
)
|
||||
@bp.input(GroupIdSchema)
|
||||
@bp.output(MessageSchema)
|
||||
def update_group_for_term_of_defence(examination_schedule_id: int, term_of_defence_id: int, data: dict) -> dict:
|
||||
set_new_group_to_term_of_defence(examination_schedule_id, term_of_defence_id, data.get("group_id"))
|
||||
def update_group_for_term_of_defence(
|
||||
examination_schedule_id: int, term_of_defence_id: int, data: dict
|
||||
) -> dict:
|
||||
set_new_group_to_term_of_defence(
|
||||
examination_schedule_id, term_of_defence_id, data.get("group_id")
|
||||
)
|
||||
db.session.commit()
|
||||
return {"message": "Group for term of defence was updated!"}
|
||||
|
@ -1,34 +1,40 @@
|
||||
import datetime
|
||||
|
||||
from apiflask import APIBlueprint
|
||||
from flask import abort, Response, make_response, current_app
|
||||
from flask import Response, abort, current_app, make_response
|
||||
|
||||
from ...base.mode import EnrollmentsMode
|
||||
from ...base.schemas import MessageSchema
|
||||
from ...base.utils import paginate_models
|
||||
from ...base.mode import ModeGroups
|
||||
from ...dependencies import db
|
||||
from ...examination_schedule.models import ExaminationSchedule, TermOfDefence
|
||||
from ...students.models import Group, YearGroup
|
||||
from ...project_supervisor.models import ProjectSupervisor
|
||||
from ..schemas import ExaminationScheduleSchema, ExaminationScheduleUpdateSchema, \
|
||||
ExaminationSchedulesQuerySchema, ExaminationSchedulesPaginationSchema
|
||||
from ..utils import generate_examination_schedule_pdf_file
|
||||
from ...base.schemas import MessageSchema
|
||||
from ...students.models import Group, YearGroup
|
||||
from ..query.enrollments import set_enrollments_mode
|
||||
from ..schemas.examination_schedule import (
|
||||
ExaminationScheduleSchema,
|
||||
ExaminationSchedulesPaginationSchema,
|
||||
ExaminationSchedulesQuerySchema,
|
||||
)
|
||||
from ..utils import generate_examination_schedule_pdf_file, get_duration_time
|
||||
|
||||
bp = APIBlueprint("examination_schedule", __name__, url_prefix="/examination_schedule")
|
||||
|
||||
|
||||
@bp.get('/<int:year_group_id>/')
|
||||
@bp.input(ExaminationSchedulesQuerySchema, location='query')
|
||||
@bp.get("/<int:year_group_id>/")
|
||||
@bp.input(ExaminationSchedulesQuerySchema, location="query")
|
||||
@bp.output(ExaminationSchedulesPaginationSchema)
|
||||
def list_examination_schedule(year_group_id: int, query: dict) -> dict:
|
||||
page = query.get('page')
|
||||
per_page = query.get('per_page')
|
||||
es_query = ExaminationSchedule.query.filter(ExaminationSchedule.year_group_id == year_group_id)
|
||||
page = query.get("page")
|
||||
per_page = query.get("per_page")
|
||||
es_query = ExaminationSchedule.query.filter(
|
||||
ExaminationSchedule.year_group_id == year_group_id
|
||||
)
|
||||
data = paginate_models(page, es_query, per_page)
|
||||
return {'examination_schedules': data['items'], 'max_pages': data['max_pages']}
|
||||
return {"examination_schedules": data["items"], "max_pages": data["max_pages"]}
|
||||
|
||||
|
||||
@bp.post('/<int:year_group_id>/')
|
||||
@bp.post("/<int:year_group_id>/")
|
||||
@bp.input(ExaminationScheduleSchema)
|
||||
@bp.output(MessageSchema, status_code=201)
|
||||
def create_examination_schedule(year_group_id: int, data: dict) -> dict:
|
||||
@ -36,29 +42,28 @@ def create_examination_schedule(year_group_id: int, data: dict) -> dict:
|
||||
if yg is None:
|
||||
abort(404, "Year group doesn't exist!")
|
||||
|
||||
if data['start_date'] > data['end_date']:
|
||||
if data.get("start_date") > data.get("end_date"):
|
||||
abort(400, "Invalid data! End date must be greater than start date!")
|
||||
|
||||
duration_time = None
|
||||
if yg.mode == ModeGroups.NON_STATIONARY.value:
|
||||
duration_time = 20
|
||||
elif yg.mode in [ModeGroups.STATIONARY.value, ModeGroups.ENGLISH_SPEAKING_STATIONARY.value]:
|
||||
duration_time = 30
|
||||
|
||||
duration_time = get_duration_time(yg.mode)
|
||||
if duration_time is None:
|
||||
abort(400, "Invalid mode of year group!")
|
||||
abort(400, "Invalid duration time!")
|
||||
|
||||
examination_schedule = ExaminationSchedule(**data, year_group_id=year_group_id, duration_time=duration_time)
|
||||
examination_schedule = ExaminationSchedule(
|
||||
**data, year_group_id=year_group_id, duration_time=duration_time
|
||||
)
|
||||
db.session.add(examination_schedule)
|
||||
db.session.commit()
|
||||
return {"message": "Examination schedule was created!"}
|
||||
|
||||
|
||||
@bp.put('/<int:id>/')
|
||||
@bp.put("/<int:examination_schedule_id>/")
|
||||
@bp.input(ExaminationScheduleSchema)
|
||||
@bp.output(MessageSchema)
|
||||
def update_examination_schedule(id: int, data: dict) -> dict:
|
||||
examination_schedule_query = db.session.query(ExaminationSchedule).filter(ExaminationSchedule.id == id)
|
||||
def update_examination_schedule(examination_schedule_id: int, data: dict) -> dict:
|
||||
examination_schedule_query = db.session.query(ExaminationSchedule).filter(
|
||||
ExaminationSchedule.id == examination_schedule_id
|
||||
)
|
||||
examination_schedule = examination_schedule_query.first()
|
||||
|
||||
if examination_schedule is None:
|
||||
@ -68,10 +73,14 @@ def update_examination_schedule(id: int, data: dict) -> dict:
|
||||
return {"message": "Examination schedule was updated!"}
|
||||
|
||||
|
||||
@bp.delete('/<int:id>/')
|
||||
@bp.delete("/<int:examination_schedule_id>/")
|
||||
@bp.output(MessageSchema)
|
||||
def delete_examination_schedule(id: int) -> dict:
|
||||
examination_schedule = db.session.query(ExaminationSchedule).filter(ExaminationSchedule.id == id).first()
|
||||
def delete_examination_schedule(examination_schedule_id: int) -> dict:
|
||||
examination_schedule = (
|
||||
db.session.query(ExaminationSchedule)
|
||||
.filter(ExaminationSchedule.id == examination_schedule_id)
|
||||
.first()
|
||||
)
|
||||
if examination_schedule is None:
|
||||
abort(404, "Examination schedule doesn't exist!")
|
||||
db.session.delete(examination_schedule)
|
||||
@ -79,52 +88,56 @@ def delete_examination_schedule(id: int) -> dict:
|
||||
return {"message": "Examination schedule was deleted!"}
|
||||
|
||||
|
||||
@bp.put('/<int:id>/date/')
|
||||
@bp.input(ExaminationScheduleUpdateSchema)
|
||||
@bp.put("/<int:examination_schedule_id>/open-enrollments/")
|
||||
@bp.output(MessageSchema)
|
||||
def set_date_of_examination_schedule(id: int, data: dict) -> dict:
|
||||
examination_schedule_query = db.session.query(ExaminationSchedule).filter(ExaminationSchedule.id == id)
|
||||
examination_schedule = examination_schedule_query.first()
|
||||
|
||||
if examination_schedule is None:
|
||||
abort(404, "Examination schedule doesn't exist!")
|
||||
|
||||
if data['start_date_for_enrollment_students'] > data['end_date_for_enrollment_students']:
|
||||
abort(400, "Invalid data! End date must be greater than start date!")
|
||||
|
||||
examination_schedule_query.update(data)
|
||||
db.session.commit()
|
||||
return {"message": "You set date of examination schedule!"}
|
||||
def open_enrollments(examination_schedule_id: int) -> dict:
|
||||
return set_enrollments_mode(examination_schedule_id, EnrollmentsMode.OPEN, "open")
|
||||
|
||||
|
||||
@bp.post('/<int:examination_schedule_id>/download/')
|
||||
@bp.put("/<int:examination_schedule_id>/close-enrollments/")
|
||||
@bp.output(MessageSchema)
|
||||
def close_enrollments(examination_schedule_id: int) -> dict:
|
||||
return set_enrollments_mode(examination_schedule_id, EnrollmentsMode.CLOSE, "close")
|
||||
|
||||
|
||||
@bp.post("/<int:examination_schedule_id>/download/")
|
||||
def download_examination_schedule(examination_schedule_id: int) -> Response:
|
||||
examination_schedule = db.session.query(ExaminationSchedule). \
|
||||
filter(ExaminationSchedule.id == examination_schedule_id).first()
|
||||
examination_schedule = (
|
||||
db.session.query(ExaminationSchedule)
|
||||
.filter(ExaminationSchedule.id == examination_schedule_id)
|
||||
.first()
|
||||
)
|
||||
|
||||
if examination_schedule is None:
|
||||
abort(404, "Examination schedule doesn't exist!")
|
||||
|
||||
distinct_dates = db.session.query(db.func.Date(TermOfDefence.start_date)).distinct().all()
|
||||
distinct_dates = (
|
||||
db.session.query(db.func.Date(TermOfDefence.start_date)).distinct().all()
|
||||
)
|
||||
|
||||
nested_term_of_defences = []
|
||||
for d in distinct_dates:
|
||||
date_tmp = datetime.datetime.strptime(d[0], "%Y-%m-%d").date()
|
||||
term_of_defences = db.session.query(TermOfDefence). \
|
||||
join(Group, isouter=True).join(ProjectSupervisor, isouter=True). \
|
||||
filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
|
||||
filter(TermOfDefence.group_id.isnot(None)). \
|
||||
filter(db.func.Date(TermOfDefence.start_date) == date_tmp). \
|
||||
all()
|
||||
term_of_defences = (
|
||||
db.session.query(TermOfDefence)
|
||||
.join(Group, isouter=True)
|
||||
.join(ProjectSupervisor, isouter=True)
|
||||
.filter(TermOfDefence.examination_schedule_id == examination_schedule_id)
|
||||
.filter(TermOfDefence.group_id.isnot(None))
|
||||
.filter(db.func.Date(TermOfDefence.start_date) == date_tmp)
|
||||
.all()
|
||||
)
|
||||
if len(term_of_defences) > 0:
|
||||
nested_term_of_defences.append(term_of_defences)
|
||||
# print(nested_term_of_defences)
|
||||
base_dir = current_app.config.get('BASE_DIR')
|
||||
pdf = generate_examination_schedule_pdf_file(examination_schedule.title, nested_term_of_defences, base_dir)
|
||||
base_dir = current_app.config.get("BASE_DIR")
|
||||
pdf = generate_examination_schedule_pdf_file(
|
||||
examination_schedule.title, nested_term_of_defences, base_dir
|
||||
)
|
||||
title = examination_schedule.title.replace("-", "_").split()
|
||||
filename = "_".join(title)
|
||||
|
||||
response = make_response(pdf)
|
||||
response.headers['Content-Type'] = 'application/pdf'
|
||||
response.headers['Content-Disposition'] = 'attachment; filename=%s.pdf' % filename
|
||||
response.headers["Content-Type"] = "application/pdf"
|
||||
response.headers["Content-Disposition"] = "attachment; filename=%s.pdf" % filename
|
||||
return response
|
||||
|
@ -1,61 +1,72 @@
|
||||
from flask import abort
|
||||
from apiflask import APIBlueprint
|
||||
from flask_sqlalchemy import get_debug_queries
|
||||
from flask import abort
|
||||
|
||||
from ...students.models import Group, Student, YearGroup, ProjectGradeSheet
|
||||
from ...project_supervisor.models import ProjectSupervisor
|
||||
from ..schemas import GroupEditSchema, GroupsPaginationSchema, GroupCreateSchema, GroupQuerySchema, DetailGroupSchema
|
||||
from ...dependencies import db
|
||||
from ...base.utils import paginate_models
|
||||
from ...base.schemas import MessageSchema
|
||||
from ...base.utils import paginate_models
|
||||
from ...dependencies import db
|
||||
from ...project_supervisor.models import ProjectSupervisor
|
||||
from ...students.models import Group, ProjectGradeSheet, Student, YearGroup
|
||||
from ..schemas.groups import (
|
||||
GroupCreateSchema,
|
||||
GroupEditSchema,
|
||||
GroupQuerySchema,
|
||||
GroupsPaginationSchema,
|
||||
)
|
||||
from ..schemas.students import DetailGroupSchema
|
||||
from ..utils import attach_points_for_first_and_second_term_to_group_models
|
||||
|
||||
bp = APIBlueprint("groups", __name__, url_prefix="/groups")
|
||||
|
||||
|
||||
@bp.get("/<int:year_group_id>/")
|
||||
@bp.input(GroupQuerySchema, location='query')
|
||||
@bp.input(GroupQuerySchema, location="query")
|
||||
@bp.output(GroupsPaginationSchema)
|
||||
def list_groups(year_group_id: int, query: dict) -> dict:
|
||||
search_name = query.get('name')
|
||||
page = query.get('page')
|
||||
per_page = query.get('per_page')
|
||||
search_name = query.get("name")
|
||||
page = query.get("page")
|
||||
per_page = query.get("per_page")
|
||||
|
||||
groups_query = Group.search_by_name(year_group_id, search_name)
|
||||
data = paginate_models(page, groups_query, per_page)
|
||||
|
||||
items = data['items']
|
||||
items = data["items"]
|
||||
attach_points_for_first_and_second_term_to_group_models(items)
|
||||
|
||||
return {
|
||||
"groups": items,
|
||||
"max_pages": data['max_pages']
|
||||
}
|
||||
return {"groups": items, "max_pages": data["max_pages"]}
|
||||
|
||||
|
||||
@bp.post("/<int:year_group_id>/")
|
||||
@bp.input(GroupCreateSchema)
|
||||
@bp.output(MessageSchema, status_code=201)
|
||||
def create_group(year_group_id: int, data: dict) -> dict:
|
||||
name = data['name']
|
||||
students_ids = data['students']
|
||||
project_supervisor_id = data['project_supervisor_id']
|
||||
name = data["name"]
|
||||
students_ids = data["students"]
|
||||
project_supervisor_id = data["project_supervisor_id"]
|
||||
|
||||
yg = YearGroup.query.filter(YearGroup.id == year_group_id).first()
|
||||
if yg is None:
|
||||
abort(404, "Not found year group!")
|
||||
|
||||
project_supervisor = ProjectSupervisor.query.filter_by(id=project_supervisor_id).first()
|
||||
project_supervisor = ProjectSupervisor.query.filter_by(
|
||||
id=project_supervisor_id
|
||||
).first()
|
||||
|
||||
if project_supervisor is None:
|
||||
abort(404, f"Not found project supervisor!")
|
||||
abort(404, "Not found project supervisor!")
|
||||
|
||||
group = Group(name=name, project_supervisor_id=project_supervisor_id, year_group_id=year_group_id)
|
||||
group = Group(
|
||||
name=name,
|
||||
project_supervisor_id=project_supervisor_id,
|
||||
year_group_id=year_group_id,
|
||||
)
|
||||
|
||||
students_without_groups = db.session.query(Student, Group). \
|
||||
join(Group, Student.groups). \
|
||||
filter(Group.year_group_id == year_group_id). \
|
||||
filter(db.or_(*[Student.id == st_id for st_id in students_ids])).all()
|
||||
students_without_groups = (
|
||||
db.session.query(Student, Group)
|
||||
.join(Group, Student.groups)
|
||||
.filter(Group.year_group_id == year_group_id)
|
||||
.filter(db.or_(*[Student.id == st_id for st_id in students_ids]))
|
||||
.all()
|
||||
)
|
||||
|
||||
if len(students_without_groups) > 0:
|
||||
abort(400, "One or more students have already belonged to group!")
|
||||
@ -81,7 +92,7 @@ def create_group(year_group_id: int, data: dict) -> dict:
|
||||
def detail_group(group_id: int) -> Group:
|
||||
group = Group.query.filter_by(id=group_id).first()
|
||||
if group is None:
|
||||
abort(404, f"Not found group!")
|
||||
abort(404, "Not found group!")
|
||||
return group
|
||||
|
||||
|
||||
@ -90,7 +101,7 @@ def detail_group(group_id: int) -> Group:
|
||||
def delete_group(group_id: int) -> dict:
|
||||
group = Group.query.filter_by(id=group_id).first()
|
||||
if group is None:
|
||||
abort(404, f"Not found group!")
|
||||
abort(404, "Not found group!")
|
||||
|
||||
group.students = []
|
||||
db.session.delete(group)
|
||||
@ -103,29 +114,31 @@ def delete_group(group_id: int) -> dict:
|
||||
@bp.output(MessageSchema)
|
||||
def edit_group(group_id: int, data: dict) -> dict:
|
||||
if not data:
|
||||
abort(400, 'You have passed empty data!')
|
||||
abort(400, "You have passed empty data!")
|
||||
|
||||
group_query = Group.query.filter_by(id=group_id)
|
||||
group = group_query.first()
|
||||
|
||||
if group is None:
|
||||
abort(404, f"Not found group!")
|
||||
abort(404, "Not found group!")
|
||||
|
||||
students_ids = data.get('students')
|
||||
name = data.get('name')
|
||||
project_supervisor_id = data.get('project_supervisor_id')
|
||||
students_ids = data.get("students")
|
||||
name = data.get("name")
|
||||
project_supervisor_id = data.get("project_supervisor_id")
|
||||
|
||||
if students_ids is not None:
|
||||
students = db.session.query(Student).filter(Student.id.in_(students_ids)).all()
|
||||
if len(students_ids) != len(students):
|
||||
abort(404, 'Not found students!')
|
||||
abort(404, "Not found students!")
|
||||
group.students = students
|
||||
|
||||
if name is not None:
|
||||
group.name = name
|
||||
|
||||
if project_supervisor_id is not None:
|
||||
ps = ProjectSupervisor.query.filter(ProjectSupervisor.id == project_supervisor_id).first()
|
||||
ps = ProjectSupervisor.query.filter(
|
||||
ProjectSupervisor.id == project_supervisor_id
|
||||
).first()
|
||||
if ps is None:
|
||||
abort(404, "Not found project supervisor!")
|
||||
group.project_supervisor_id = project_supervisor_id
|
||||
|
@ -1,37 +1,40 @@
|
||||
from flask import abort
|
||||
from apiflask import APIBlueprint
|
||||
from flask_sqlalchemy import get_debug_queries
|
||||
from flask import abort
|
||||
|
||||
from ...base.schemas import MessageSchema
|
||||
from ...base.utils import paginate_models
|
||||
from ...dependencies import db
|
||||
from ...project_supervisor.models import ProjectSupervisor
|
||||
from ...students.models import Group, YearGroup
|
||||
from ..schemas import ProjectSupervisorSchema, ProjectSupervisorEditSchema, ProjectSupervisorsPaginationSchema, \
|
||||
ProjectSupervisorCreateSchema, MessageWithIdSchema, ProjectSupervisorQuerySchema
|
||||
from ...base.schemas import MessageSchema
|
||||
from ...dependencies import db
|
||||
from ...base.utils import paginate_models
|
||||
from ..schemas.project_supervisor import (
|
||||
ProjectSupervisorCreateSchema,
|
||||
ProjectSupervisorEditSchema,
|
||||
ProjectSupervisorQuerySchema,
|
||||
ProjectSupervisorSchema,
|
||||
ProjectSupervisorsPaginationSchema,
|
||||
)
|
||||
from ..schemas.students import MessageWithIdSchema
|
||||
|
||||
bp = APIBlueprint("project_supervisor", __name__, url_prefix="/project_supervisor")
|
||||
|
||||
|
||||
@bp.get("/<int:year_group_id>/")
|
||||
@bp.input(ProjectSupervisorQuerySchema, location='query')
|
||||
@bp.input(ProjectSupervisorQuerySchema, location="query")
|
||||
@bp.output(ProjectSupervisorsPaginationSchema)
|
||||
def list_project_supervisors(year_group_id: int, query: dict) -> dict:
|
||||
fullname = query.get('fullname')
|
||||
order_by_first_name = query.get('order_by_first_name')
|
||||
order_by_last_name = query.get('order_by_last_name')
|
||||
page = query.get('page')
|
||||
per_page = query.get('per_page')
|
||||
fullname = query.get("fullname")
|
||||
order_by_first_name = query.get("order_by_first_name")
|
||||
order_by_last_name = query.get("order_by_last_name")
|
||||
page = query.get("page")
|
||||
per_page = query.get("per_page")
|
||||
|
||||
project_supervisor_query = ProjectSupervisor.search_by_fullname_and_mode_and_order_by_first_name_or_last_name(
|
||||
year_group_id, fullname, order_by_first_name, order_by_last_name)
|
||||
project_supervisor_query = ProjectSupervisor.search_by_fullname(
|
||||
year_group_id, fullname, order_by_first_name, order_by_last_name
|
||||
)
|
||||
|
||||
data = paginate_models(page, project_supervisor_query, per_page)
|
||||
# print(get_debug_queries()[0])
|
||||
return {
|
||||
"project_supervisors": data['items'],
|
||||
"max_pages": data['max_pages']
|
||||
}
|
||||
return {"project_supervisors": data["items"], "max_pages": data["max_pages"]}
|
||||
|
||||
|
||||
@bp.post("/<int:year_group_id>/")
|
||||
@ -42,8 +45,11 @@ def create_project_supervisor(year_group_id: int, data: dict) -> dict:
|
||||
if year_group is None:
|
||||
abort(404, "Not found year group!")
|
||||
|
||||
email = data['email']
|
||||
project_supervisor = ProjectSupervisor.query.filter(ProjectSupervisor.email == email).first()
|
||||
email = data["email"]
|
||||
project_supervisor = ProjectSupervisor.query.filter(
|
||||
ProjectSupervisor.email == email,
|
||||
ProjectSupervisor.year_group_id == year_group_id,
|
||||
).first()
|
||||
if project_supervisor is not None:
|
||||
abort(400, "Project Supervisor has already exists!")
|
||||
|
||||
@ -57,20 +63,26 @@ def create_project_supervisor(year_group_id: int, data: dict) -> dict:
|
||||
@bp.get("/<int:project_supervisor_id>/detail/")
|
||||
@bp.output(ProjectSupervisorSchema)
|
||||
def detail_project_supervisor(project_supervisor_id: int) -> ProjectSupervisor:
|
||||
project_supervisor = ProjectSupervisor.query.filter_by(id=project_supervisor_id).first()
|
||||
project_supervisor = ProjectSupervisor.query.filter_by(
|
||||
id=project_supervisor_id
|
||||
).first()
|
||||
if project_supervisor is None:
|
||||
abort(404, 'Not found project supervisor!')
|
||||
abort(404, "Not found project supervisor!")
|
||||
return project_supervisor
|
||||
|
||||
|
||||
@bp.delete("/<int:project_supervisor_id>/")
|
||||
@bp.output(MessageSchema)
|
||||
def delete_project_supervisor(project_supervisor_id: int) -> dict:
|
||||
project_supervisor = ProjectSupervisor.query.filter_by(id=project_supervisor_id).first()
|
||||
project_supervisor = ProjectSupervisor.query.filter_by(
|
||||
id=project_supervisor_id
|
||||
).first()
|
||||
if project_supervisor is None:
|
||||
abort(404, "Not found project supervisor!")
|
||||
|
||||
count_groups = len(Group.query.filter(Group.project_supervisor_id == project_supervisor.id).all())
|
||||
count_groups = len(
|
||||
Group.query.filter(Group.project_supervisor_id == project_supervisor.id).all()
|
||||
)
|
||||
if count_groups > 0:
|
||||
abort(400, "Project Supervisor has at least one group!")
|
||||
|
||||
@ -84,13 +96,15 @@ def delete_project_supervisor(project_supervisor_id: int) -> dict:
|
||||
@bp.output(MessageSchema)
|
||||
def edit_project_supervisor(project_supervisor_id: int, data: dict) -> dict:
|
||||
if not data:
|
||||
abort(400, 'You have passed empty data!')
|
||||
abort(400, "You have passed empty data!")
|
||||
|
||||
project_supervisor_query = ProjectSupervisor.query.filter_by(id=project_supervisor_id)
|
||||
project_supervisor_query = ProjectSupervisor.query.filter_by(
|
||||
id=project_supervisor_id
|
||||
)
|
||||
project_supervisor = project_supervisor_query.first()
|
||||
|
||||
if project_supervisor is None:
|
||||
abort(404, f"Not found project supervisor!")
|
||||
abort(404, "Not found project supervisor!")
|
||||
|
||||
project_supervisor_query.update(data)
|
||||
db.session.commit()
|
||||
@ -104,19 +118,34 @@ def copy_project_supervisors_from_last_year_group(year_group_id: int) -> dict:
|
||||
if year_group is None:
|
||||
abort(404, "Not found year group!")
|
||||
|
||||
last_year_group = YearGroup.query.filter(YearGroup.mode == year_group.mode). \
|
||||
filter(YearGroup.id != year_group_id).filter(YearGroup.created_at < year_group.created_at). \
|
||||
order_by(db.desc(YearGroup.created_at)).first()
|
||||
last_year_group = (
|
||||
YearGroup.query.filter(YearGroup.mode == year_group.mode)
|
||||
.filter(YearGroup.id != year_group_id)
|
||||
.filter(YearGroup.created_at < year_group.created_at)
|
||||
.order_by(db.desc(YearGroup.created_at))
|
||||
.first()
|
||||
)
|
||||
if last_year_group is None:
|
||||
abort(400, "The latest year group doesn't exist!")
|
||||
|
||||
project_supervisors = ProjectSupervisor.query.filter(ProjectSupervisor.year_group_id == last_year_group.id).all()
|
||||
current_project_supervisors_email_in_new_year_group = [ps.email for ps in ProjectSupervisor.query.filter(
|
||||
ProjectSupervisor.year_group_id == year_group_id).all()]
|
||||
project_supervisors = ProjectSupervisor.query.filter(
|
||||
ProjectSupervisor.year_group_id == last_year_group.id
|
||||
).all()
|
||||
current_project_supervisors_email_in_new_year_group = [
|
||||
ps.email
|
||||
for ps in ProjectSupervisor.query.filter(
|
||||
ProjectSupervisor.year_group_id == year_group_id
|
||||
).all()
|
||||
]
|
||||
for ps in project_supervisors:
|
||||
if ps.email not in current_project_supervisors_email_in_new_year_group:
|
||||
new_ps = ProjectSupervisor(first_name=ps.first_name, last_name=ps.last_name, email=ps.email,
|
||||
limit_group=ps.limit_group, year_group_id=year_group_id)
|
||||
new_ps = ProjectSupervisor(
|
||||
first_name=ps.first_name,
|
||||
last_name=ps.last_name,
|
||||
email=ps.email,
|
||||
limit_group=ps.limit_group,
|
||||
year_group_id=year_group_id,
|
||||
)
|
||||
db.session.add(new_ps)
|
||||
db.session.commit()
|
||||
|
||||
|
@ -1,44 +1,51 @@
|
||||
from random import randint
|
||||
from itertools import islice
|
||||
from random import randint
|
||||
|
||||
from flask import Response, abort
|
||||
from apiflask import APIBlueprint
|
||||
from flask import Response, abort
|
||||
from sqlalchemy import or_
|
||||
from flask_sqlalchemy import get_debug_queries
|
||||
|
||||
from ...students.models import Student, Group, YearGroup
|
||||
from ...project_supervisor.models import ProjectSupervisor
|
||||
from ..schemas import StudentSchema, StudentEditSchema, StudentsPaginationSchema, YearGroupInfoQuery, \
|
||||
StudentCreateSchema, FileSchema, StudentQuerySchema, StudentListFileDownloaderSchema
|
||||
from ...dependencies import db
|
||||
from ..utils import parse_csv, generate_csv
|
||||
from ..exceptions import InvalidNameOrTypeHeaderException
|
||||
from ...base.utils import paginate_models, is_allowed_extensions
|
||||
from ...base.schemas import MessageSchema
|
||||
from ...base.utils import is_allowed_extensions, paginate_models
|
||||
from ...dependencies import db
|
||||
from ...project_supervisor.models import ProjectSupervisor
|
||||
from ...students.models import Group, Student, YearGroup
|
||||
from ..exceptions import InvalidNameOrTypeHeaderException
|
||||
from ..schemas.students import (
|
||||
FileSchema,
|
||||
StudentCreateSchema,
|
||||
StudentEditSchema,
|
||||
StudentListFileDownloaderSchema,
|
||||
StudentQuerySchema,
|
||||
StudentSchema,
|
||||
StudentsPaginationSchema,
|
||||
YearGroupInfoQuery,
|
||||
)
|
||||
from ..utils import generate_csv, parse_csv
|
||||
|
||||
bp = APIBlueprint("students", __name__, url_prefix="/students")
|
||||
|
||||
|
||||
@bp.get("/<int:year_group_id>/")
|
||||
@bp.input(StudentQuerySchema, location='query')
|
||||
@bp.input(StudentQuerySchema, location="query")
|
||||
@bp.output(StudentsPaginationSchema)
|
||||
def list_students(year_group_id: int, query: dict) -> dict:
|
||||
# add filter by year group
|
||||
fullname = query.get('fullname')
|
||||
order_by_first_name = query.get('order_by_first_name')
|
||||
order_by_last_name = query.get('order_by_last_name')
|
||||
page = query.get('page')
|
||||
per_page = query.get('per_page')
|
||||
fullname = query.get("fullname")
|
||||
order_by_first_name = query.get("order_by_first_name")
|
||||
order_by_last_name = query.get("order_by_last_name")
|
||||
page = query.get("page")
|
||||
per_page = query.get("per_page")
|
||||
|
||||
student_query = Student.search_by_fullname_and_mode_and_order_by_first_name_or_last_name(
|
||||
year_group_id, fullname, order_by_first_name, order_by_last_name)
|
||||
student_query = (
|
||||
Student.search_by_fullname_and_mode_and_order_by_first_name_or_last_name(
|
||||
year_group_id, fullname, order_by_first_name, order_by_last_name
|
||||
)
|
||||
)
|
||||
|
||||
data = paginate_models(page, student_query, per_page)
|
||||
# print(get_debug_queries()[0])
|
||||
return {
|
||||
"students": data['items'],
|
||||
"max_pages": data['max_pages']
|
||||
}
|
||||
return {"students": data["items"], "max_pages": data["max_pages"]}
|
||||
|
||||
|
||||
@bp.get("/<int:student_id>/detail/")
|
||||
@ -66,13 +73,13 @@ def delete_student(student_id: int) -> dict:
|
||||
@bp.output(MessageSchema)
|
||||
def edit_student(student_id: int, data: dict) -> dict:
|
||||
if not data:
|
||||
abort(400, 'You have passed empty data!')
|
||||
abort(400, "You have passed empty data!")
|
||||
|
||||
student_query = Student.query.filter(Student.id==student_id)
|
||||
student_query = Student.query.filter(Student.id == student_id)
|
||||
student = student_query.first()
|
||||
|
||||
if student is None:
|
||||
abort(404, 'Not found student!')
|
||||
abort(404, "Not found student!")
|
||||
|
||||
student_query.update(data)
|
||||
db.session.commit()
|
||||
@ -84,20 +91,21 @@ def edit_student(student_id: int, data: dict) -> dict:
|
||||
@bp.input(StudentCreateSchema)
|
||||
@bp.output(MessageSchema)
|
||||
def create_student(data: dict) -> dict:
|
||||
index = data['index']
|
||||
yg_id = data['year_group_id']
|
||||
del data['year_group_id']
|
||||
index = data["index"]
|
||||
yg_id = data["year_group_id"]
|
||||
del data["year_group_id"]
|
||||
|
||||
student = Student.query.filter(Student.index == index, Student.year_group_id == yg_id).first()
|
||||
student = Student.query.filter(
|
||||
Student.index == index, Student.year_group_id == yg_id
|
||||
).first()
|
||||
if student is not None:
|
||||
abort(400, "Student has already assigned to this year group!")
|
||||
|
||||
# add student to the chosen year group
|
||||
year_group = YearGroup.query.filter(YearGroup.id == yg_id).first()
|
||||
if year_group is None:
|
||||
abort(404, "Not found year group!")
|
||||
|
||||
dummy_email = f'student{randint(1, 300_000)}@gmail.com'
|
||||
dummy_email = f"student{randint(1, 300_000)}@gmail.com"
|
||||
student = Student(**data, email=dummy_email, year_group_id=yg_id)
|
||||
db.session.add(student)
|
||||
db.session.commit()
|
||||
@ -106,18 +114,18 @@ def create_student(data: dict) -> dict:
|
||||
|
||||
|
||||
@bp.post("/upload/")
|
||||
@bp.input(YearGroupInfoQuery, location='query')
|
||||
@bp.input(FileSchema, location='form_and_files')
|
||||
@bp.input(YearGroupInfoQuery, location="query")
|
||||
@bp.input(FileSchema, location="form_and_files")
|
||||
@bp.output(MessageSchema)
|
||||
def upload_students(query: dict, file: dict) -> dict:
|
||||
"""Add only Students to chosen year group if students exist in db and assigned to correct year group,
|
||||
they will be omitted"""
|
||||
year_group_id = query.get('year_group_id')
|
||||
"""Add only Students to chosen year group if students exist in db and
|
||||
assigned to correct year group, they will be omitted"""
|
||||
year_group_id = query.get("year_group_id")
|
||||
yg = YearGroup.query.filter(YearGroup.id == year_group_id).first()
|
||||
if yg is None:
|
||||
abort(404, "Not found year group!")
|
||||
|
||||
uploaded_file = file.get('file')
|
||||
uploaded_file = file.get("file")
|
||||
if uploaded_file and is_allowed_extensions(uploaded_file.filename):
|
||||
try:
|
||||
students = parse_csv(uploaded_file, year_group_id)
|
||||
@ -128,10 +136,19 @@ def upload_students(query: dict, file: dict) -> dict:
|
||||
if len(list_of_students) == 0:
|
||||
break
|
||||
|
||||
students_in_db = Student.query.filter(or_(Student.index == s.index for s in list_of_students)).\
|
||||
filter(Student.year_group_id==year_group_id).all()
|
||||
students_in_db = (
|
||||
Student.query.filter(
|
||||
or_(Student.index == s.index for s in list_of_students)
|
||||
)
|
||||
.filter(Student.year_group_id == year_group_id)
|
||||
.all()
|
||||
)
|
||||
student_index_in_db = [s.index for s in students_in_db]
|
||||
students_not_exists_in_db = list(filter(lambda s: s.index not in student_index_in_db, list_of_students))
|
||||
students_not_exists_in_db = list(
|
||||
filter(
|
||||
lambda s: s.index not in student_index_in_db, list_of_students
|
||||
)
|
||||
)
|
||||
db.session.add_all(students_not_exists_in_db)
|
||||
db.session.commit()
|
||||
|
||||
@ -144,17 +161,23 @@ def upload_students(query: dict, file: dict) -> dict:
|
||||
|
||||
|
||||
@bp.post("/download/")
|
||||
@bp.input(StudentListFileDownloaderSchema, location='query')
|
||||
@bp.input(StudentListFileDownloaderSchema, location="query")
|
||||
def download_students(query: dict) -> Response:
|
||||
year_group_id = query.get('year_group_id')
|
||||
students_and_groups = db.session.query(Student, Group).join(Group, Student.groups). \
|
||||
filter(Group.year_group_id == year_group_id). \
|
||||
join(ProjectSupervisor).all()
|
||||
year_group_id = query.get("year_group_id")
|
||||
students_and_groups = (
|
||||
db.session.query(Student, Group)
|
||||
.join(Group, Student.groups)
|
||||
.filter(Group.year_group_id == year_group_id)
|
||||
.join(ProjectSupervisor)
|
||||
.all()
|
||||
)
|
||||
|
||||
if len(students_and_groups) == 0:
|
||||
abort(404, "Not found students!")
|
||||
|
||||
csv_file = generate_csv(students_and_groups)
|
||||
response = Response(csv_file, mimetype='text/csv')
|
||||
response.headers.set("Content-Disposition", "attachment", filename="students_list.csv")
|
||||
response = Response(csv_file, mimetype="text/csv")
|
||||
response.headers.set(
|
||||
"Content-Disposition", "attachment", filename="students_list.csv"
|
||||
)
|
||||
return response
|
||||
|
@ -1,32 +1,38 @@
|
||||
from apiflask import APIBlueprint
|
||||
from flask import abort
|
||||
from flask_sqlalchemy import get_debug_queries
|
||||
|
||||
from ...dependencies import db
|
||||
from ...examination_schedule.models import ExaminationSchedule, TermOfDefence
|
||||
from ...project_supervisor.models import ProjectSupervisor
|
||||
from ..schemas import WorkloadSchema
|
||||
from ..schemas.examination_schedule import WorkloadSchema
|
||||
|
||||
bp = APIBlueprint("workloads", __name__, url_prefix="/")
|
||||
|
||||
|
||||
@bp.get('/examination_schedule/<int:examination_schedule_id>/workloads/')
|
||||
@bp.get("/examination_schedule/<int:examination_schedule_id>/workloads/")
|
||||
@bp.output(WorkloadSchema)
|
||||
def workloads_statistics(examination_schedule_id: int) -> dict:
|
||||
es = ExaminationSchedule.query.filter_by(id=examination_schedule_id).first()
|
||||
if es is None:
|
||||
abort(404, "Not found examination schedule!")
|
||||
|
||||
statistics = db.session.query(
|
||||
statistics = (
|
||||
db.session.query(
|
||||
ProjectSupervisor.first_name + " " + ProjectSupervisor.last_name,
|
||||
db.func.count(TermOfDefence.group_id),
|
||||
db.func.count(TermOfDefence.id),
|
||||
).join(TermOfDefence.members_of_committee). \
|
||||
group_by(ProjectSupervisor.id).all()
|
||||
)
|
||||
.join(TermOfDefence.members_of_committee)
|
||||
.group_by(ProjectSupervisor.id)
|
||||
.all()
|
||||
)
|
||||
|
||||
# print(statistics)
|
||||
# print(len(statistics))
|
||||
# print(get_debug_queries())
|
||||
workloads = ({"full_name": s[0], "groups_assigned_to_his_committee": s[1],
|
||||
"assigned_to_committee": s[2]} for s in statistics)
|
||||
return {'workloads': workloads}
|
||||
workloads = (
|
||||
{
|
||||
"full_name": s[0],
|
||||
"groups_assigned_to_his_committee": s[1],
|
||||
"assigned_to_committee": s[2],
|
||||
}
|
||||
for s in statistics
|
||||
)
|
||||
return {"workloads": workloads}
|
||||
|
@ -1,22 +1,28 @@
|
||||
from flask import abort
|
||||
from apiflask import APIBlueprint
|
||||
from flask import abort
|
||||
|
||||
from ...students.models import YearGroup
|
||||
from ..schemas import YearGroupSchema, YearGroupPaginationSchema, YearGroupQuerySchema
|
||||
from ...dependencies import db
|
||||
from ...base.utils import paginate_models
|
||||
from ...base.schemas import MessageSchema
|
||||
from ...base.utils import paginate_models
|
||||
from ...dependencies import db
|
||||
from ...students.models import YearGroup
|
||||
from ..schemas.year_group import (
|
||||
YearGroupPaginationSchema,
|
||||
YearGroupQuerySchema,
|
||||
YearGroupSchema,
|
||||
)
|
||||
|
||||
bp = APIBlueprint("year_group", __name__, url_prefix="/year-group")
|
||||
|
||||
|
||||
@bp.post('/')
|
||||
@bp.post("/")
|
||||
@bp.input(YearGroupSchema)
|
||||
@bp.output(MessageSchema, status_code=201)
|
||||
def create_year_group(data: dict) -> dict:
|
||||
name = data['name']
|
||||
mode = data['mode']
|
||||
year_group = YearGroup.query.filter(YearGroup.name == name, YearGroup.mode == mode).first()
|
||||
name = data["name"]
|
||||
mode = data["mode"]
|
||||
year_group = YearGroup.query.filter(
|
||||
YearGroup.name == name, YearGroup.mode == mode
|
||||
).first()
|
||||
if year_group is not None:
|
||||
abort(400, "Year group has already exists!")
|
||||
|
||||
@ -27,38 +33,37 @@ def create_year_group(data: dict) -> dict:
|
||||
return {"message": "Year group was created!"}
|
||||
|
||||
|
||||
@bp.get('/')
|
||||
@bp.input(YearGroupQuerySchema, location='query')
|
||||
@bp.get("/")
|
||||
@bp.input(YearGroupQuerySchema, location="query")
|
||||
@bp.output(YearGroupPaginationSchema)
|
||||
def list_of_year_groups(query: dict) -> dict:
|
||||
page = query.get('page')
|
||||
per_page = query.get('per_page')
|
||||
page = query.get("page")
|
||||
per_page = query.get("per_page")
|
||||
|
||||
year_group_query = YearGroup.query.order_by(db.desc(YearGroup.created_at))
|
||||
data = paginate_models(page, year_group_query, per_page)
|
||||
|
||||
return {
|
||||
"year_groups": data['items'],
|
||||
"max_pages": data['max_pages']
|
||||
}
|
||||
return {"year_groups": data["items"], "max_pages": data["max_pages"]}
|
||||
|
||||
|
||||
@bp.put('/<int:id>/')
|
||||
@bp.put("/<int:id>/")
|
||||
@bp.input(YearGroupSchema)
|
||||
@bp.output(MessageSchema)
|
||||
def update_year_of_group(id: int, data: dict) -> dict:
|
||||
if not data:
|
||||
abort(400, 'You have passed empty data!')
|
||||
abort(400, "You have passed empty data!")
|
||||
|
||||
year_group_query = YearGroup.query.filter(YearGroup.id == id)
|
||||
year_group = year_group_query.first()
|
||||
|
||||
if year_group is None:
|
||||
abort(404, 'Not found year group!')
|
||||
abort(404, "Not found year group!")
|
||||
|
||||
name = data['name']
|
||||
mode = data['mode']
|
||||
year_group = YearGroup.query.filter(YearGroup.name == name, YearGroup.mode == mode, YearGroup.id != id).first()
|
||||
name = data["name"]
|
||||
mode = data["mode"]
|
||||
year_group = YearGroup.query.filter(
|
||||
YearGroup.name == name, YearGroup.mode == mode, YearGroup.id != id
|
||||
).first()
|
||||
if year_group is not None:
|
||||
abort(400, "Year group has already exists!")
|
||||
|
||||
@ -68,12 +73,12 @@ def update_year_of_group(id: int, data: dict) -> dict:
|
||||
return {"message": "Year group was updated!"}
|
||||
|
||||
|
||||
@bp.delete('/<int:id>/')
|
||||
@bp.delete("/<int:id>/")
|
||||
@bp.output(MessageSchema, status_code=202)
|
||||
def delete_year_of_group(id: int) -> dict:
|
||||
year_group = YearGroup.query.filter_by(id=id).first()
|
||||
if year_group is None:
|
||||
abort(404, f"Year group doesn't exist!")
|
||||
abort(404, "Year group doesn't exist!")
|
||||
db.session.delete(year_group)
|
||||
db.session.commit()
|
||||
return {"message": "Year group was deleted!"}
|
||||
|
@ -1,11 +0,0 @@
|
||||
from .enrollments import TermOfDefenceSchema, TermOfDefenceListSchema, TemporaryAvailabilityListSchema, \
|
||||
AssignedGroupToTermOfDefenceListSchema
|
||||
from .examination_schedule import ExaminationScheduleSchema, ExaminationScheduleUpdateSchema, \
|
||||
ExaminationSchedulesPaginationSchema, ExaminationSchedulesQuerySchema, WorkloadSchema
|
||||
from .groups import GroupQuerySchema, GroupsPaginationSchema, GroupCreateSchema, GroupEditSchema, GroupIdSchema
|
||||
from .project_supervisor import ProjectSupervisorQuerySchema, ProjectSupervisorsPaginationSchema, \
|
||||
ProjectSupervisorCreateSchema, ProjectSupervisorEditSchema
|
||||
from .students import ProjectSupervisorSchema, GroupSchema, StudentSchema, StudentsPaginationSchema, \
|
||||
StudentListFileDownloaderSchema, StudentCreateSchema, StudentEditSchema, MessageWithIdSchema, FileSchema, \
|
||||
StudentQuerySchema, YearGroupInfoQuery, DetailGroupSchema
|
||||
from .year_group import YearGroupSchema, YearGroupPaginationSchema, YearGroupQuerySchema
|
@ -4,9 +4,16 @@ from ..validators import validate_datetime_greater_than_now
|
||||
|
||||
|
||||
class TermOfDefenceSchema(Schema):
|
||||
start_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
|
||||
end_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
|
||||
project_supervisors = fields.List(fields.Integer(required=True), validate=validate.Length(3, 3))
|
||||
start_date = fields.DateTime(
|
||||
validate=validate_datetime_greater_than_now, required=True
|
||||
)
|
||||
end_date = fields.DateTime(
|
||||
validate=validate_datetime_greater_than_now, required=True
|
||||
)
|
||||
project_supervisors = fields.List(
|
||||
fields.Integer(required=True), validate=validate.Length(3, 3)
|
||||
)
|
||||
chairman_of_committee = fields.Integer(required=True)
|
||||
|
||||
|
||||
class ProjectSupervisorForTermOfDefenceSchema(Schema):
|
||||
@ -19,30 +26,35 @@ class TermOfDefenceItemSchema(Schema):
|
||||
id = fields.Integer()
|
||||
start_date = fields.DateTime()
|
||||
end_date = fields.DateTime()
|
||||
members_of_committee = fields.List(fields.Nested(ProjectSupervisorForTermOfDefenceSchema))
|
||||
members_of_committee = fields.List(
|
||||
fields.Nested(ProjectSupervisorForTermOfDefenceSchema)
|
||||
)
|
||||
chairman_of_committee = fields.Integer()
|
||||
|
||||
|
||||
class TermOfDefenceListSchema(Schema):
|
||||
term_of_defences = fields.List(fields.Nested(TermOfDefenceItemSchema))
|
||||
|
||||
|
||||
class StudentDataItemSchema(Schema):
|
||||
class StudentDataItemAssignedGroupSchema(Schema):
|
||||
index = fields.Integer()
|
||||
first_name = fields.Str()
|
||||
last_name = fields.Str()
|
||||
|
||||
|
||||
class GroupDataItemSchema(Schema):
|
||||
class GroupDataItemAssignedGroupSchema(Schema):
|
||||
name = fields.Str()
|
||||
students = fields.List(fields.Nested(StudentDataItemSchema))
|
||||
students = fields.List(fields.Nested(StudentDataItemAssignedGroupSchema))
|
||||
|
||||
|
||||
class AssignedGroupToTermOfDefenceItemSchema(TermOfDefenceItemSchema):
|
||||
group = fields.Nested(GroupDataItemSchema)
|
||||
class AssignedGroupToTermOfDefenceDataItemSchema(TermOfDefenceItemSchema):
|
||||
group = fields.Nested(GroupDataItemAssignedGroupSchema)
|
||||
|
||||
|
||||
class AssignedGroupToTermOfDefenceListSchema(Schema):
|
||||
term_of_defences = fields.List(fields.Nested(AssignedGroupToTermOfDefenceItemSchema))
|
||||
term_of_defences = fields.List(
|
||||
fields.Nested(AssignedGroupToTermOfDefenceDataItemSchema)
|
||||
)
|
||||
|
||||
|
||||
class ProjectSupervisorForTemporaryAvailabilitySchema(Schema):
|
||||
@ -58,4 +70,6 @@ class TemporaryAvailabilityItemSchema(Schema):
|
||||
|
||||
|
||||
class TemporaryAvailabilityListSchema(Schema):
|
||||
temporary_availabilities = fields.List(fields.Nested(TemporaryAvailabilityItemSchema))
|
||||
temporary_availabilities = fields.List(
|
||||
fields.Nested(TemporaryAvailabilityItemSchema)
|
||||
)
|
||||
|
@ -1,30 +1,30 @@
|
||||
from marshmallow import fields, validate, Schema
|
||||
from marshmallow import Schema, fields, validate
|
||||
|
||||
from ..validators import validate_datetime_greater_than_now
|
||||
|
||||
|
||||
class ExaminationScheduleSchema(Schema):
|
||||
title = fields.Str(validate=validate.Length(min=1, max=100), required=True)
|
||||
start_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
|
||||
end_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
|
||||
|
||||
|
||||
class ExaminationScheduleUpdateSchema(Schema):
|
||||
start_date_for_enrollment_students = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
|
||||
end_date_for_enrollment_students = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
|
||||
start_date = fields.DateTime(
|
||||
validate=validate_datetime_greater_than_now, required=True
|
||||
)
|
||||
end_date = fields.DateTime(
|
||||
validate=validate_datetime_greater_than_now, required=True
|
||||
)
|
||||
|
||||
|
||||
class ExaminationScheduleListItemSchema(Schema):
|
||||
id = fields.Integer()
|
||||
title = fields.Str()
|
||||
open_enrollments = fields.String()
|
||||
start_date = fields.DateTime()
|
||||
end_date = fields.DateTime()
|
||||
start_date_for_enrollment_students = fields.DateTime()
|
||||
end_date_for_enrollment_students = fields.DateTime()
|
||||
|
||||
|
||||
class ExaminationSchedulesPaginationSchema(Schema):
|
||||
examination_schedules = fields.List(fields.Nested(ExaminationScheduleListItemSchema))
|
||||
examination_schedules = fields.List(
|
||||
fields.Nested(ExaminationScheduleListItemSchema)
|
||||
)
|
||||
max_pages = fields.Integer()
|
||||
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
from marshmallow import Schema, fields, validate
|
||||
|
||||
from ..validators import validate_index
|
||||
from .students import GroupSchema
|
||||
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
from marshmallow import fields, validate, Schema
|
||||
from marshmallow import Schema, fields, validate
|
||||
|
||||
from .students import ProjectSupervisorSchema
|
||||
|
||||
class ProjectSupervisorSchema(Schema):
|
||||
id = fields.Integer()
|
||||
first_name = fields.Str()
|
||||
last_name = fields.Str()
|
||||
email = fields.Str()
|
||||
limit_group = fields.Integer()
|
||||
|
||||
|
||||
class ProjectSupervisorQuerySchema(Schema):
|
||||
@ -19,7 +25,9 @@ class ProjectSupervisorsPaginationSchema(Schema):
|
||||
class ProjectSupervisorCreateSchema(Schema):
|
||||
first_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
||||
last_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
||||
email = fields.Str(validate=[validate.Length(min=1, max=255), validate.Email()], required=True)
|
||||
email = fields.Str(
|
||||
validate=[validate.Length(min=1, max=255), validate.Email()], required=True
|
||||
)
|
||||
limit_group = fields.Integer(required=True)
|
||||
|
||||
|
||||
|
@ -1,15 +1,9 @@
|
||||
from marshmallow import fields, validate, Schema
|
||||
from marshmallow import Schema, fields, validate
|
||||
|
||||
from ...dependencies import ma
|
||||
from ...students.models import Student, Group
|
||||
from ...project_supervisor.models import ProjectSupervisor
|
||||
from ...students.models import Group, Student
|
||||
from ..validators import validate_index
|
||||
|
||||
|
||||
class ProjectSupervisorSchema(ma.SQLAlchemyAutoSchema):
|
||||
class Meta:
|
||||
model = ProjectSupervisor
|
||||
include_relationships = False
|
||||
from .project_supervisor import ProjectSupervisorSchema
|
||||
|
||||
|
||||
class GroupSchema(ma.SQLAlchemyAutoSchema):
|
||||
@ -45,7 +39,6 @@ class StudentCreateSchema(ma.Schema):
|
||||
class StudentEditSchema(ma.Schema):
|
||||
first_name = fields.Str(validate=validate.Length(min=1, max=255))
|
||||
last_name = fields.Str(validate=validate.Length(min=1, max=255))
|
||||
pesel = fields.Str(validate=validate.Length(min=0, max=11))
|
||||
index = fields.Integer(validate=validate_index)
|
||||
|
||||
|
||||
@ -55,7 +48,7 @@ class MessageWithIdSchema(ma.Schema):
|
||||
|
||||
|
||||
class FileSchema(ma.Schema):
|
||||
file = fields.Raw(metadata={'type': 'file'}, required=True)
|
||||
file = fields.Raw(metadata={"type": "file"}, required=True)
|
||||
|
||||
|
||||
class StudentQuerySchema(ma.Schema):
|
||||
@ -69,8 +62,12 @@ class StudentQuerySchema(ma.Schema):
|
||||
class YearGroupInfoQuery(Schema):
|
||||
year_group_id = fields.Integer(required=True)
|
||||
|
||||
|
||||
class DetailGroupSchema(ma.SQLAlchemyAutoSchema):
|
||||
project_supervisor = fields.Nested(ProjectSupervisorSchema)
|
||||
students = fields.List(fields.Nested(StudentSchema), validate=validate.Length(min=1, max=255))
|
||||
students = fields.List(
|
||||
fields.Nested(StudentSchema), validate=validate.Length(min=1, max=255)
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Group
|
||||
|
@ -1,4 +1,4 @@
|
||||
from marshmallow import Schema, fields, validate, ValidationError
|
||||
from marshmallow import Schema, ValidationError, fields, validate
|
||||
|
||||
from ...base.mode import ModeGroups
|
||||
|
||||
@ -10,7 +10,7 @@ def validate_mode(value: str) -> str:
|
||||
|
||||
|
||||
class YearGroupSchema(Schema):
|
||||
name = fields.Str(validate=validate.Regexp(r'^\d{4}\/\d{4}$'), required=True)
|
||||
name = fields.Str(validate=validate.Regexp(r"^\d{4}\/\d{4}$"), required=True)
|
||||
mode = fields.Str(validate=validate_mode, required=True)
|
||||
|
||||
|
||||
|
@ -3,54 +3,85 @@ import json
|
||||
from collections import defaultdict
|
||||
from datetime import datetime, timedelta
|
||||
from io import BytesIO
|
||||
from typing import Generator, Union, Any, List, Tuple, TextIO
|
||||
from pathlib import Path
|
||||
from typing import Any, Generator, List, TextIO, Tuple, Union
|
||||
|
||||
import pandas as pd
|
||||
from flask import current_app
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.enums import TA_CENTER
|
||||
from reportlab.lib.styles import getSampleStyleSheet
|
||||
from reportlab.lib.units import mm, inch
|
||||
from reportlab.platypus import SimpleDocTemplate, Paragraph, PageBreak, Table
|
||||
from reportlab.lib.units import inch, mm
|
||||
from reportlab.pdfbase import pdfmetrics
|
||||
from reportlab.pdfbase.ttfonts import TTFont
|
||||
from reportlab.platypus import PageBreak, Paragraph, SimpleDocTemplate, Table
|
||||
from werkzeug.datastructures import FileStorage
|
||||
|
||||
from .exceptions import InvalidNameOrTypeHeaderException
|
||||
from ..students.models import Student, Group, ProjectGradeSheet
|
||||
from ..base.mode import ModeGroups
|
||||
from ..examination_schedule.models import TermOfDefence
|
||||
from ..students.models import Group, ProjectGradeSheet, Student
|
||||
from .exceptions import InvalidNameOrTypeHeaderException
|
||||
|
||||
|
||||
def check_columns(df: pd.DataFrame) -> bool:
|
||||
headers = set(df.keys().values)
|
||||
column_names = ['NAZWISKO', 'IMIE', 'INDEKS', 'EMAIL']
|
||||
column_types = ['object', 'object', 'int', 'object']
|
||||
return all((column_name in headers for column_name in column_names)) and \
|
||||
all((str(df.dtypes[column_name]).startswith(column_type) for column_name, column_type in
|
||||
zip(column_names, column_types)))
|
||||
column_names = ["NAZWISKO", "IMIE", "INDEKS", "EMAIL"]
|
||||
column_types = ["object", "object", "int", "object"]
|
||||
return all((column_name in headers for column_name in column_names)) and all(
|
||||
(
|
||||
str(df.dtypes[column_name]).startswith(column_type)
|
||||
for column_name, column_type in zip(column_names, column_types)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def parse_csv(file: Union[FileStorage, TextIO], year_group_id: int) -> Generator[Student, Any, None]:
|
||||
def parse_csv(
|
||||
file: Union[FileStorage, TextIO], year_group_id: int
|
||||
) -> Generator[Student, Any, None]:
|
||||
df = pd.read_csv(file)
|
||||
|
||||
if not check_columns(df):
|
||||
raise InvalidNameOrTypeHeaderException
|
||||
students = (Student(last_name=dict(item.items())['NAZWISKO'],
|
||||
first_name=dict(item.items())['IMIE'],
|
||||
index=dict(item.items())['INDEKS'],
|
||||
email=dict(item.items())['EMAIL'],
|
||||
year_group_id=year_group_id)
|
||||
for _, item in df.iterrows())
|
||||
students = (
|
||||
Student(
|
||||
last_name=dict(item.items())["NAZWISKO"],
|
||||
first_name=dict(item.items())["IMIE"],
|
||||
index=dict(item.items())["INDEKS"],
|
||||
email=dict(item.items())["EMAIL"],
|
||||
year_group_id=year_group_id,
|
||||
)
|
||||
for _, item in df.iterrows()
|
||||
)
|
||||
|
||||
return students
|
||||
|
||||
|
||||
def generate_csv(students_and_groups: List[Tuple[Student, Group]]) -> str:
|
||||
headers = ['INDEKS', 'IMIE', 'NAZWISKO', 'EMAIL', 'CDYD_KOD', 'PRZ_KOD', 'TZAJ_KOD', 'GR_NR', 'PRG_KOD']
|
||||
data = [(student.index, student.first_name, student.last_name, student.email,
|
||||
group.cdyd_kod, group.prz_kod, group.tzaj_kod, group.project_supervisor_id,
|
||||
None) for student, group in students_and_groups]
|
||||
headers = [
|
||||
"INDEKS",
|
||||
"IMIE",
|
||||
"NAZWISKO",
|
||||
"EMAIL",
|
||||
"CDYD_KOD",
|
||||
"PRZ_KOD",
|
||||
"TZAJ_KOD",
|
||||
"GR_NR",
|
||||
"PRG_KOD",
|
||||
]
|
||||
data = [
|
||||
(
|
||||
student.index,
|
||||
student.first_name,
|
||||
student.last_name,
|
||||
student.email,
|
||||
group.cdyd_kod,
|
||||
group.prz_kod,
|
||||
group.tzaj_kod,
|
||||
group.project_supervisor_id,
|
||||
None,
|
||||
)
|
||||
for student, group in students_and_groups
|
||||
]
|
||||
dataframe = defaultdict(list)
|
||||
for row in data:
|
||||
for idx, item in enumerate(row):
|
||||
@ -60,8 +91,9 @@ def generate_csv(students_and_groups: List[Tuple[Student, Group]]) -> str:
|
||||
return df.to_csv(index=False)
|
||||
|
||||
|
||||
def generate_range_dates(start_date: datetime, end_date: datetime, step_in_minutes: int) -> \
|
||||
Generator[Union[datetime, timedelta], Any, None]:
|
||||
def generate_range_dates(
|
||||
start_date: datetime, end_date: datetime, step_in_minutes: int
|
||||
) -> Generator[Union[datetime, timedelta], Any, None]:
|
||||
current_date = copy.copy(start_date)
|
||||
while True:
|
||||
next_date = current_date + timedelta(minutes=step_in_minutes)
|
||||
@ -72,10 +104,19 @@ def generate_range_dates(start_date: datetime, end_date: datetime, step_in_minut
|
||||
current_date = copy.copy(next_date)
|
||||
|
||||
|
||||
def generate_examination_schedule_pdf_file(title: str, nested_term_of_defences: List[List[TermOfDefence]],
|
||||
base_dir: Path) -> bytes:
|
||||
def generate_examination_schedule_pdf_file(
|
||||
title: str, nested_term_of_defences: List[List[TermOfDefence]], base_dir: Path
|
||||
) -> bytes:
|
||||
pagesize = (297 * mm, 210 * mm)
|
||||
headers = ["lp.", "Godzina", "Nazwa projektu", "Opiekun", "Zespol", "Komisja", "Uwagi"]
|
||||
headers = [
|
||||
"lp.",
|
||||
"Godzina",
|
||||
"Nazwa projektu",
|
||||
"Opiekun",
|
||||
"Zespol",
|
||||
"Komisja",
|
||||
"Uwagi",
|
||||
]
|
||||
pdf_buffer = BytesIO()
|
||||
my_doc = SimpleDocTemplate(
|
||||
pdf_buffer,
|
||||
@ -84,13 +125,13 @@ def generate_examination_schedule_pdf_file(title: str, nested_term_of_defences:
|
||||
leftMargin=1 * inch,
|
||||
rightMargin=1 * inch,
|
||||
bottomMargin=1 * inch,
|
||||
title=title
|
||||
title=title,
|
||||
)
|
||||
|
||||
pdfmetrics.registerFont(TTFont('Lato', base_dir / 'fonts' / 'Lato.ttf'))
|
||||
pdfmetrics.registerFont(TTFont("Lato", base_dir / "fonts" / "Lato.ttf"))
|
||||
style = getSampleStyleSheet()
|
||||
bodyText = style['BodyText']
|
||||
bodyText.fontName = 'Lato'
|
||||
bodyText = style["BodyText"]
|
||||
bodyText.fontName = "Lato"
|
||||
normal = style["Heading1"]
|
||||
normal.alignment = TA_CENTER
|
||||
flowables = []
|
||||
@ -99,7 +140,7 @@ def generate_examination_schedule_pdf_file(title: str, nested_term_of_defences:
|
||||
for term_of_defences in nested_term_of_defences:
|
||||
if len(term_of_defences) == 0:
|
||||
continue
|
||||
date = datetime.strftime(term_of_defences[0].start_date.date(), '%d.%m.%Y')
|
||||
date = datetime.strftime(term_of_defences[0].start_date.date(), "%d.%m.%Y")
|
||||
paragraph_1 = Paragraph(f"{title} ~ {date}", normal)
|
||||
flowables.append(paragraph_1)
|
||||
data = [headers]
|
||||
@ -107,7 +148,7 @@ def generate_examination_schedule_pdf_file(title: str, nested_term_of_defences:
|
||||
for idx, td in enumerate(term_of_defences, start=1):
|
||||
new_date = td.start_date + timedelta(hours=2)
|
||||
group_name = td.group.name if td.group is not None else ""
|
||||
if group_name != '':
|
||||
if group_name != "":
|
||||
ps = td.group.project_supervisor
|
||||
project_supervisor_fullname = f"{ps.first_name[0]}. {ps.last_name}"
|
||||
students = td.group.students
|
||||
@ -120,26 +161,39 @@ def generate_examination_schedule_pdf_file(title: str, nested_term_of_defences:
|
||||
members = td.members_of_committee
|
||||
# print(members)
|
||||
if len(members) == 0:
|
||||
committee = ''
|
||||
committee = ""
|
||||
else:
|
||||
members_iter = (f"{m.first_name[0]} {m.last_name}" for m in members)
|
||||
committee = ", ".join(members_iter)
|
||||
|
||||
data.append([str(idx), new_date.strftime("%H:%M"),
|
||||
data.append(
|
||||
[
|
||||
str(idx),
|
||||
new_date.strftime("%H:%M"),
|
||||
Paragraph(group_name, bodyText),
|
||||
Paragraph(project_supervisor_fullname, bodyText),
|
||||
Paragraph(team, bodyText),
|
||||
Paragraph(committee, bodyText),
|
||||
])
|
||||
]
|
||||
)
|
||||
# print(data)
|
||||
|
||||
table = Table(data=data,
|
||||
table = Table(
|
||||
data=data,
|
||||
style=[
|
||||
('GRID', (0, 0), (-1, -1), 0.5, colors.black),
|
||||
('BACKGROUND', (0, 0), (-1, 0), colors.HexColor("#A6F1A6")),
|
||||
('BACKGROUND', (0, 0), (1, -1), colors.HexColor("#A6F1A6"))
|
||||
("GRID", (0, 0), (-1, -1), 0.5, colors.black),
|
||||
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#A6F1A6")),
|
||||
("BACKGROUND", (0, 0), (1, -1), colors.HexColor("#A6F1A6")),
|
||||
],
|
||||
colWidths=[
|
||||
0.25 * inch,
|
||||
0.7 * inch,
|
||||
1.6 * inch,
|
||||
1.5 * inch,
|
||||
2.5 * inch,
|
||||
2.2 * inch,
|
||||
2 * inch,
|
||||
],
|
||||
colWidths=[0.25 * inch, 0.7 * inch, 1.6 * inch, 1.5 * inch, 2.5 * inch, 2.2 * inch, 2 * inch]
|
||||
)
|
||||
flowables.append(table)
|
||||
flowables.append(PageBreak())
|
||||
@ -150,8 +204,20 @@ def generate_examination_schedule_pdf_file(title: str, nested_term_of_defences:
|
||||
return pdf_value
|
||||
|
||||
|
||||
def get_duration_time(mode: str) -> int:
|
||||
duration_time = None
|
||||
if mode == ModeGroups.NON_STATIONARY.value:
|
||||
duration_time = 20
|
||||
elif mode in [
|
||||
ModeGroups.STATIONARY.value,
|
||||
ModeGroups.ENGLISH_SPEAKING_STATIONARY.value,
|
||||
]:
|
||||
duration_time = 30
|
||||
return duration_time
|
||||
|
||||
|
||||
def load_weight_for_project_grade_sheet() -> Union[dict, None]:
|
||||
base_dir = current_app.config.get('BASE_DIR')
|
||||
base_dir = current_app.config.get("BASE_DIR")
|
||||
config_dir = base_dir / "config"
|
||||
|
||||
with open(config_dir / "weights_project_grade_sheet.json") as f:
|
||||
@ -160,7 +226,9 @@ def load_weight_for_project_grade_sheet() -> Union[dict, None]:
|
||||
return data
|
||||
|
||||
|
||||
def calculate_points_for_one_term(weights: dict, project_grade_sheets: List[ProjectGradeSheet]) -> list:
|
||||
def calculate_points_for_one_term(
|
||||
weights: dict, project_grade_sheets: List[ProjectGradeSheet]
|
||||
) -> list:
|
||||
terms = []
|
||||
for pgs in project_grade_sheets:
|
||||
if pgs is None:
|
||||
@ -168,28 +236,30 @@ def calculate_points_for_one_term(weights: dict, project_grade_sheets: List[Proj
|
||||
continue
|
||||
|
||||
first_term_points = {
|
||||
'nominator': 0,
|
||||
'denominator': 0,
|
||||
"nominator": 0,
|
||||
"denominator": 0,
|
||||
}
|
||||
second_term_points = {
|
||||
'nominator': 0,
|
||||
'denominator': 0,
|
||||
"nominator": 0,
|
||||
"denominator": 0,
|
||||
}
|
||||
for weight_key, weight_value in weights.items():
|
||||
points = first_term_points if weight_key.endswith('1') else second_term_points
|
||||
points = (
|
||||
first_term_points if weight_key.endswith("1") else second_term_points
|
||||
)
|
||||
try:
|
||||
attribute_value = getattr(pgs, weight_key)
|
||||
except AttributeError:
|
||||
attribute_value = 0
|
||||
points['nominator'] += attribute_value * weight_value * 1 / 4
|
||||
points['denominator'] += weight_value
|
||||
points["nominator"] += attribute_value * weight_value * 1 / 4
|
||||
points["denominator"] += weight_value
|
||||
|
||||
try:
|
||||
fp = first_term_points['nominator'] / first_term_points['denominator']
|
||||
fp = first_term_points["nominator"] / first_term_points["denominator"]
|
||||
except ZeroDivisionError:
|
||||
fp = 0
|
||||
try:
|
||||
sp = second_term_points['nominator'] / second_term_points['denominator']
|
||||
sp = second_term_points["nominator"] / second_term_points["denominator"]
|
||||
except ZeroDivisionError:
|
||||
sp = 0
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_marshmallow import Marshmallow
|
||||
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
ma = Marshmallow()
|
||||
|
||||
|
@ -8,6 +8,6 @@ def register_error_handlers(app: APIFlask):
|
||||
@app.errorhandler(HTTPException)
|
||||
def handle_http_exception(e):
|
||||
response = e.get_response()
|
||||
response.data = json.dumps({'error': e.description})
|
||||
response.content_type = 'application/json'
|
||||
response.data = json.dumps({"error": e.description})
|
||||
response.content_type = "application/json"
|
||||
return response
|
||||
|
@ -1,18 +1,22 @@
|
||||
from ..dependencies import db
|
||||
from ..base.mode import EnrollmentsMode
|
||||
from ..base.models import Base
|
||||
from ..dependencies import db
|
||||
|
||||
|
||||
class ExaminationSchedule(Base):
|
||||
__tablename__ = 'examination_schedules'
|
||||
__tablename__ = "examination_schedules"
|
||||
|
||||
title = db.Column(db.String(100), unique=True, nullable=False)
|
||||
duration_time = db.Column(db.Integer, nullable=False) # in minutes
|
||||
start_date_for_enrollment_students = db.Column(db.DateTime)
|
||||
end_date_for_enrollment_students = db.Column(db.DateTime)
|
||||
open_enrollments = db.Column(
|
||||
db.String(1), default=EnrollmentsMode.INIT.value, nullable=False
|
||||
)
|
||||
start_date = db.Column(db.DateTime, nullable=False)
|
||||
end_date = db.Column(db.DateTime, nullable=False)
|
||||
year_group_id = db.Column(db.Integer, db.ForeignKey('year_groups.id'), nullable=False)
|
||||
year_group = db.relationship('YearGroup', backref='examination_schedules')
|
||||
year_group_id = db.Column(
|
||||
db.Integer, db.ForeignKey("year_groups.id"), nullable=False
|
||||
)
|
||||
year_group = db.relationship("YearGroup", backref="examination_schedules")
|
||||
|
||||
|
||||
committee = db.Table(
|
||||
@ -23,23 +27,42 @@ committee = db.Table(
|
||||
|
||||
|
||||
class TermOfDefence(Base):
|
||||
__tablename__ = 'term_of_defences'
|
||||
__tablename__ = "term_of_defences"
|
||||
|
||||
start_date = db.Column(db.DateTime, nullable=False)
|
||||
end_date = db.Column(db.DateTime, nullable=False)
|
||||
examination_schedule_id = db.Column(db.Integer, db.ForeignKey('examination_schedules.id'))
|
||||
examination_schedule = db.relationship('ExaminationSchedule', backref='term_of_defences')
|
||||
group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
|
||||
group = db.relationship("Group", uselist=False, backref='term_of_defence', lazy='joined')
|
||||
members_of_committee = db.relationship("ProjectSupervisor", secondary=committee, lazy='joined')
|
||||
examination_schedule_id = db.Column(
|
||||
db.Integer, db.ForeignKey("examination_schedules.id")
|
||||
)
|
||||
examination_schedule = db.relationship(
|
||||
"ExaminationSchedule", backref="term_of_defences"
|
||||
)
|
||||
group_id = db.Column(db.Integer, db.ForeignKey("groups.id"))
|
||||
group = db.relationship(
|
||||
"Group", uselist=False, backref="term_of_defence", lazy="joined"
|
||||
)
|
||||
members_of_committee = db.relationship(
|
||||
"ProjectSupervisor", secondary=committee, lazy="joined"
|
||||
)
|
||||
chairman_of_committee = db.Column(
|
||||
db.Integer, db.ForeignKey("project_supervisors.id")
|
||||
)
|
||||
|
||||
|
||||
class TemporaryAvailability(Base):
|
||||
__tablename__ = 'temporary_availabilities'
|
||||
__tablename__ = "temporary_availabilities"
|
||||
|
||||
start_date = db.Column(db.DateTime, nullable=False)
|
||||
end_date = db.Column(db.DateTime, nullable=False)
|
||||
examination_schedule_id = db.Column(db.Integer, db.ForeignKey('examination_schedules.id'), nullable=False)
|
||||
examination_schedule = db.relationship("ExaminationSchedule", backref='temporary_availabilities')
|
||||
project_supervisor_id = db.Column(db.Integer, db.ForeignKey('project_supervisors.id'), nullable=False)
|
||||
project_supervisor = db.relationship("ProjectSupervisor", backref='temporary_availabilities')
|
||||
examination_schedule_id = db.Column(
|
||||
db.Integer, db.ForeignKey("examination_schedules.id"), nullable=False
|
||||
)
|
||||
examination_schedule = db.relationship(
|
||||
"ExaminationSchedule", backref="temporary_availabilities"
|
||||
)
|
||||
project_supervisor_id = db.Column(
|
||||
db.Integer, db.ForeignKey("project_supervisors.id"), nullable=False
|
||||
)
|
||||
project_supervisor = db.relationship(
|
||||
"ProjectSupervisor", backref="temporary_availabilities"
|
||||
)
|
||||
|
@ -1,8 +1,8 @@
|
||||
from flask_sqlalchemy import BaseQuery
|
||||
|
||||
from ..dependencies import db
|
||||
from ..base.models import Person, Base
|
||||
from ..base.models import Base, Person
|
||||
from ..base.utils import order_by_column_name
|
||||
from ..dependencies import db
|
||||
from ..students.models import YearGroup
|
||||
|
||||
|
||||
@ -10,27 +10,41 @@ class ProjectSupervisor(Base, Person):
|
||||
__tablename__ = "project_supervisors"
|
||||
|
||||
limit_group = db.Column(db.Integer, default=3, nullable=False)
|
||||
year_group_id = db.Column(db.Integer, db.ForeignKey('year_groups.id'))
|
||||
year_group = db.relationship('YearGroup', backref='project_supervisors')
|
||||
is_coordinator = db.Column(db.Boolean, default=False, nullable=False)
|
||||
year_group_id = db.Column(db.Integer, db.ForeignKey("year_groups.id"))
|
||||
year_group = db.relationship("YearGroup", backref="project_supervisors")
|
||||
|
||||
__table__args = db.UniqueConstraint(
|
||||
"email", "year_group_id", name="uc_email_year_group_id"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def search_by_fullname_and_mode_and_order_by_first_name_or_last_name(cls, year_group_id: int = None,
|
||||
def search_by_fullname(
|
||||
cls,
|
||||
year_group_id: int = None,
|
||||
fullname: str = None,
|
||||
order_by_first_name: str = None,
|
||||
order_by_last_name: str = None) -> BaseQuery:
|
||||
order_by_last_name: str = None,
|
||||
) -> BaseQuery:
|
||||
project_supervisors_query = cls.query
|
||||
|
||||
if year_group_id is not None:
|
||||
project_supervisors_query = project_supervisors_query. \
|
||||
filter(ProjectSupervisor.year_group_id == year_group_id)
|
||||
project_supervisors_query = project_supervisors_query.filter(
|
||||
ProjectSupervisor.year_group_id == year_group_id
|
||||
)
|
||||
|
||||
if fullname is not None:
|
||||
project_supervisors_query = project_supervisors_query.filter(
|
||||
(ProjectSupervisor.first_name + ' ' + ProjectSupervisor.last_name).like(f'{fullname}%'))
|
||||
(ProjectSupervisor.first_name + " " + ProjectSupervisor.last_name).like(
|
||||
f"{fullname}%"
|
||||
)
|
||||
)
|
||||
|
||||
project_supervisors_query = order_by_column_name(project_supervisors_query, ProjectSupervisor.first_name,
|
||||
order_by_first_name)
|
||||
project_supervisors_query = order_by_column_name(project_supervisors_query, ProjectSupervisor.last_name,
|
||||
order_by_last_name)
|
||||
project_supervisors_query = order_by_column_name(
|
||||
project_supervisors_query, ProjectSupervisor.first_name, order_by_first_name
|
||||
)
|
||||
project_supervisors_query = order_by_column_name(
|
||||
project_supervisors_query, ProjectSupervisor.last_name, order_by_last_name
|
||||
)
|
||||
|
||||
return project_supervisors_query
|
||||
|
0
backend/app/project_supervisor/query/__init__.py
Normal file
0
backend/app/project_supervisor/query/__init__.py
Normal file
31
backend/app/project_supervisor/query/project_grade_sheet.py
Normal file
31
backend/app/project_supervisor/query/project_grade_sheet.py
Normal file
@ -0,0 +1,31 @@
|
||||
from flask import abort
|
||||
|
||||
from ...dependencies import db
|
||||
from ...students.models import Group, ProjectGradeSheet
|
||||
from ..models import ProjectSupervisor
|
||||
|
||||
|
||||
def update_project_grade_sheet(group_id: int, query: dict, data: dict) -> None:
|
||||
project_supervisor_id = query.get("id")
|
||||
project_supervisor = ProjectSupervisor.query.filter(
|
||||
ProjectSupervisor.id == project_supervisor_id
|
||||
).first()
|
||||
if project_supervisor is None:
|
||||
abort(404, "ProjectSupervisor doesn't exist!")
|
||||
####################################
|
||||
if len(data) == 0:
|
||||
abort(400, "You passed empty data!")
|
||||
|
||||
group = Group.query.filter(
|
||||
Group.project_supervisor_id == project_supervisor_id, Group.id == group_id
|
||||
).first()
|
||||
if group is None:
|
||||
abort(400, "You cannot update project grade sheet! It's not your group!")
|
||||
|
||||
pgs_query = ProjectGradeSheet.query.filter(ProjectGradeSheet.group_id == group_id)
|
||||
|
||||
if pgs_query.first() is None:
|
||||
abort(404, "Not found project grade sheet!")
|
||||
|
||||
pgs_query.update(data)
|
||||
db.session.commit()
|
@ -1,53 +1,92 @@
|
||||
from datetime import datetime
|
||||
|
||||
from apiflask import APIBlueprint
|
||||
from flask import abort
|
||||
from sqlalchemy import and_, or_
|
||||
from ..schemas import TimeAvailabilityCreateSchema, TemporaryProjectSupervisorSchema, \
|
||||
ListOfFreeTimesSchema, ListOfTermOfDefenceSchema
|
||||
from ...dependencies import db
|
||||
from ..models import ProjectSupervisor
|
||||
from ...examination_schedule.models import ExaminationSchedule, TemporaryAvailability, TermOfDefence
|
||||
|
||||
from ...base.mode import EnrollmentsMode
|
||||
from ...base.schemas import MessageSchema
|
||||
from ...dependencies import db
|
||||
from ...examination_schedule.models import (
|
||||
ExaminationSchedule,
|
||||
TemporaryAvailability,
|
||||
TermOfDefence,
|
||||
)
|
||||
from ..models import ProjectSupervisor
|
||||
from ..schemas import (
|
||||
ListOfFreeTimesSchema,
|
||||
ListOfTermOfDefenceSchema,
|
||||
TemporaryProjectSupervisorSchema,
|
||||
TimeAvailabilityCreateSchema,
|
||||
)
|
||||
|
||||
bp = APIBlueprint("enrollments", __name__, url_prefix="/")
|
||||
|
||||
|
||||
@bp.post('/<int:examination_schedule_id>/enrollments/')
|
||||
@bp.post("/<int:examination_schedule_id>/enrollments/")
|
||||
@bp.input(TimeAvailabilityCreateSchema)
|
||||
@bp.output(MessageSchema)
|
||||
def set_your_free_time_to_examination_schedule(examination_schedule_id: int, data: dict) -> dict:
|
||||
def set_your_free_time_to_examination_schedule(
|
||||
examination_schedule_id: int, data: dict
|
||||
) -> dict:
|
||||
# this code will be removed
|
||||
project_supervisor = ProjectSupervisor.query.filter(ProjectSupervisor.id == data['project_supervisor_id']).first()
|
||||
project_supervisor = ProjectSupervisor.query.filter(
|
||||
ProjectSupervisor.id == data["project_supervisor_id"]
|
||||
).first()
|
||||
if project_supervisor is None:
|
||||
abort(404, "ProjectSupervisor doesn't exist!")
|
||||
print(project_supervisor)
|
||||
################
|
||||
|
||||
es = ExaminationSchedule.query.filter(ExaminationSchedule.id == examination_schedule_id).first()
|
||||
if es is None:
|
||||
examination_schedule = ExaminationSchedule.query.filter(
|
||||
ExaminationSchedule.id == examination_schedule_id
|
||||
).first()
|
||||
if examination_schedule is None:
|
||||
abort(404, "Examination schedule doesn't exist!")
|
||||
if examination_schedule.year_group_id != project_supervisor.year_group_id:
|
||||
abort(400, "You are not assigned to this year group!")
|
||||
|
||||
sd = data['start_date']
|
||||
ed = data['end_date']
|
||||
if examination_schedule.open_enrollments != EnrollmentsMode.INIT.value:
|
||||
abort(400, "Enrollments has started or closed! You have been delayed!")
|
||||
|
||||
sd = data.get("start_date")
|
||||
ed = data.get("end_date")
|
||||
if sd > ed:
|
||||
abort(400, "Invalid data! End date must be greater than start date!")
|
||||
|
||||
if not (es.start_date.timestamp() <= sd.timestamp() and es.end_date.timestamp() >= ed.timestamp()):
|
||||
abort(400, "Date range is not within the examination schedule!")
|
||||
start_date = examination_schedule.start_date
|
||||
end_date = examination_schedule.end_date
|
||||
if not (
|
||||
start_date.timestamp() <= sd.timestamp()
|
||||
and end_date.timestamp() >= ed.timestamp()
|
||||
):
|
||||
abort(400, "Invalid date range!")
|
||||
|
||||
now = datetime.utcnow()
|
||||
if es.start_date_for_enrollment_students is not None and \
|
||||
es.start_date_for_enrollment_students.timestamp() < now.timestamp():
|
||||
abort(403, "Enrollment has started! You cannot set your free time!")
|
||||
|
||||
ta = TemporaryAvailability.query.filter(TemporaryAvailability.examination_schedule_id == examination_schedule_id). \
|
||||
filter(TemporaryAvailability.project_supervisor_id == project_supervisor.id). \
|
||||
filter(or_(and_(TemporaryAvailability.start_date >= sd, TemporaryAvailability.start_date < ed,
|
||||
TemporaryAvailability.end_date >= ed),
|
||||
and_(TemporaryAvailability.start_date <= sd, TemporaryAvailability.end_date > sd,
|
||||
TemporaryAvailability.end_date <= ed))).first()
|
||||
ta = (
|
||||
TemporaryAvailability.query.filter(
|
||||
TemporaryAvailability.examination_schedule_id == examination_schedule_id
|
||||
)
|
||||
.filter(TemporaryAvailability.project_supervisor_id == project_supervisor.id)
|
||||
.filter(
|
||||
or_(
|
||||
and_(
|
||||
TemporaryAvailability.start_date >= sd,
|
||||
TemporaryAvailability.start_date < ed,
|
||||
TemporaryAvailability.end_date >= ed,
|
||||
),
|
||||
and_(
|
||||
TemporaryAvailability.start_date <= sd,
|
||||
TemporaryAvailability.end_date > sd,
|
||||
TemporaryAvailability.end_date <= ed,
|
||||
),
|
||||
)
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if ta is not None:
|
||||
abort(400, "Invalid date ranges. You set your free time in this date range! Choose another date!")
|
||||
abort(
|
||||
400,
|
||||
"Invalid date ranges. You set your free time "
|
||||
"in this date range! Choose another date!",
|
||||
)
|
||||
|
||||
ta = TemporaryAvailability(**data, examination_schedule_id=examination_schedule_id)
|
||||
db.session.add(ta)
|
||||
@ -56,19 +95,37 @@ def set_your_free_time_to_examination_schedule(examination_schedule_id: int, dat
|
||||
return {"message": "You have just assigned your free time!"}
|
||||
|
||||
|
||||
@bp.delete('/<int:examination_schedule_id>/enrollments/<int:temporary_availability_id>/')
|
||||
@bp.delete(
|
||||
"/<int:examination_schedule_id>/enrollments/<int:temporary_availability_id>/"
|
||||
)
|
||||
@bp.input(TemporaryProjectSupervisorSchema)
|
||||
@bp.output(MessageSchema)
|
||||
def delete_your_free_time_from_examination_schedule(examination_schedule_id: int, temporary_availability_id: int,
|
||||
data: dict) -> dict:
|
||||
def delete_your_free_time_from_examination_schedule(
|
||||
examination_schedule_id: int, temporary_availability_id: int, data: dict
|
||||
) -> dict:
|
||||
# this code will be removed
|
||||
project_supervisor = db.session.query(ProjectSupervisor).filter(ProjectSupervisor.id == data['id']).first()
|
||||
project_supervisor = (
|
||||
db.session.query(ProjectSupervisor)
|
||||
.filter(ProjectSupervisor.id == data["id"])
|
||||
.first()
|
||||
)
|
||||
if project_supervisor is None:
|
||||
abort(404, "ProjectSupervisor doesn't exist!")
|
||||
################
|
||||
ta = TemporaryAvailability.query.filter(TemporaryAvailability.examination_schedule_id == examination_schedule_id,
|
||||
examination_schedule = ExaminationSchedule.query.filter(
|
||||
ExaminationSchedule.id == examination_schedule_id
|
||||
).first()
|
||||
if examination_schedule is None:
|
||||
abort(404, "Examination schedule doesn't exist!")
|
||||
|
||||
if examination_schedule.open_enrollments != EnrollmentsMode.INIT.value:
|
||||
abort(400, "Enrollments has started or closed! You have been delayed!")
|
||||
|
||||
ta = TemporaryAvailability.query.filter(
|
||||
TemporaryAvailability.examination_schedule_id == examination_schedule_id,
|
||||
TemporaryAvailability.project_supervisor_id == project_supervisor.id,
|
||||
TemporaryAvailability.id == temporary_availability_id).first()
|
||||
TemporaryAvailability.id == temporary_availability_id,
|
||||
).first()
|
||||
|
||||
if ta is None:
|
||||
abort(404, "Your free time doesn't exist!")
|
||||
@ -78,49 +135,65 @@ def delete_your_free_time_from_examination_schedule(examination_schedule_id: int
|
||||
return {"message": "You have just removed your free time!"}
|
||||
|
||||
|
||||
@bp.get('/<int:examination_schedule_id>/temporary-availabilities/')
|
||||
@bp.input(TemporaryProjectSupervisorSchema, location='query')
|
||||
@bp.get("/<int:examination_schedule_id>/temporary-availabilities/")
|
||||
@bp.input(TemporaryProjectSupervisorSchema, location="query")
|
||||
@bp.output(ListOfFreeTimesSchema)
|
||||
def list_enrollments_for_project_supervisor(examination_schedule_id: int, data: dict) -> dict:
|
||||
def list_enrollments_for_project_supervisor(
|
||||
examination_schedule_id: int, data: dict
|
||||
) -> dict:
|
||||
# this code will be removed
|
||||
project_supervisor = db.session.query(ProjectSupervisor).filter(ProjectSupervisor.id == data['id']).first()
|
||||
project_supervisor = (
|
||||
db.session.query(ProjectSupervisor)
|
||||
.filter(ProjectSupervisor.id == data["id"])
|
||||
.first()
|
||||
)
|
||||
if project_supervisor is None:
|
||||
abort(404, "ProjectSupervisor doesn't exist!")
|
||||
################
|
||||
es = ExaminationSchedule.query.filter(ExaminationSchedule.id == examination_schedule_id,
|
||||
ExaminationSchedule.year_group_id).first()
|
||||
|
||||
if es is None:
|
||||
examination_schedule = ExaminationSchedule.query.filter(
|
||||
ExaminationSchedule.id == examination_schedule_id
|
||||
).first()
|
||||
if examination_schedule is None:
|
||||
abort(404, "Examination schedule doesn't exist!")
|
||||
|
||||
now = datetime.utcnow()
|
||||
start_date = es.start_date_for_enrollment_students
|
||||
if start_date is not None and start_date.timestamp() < now.timestamp():
|
||||
abort(403, "Forbidden! Enrollment has just started! You cannot assign to the exam committees!")
|
||||
if examination_schedule.open_enrollments != EnrollmentsMode.INIT.value:
|
||||
abort(400, "Enrollments has started or closed! You have been delayed!")
|
||||
|
||||
# list of your term of defences first enrollment
|
||||
ta = TemporaryAvailability.query.filter(TemporaryAvailability.examination_schedule_id == examination_schedule_id,
|
||||
TemporaryAvailability.project_supervisor_id == project_supervisor.id).all()
|
||||
ta = TemporaryAvailability.query.filter(
|
||||
TemporaryAvailability.examination_schedule_id == examination_schedule_id,
|
||||
TemporaryAvailability.project_supervisor_id == project_supervisor.id,
|
||||
).all()
|
||||
return {"free_times": ta}
|
||||
|
||||
|
||||
@bp.get('/<int:examination_schedule_id>/term-of-defences/')
|
||||
@bp.input(TemporaryProjectSupervisorSchema, location='query')
|
||||
@bp.get("/<int:examination_schedule_id>/term-of-defences/")
|
||||
@bp.input(TemporaryProjectSupervisorSchema, location="query")
|
||||
@bp.output(ListOfTermOfDefenceSchema)
|
||||
def list_created_term_of_defences_by_coordinator_for_project_supervisor(examination_schedule_id: int,
|
||||
data: dict) -> dict:
|
||||
def list_created_term_of_defences_by_coordinator_for_project_supervisor(
|
||||
examination_schedule_id: int, data: dict
|
||||
) -> dict:
|
||||
# this code will be removed
|
||||
project_supervisor = db.session.query(ProjectSupervisor).filter(ProjectSupervisor.id == data['id']).first()
|
||||
project_supervisor = (
|
||||
db.session.query(ProjectSupervisor)
|
||||
.filter(ProjectSupervisor.id == data["id"])
|
||||
.first()
|
||||
)
|
||||
if project_supervisor is None:
|
||||
abort(404, "ProjectSupervisor doesn't exist!")
|
||||
################
|
||||
es = ExaminationSchedule.query.filter(ExaminationSchedule.id == examination_schedule_id,
|
||||
ExaminationSchedule.year_group_id).first()
|
||||
es = ExaminationSchedule.query.filter(
|
||||
ExaminationSchedule.id == examination_schedule_id,
|
||||
ExaminationSchedule.year_group_id,
|
||||
).first()
|
||||
if es is None:
|
||||
abort(404, "Examination schedule doesn't exist!")
|
||||
|
||||
# list of your free times first enrollment
|
||||
td = TermOfDefence.query.join(TermOfDefence.members_of_committee). \
|
||||
filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
|
||||
filter_by(id=project_supervisor.id).all()
|
||||
td = (
|
||||
TermOfDefence.query.join(TermOfDefence.members_of_committee)
|
||||
.filter(TermOfDefence.examination_schedule_id == examination_schedule_id)
|
||||
.filter_by(id=project_supervisor.id)
|
||||
.all()
|
||||
)
|
||||
return {"term_of_defences": td}
|
||||
|
@ -1,29 +1,43 @@
|
||||
from apiflask import APIBlueprint
|
||||
from flask import abort
|
||||
|
||||
from ...dependencies import db
|
||||
from ..models import ProjectSupervisor
|
||||
from ..schemas import ProjectSupervisorTermQuerySchema, TemporaryProjectSupervisorSchema
|
||||
from ...students.schemas import ProjectGradeSheetDetailFirstTermSchema, ProjectGradeSheetDetailSecondTermSchema, \
|
||||
ProjectGradeSheetEditFirstTermSchema, ProjectGradeSheetEditSecondTermSchema
|
||||
from ...students.models import Group, ProjectGradeSheet
|
||||
from ...base.schemas import MessageSchema
|
||||
from ...students.models import Group
|
||||
from ...students.schemas import (
|
||||
ProjectGradeSheetDetailFirstTermSchema,
|
||||
ProjectGradeSheetDetailSecondTermSchema,
|
||||
ProjectGradeSheetEditFirstTermSchema,
|
||||
ProjectGradeSheetEditSecondTermSchema,
|
||||
)
|
||||
from ..models import ProjectSupervisor
|
||||
from ..query.project_grade_sheet import update_project_grade_sheet
|
||||
from ..schemas import ProjectSupervisorTermQuerySchema, TemporaryProjectSupervisorSchema
|
||||
|
||||
bp = APIBlueprint("project_grade_sheet_for_project_supervisor", __name__, url_prefix="/project-grade-sheet")
|
||||
bp = APIBlueprint(
|
||||
"project_grade_sheet_for_project_supervisor",
|
||||
__name__,
|
||||
url_prefix="/project-grade-sheet",
|
||||
)
|
||||
|
||||
|
||||
@bp.get('/group/<int:group_id>/')
|
||||
@bp.input(ProjectSupervisorTermQuerySchema, location='query')
|
||||
@bp.get("/group/<int:group_id>/")
|
||||
@bp.input(ProjectSupervisorTermQuerySchema, location="query")
|
||||
def detail_project_grade_sheet(group_id: int, query: dict) -> dict:
|
||||
project_supervisor_id = query.get('id')
|
||||
project_supervisor = ProjectSupervisor.query.filter(ProjectSupervisor.id == project_supervisor_id).first()
|
||||
project_supervisor_id = query.get("id")
|
||||
project_supervisor = ProjectSupervisor.query.filter(
|
||||
ProjectSupervisor.id == project_supervisor_id
|
||||
).first()
|
||||
if project_supervisor is None:
|
||||
abort(404, "ProjectSupervisor doesn't exist!")
|
||||
####################################
|
||||
term = query.get('term')
|
||||
group = Group.query.filter(Group.project_supervisor_id == project_supervisor_id, Group.id == group_id).first()
|
||||
term = query.get("term")
|
||||
group = Group.query.filter(
|
||||
Group.project_supervisor_id == project_supervisor_id, Group.id == group_id
|
||||
).first()
|
||||
if group is None or len(group.project_grade_sheet) == 0:
|
||||
abort(400, "Group doesn't exist!")
|
||||
abort(
|
||||
400, "Group doesn't exist or you are not project supervisor of that group!"
|
||||
)
|
||||
|
||||
pgs = group.project_grade_sheet[0]
|
||||
if term == 1:
|
||||
@ -34,36 +48,23 @@ def detail_project_grade_sheet(group_id: int, query: dict) -> dict:
|
||||
return schema.dump(pgs)
|
||||
|
||||
|
||||
def update_project_grade_sheet(group_id: int, query: dict, data: dict) -> None:
|
||||
project_supervisor_id = query.get('id')
|
||||
project_supervisor = ProjectSupervisor.query.filter(ProjectSupervisor.id == project_supervisor_id).first()
|
||||
if project_supervisor is None:
|
||||
abort(404, "ProjectSupervisor doesn't exist!")
|
||||
####################################
|
||||
if len(data) == 0:
|
||||
abort(400, "You passed empty data!")
|
||||
pgs_query = ProjectGradeSheet.query.filter(ProjectGradeSheet.group_id == group_id)
|
||||
|
||||
if pgs_query.first() is None:
|
||||
abort(404, "Not found project grade sheet!")
|
||||
|
||||
pgs_query.update(data)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
@bp.patch('/group/<int:group_id>/first-term/')
|
||||
@bp.input(TemporaryProjectSupervisorSchema, location='query')
|
||||
@bp.input(ProjectGradeSheetEditFirstTermSchema, location='json')
|
||||
@bp.patch("/group/<int:group_id>/first-term/")
|
||||
@bp.input(TemporaryProjectSupervisorSchema, location="query")
|
||||
@bp.input(ProjectGradeSheetEditFirstTermSchema, location="json")
|
||||
@bp.output(MessageSchema)
|
||||
def update_project_grade_sheet_for_first_term(group_id: int, query: dict, data: dict) -> dict:
|
||||
def update_project_grade_sheet_for_first_term(
|
||||
group_id: int, query: dict, data: dict
|
||||
) -> dict:
|
||||
update_project_grade_sheet(group_id, query, data)
|
||||
return {"message": "Your project grade sheet was updated!"}
|
||||
|
||||
|
||||
@bp.patch('/group/<int:group_id>/second-term/')
|
||||
@bp.input(TemporaryProjectSupervisorSchema, location='query')
|
||||
@bp.input(ProjectGradeSheetEditSecondTermSchema, location='json')
|
||||
@bp.patch("/group/<int:group_id>/second-term/")
|
||||
@bp.input(TemporaryProjectSupervisorSchema, location="query")
|
||||
@bp.input(ProjectGradeSheetEditSecondTermSchema, location="json")
|
||||
@bp.output(MessageSchema)
|
||||
def update_project_grade_sheet_for_second_term(group_id: int, query: dict, data: dict) -> dict:
|
||||
def update_project_grade_sheet_for_second_term(
|
||||
group_id: int, query: dict, data: dict
|
||||
) -> dict:
|
||||
update_project_grade_sheet(group_id, query, data)
|
||||
return {"message": "Your project grade sheet was updated!"}
|
||||
|
@ -1,4 +1,4 @@
|
||||
from marshmallow import fields, validate, Schema
|
||||
from marshmallow import Schema, fields, validate
|
||||
|
||||
|
||||
class FreeTimeSchema(Schema):
|
||||
@ -18,7 +18,9 @@ class ListOfTermOfDefenceSchema(Schema):
|
||||
class TimeAvailabilityCreateSchema(Schema):
|
||||
start_date = fields.DateTime(required=True)
|
||||
end_date = fields.DateTime(required=True)
|
||||
project_supervisor_id = fields.Integer(required=True) # temporary field it will be removed in the future
|
||||
project_supervisor_id = fields.Integer(
|
||||
required=True
|
||||
) # temporary field it will be removed in the future
|
||||
|
||||
|
||||
# temporary class it will be removed in the future
|
||||
|
@ -2,59 +2,63 @@ from datetime import datetime
|
||||
|
||||
from flask_sqlalchemy import BaseQuery
|
||||
|
||||
from ..dependencies import db
|
||||
from ..base.models import Person, Base
|
||||
from ..base.models import Base, Person
|
||||
from ..base.utils import order_by_column_name
|
||||
from ..dependencies import db
|
||||
from ..examination_schedule.models import TermOfDefence
|
||||
|
||||
|
||||
class YearGroup(Base):
|
||||
__tablename__ = 'year_groups'
|
||||
__tablename__ = "year_groups"
|
||||
|
||||
name = db.Column(db.String(50), nullable=False)
|
||||
mode = db.Column(db.String(1), nullable=False)
|
||||
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
|
||||
|
||||
__table__args = (
|
||||
db.UniqueConstraint('name', 'mode', name='uc_name_mode_year_group')
|
||||
)
|
||||
__table__args = db.UniqueConstraint("name", "mode", name="uc_name_mode_year_group")
|
||||
|
||||
|
||||
students_groups = db.Table('students_groups',
|
||||
db.Column('group_id', db.ForeignKey('groups.id'), nullable=False),
|
||||
db.Column('student_id', db.ForeignKey('students.id'), nullable=False))
|
||||
students_groups = db.Table(
|
||||
"students_groups",
|
||||
db.Column("group_id", db.ForeignKey("groups.id"), nullable=False),
|
||||
db.Column("student_id", db.ForeignKey("students.id"), nullable=False),
|
||||
)
|
||||
|
||||
|
||||
class Group(Base):
|
||||
__tablename__ = "groups"
|
||||
|
||||
name = db.Column(db.String(60), nullable=False)
|
||||
cdyd_kod = db.Column(db.String(60), default='2022/SZ')
|
||||
prz_kod = db.Column(db.String(60), default='06-DPRILI0')
|
||||
tzaj_kod = db.Column(db.String(60), default='LAB')
|
||||
project_supervisor_id = db.Column(db.Integer, db.ForeignKey('project_supervisors.id'))
|
||||
project_supervisor = db.relationship('ProjectSupervisor', backref='groups')
|
||||
year_group_id = db.Column(db.Integer, db.ForeignKey('year_groups.id'))
|
||||
year_group = db.relationship('YearGroup', backref='groups', lazy='joined')
|
||||
cdyd_kod = db.Column(db.String(60), default="2022/SZ")
|
||||
prz_kod = db.Column(db.String(60), default="06-DPRILI0")
|
||||
tzaj_kod = db.Column(db.String(60), default="LAB")
|
||||
project_supervisor_id = db.Column(
|
||||
db.Integer, db.ForeignKey("project_supervisors.id")
|
||||
)
|
||||
project_supervisor = db.relationship("ProjectSupervisor", backref="groups")
|
||||
year_group_id = db.Column(db.Integer, db.ForeignKey("year_groups.id"))
|
||||
year_group = db.relationship("YearGroup", backref="groups", lazy="joined")
|
||||
points_for_first_term = db.Column(db.Integer, default=0, nullable=False)
|
||||
points_for_second_term = db.Column(db.Integer, default=0, nullable=False)
|
||||
students = db.relationship('Student', secondary=students_groups, back_populates='groups')
|
||||
students = db.relationship(
|
||||
"Student", secondary=students_groups, back_populates="groups"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def search_by_name(cls, year_group_id: int, search_name: str = None) -> BaseQuery:
|
||||
group_query = cls.query.filter(Group.year_group_id == year_group_id)
|
||||
|
||||
if search_name is not None:
|
||||
group_query = group_query.filter(Group.name.like(f'{search_name}%'))
|
||||
group_query = group_query.filter(Group.name.like(f"{search_name}%"))
|
||||
|
||||
return group_query
|
||||
|
||||
|
||||
class ProjectGradeSheet(Base):
|
||||
__tablename__ = 'project_grade_sheets'
|
||||
__tablename__ = "project_grade_sheets"
|
||||
|
||||
group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
|
||||
group = db.relationship('Group', backref='project_grade_sheet', uselist=False)
|
||||
group_id = db.Column(db.Integer, db.ForeignKey("groups.id"))
|
||||
group = db.relationship("Group", backref="project_grade_sheet", uselist=False)
|
||||
|
||||
presentation_required_content_1 = db.Column(db.Integer, default=0)
|
||||
presentation_required_content_2 = db.Column(db.Integer, default=0)
|
||||
@ -62,8 +66,12 @@ class ProjectGradeSheet(Base):
|
||||
presentation_was_compatible_2 = db.Column(db.Integer, default=0)
|
||||
presentation_showing_1 = db.Column(db.Integer, default=0)
|
||||
presentation_showing_2 = db.Column(db.Integer, default=0)
|
||||
presentation_answers_to_questions_from_committee_1 = db.Column(db.Integer, default=0)
|
||||
presentation_answers_to_questions_from_committee_2 = db.Column(db.Integer, default=0)
|
||||
presentation_answers_to_questions_from_committee_1 = db.Column(
|
||||
db.Integer, default=0
|
||||
)
|
||||
presentation_answers_to_questions_from_committee_2 = db.Column(
|
||||
db.Integer, default=0
|
||||
)
|
||||
|
||||
documentation_project_vision_1 = db.Column(db.Integer, default=0)
|
||||
documentation_project_vision_2 = db.Column(db.Integer, default=0)
|
||||
@ -121,20 +129,36 @@ class Student(Base, Person):
|
||||
__tablename__ = "students"
|
||||
|
||||
index = db.Column(db.Integer, nullable=False)
|
||||
groups = db.relationship('Group', secondary=students_groups, back_populates='students')
|
||||
year_group_id = db.Column(db.Integer, db.ForeignKey('year_groups.id'))
|
||||
year_group = db.relationship('YearGroup', backref='students')
|
||||
groups = db.relationship(
|
||||
"Group", secondary=students_groups, back_populates="students"
|
||||
)
|
||||
year_group_id = db.Column(db.Integer, db.ForeignKey("year_groups.id"))
|
||||
year_group = db.relationship("YearGroup", backref="students")
|
||||
|
||||
__table__args = db.UniqueConstraint(
|
||||
"index", "year_group_id", name="uc_index_year_group_id"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def search_by_fullname_and_mode_and_order_by_first_name_or_last_name(cls, year_group_id: int, fullname: str = None,
|
||||
def search_by_fullname_and_mode_and_order_by_first_name_or_last_name(
|
||||
cls,
|
||||
year_group_id: int,
|
||||
fullname: str = None,
|
||||
order_by_first_name: str = None,
|
||||
order_by_last_name: str = None) -> BaseQuery:
|
||||
order_by_last_name: str = None,
|
||||
) -> BaseQuery:
|
||||
student_query = cls.query.filter(Student.year_group_id == year_group_id)
|
||||
|
||||
if fullname is not None:
|
||||
student_query = student_query.filter((Student.first_name + ' ' + Student.last_name).like(f'{fullname}%'))
|
||||
student_query = student_query.filter(
|
||||
(Student.first_name + " " + Student.last_name).like(f"{fullname}%")
|
||||
)
|
||||
|
||||
student_query = order_by_column_name(student_query, Student.first_name, order_by_first_name)
|
||||
student_query = order_by_column_name(student_query, Student.last_name, order_by_last_name)
|
||||
student_query = order_by_column_name(
|
||||
student_query, Student.first_name, order_by_first_name
|
||||
)
|
||||
student_query = order_by_column_name(
|
||||
student_query, Student.last_name, order_by_last_name
|
||||
)
|
||||
|
||||
return student_query
|
||||
|
@ -1,46 +1,69 @@
|
||||
import datetime
|
||||
|
||||
from apiflask import APIBlueprint
|
||||
from flask import abort
|
||||
|
||||
from ..schemas import TemporaryStudentSchema, ExaminationScheduleListSchema, \
|
||||
TermOfDefenceStudentListSchema
|
||||
from ...base.schemas import MessageSchema
|
||||
from ...dependencies import db
|
||||
from ..models import Student, Group, TermOfDefence
|
||||
from ...examination_schedule.models import ExaminationSchedule
|
||||
from ...project_supervisor.models import ProjectSupervisor
|
||||
from ...base.schemas import MessageSchema
|
||||
from ..models import Group, Student, TermOfDefence
|
||||
from ..schemas import (
|
||||
ExaminationScheduleListSchema,
|
||||
TemporaryStudentSchema,
|
||||
TermOfDefenceStudentListSchema,
|
||||
)
|
||||
|
||||
bp = APIBlueprint("enrollments", __name__, url_prefix="/")
|
||||
|
||||
|
||||
@bp.post('/<int:examination_schedule_id>/enrollments/<int:term_of_defence_id>/')
|
||||
@bp.post("/<int:examination_schedule_id>/enrollments/<int:term_of_defence_id>/")
|
||||
@bp.input(TemporaryStudentSchema)
|
||||
@bp.output(MessageSchema)
|
||||
def assign_your_group_to_term_of_defence(examination_schedule_id: int, term_of_defence_id: int, data: dict) -> dict:
|
||||
def assign_your_group_to_term_of_defence(
|
||||
examination_schedule_id: int, term_of_defence_id: int, data: dict
|
||||
) -> dict:
|
||||
# this code will be removed
|
||||
student = Student.query.filter(Student.index == data['student_index']).first()
|
||||
student = Student.query.filter(Student.id == data.get("student_id")).first()
|
||||
if student is None:
|
||||
abort(404, "Student doesn't exist!")
|
||||
abort(404, "Not found student!")
|
||||
################
|
||||
term_of_defence = TermOfDefence.query.filter(TermOfDefence.id == term_of_defence_id,
|
||||
TermOfDefence.examination_schedule_id == examination_schedule_id).first()
|
||||
ex = term_of_defence.examination_schedule
|
||||
if term_of_defence is None or ex is None:
|
||||
term_of_defence = (
|
||||
TermOfDefence.query.filter(
|
||||
TermOfDefence.id == term_of_defence_id,
|
||||
TermOfDefence.examination_schedule_id == examination_schedule_id,
|
||||
)
|
||||
.join(ExaminationSchedule)
|
||||
.first()
|
||||
)
|
||||
|
||||
if term_of_defence is None or (ex := term_of_defence.examination_schedule) is None:
|
||||
abort(400, "Term of defence not found!")
|
||||
|
||||
g = Group.query.join(ProjectSupervisor).filter(Group.year_group_id == ex.year_group_id). \
|
||||
join(Group.students).filter_by(index=student.index).first()
|
||||
g = (
|
||||
Group.query.join(ProjectSupervisor)
|
||||
.filter(Group.year_group_id == ex.year_group_id)
|
||||
.join(Group.students)
|
||||
.filter_by(index=student.index)
|
||||
.first()
|
||||
)
|
||||
if g is None or g.project_supervisor is None:
|
||||
abort(400, "You don't have a group or your group doesn't have an assigned project supervisor!")
|
||||
abort(
|
||||
400,
|
||||
"You don't have a group or your group doesn't"
|
||||
" have an assigned project supervisor!",
|
||||
)
|
||||
|
||||
defence = TermOfDefence.query.filter(TermOfDefence.group_id == g.id,
|
||||
TermOfDefence.examination_schedule_id == examination_schedule_id).first()
|
||||
defence = TermOfDefence.query.filter(
|
||||
TermOfDefence.group_id == g.id,
|
||||
TermOfDefence.examination_schedule_id == examination_schedule_id,
|
||||
).first()
|
||||
if defence is not None:
|
||||
abort(400, "Your group has already assigned to any exam date!")
|
||||
|
||||
td = TermOfDefence.query.join(TermOfDefence.members_of_committee). \
|
||||
filter_by(id=g.project_supervisor_id).first()
|
||||
td = (
|
||||
TermOfDefence.query.join(TermOfDefence.members_of_committee)
|
||||
.filter_by(id=g.project_supervisor_id)
|
||||
.first()
|
||||
)
|
||||
|
||||
if td is None:
|
||||
abort(400, "Your project supervisor is not in committee!")
|
||||
@ -51,25 +74,35 @@ def assign_your_group_to_term_of_defence(examination_schedule_id: int, term_of_d
|
||||
return {"message": "You have just assigned the group for this exam date!"}
|
||||
|
||||
|
||||
@bp.delete('/<int:examination_schedule_id>/enrollments/<int:term_of_defence_id>/')
|
||||
@bp.delete("/<int:examination_schedule_id>/enrollments/<int:term_of_defence_id>/")
|
||||
@bp.input(TemporaryStudentSchema)
|
||||
@bp.output(MessageSchema)
|
||||
def delete_your_group_from_term_of_defence(examination_schedule_id: int, term_of_defence_id: int, data: dict) -> dict:
|
||||
def delete_your_group_from_term_of_defence(
|
||||
examination_schedule_id: int, term_of_defence_id: int, data: dict
|
||||
) -> dict:
|
||||
# this code will be removed
|
||||
student = Student.query.filter(Student.index == data['student_index']).first()
|
||||
student = Student.query.filter(Student.id == data.get("student_id")).first()
|
||||
if student is None:
|
||||
abort(404, "Student doesn't exist!")
|
||||
abort(404, "Not found student!")
|
||||
################
|
||||
|
||||
term_of_defence = TermOfDefence.query.join(ExaminationSchedule).filter(TermOfDefence.id == term_of_defence_id). \
|
||||
filter(TermOfDefence.examination_schedule_id == examination_schedule_id).first()
|
||||
term_of_defence = (
|
||||
TermOfDefence.query.join(ExaminationSchedule)
|
||||
.filter(TermOfDefence.id == term_of_defence_id)
|
||||
.filter(TermOfDefence.examination_schedule_id == examination_schedule_id)
|
||||
.first()
|
||||
)
|
||||
|
||||
ex = term_of_defence.examination_schedule
|
||||
if term_of_defence is None:
|
||||
abort(404, "Term of defence doesn't exist!")
|
||||
|
||||
group = Group.query.filter(Group.year_group_id == ex.year_group_id). \
|
||||
join(Group.students).filter_by(index=student.index).first()
|
||||
group = (
|
||||
Group.query.filter(Group.year_group_id == ex.year_group_id)
|
||||
.join(Group.students)
|
||||
.filter_by(index=student.index)
|
||||
.first()
|
||||
)
|
||||
if group.id != term_of_defence.group_id:
|
||||
abort(400, "You are not assigned to this group!")
|
||||
|
||||
@ -80,41 +113,51 @@ def delete_your_group_from_term_of_defence(examination_schedule_id: int, term_of
|
||||
return {"message": "You have just removed the group for this exam date!"}
|
||||
|
||||
|
||||
@bp.get('/examination-schedule/year-group/<int:year_group_id>/')
|
||||
@bp.input(TemporaryStudentSchema, location='query')
|
||||
@bp.get("/examination-schedule/year-group/<int:year_group_id>/")
|
||||
@bp.input(TemporaryStudentSchema, location="query")
|
||||
@bp.output(ExaminationScheduleListSchema)
|
||||
def list_examination_schedule(year_group_id: int, data: dict) -> dict:
|
||||
# this code will be removed
|
||||
student = Student.query.filter(Student.index == data['student_index']).first()
|
||||
student = Student.query.filter(Student.id == data.get("student_id")).first()
|
||||
if student is None:
|
||||
abort(404, "Student doesn't exist!")
|
||||
abort(404, "Not found student!")
|
||||
################
|
||||
|
||||
# in the future filter after the mode of examination schedule if we will have authorization module
|
||||
now = datetime.datetime.utcnow()
|
||||
examination_schedules = ExaminationSchedule.query. \
|
||||
filter(ExaminationSchedule.year_group_id == year_group_id). \
|
||||
filter(ExaminationSchedule.start_date_for_enrollment_students < now). \
|
||||
filter(ExaminationSchedule.end_date_for_enrollment_students > now).all()
|
||||
return {'examination_schedules': examination_schedules}
|
||||
examination_schedules = ExaminationSchedule.query.filter(
|
||||
ExaminationSchedule.year_group_id == year_group_id
|
||||
).all()
|
||||
return {"examination_schedules": examination_schedules}
|
||||
|
||||
|
||||
@bp.get('/examination-schedule/<int:examination_schedule_id>/enrollments/')
|
||||
@bp.input(TemporaryStudentSchema, location='query')
|
||||
@bp.get("/examination-schedule/<int:examination_schedule_id>/enrollments/")
|
||||
@bp.input(TemporaryStudentSchema, location="query")
|
||||
@bp.output(TermOfDefenceStudentListSchema)
|
||||
def list_term_of_defences(examination_schedule_id: int, data: dict) -> dict:
|
||||
# this code will be removed
|
||||
student = Student.query.filter(Student.index == data['student_index']).first()
|
||||
student = Student.query.filter(Student.id == data.get("student_id")).first()
|
||||
if student is None:
|
||||
abort(404, "Student doesn't exist!")
|
||||
abort(404, "Not found student!")
|
||||
################
|
||||
# in the future filter after the mode of examination schedule if we will have authorization module
|
||||
now = datetime.datetime.utcnow()
|
||||
term_of_defences = TermOfDefence.query.filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
|
||||
join(ExaminationSchedule, isouter=True). \
|
||||
filter(ExaminationSchedule.start_date_for_enrollment_students < now). \
|
||||
filter(ExaminationSchedule.end_date_for_enrollment_students > now).all()
|
||||
term_of_defences = (
|
||||
TermOfDefence.query.filter(
|
||||
TermOfDefence.examination_schedule_id == examination_schedule_id
|
||||
)
|
||||
.join(ExaminationSchedule, isouter=True)
|
||||
.all()
|
||||
)
|
||||
|
||||
term_of_defences = list(filter(lambda n: len([d.id for d in n.members_of_committee if d.id == student.groups[0].project_supervisor.id]) > 0, term_of_defences))
|
||||
term_of_defences = list(
|
||||
filter(
|
||||
lambda n: len(
|
||||
[
|
||||
d.id
|
||||
for d in n.members_of_committee
|
||||
if d.id == student.groups[0].project_supervisor.id
|
||||
]
|
||||
)
|
||||
> 0,
|
||||
term_of_defences,
|
||||
)
|
||||
)
|
||||
|
||||
return {'term_of_defences': term_of_defences}
|
||||
return {"term_of_defences": term_of_defences}
|
||||
|
@ -1,22 +1,25 @@
|
||||
from apiflask import APIBlueprint
|
||||
from flask import abort
|
||||
|
||||
from ..schemas import StudentIndexQueryTempSchema, ProjectGradeSheetDetailFirstTermSchema, \
|
||||
ProjectGradeSheetDetailSecondTermSchema
|
||||
from ..models import Student, ProjectGradeSheet
|
||||
from ..models import ProjectGradeSheet, Student
|
||||
from ..schemas import (
|
||||
ProjectGradeSheetDetailFirstTermSchema,
|
||||
ProjectGradeSheetDetailSecondTermSchema,
|
||||
StudentIndexQueryTempSchema,
|
||||
)
|
||||
|
||||
bp = APIBlueprint("project_grade_sheet", __name__, url_prefix="/project-grade-sheet")
|
||||
|
||||
|
||||
@bp.get('/year-group/<int:year_group_id>/')
|
||||
@bp.input(StudentIndexQueryTempSchema, location='query')
|
||||
@bp.get("/year-group/<int:year_group_id>/")
|
||||
@bp.input(StudentIndexQueryTempSchema, location="query")
|
||||
def detail_project_grade_sheet(year_group_id: int, query: dict) -> dict:
|
||||
index = query.get('index')
|
||||
st = Student.query.filter(Student.index == index).first()
|
||||
student_id = query.get("student_id")
|
||||
st = Student.query.filter(Student.id == student_id).first()
|
||||
if st is None:
|
||||
abort(404, "Not found student!")
|
||||
####################################
|
||||
term = int(query.get('term'))
|
||||
term = int(query.get("term"))
|
||||
|
||||
groups = [g for g in st.groups if g.year_group_id == year_group_id]
|
||||
if len(groups) == 0:
|
||||
|
@ -1,36 +1,34 @@
|
||||
from apiflask import APIBlueprint
|
||||
|
||||
from ...base.utils import paginate_models
|
||||
from ...dependencies import db
|
||||
from ...project_supervisor.models import ProjectSupervisor
|
||||
from ..models import Group
|
||||
from ...dependencies import db
|
||||
from ..schemas import ProjectSupervisorQuerySchema, ProjectSupervisorPaginationSchema
|
||||
from ...base.utils import paginate_models
|
||||
from ..schemas import ProjectSupervisorPaginationSchema, ProjectSupervisorQuerySchema
|
||||
|
||||
bp = APIBlueprint("registrations", __name__, url_prefix="/registrations")
|
||||
|
||||
|
||||
@bp.get('/<int:year_group_id>/')
|
||||
@bp.input(ProjectSupervisorQuerySchema, location='query')
|
||||
@bp.get("/<int:year_group_id>/")
|
||||
@bp.input(ProjectSupervisorQuerySchema, location="query")
|
||||
@bp.output(ProjectSupervisorPaginationSchema)
|
||||
def list_available_groups(year_group_id: int, query: dict) -> dict:
|
||||
page = query.get('page')
|
||||
per_page = query.get('per_page')
|
||||
page = query.get("page")
|
||||
per_page = query.get("per_page")
|
||||
|
||||
available_groups = (ProjectSupervisor.limit_group - db.func.count(Group.id))
|
||||
ps_query = db.session. \
|
||||
query(ProjectSupervisor, available_groups). \
|
||||
join(Group, isouter=True). \
|
||||
filter(ProjectSupervisor.year_group_id == year_group_id).\
|
||||
group_by(ProjectSupervisor.id)
|
||||
available_groups = ProjectSupervisor.limit_group - db.func.count(Group.id)
|
||||
ps_query = (
|
||||
db.session.query(ProjectSupervisor, available_groups)
|
||||
.join(Group, isouter=True)
|
||||
.filter(ProjectSupervisor.year_group_id == year_group_id)
|
||||
.group_by(ProjectSupervisor.id)
|
||||
)
|
||||
|
||||
data = paginate_models(page, ps_query, per_page)
|
||||
|
||||
project_supervisors = []
|
||||
for project_supervisor, available_groups in data['items']:
|
||||
setattr(project_supervisor, 'available_groups', available_groups)
|
||||
for project_supervisor, available_groups in data["items"]:
|
||||
setattr(project_supervisor, "available_groups", available_groups)
|
||||
project_supervisors.append(project_supervisor)
|
||||
|
||||
return {
|
||||
"project_supervisors": project_supervisors,
|
||||
"max_pages": data['max_pages']
|
||||
}
|
||||
return {"project_supervisors": project_supervisors, "max_pages": data["max_pages"]}
|
||||
|
@ -1,9 +1,9 @@
|
||||
from marshmallow import fields, Schema, validate
|
||||
from marshmallow import Schema, fields, validate
|
||||
|
||||
POINTS = [0, 1, 3, 4]
|
||||
|
||||
|
||||
class ProjectSupervisorSchema(Schema):
|
||||
class ProjectSupervisorWithAvailableGroupsSchema(Schema):
|
||||
first_name = fields.Str()
|
||||
last_name = fields.Str()
|
||||
email = fields.Str()
|
||||
@ -11,7 +11,9 @@ class ProjectSupervisorSchema(Schema):
|
||||
|
||||
|
||||
class ProjectSupervisorPaginationSchema(Schema):
|
||||
project_supervisors = fields.List(fields.Nested(ProjectSupervisorSchema))
|
||||
project_supervisors = fields.List(
|
||||
fields.Nested(ProjectSupervisorWithAvailableGroupsSchema)
|
||||
)
|
||||
max_pages = fields.Integer()
|
||||
|
||||
|
||||
@ -21,18 +23,19 @@ class ProjectSupervisorQuerySchema(Schema):
|
||||
|
||||
|
||||
class TemporaryStudentSchema(Schema):
|
||||
student_index = fields.Integer(required=True)
|
||||
student_id = fields.Integer(required=True)
|
||||
|
||||
|
||||
class ExaminationScheduleSchema(Schema):
|
||||
class ExaminationScheduleStudentSchema(Schema):
|
||||
id = fields.Integer()
|
||||
title = fields.Str()
|
||||
start_date = fields.DateTime()
|
||||
end_date = fields.DateTime()
|
||||
open_enrollments = fields.Boolean()
|
||||
|
||||
|
||||
class ExaminationScheduleListSchema(Schema):
|
||||
examination_schedules = fields.List(fields.Nested(ExaminationScheduleSchema))
|
||||
examination_schedules = fields.List(fields.Nested(ExaminationScheduleStudentSchema))
|
||||
|
||||
|
||||
class ProjectSupervisorCommitteeSchema(Schema):
|
||||
@ -64,11 +67,13 @@ class AssignedGroupToTermOfDefenceItemSchema(TermOfDefenceStudentItemSchema):
|
||||
|
||||
|
||||
class TermOfDefenceStudentListSchema(Schema):
|
||||
term_of_defences = fields.List(fields.Nested(AssignedGroupToTermOfDefenceItemSchema))
|
||||
term_of_defences = fields.List(
|
||||
fields.Nested(AssignedGroupToTermOfDefenceItemSchema)
|
||||
)
|
||||
|
||||
|
||||
class StudentIndexQueryTempSchema(Schema):
|
||||
index = fields.Integer(required=True) # it will be removed
|
||||
student_id = fields.Integer(required=True) # it will be removed
|
||||
term = fields.Integer(required=True, validate=validate.OneOf([1, 2]))
|
||||
|
||||
|
||||
@ -76,7 +81,9 @@ class ProjectGradeSheetEditFirstTermSchema(Schema):
|
||||
presentation_required_content_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
presentation_was_compatible_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
presentation_showing_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
presentation_answers_to_questions_from_committee_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
presentation_answers_to_questions_from_committee_1 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
|
||||
documentation_project_vision_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
documentation_requirements_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
@ -89,17 +96,31 @@ class ProjectGradeSheetEditFirstTermSchema(Schema):
|
||||
group_work_contact_with_client_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
group_work_management_of_risk_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
group_work_work_methodology_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
group_work_management_of_source_code_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
group_work_management_of_source_code_1 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
group_work_devops_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
|
||||
products_project_complexity_of_product_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_access_to_application_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_complexity_of_product_1 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
products_project_access_to_application_1 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
products_project_security_issues_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_access_to_test_application_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_acceptance_criteria_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_expected_functionality_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_access_to_test_application_1 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
products_project_acceptance_criteria_1 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
products_project_expected_functionality_1 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
products_project_promises_well_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_has_been_implemented_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_has_been_implemented_1 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
products_project_is_useful_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_prototype_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_tests_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
@ -114,7 +135,9 @@ class ProjectGradeSheetEditSecondTermSchema(Schema):
|
||||
presentation_required_content_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
presentation_was_compatible_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
presentation_showing_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
presentation_answers_to_questions_from_committee_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
presentation_answers_to_questions_from_committee_2 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
|
||||
documentation_project_vision_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
documentation_requirements_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
@ -127,17 +150,31 @@ class ProjectGradeSheetEditSecondTermSchema(Schema):
|
||||
group_work_contact_with_client_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
group_work_management_of_risk_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
group_work_work_methodology_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
group_work_management_of_source_code_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
group_work_management_of_source_code_2 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
group_work_devops_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
|
||||
products_project_complexity_of_product_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_access_to_application_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_complexity_of_product_2 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
products_project_access_to_application_2 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
products_project_security_issues_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_access_to_test_application_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_acceptance_criteria_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_expected_functionality_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_access_to_test_application_2 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
products_project_acceptance_criteria_2 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
products_project_expected_functionality_2 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
products_project_promises_well_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_has_been_implemented_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_has_been_implemented_2 = fields.Integer(
|
||||
validate=validate.OneOf(POINTS)
|
||||
)
|
||||
products_project_is_useful_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_prototype_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
products_project_tests_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||
|
@ -1,5 +1,5 @@
|
||||
import os
|
||||
import importlib
|
||||
import os
|
||||
import warnings
|
||||
|
||||
from flask import current_app
|
||||
@ -7,8 +7,8 @@ from flask import current_app
|
||||
|
||||
def get_app_directories() -> list:
|
||||
directories = []
|
||||
src_dir = current_app.config['SRC_DIR']
|
||||
excluded_dirs = current_app.config['EXCLUDED_DIRS']
|
||||
src_dir = current_app.config["SRC_DIR"]
|
||||
excluded_dirs = current_app.config["EXCLUDED_DIRS"]
|
||||
|
||||
for dirname in os.listdir(src_dir):
|
||||
path = src_dir / dirname
|
||||
|
@ -1,4 +1,5 @@
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from app import create_app
|
||||
|
||||
load_dotenv()
|
||||
|
@ -3,9 +3,8 @@ from __future__ import with_statement
|
||||
import logging
|
||||
from logging.config import fileConfig
|
||||
|
||||
from flask import current_app
|
||||
|
||||
from alembic import context
|
||||
from flask import current_app
|
||||
|
||||
# this is the Alembic Config object, which provides
|
||||
# access to the values within the .ini file in use.
|
||||
@ -14,17 +13,17 @@ config = context.config
|
||||
# Interpret the config file for Python logging.
|
||||
# This line sets up loggers basically.
|
||||
fileConfig(config.config_file_name)
|
||||
logger = logging.getLogger('alembic.env')
|
||||
logger = logging.getLogger("alembic.env")
|
||||
|
||||
# add your model's MetaData object here
|
||||
# for 'autogenerate' support
|
||||
# from myapp import mymodel
|
||||
# target_metadata = mymodel.Base.metadata
|
||||
config.set_main_option(
|
||||
'sqlalchemy.url',
|
||||
str(current_app.extensions['migrate'].db.get_engine().url).replace(
|
||||
'%', '%%'))
|
||||
target_metadata = current_app.extensions['migrate'].db.metadata
|
||||
"sqlalchemy.url",
|
||||
str(current_app.extensions["migrate"].db.get_engine().url).replace("%", "%%"),
|
||||
)
|
||||
target_metadata = current_app.extensions["migrate"].db.metadata
|
||||
|
||||
# other values from the config, defined by the needs of env.py,
|
||||
# can be acquired:
|
||||
@ -45,9 +44,7 @@ def run_migrations_offline():
|
||||
|
||||
"""
|
||||
url = config.get_main_option("sqlalchemy.url")
|
||||
context.configure(
|
||||
url=url, target_metadata=target_metadata, literal_binds=True
|
||||
)
|
||||
context.configure(url=url, target_metadata=target_metadata, literal_binds=True)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
@ -65,20 +62,20 @@ def run_migrations_online():
|
||||
# when there are no changes to the schema
|
||||
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
|
||||
def process_revision_directives(context, revision, directives):
|
||||
if getattr(config.cmd_opts, 'autogenerate', False):
|
||||
if getattr(config.cmd_opts, "autogenerate", False):
|
||||
script = directives[0]
|
||||
if script.upgrade_ops.is_empty():
|
||||
directives[:] = []
|
||||
logger.info('No changes in schema detected.')
|
||||
logger.info("No changes in schema detected.")
|
||||
|
||||
connectable = current_app.extensions['migrate'].db.get_engine()
|
||||
connectable = current_app.extensions["migrate"].db.get_engine()
|
||||
|
||||
with connectable.connect() as connection:
|
||||
context.configure(
|
||||
connection=connection,
|
||||
target_metadata=target_metadata,
|
||||
process_revision_directives=process_revision_directives,
|
||||
**current_app.extensions['migrate'].configure_args
|
||||
**current_app.extensions["migrate"].configure_args
|
||||
)
|
||||
|
||||
with context.begin_transaction():
|
||||
|
@ -1,196 +0,0 @@
|
||||
"""empty message
|
||||
|
||||
Revision ID: 3fd120fc5e12
|
||||
Revises:
|
||||
Create Date: 2023-01-14 00:03:06.327441
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '3fd120fc5e12'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('year_groups',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('name', sa.String(length=50), nullable=False),
|
||||
sa.Column('mode', sa.String(length=1), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('examination_schedules',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('title', sa.String(length=100), nullable=False),
|
||||
sa.Column('duration_time', sa.Integer(), nullable=False),
|
||||
sa.Column('start_date_for_enrollment_students', sa.DateTime(), nullable=True),
|
||||
sa.Column('end_date_for_enrollment_students', sa.DateTime(), nullable=True),
|
||||
sa.Column('start_date', sa.DateTime(), nullable=False),
|
||||
sa.Column('end_date', sa.DateTime(), nullable=False),
|
||||
sa.Column('year_group_id', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['year_group_id'], ['year_groups.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('title')
|
||||
)
|
||||
op.create_table('project_supervisors',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('first_name', sa.String(length=255), nullable=False),
|
||||
sa.Column('last_name', sa.String(length=255), nullable=False),
|
||||
sa.Column('email', sa.String(length=120), nullable=False),
|
||||
sa.Column('limit_group', sa.Integer(), nullable=False),
|
||||
sa.Column('year_group_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['year_group_id'], ['year_groups.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_project_supervisors_email'), 'project_supervisors', ['email'], unique=False)
|
||||
op.create_index(op.f('ix_project_supervisors_first_name'), 'project_supervisors', ['first_name'], unique=False)
|
||||
op.create_index(op.f('ix_project_supervisors_last_name'), 'project_supervisors', ['last_name'], unique=False)
|
||||
op.create_table('students',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('first_name', sa.String(length=255), nullable=False),
|
||||
sa.Column('last_name', sa.String(length=255), nullable=False),
|
||||
sa.Column('email', sa.String(length=120), nullable=False),
|
||||
sa.Column('index', sa.Integer(), nullable=False),
|
||||
sa.Column('year_group_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['year_group_id'], ['year_groups.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_students_email'), 'students', ['email'], unique=False)
|
||||
op.create_index(op.f('ix_students_first_name'), 'students', ['first_name'], unique=False)
|
||||
op.create_index(op.f('ix_students_last_name'), 'students', ['last_name'], unique=False)
|
||||
op.create_table('groups',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('name', sa.String(length=60), nullable=False),
|
||||
sa.Column('cdyd_kod', sa.String(length=60), nullable=True),
|
||||
sa.Column('prz_kod', sa.String(length=60), nullable=True),
|
||||
sa.Column('tzaj_kod', sa.String(length=60), nullable=True),
|
||||
sa.Column('project_supervisor_id', sa.Integer(), nullable=True),
|
||||
sa.Column('year_group_id', sa.Integer(), nullable=True),
|
||||
sa.Column('points_for_first_term', sa.Integer(), nullable=False),
|
||||
sa.Column('points_for_second_term', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['project_supervisor_id'], ['project_supervisors.id'], ),
|
||||
sa.ForeignKeyConstraint(['year_group_id'], ['year_groups.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('temporary_availabilities',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('start_date', sa.DateTime(), nullable=False),
|
||||
sa.Column('end_date', sa.DateTime(), nullable=False),
|
||||
sa.Column('examination_schedule_id', sa.Integer(), nullable=False),
|
||||
sa.Column('project_supervisor_id', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['examination_schedule_id'], ['examination_schedules.id'], ),
|
||||
sa.ForeignKeyConstraint(['project_supervisor_id'], ['project_supervisors.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('project_grade_sheets',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('group_id', sa.Integer(), nullable=True),
|
||||
sa.Column('presentation_required_content_1', sa.Integer(), nullable=True),
|
||||
sa.Column('presentation_required_content_2', sa.Integer(), nullable=True),
|
||||
sa.Column('presentation_was_compatible_1', sa.Integer(), nullable=True),
|
||||
sa.Column('presentation_was_compatible_2', sa.Integer(), nullable=True),
|
||||
sa.Column('presentation_showing_1', sa.Integer(), nullable=True),
|
||||
sa.Column('presentation_showing_2', sa.Integer(), nullable=True),
|
||||
sa.Column('presentation_answers_to_questions_from_committee_1', sa.Integer(), nullable=True),
|
||||
sa.Column('presentation_answers_to_questions_from_committee_2', sa.Integer(), nullable=True),
|
||||
sa.Column('documentation_project_vision_1', sa.Integer(), nullable=True),
|
||||
sa.Column('documentation_project_vision_2', sa.Integer(), nullable=True),
|
||||
sa.Column('documentation_requirements_1', sa.Integer(), nullable=True),
|
||||
sa.Column('documentation_requirements_2', sa.Integer(), nullable=True),
|
||||
sa.Column('documentation_for_clients_1', sa.Integer(), nullable=True),
|
||||
sa.Column('documentation_for_clients_2', sa.Integer(), nullable=True),
|
||||
sa.Column('documentation_for_developers_1', sa.Integer(), nullable=True),
|
||||
sa.Column('documentation_for_developers_2', sa.Integer(), nullable=True),
|
||||
sa.Column('documentation_license_1', sa.Integer(), nullable=True),
|
||||
sa.Column('documentation_license_2', sa.Integer(), nullable=True),
|
||||
sa.Column('group_work_regularity_1', sa.Integer(), nullable=True),
|
||||
sa.Column('group_work_regularity_2', sa.Integer(), nullable=True),
|
||||
sa.Column('group_work_division_of_work_1', sa.Integer(), nullable=True),
|
||||
sa.Column('group_work_division_of_work_2', sa.Integer(), nullable=True),
|
||||
sa.Column('group_work_contact_with_client_1', sa.Integer(), nullable=True),
|
||||
sa.Column('group_work_contact_with_client_2', sa.Integer(), nullable=True),
|
||||
sa.Column('group_work_management_of_risk_1', sa.Integer(), nullable=True),
|
||||
sa.Column('group_work_management_of_risk_2', sa.Integer(), nullable=True),
|
||||
sa.Column('group_work_work_methodology_1', sa.Integer(), nullable=True),
|
||||
sa.Column('group_work_work_methodology_2', sa.Integer(), nullable=True),
|
||||
sa.Column('group_work_management_of_source_code_1', sa.Integer(), nullable=True),
|
||||
sa.Column('group_work_management_of_source_code_2', sa.Integer(), nullable=True),
|
||||
sa.Column('group_work_devops_1', sa.Integer(), nullable=True),
|
||||
sa.Column('group_work_devops_2', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_complexity_of_product_1', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_complexity_of_product_2', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_access_to_application_1', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_access_to_application_2', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_security_issues_1', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_security_issues_2', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_access_to_test_application_1', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_access_to_test_application_2', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_acceptance_criteria_1', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_acceptance_criteria_2', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_expected_functionality_1', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_expected_functionality_2', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_promises_well_1', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_promises_well_2', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_has_been_implemented_1', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_has_been_implemented_2', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_is_useful_1', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_is_useful_2', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_prototype_1', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_prototype_2', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_tests_1', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_tests_2', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_technology_1', sa.Integer(), nullable=True),
|
||||
sa.Column('products_project_technology_2', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['group_id'], ['groups.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('students_groups',
|
||||
sa.Column('group_id', sa.Integer(), nullable=False),
|
||||
sa.Column('student_id', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['group_id'], ['groups.id'], ),
|
||||
sa.ForeignKeyConstraint(['student_id'], ['students.id'], )
|
||||
)
|
||||
op.create_table('term_of_defences',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('start_date', sa.DateTime(), nullable=False),
|
||||
sa.Column('end_date', sa.DateTime(), nullable=False),
|
||||
sa.Column('examination_schedule_id', sa.Integer(), nullable=True),
|
||||
sa.Column('group_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['examination_schedule_id'], ['examination_schedules.id'], ),
|
||||
sa.ForeignKeyConstraint(['group_id'], ['groups.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('committees',
|
||||
sa.Column('term_of_defence_id', sa.Integer(), nullable=True),
|
||||
sa.Column('project_supervisor_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['project_supervisor_id'], ['project_supervisors.id'], ),
|
||||
sa.ForeignKeyConstraint(['term_of_defence_id'], ['term_of_defences.id'], )
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('committees')
|
||||
op.drop_table('term_of_defences')
|
||||
op.drop_table('students_groups')
|
||||
op.drop_table('project_grade_sheets')
|
||||
op.drop_table('temporary_availabilities')
|
||||
op.drop_table('groups')
|
||||
op.drop_index(op.f('ix_students_last_name'), table_name='students')
|
||||
op.drop_index(op.f('ix_students_first_name'), table_name='students')
|
||||
op.drop_index(op.f('ix_students_email'), table_name='students')
|
||||
op.drop_table('students')
|
||||
op.drop_index(op.f('ix_project_supervisors_last_name'), table_name='project_supervisors')
|
||||
op.drop_index(op.f('ix_project_supervisors_first_name'), table_name='project_supervisors')
|
||||
op.drop_index(op.f('ix_project_supervisors_email'), table_name='project_supervisors')
|
||||
op.drop_table('project_supervisors')
|
||||
op.drop_table('examination_schedules')
|
||||
op.drop_table('year_groups')
|
||||
# ### end Alembic commands ###
|
313
backend/migrations/versions/559c8f18a125_.py
Normal file
313
backend/migrations/versions/559c8f18a125_.py
Normal file
@ -0,0 +1,313 @@
|
||||
"""empty message
|
||||
|
||||
Revision ID: 559c8f18a125
|
||||
Revises:
|
||||
Create Date: 2023-01-14 15:25:59.137169
|
||||
|
||||
"""
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "559c8f18a125"
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table(
|
||||
"year_groups",
|
||||
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column("name", sa.String(length=50), nullable=False),
|
||||
sa.Column("mode", sa.String(length=1), nullable=False),
|
||||
sa.Column("created_at", sa.DateTime(), nullable=False),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"examination_schedules",
|
||||
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column("title", sa.String(length=100), nullable=False),
|
||||
sa.Column("duration_time", sa.Integer(), nullable=False),
|
||||
sa.Column("open_enrollments", sa.String(length=1), nullable=False),
|
||||
sa.Column("start_date", sa.DateTime(), nullable=False),
|
||||
sa.Column("end_date", sa.DateTime(), nullable=False),
|
||||
sa.Column("year_group_id", sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
["year_group_id"],
|
||||
["year_groups.id"],
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
sa.UniqueConstraint("title"),
|
||||
)
|
||||
op.create_table(
|
||||
"project_supervisors",
|
||||
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column("first_name", sa.String(length=255), nullable=False),
|
||||
sa.Column("last_name", sa.String(length=255), nullable=False),
|
||||
sa.Column("email", sa.String(length=120), nullable=False),
|
||||
sa.Column("limit_group", sa.Integer(), nullable=False),
|
||||
sa.Column("is_coordinator", sa.Boolean(), nullable=False),
|
||||
sa.Column("year_group_id", sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
["year_group_id"],
|
||||
["year_groups.id"],
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_project_supervisors_email"),
|
||||
"project_supervisors",
|
||||
["email"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_project_supervisors_first_name"),
|
||||
"project_supervisors",
|
||||
["first_name"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_project_supervisors_last_name"),
|
||||
"project_supervisors",
|
||||
["last_name"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_table(
|
||||
"students",
|
||||
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column("first_name", sa.String(length=255), nullable=False),
|
||||
sa.Column("last_name", sa.String(length=255), nullable=False),
|
||||
sa.Column("email", sa.String(length=120), nullable=False),
|
||||
sa.Column("index", sa.Integer(), nullable=False),
|
||||
sa.Column("year_group_id", sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
["year_group_id"],
|
||||
["year_groups.id"],
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_index(op.f("ix_students_email"), "students", ["email"], unique=False)
|
||||
op.create_index(
|
||||
op.f("ix_students_first_name"), "students", ["first_name"], unique=False
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_students_last_name"), "students", ["last_name"], unique=False
|
||||
)
|
||||
op.create_table(
|
||||
"groups",
|
||||
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column("name", sa.String(length=60), nullable=False),
|
||||
sa.Column("cdyd_kod", sa.String(length=60), nullable=True),
|
||||
sa.Column("prz_kod", sa.String(length=60), nullable=True),
|
||||
sa.Column("tzaj_kod", sa.String(length=60), nullable=True),
|
||||
sa.Column("project_supervisor_id", sa.Integer(), nullable=True),
|
||||
sa.Column("year_group_id", sa.Integer(), nullable=True),
|
||||
sa.Column("points_for_first_term", sa.Integer(), nullable=False),
|
||||
sa.Column("points_for_second_term", sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
["project_supervisor_id"],
|
||||
["project_supervisors.id"],
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
["year_group_id"],
|
||||
["year_groups.id"],
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"temporary_availabilities",
|
||||
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column("start_date", sa.DateTime(), nullable=False),
|
||||
sa.Column("end_date", sa.DateTime(), nullable=False),
|
||||
sa.Column("examination_schedule_id", sa.Integer(), nullable=False),
|
||||
sa.Column("project_supervisor_id", sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
["examination_schedule_id"],
|
||||
["examination_schedules.id"],
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
["project_supervisor_id"],
|
||||
["project_supervisors.id"],
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"project_grade_sheets",
|
||||
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column("group_id", sa.Integer(), nullable=True),
|
||||
sa.Column("presentation_required_content_1", sa.Integer(), nullable=True),
|
||||
sa.Column("presentation_required_content_2", sa.Integer(), nullable=True),
|
||||
sa.Column("presentation_was_compatible_1", sa.Integer(), nullable=True),
|
||||
sa.Column("presentation_was_compatible_2", sa.Integer(), nullable=True),
|
||||
sa.Column("presentation_showing_1", sa.Integer(), nullable=True),
|
||||
sa.Column("presentation_showing_2", sa.Integer(), nullable=True),
|
||||
sa.Column(
|
||||
"presentation_answers_to_questions_from_committee_1",
|
||||
sa.Integer(),
|
||||
nullable=True,
|
||||
),
|
||||
sa.Column(
|
||||
"presentation_answers_to_questions_from_committee_2",
|
||||
sa.Integer(),
|
||||
nullable=True,
|
||||
),
|
||||
sa.Column("documentation_project_vision_1", sa.Integer(), nullable=True),
|
||||
sa.Column("documentation_project_vision_2", sa.Integer(), nullable=True),
|
||||
sa.Column("documentation_requirements_1", sa.Integer(), nullable=True),
|
||||
sa.Column("documentation_requirements_2", sa.Integer(), nullable=True),
|
||||
sa.Column("documentation_for_clients_1", sa.Integer(), nullable=True),
|
||||
sa.Column("documentation_for_clients_2", sa.Integer(), nullable=True),
|
||||
sa.Column("documentation_for_developers_1", sa.Integer(), nullable=True),
|
||||
sa.Column("documentation_for_developers_2", sa.Integer(), nullable=True),
|
||||
sa.Column("documentation_license_1", sa.Integer(), nullable=True),
|
||||
sa.Column("documentation_license_2", sa.Integer(), nullable=True),
|
||||
sa.Column("group_work_regularity_1", sa.Integer(), nullable=True),
|
||||
sa.Column("group_work_regularity_2", sa.Integer(), nullable=True),
|
||||
sa.Column("group_work_division_of_work_1", sa.Integer(), nullable=True),
|
||||
sa.Column("group_work_division_of_work_2", sa.Integer(), nullable=True),
|
||||
sa.Column("group_work_contact_with_client_1", sa.Integer(), nullable=True),
|
||||
sa.Column("group_work_contact_with_client_2", sa.Integer(), nullable=True),
|
||||
sa.Column("group_work_management_of_risk_1", sa.Integer(), nullable=True),
|
||||
sa.Column("group_work_management_of_risk_2", sa.Integer(), nullable=True),
|
||||
sa.Column("group_work_work_methodology_1", sa.Integer(), nullable=True),
|
||||
sa.Column("group_work_work_methodology_2", sa.Integer(), nullable=True),
|
||||
sa.Column(
|
||||
"group_work_management_of_source_code_1", sa.Integer(), nullable=True
|
||||
),
|
||||
sa.Column(
|
||||
"group_work_management_of_source_code_2", sa.Integer(), nullable=True
|
||||
),
|
||||
sa.Column("group_work_devops_1", sa.Integer(), nullable=True),
|
||||
sa.Column("group_work_devops_2", sa.Integer(), nullable=True),
|
||||
sa.Column(
|
||||
"products_project_complexity_of_product_1", sa.Integer(), nullable=True
|
||||
),
|
||||
sa.Column(
|
||||
"products_project_complexity_of_product_2", sa.Integer(), nullable=True
|
||||
),
|
||||
sa.Column(
|
||||
"products_project_access_to_application_1", sa.Integer(), nullable=True
|
||||
),
|
||||
sa.Column(
|
||||
"products_project_access_to_application_2", sa.Integer(), nullable=True
|
||||
),
|
||||
sa.Column("products_project_security_issues_1", sa.Integer(), nullable=True),
|
||||
sa.Column("products_project_security_issues_2", sa.Integer(), nullable=True),
|
||||
sa.Column(
|
||||
"products_project_access_to_test_application_1", sa.Integer(), nullable=True
|
||||
),
|
||||
sa.Column(
|
||||
"products_project_access_to_test_application_2", sa.Integer(), nullable=True
|
||||
),
|
||||
sa.Column(
|
||||
"products_project_acceptance_criteria_1", sa.Integer(), nullable=True
|
||||
),
|
||||
sa.Column(
|
||||
"products_project_acceptance_criteria_2", sa.Integer(), nullable=True
|
||||
),
|
||||
sa.Column(
|
||||
"products_project_expected_functionality_1", sa.Integer(), nullable=True
|
||||
),
|
||||
sa.Column(
|
||||
"products_project_expected_functionality_2", sa.Integer(), nullable=True
|
||||
),
|
||||
sa.Column("products_project_promises_well_1", sa.Integer(), nullable=True),
|
||||
sa.Column("products_project_promises_well_2", sa.Integer(), nullable=True),
|
||||
sa.Column(
|
||||
"products_project_has_been_implemented_1", sa.Integer(), nullable=True
|
||||
),
|
||||
sa.Column(
|
||||
"products_project_has_been_implemented_2", sa.Integer(), nullable=True
|
||||
),
|
||||
sa.Column("products_project_is_useful_1", sa.Integer(), nullable=True),
|
||||
sa.Column("products_project_is_useful_2", sa.Integer(), nullable=True),
|
||||
sa.Column("products_project_prototype_1", sa.Integer(), nullable=True),
|
||||
sa.Column("products_project_prototype_2", sa.Integer(), nullable=True),
|
||||
sa.Column("products_project_tests_1", sa.Integer(), nullable=True),
|
||||
sa.Column("products_project_tests_2", sa.Integer(), nullable=True),
|
||||
sa.Column("products_project_technology_1", sa.Integer(), nullable=True),
|
||||
sa.Column("products_project_technology_2", sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
["group_id"],
|
||||
["groups.id"],
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"students_groups",
|
||||
sa.Column("group_id", sa.Integer(), nullable=False),
|
||||
sa.Column("student_id", sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
["group_id"],
|
||||
["groups.id"],
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
["student_id"],
|
||||
["students.id"],
|
||||
),
|
||||
)
|
||||
op.create_table(
|
||||
"term_of_defences",
|
||||
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column("start_date", sa.DateTime(), nullable=False),
|
||||
sa.Column("end_date", sa.DateTime(), nullable=False),
|
||||
sa.Column("examination_schedule_id", sa.Integer(), nullable=True),
|
||||
sa.Column("group_id", sa.Integer(), nullable=True),
|
||||
sa.Column("chairman_of_committee", sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
["chairman_of_committee"],
|
||||
["project_supervisors.id"],
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
["examination_schedule_id"],
|
||||
["examination_schedules.id"],
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
["group_id"],
|
||||
["groups.id"],
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"committees",
|
||||
sa.Column("term_of_defence_id", sa.Integer(), nullable=True),
|
||||
sa.Column("project_supervisor_id", sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
["project_supervisor_id"],
|
||||
["project_supervisors.id"],
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
["term_of_defence_id"],
|
||||
["term_of_defences.id"],
|
||||
),
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table("committees")
|
||||
op.drop_table("term_of_defences")
|
||||
op.drop_table("students_groups")
|
||||
op.drop_table("project_grade_sheets")
|
||||
op.drop_table("temporary_availabilities")
|
||||
op.drop_table("groups")
|
||||
op.drop_index(op.f("ix_students_last_name"), table_name="students")
|
||||
op.drop_index(op.f("ix_students_first_name"), table_name="students")
|
||||
op.drop_index(op.f("ix_students_email"), table_name="students")
|
||||
op.drop_table("students")
|
||||
op.drop_index(
|
||||
op.f("ix_project_supervisors_last_name"), table_name="project_supervisors"
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_project_supervisors_first_name"), table_name="project_supervisors"
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_project_supervisors_email"), table_name="project_supervisors"
|
||||
)
|
||||
op.drop_table("project_supervisors")
|
||||
op.drop_table("examination_schedules")
|
||||
op.drop_table("year_groups")
|
||||
# ### end Alembic commands ###
|
2
backend/pyproject.toml
Normal file
2
backend/pyproject.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[tool.isort]
|
||||
profile = "black"
|
@ -14,3 +14,6 @@ python-dotenv==0.21.0
|
||||
factory_boy>=3.2.1,<3.3.0
|
||||
reportlab>=3.6.12,<3.7.0
|
||||
gunicorn>=20.1.0,<20.2.0
|
||||
black>=22.12.0,<22.13.0
|
||||
flake8>=6.0.0,<6.1.0
|
||||
isort>=5.11.4,<5.12.0
|
||||
|
10
backend/setup.cfg
Normal file
10
backend/setup.cfg
Normal file
@ -0,0 +1,10 @@
|
||||
[flake8]
|
||||
max-line-length = 88
|
||||
extend-ignore =
|
||||
E203,
|
||||
exclude =
|
||||
migrations,
|
||||
__pycache__,
|
||||
tests
|
||||
per-file-ignores = **/*/models.py:F401
|
||||
|
@ -3,8 +3,8 @@ from typing import Generator
|
||||
import pytest
|
||||
from apiflask import APIFlask
|
||||
from flask import Flask
|
||||
from flask.testing import FlaskClient
|
||||
from flask.ctx import AppContext
|
||||
from flask.testing import FlaskClient
|
||||
|
||||
from app import create_app
|
||||
from app.dependencies import db
|
||||
|
@ -1,13 +1,13 @@
|
||||
import datetime
|
||||
|
||||
from factory import alchemy, Sequence
|
||||
from factory import Sequence, alchemy
|
||||
from factory.faker import Faker
|
||||
from factory.fuzzy import FuzzyInteger, FuzzyDateTime
|
||||
from factory.fuzzy import FuzzyDateTime, FuzzyInteger
|
||||
|
||||
from app.dependencies import db
|
||||
from app.students.models import Student, Group, YearGroupStudents
|
||||
from app.project_supervisor.models import ProjectSupervisor, YearGroupProjectSupervisors
|
||||
from app.examination_schedule.models import ExaminationSchedule
|
||||
from app.project_supervisor.models import ProjectSupervisor, YearGroupProjectSupervisors
|
||||
from app.students.models import Group, Student, YearGroupStudents
|
||||
|
||||
|
||||
class ProjectSupervisorFactory(alchemy.SQLAlchemyModelFactory):
|
||||
@ -15,9 +15,9 @@ class ProjectSupervisorFactory(alchemy.SQLAlchemyModelFactory):
|
||||
model = ProjectSupervisor
|
||||
sqlalchemy_session = db.session
|
||||
|
||||
first_name = Faker('first_name')
|
||||
last_name = Faker('last_name')
|
||||
email = Faker('email')
|
||||
first_name = Faker("first_name")
|
||||
last_name = Faker("last_name")
|
||||
email = Faker("email")
|
||||
|
||||
|
||||
class YearGroupProjectSupervisorsFactory(alchemy.SQLAlchemyModelFactory):
|
||||
@ -33,7 +33,7 @@ class GroupFactory(alchemy.SQLAlchemyModelFactory):
|
||||
model = Group
|
||||
sqlalchemy_session = db.session
|
||||
|
||||
name = Sequence(lambda n: f'Group-{n}')
|
||||
name = Sequence(lambda n: f"Group-{n}")
|
||||
points_for_first_term = FuzzyInteger(1, 5)
|
||||
points_for_second_term = FuzzyInteger(1, 5)
|
||||
|
||||
@ -43,9 +43,9 @@ class StudentFactory(alchemy.SQLAlchemyModelFactory):
|
||||
model = Student
|
||||
sqlalchemy_session = db.session
|
||||
|
||||
first_name = Faker('first_name')
|
||||
last_name = Faker('last_name')
|
||||
email = Faker('email')
|
||||
first_name = Faker("first_name")
|
||||
last_name = Faker("last_name")
|
||||
email = Faker("email")
|
||||
index = Sequence(lambda n: 400_000 + n)
|
||||
|
||||
|
||||
@ -60,9 +60,13 @@ class ExaminationScheduleFactory(alchemy.SQLAlchemyModelFactory):
|
||||
model = ExaminationSchedule
|
||||
sqlalchemy_session = db.session
|
||||
|
||||
title = Sequence(lambda n: f'Examination schedule {n}')
|
||||
title = Sequence(lambda n: f"Examination schedule {n}")
|
||||
duration_time = 30
|
||||
start_date = FuzzyDateTime(datetime.datetime(2020, 1, 1, tzinfo=datetime.timezone.utc),
|
||||
datetime.datetime(2020, 1, 5, tzinfo=datetime.timezone.utc))
|
||||
end_date = FuzzyDateTime(datetime.datetime(2020, 1, 10, tzinfo=datetime.timezone.utc),
|
||||
datetime.datetime(2020, 1, 20, tzinfo=datetime.timezone.utc))
|
||||
start_date = FuzzyDateTime(
|
||||
datetime.datetime(2020, 1, 1, tzinfo=datetime.timezone.utc),
|
||||
datetime.datetime(2020, 1, 5, tzinfo=datetime.timezone.utc),
|
||||
)
|
||||
end_date = FuzzyDateTime(
|
||||
datetime.datetime(2020, 1, 10, tzinfo=datetime.timezone.utc),
|
||||
datetime.datetime(2020, 1, 20, tzinfo=datetime.timezone.utc),
|
||||
)
|
||||
|
@ -1,30 +1,44 @@
|
||||
from typing import List
|
||||
|
||||
from .factory import ProjectSupervisorFactory, YearGroupProjectSupervisorsFactory, \
|
||||
StudentFactory, YearGroupStudentsFactory, GroupFactory, ExaminationScheduleFactory
|
||||
from app.dependencies import db
|
||||
from app.project_supervisor.models import YearGroup, ProjectSupervisor
|
||||
from app.students.models import Group, Student, YearGroupStudents
|
||||
from app.examination_schedule.models import ExaminationSchedule
|
||||
from app.base.mode import ModeGroups
|
||||
from app.dependencies import db
|
||||
from app.examination_schedule.models import ExaminationSchedule
|
||||
from app.project_supervisor.models import ProjectSupervisor, YearGroup
|
||||
from app.students.models import Group, Student, YearGroupStudents
|
||||
|
||||
from .factory import (
|
||||
ExaminationScheduleFactory,
|
||||
GroupFactory,
|
||||
ProjectSupervisorFactory,
|
||||
StudentFactory,
|
||||
YearGroupProjectSupervisorsFactory,
|
||||
YearGroupStudentsFactory,
|
||||
)
|
||||
|
||||
|
||||
def create_year_group(data: dict = None) -> YearGroup:
|
||||
if data is None:
|
||||
data = {'mode': ModeGroups.STATIONARY.value, 'name': '2022/2023'}
|
||||
data = {"mode": ModeGroups.STATIONARY.value, "name": "2022/2023"}
|
||||
yg = YearGroup(**data)
|
||||
db.session.add(yg)
|
||||
db.session.commit()
|
||||
return yg
|
||||
|
||||
|
||||
def create_project_supervisors(yg: YearGroup, amount: int, limit_group: int = 3) -> List[ProjectSupervisorFactory]:
|
||||
def create_project_supervisors(
|
||||
yg: YearGroup, amount: int, limit_group: int = 3
|
||||
) -> List[ProjectSupervisorFactory]:
|
||||
ps = [ProjectSupervisorFactory() for _ in range(amount)]
|
||||
db.session.add_all(ps)
|
||||
db.session.commit()
|
||||
db.session.add_all(
|
||||
[YearGroupProjectSupervisorsFactory(limit_group=limit_group, year_group_id=yg.id, project_supervisor_id=p.id)
|
||||
for p in ps])
|
||||
[
|
||||
YearGroupProjectSupervisorsFactory(
|
||||
limit_group=limit_group, year_group_id=yg.id, project_supervisor_id=p.id
|
||||
)
|
||||
for p in ps
|
||||
]
|
||||
)
|
||||
db.session.commit()
|
||||
return ps
|
||||
|
||||
@ -47,7 +61,12 @@ def create_students(yg: YearGroup, amount: int) -> List[StudentFactory]:
|
||||
students = [StudentFactory() for _ in range(amount)]
|
||||
db.session.add_all(students)
|
||||
db.session.commit()
|
||||
db.session.add_all([YearGroupStudentsFactory(year_group_id=yg.id, student_index=s.index) for s in students])
|
||||
db.session.add_all(
|
||||
[
|
||||
YearGroupStudentsFactory(year_group_id=yg.id, student_index=s.index)
|
||||
for s in students
|
||||
]
|
||||
)
|
||||
db.session.commit()
|
||||
return students
|
||||
|
||||
@ -57,7 +76,9 @@ def create_student(data: dict, year_group_id: int = None) -> Student:
|
||||
db.session.add(st)
|
||||
db.session.commit()
|
||||
if year_group_id is not None:
|
||||
db.session.add(YearGroupStudents(year_group_id=year_group_id, student_index=st.index))
|
||||
db.session.add(
|
||||
YearGroupStudents(year_group_id=year_group_id, student_index=st.index)
|
||||
)
|
||||
db.session.commit()
|
||||
return st
|
||||
|
||||
@ -76,8 +97,12 @@ def create_group(data: dict, yg: YearGroup) -> Group:
|
||||
return group
|
||||
|
||||
|
||||
def create_examination_schedules(yg: YearGroup, amount: int) -> List[ExaminationScheduleFactory]:
|
||||
examination_schedules = [ExaminationScheduleFactory(year_group_id=yg.id) for _ in range(amount)]
|
||||
def create_examination_schedules(
|
||||
yg: YearGroup, amount: int
|
||||
) -> List[ExaminationScheduleFactory]:
|
||||
examination_schedules = [
|
||||
ExaminationScheduleFactory(year_group_id=yg.id) for _ in range(amount)
|
||||
]
|
||||
db.session.add_all(examination_schedules)
|
||||
db.session.commit()
|
||||
return examination_schedules
|
||||
|
@ -1,28 +1,42 @@
|
||||
import datetime
|
||||
|
||||
from ...utils import _test_case_client, _test_case_client_without_response, assert_model_changes
|
||||
from ...fake_data import create_examination_schedule, create_year_group, create_examination_schedules
|
||||
from app.dependencies import db
|
||||
|
||||
valid_data = {
|
||||
'title': 'examination schedule summer',
|
||||
'start_date': datetime.datetime.now() + datetime.timedelta(days=5),
|
||||
'end_date': datetime.datetime.now() + datetime.timedelta(days=10),
|
||||
'duration_time': 30
|
||||
from ...fake_data import (
|
||||
create_examination_schedule,
|
||||
create_examination_schedules,
|
||||
create_year_group,
|
||||
)
|
||||
from ...utils import (
|
||||
_test_case_client,
|
||||
_test_case_client_without_response,
|
||||
assert_model_changes,
|
||||
)
|
||||
|
||||
valid_data = {
|
||||
"title": "examination schedule summer",
|
||||
"start_date": datetime.datetime.now() + datetime.timedelta(days=5),
|
||||
"end_date": datetime.datetime.now() + datetime.timedelta(days=10),
|
||||
"duration_time": 30,
|
||||
}
|
||||
|
||||
ex_data = {
|
||||
'title': 'new title',
|
||||
'start_date': (datetime.datetime.now() + datetime.timedelta(days=5)).strftime("%Y-%m-%dT%H:%M:%S.000Z"),
|
||||
'end_date': (datetime.datetime.now() + datetime.timedelta(days=10)).strftime("%Y-%m-%dT%H:%M:%S.000Z")
|
||||
"title": "new title",
|
||||
"start_date": (datetime.datetime.now() + datetime.timedelta(days=5)).strftime(
|
||||
"%Y-%m-%dT%H:%M:%S.000Z"
|
||||
),
|
||||
"end_date": (datetime.datetime.now() + datetime.timedelta(days=10)).strftime(
|
||||
"%Y-%m-%dT%H:%M:%S.000Z"
|
||||
),
|
||||
}
|
||||
|
||||
enrollments_data = {
|
||||
'start_date_for_enrollment_students': (datetime.datetime.now() + datetime.timedelta(days=2)).strftime(
|
||||
"%Y-%m-%dT%H:%M:%S.000Z"),
|
||||
'end_date_for_enrollment_students': (datetime.datetime.now() + datetime.timedelta(days=4)).strftime(
|
||||
"%Y-%m-%dT%H:%M:%S.000Z")
|
||||
"start_date_for_enrollment_students": (
|
||||
datetime.datetime.now() + datetime.timedelta(days=2)
|
||||
).strftime("%Y-%m-%dT%H:%M:%S.000Z"),
|
||||
"end_date_for_enrollment_students": (
|
||||
datetime.datetime.now() + datetime.timedelta(days=4)
|
||||
).strftime("%Y-%m-%dT%H:%M:%S.000Z"),
|
||||
}
|
||||
|
||||
|
||||
@ -31,89 +45,169 @@ def test_list_examination_schedules(test_app_with_context) -> None:
|
||||
year_group = create_year_group()
|
||||
create_examination_schedules(year_group, 34)
|
||||
|
||||
url = f'/api/coordinator/examination_schedule/{year_group.id}/?per_page=10'
|
||||
data = _test_case_client_without_response(client, url, None, 200, method='get')
|
||||
assert data.get('max_pages') == 4
|
||||
assert len(data.get('examination_schedules')) == 10
|
||||
url = f"/api/coordinator/examination_schedule/{year_group.id}/?per_page=10"
|
||||
data = _test_case_client_without_response(client, url, None, 200, method="get")
|
||||
assert data.get("max_pages") == 4
|
||||
assert len(data.get("examination_schedules")) == 10
|
||||
|
||||
|
||||
def test_delete_examination_schedule(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
year_group = create_year_group()
|
||||
ex = create_examination_schedules(year_group, 1)[0]
|
||||
_test_case_client(client, f'/api/coordinator/examination_schedule/{ex.id}/', None,
|
||||
'Examination schedule was deleted!', 200, method='delete')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/examination_schedule/{ex.id}/",
|
||||
None,
|
||||
"Examination schedule was deleted!",
|
||||
200,
|
||||
method="delete",
|
||||
)
|
||||
|
||||
|
||||
def test_delete_examination_schedule_if_examination_schedule_doesnt_exist(test_app_with_context) -> None:
|
||||
def test_delete_examination_schedule_if_examination_schedule_doesnt_exist(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/examination_schedule/32/', None,
|
||||
"Examination schedule doesn't exist!", 404, method='delete', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/examination_schedule/32/",
|
||||
None,
|
||||
"Examination schedule doesn't exist!",
|
||||
404,
|
||||
method="delete",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_update_examination_schedule(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
year_group = create_year_group()
|
||||
ex = create_examination_schedules(year_group, 1)[0]
|
||||
_test_case_client(client, f'/api/coordinator/examination_schedule/{ex.id}/', ex_data,
|
||||
'Examination schedule was updated!', 200, method='put')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/examination_schedule/{ex.id}/",
|
||||
ex_data,
|
||||
"Examination schedule was updated!",
|
||||
200,
|
||||
method="put",
|
||||
)
|
||||
assert_model_changes(ex, ex_data)
|
||||
|
||||
|
||||
def test_update_examination_schedule_schedule_if_examination_schedule_doesnt_exist(test_app_with_context) -> None:
|
||||
def test_update_examination_schedule_schedule_if_examination_schedule_doesnt_exist(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/examination_schedule/32/', ex_data,
|
||||
"Examination schedule doesn't exist!", 404, method='put', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/examination_schedule/32/",
|
||||
ex_data,
|
||||
"Examination schedule doesn't exist!",
|
||||
404,
|
||||
method="put",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_set_date_of_examination_schedule(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
year_group = create_year_group()
|
||||
ex = create_examination_schedule(valid_data, year_group)
|
||||
_test_case_client(client, f'/api/coordinator/examination_schedule/{ex.id}/date/', enrollments_data,
|
||||
'You set date of examination schedule!', 200, method='put')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/examination_schedule/{ex.id}/date/",
|
||||
enrollments_data,
|
||||
"You set date of examination schedule!",
|
||||
200,
|
||||
method="put",
|
||||
)
|
||||
assert_model_changes(ex, enrollments_data)
|
||||
|
||||
|
||||
def test_set_date_of_examination_schedule_if_examination_schedule_doesnt_exist(test_app_with_context) -> None:
|
||||
def test_set_date_of_examination_schedule_if_examination_schedule_doesnt_exist(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/examination_schedule/43/date/', enrollments_data,
|
||||
'Examination schedule doesn\'t exist!', 404, method='put', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/examination_schedule/43/date/",
|
||||
enrollments_data,
|
||||
"Examination schedule doesn't exist!",
|
||||
404,
|
||||
method="put",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_set_date_of_examination_schedule_with_invalid_date(test_app_with_context) -> None:
|
||||
def test_set_date_of_examination_schedule_with_invalid_date(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
invalid_dates = {
|
||||
'start_date_for_enrollment_students': enrollments_data['end_date_for_enrollment_students'],
|
||||
'end_date_for_enrollment_students': enrollments_data['start_date_for_enrollment_students'],
|
||||
"start_date_for_enrollment_students": enrollments_data[
|
||||
"end_date_for_enrollment_students"
|
||||
],
|
||||
"end_date_for_enrollment_students": enrollments_data[
|
||||
"start_date_for_enrollment_students"
|
||||
],
|
||||
}
|
||||
|
||||
with test_app_with_context.test_client() as client:
|
||||
year_group = create_year_group()
|
||||
ex = create_examination_schedule(valid_data, year_group)
|
||||
_test_case_client(client, f'/api/coordinator/examination_schedule/{ex.id}/date/', invalid_dates,
|
||||
'Invalid data! End date must be greater than start date!', 400, method='put', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/examination_schedule/{ex.id}/date/",
|
||||
invalid_dates,
|
||||
"Invalid data! End date must be greater than start date!",
|
||||
400,
|
||||
method="put",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_create_project_supervisors(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
year_group = create_year_group()
|
||||
_test_case_client(client, f'/api/coordinator/examination_schedule/{year_group.id}/', ex_data,
|
||||
'Examination schedule was created!', 201, method='post')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/examination_schedule/{year_group.id}/",
|
||||
ex_data,
|
||||
"Examination schedule was created!",
|
||||
201,
|
||||
method="post",
|
||||
)
|
||||
|
||||
|
||||
def test_create_project_supervisors_if_year_group_doesnt_exist(test_app_with_context) -> None:
|
||||
def test_create_project_supervisors_if_year_group_doesnt_exist(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/examination_schedule/33/', ex_data,
|
||||
'Year group doesn\'t exist!', 404, method='post', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/examination_schedule/33/",
|
||||
ex_data,
|
||||
"Year group doesn't exist!",
|
||||
404,
|
||||
method="post",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_create_project_supervisors_with_invalid_dates(test_app_with_context) -> None:
|
||||
invalid_data = {
|
||||
'title': 'examination schedule winter',
|
||||
'start_date': ex_data['end_date'],
|
||||
'end_date': ex_data['start_date']
|
||||
"title": "examination schedule winter",
|
||||
"start_date": ex_data["end_date"],
|
||||
"end_date": ex_data["start_date"],
|
||||
}
|
||||
with test_app_with_context.test_client() as client:
|
||||
year_group = create_year_group()
|
||||
_test_case_client(client, f'/api/coordinator/examination_schedule/{year_group.id}/', invalid_data,
|
||||
'Invalid data! End date must be greater than start date!', 400, method='post', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/examination_schedule/{year_group.id}/",
|
||||
invalid_data,
|
||||
"Invalid data! End date must be greater than start date!",
|
||||
400,
|
||||
method="post",
|
||||
key="error",
|
||||
)
|
||||
|
@ -2,24 +2,32 @@ import copy
|
||||
|
||||
from flask import current_app
|
||||
|
||||
from ...utils import _test_case_client, _test_case_client_without_response, assert_model_changes, _test_case_group
|
||||
from ...fake_data import create_year_group, create_groups, create_group, create_students, create_project_supervisors
|
||||
from app.dependencies import db
|
||||
from app.students.models import Group
|
||||
from app.project_supervisor.models import YearGroupProjectSupervisors
|
||||
from app.students.models import Group
|
||||
|
||||
valid_data = {
|
||||
'name': 'System Pri'
|
||||
}
|
||||
from ...fake_data import (
|
||||
create_group,
|
||||
create_groups,
|
||||
create_project_supervisors,
|
||||
create_students,
|
||||
create_year_group,
|
||||
)
|
||||
from ...utils import (
|
||||
_test_case_client,
|
||||
_test_case_client_without_response,
|
||||
_test_case_group,
|
||||
assert_model_changes,
|
||||
)
|
||||
|
||||
new_data = {
|
||||
'name': 'Mobile app'
|
||||
}
|
||||
valid_data = {"name": "System Pri"}
|
||||
|
||||
new_data = {"name": "Mobile app"}
|
||||
|
||||
invalid_data = {
|
||||
'name': 'Mobile app v2',
|
||||
'students': [123_344, 455_444],
|
||||
'project_supervisor_id': 1
|
||||
"name": "Mobile app v2",
|
||||
"students": [123_344, 455_444],
|
||||
"project_supervisor_id": 1,
|
||||
}
|
||||
|
||||
|
||||
@ -27,39 +35,69 @@ def test_list_groups(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
create_groups(yg, 33)
|
||||
data = _test_case_client_without_response(client, f'/api/coordinator/groups/{yg.id}/?per_page=10', None, 200,
|
||||
method='get')
|
||||
assert data.get('max_pages') == 4
|
||||
assert len(data.get('groups')) == 10
|
||||
data = _test_case_client_without_response(
|
||||
client,
|
||||
f"/api/coordinator/groups/{yg.id}/?per_page=10",
|
||||
None,
|
||||
200,
|
||||
method="get",
|
||||
)
|
||||
assert data.get("max_pages") == 4
|
||||
assert len(data.get("groups")) == 10
|
||||
|
||||
|
||||
def test_detail_group(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
group = create_group(valid_data, yg)
|
||||
data = _test_case_client_without_response(client, f'/api/coordinator/groups/{group.id}/detail/', None, 200,
|
||||
method='get')
|
||||
data = _test_case_client_without_response(
|
||||
client,
|
||||
f"/api/coordinator/groups/{group.id}/detail/",
|
||||
None,
|
||||
200,
|
||||
method="get",
|
||||
)
|
||||
assert_model_changes(group, data)
|
||||
|
||||
|
||||
def test_detail_group_if_group_doesnt_exist(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/groups/11/detail/', None, 'Not found group!', 404, method='get',
|
||||
key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/groups/11/detail/",
|
||||
None,
|
||||
"Not found group!",
|
||||
404,
|
||||
method="get",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_delete_group(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
group = create_group(valid_data, yg)
|
||||
_test_case_client(client, f'/api/coordinator/groups/{group.id}/', None, 'Group was deleted!', 202,
|
||||
method='delete')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/groups/{group.id}/",
|
||||
None,
|
||||
"Group was deleted!",
|
||||
202,
|
||||
method="delete",
|
||||
)
|
||||
|
||||
|
||||
def test_delete_group_if_group_doesnt_exist(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/groups/32/', None, 'Not found group!', 404, method='delete',
|
||||
key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/groups/32/",
|
||||
None,
|
||||
"Not found group!",
|
||||
404,
|
||||
method="delete",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_edit_group(test_app_with_context) -> None:
|
||||
@ -69,11 +107,17 @@ def test_edit_group(test_app_with_context) -> None:
|
||||
students = create_students(yg, 3)
|
||||
ps = create_project_supervisors(yg, 1)[0]
|
||||
group = create_group(valid_data, yg)
|
||||
data['students'] = [student.index for student in students]
|
||||
data['project_supervisor_id'] = ps.id
|
||||
data["students"] = [student.index for student in students]
|
||||
data["project_supervisor_id"] = ps.id
|
||||
|
||||
_test_case_client(client, f'/api/coordinator/groups/{group.id}/', data, 'Group was updated!', 200,
|
||||
method='put')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/groups/{group.id}/",
|
||||
data,
|
||||
"Group was updated!",
|
||||
200,
|
||||
method="put",
|
||||
)
|
||||
_test_case_group(group, data)
|
||||
|
||||
|
||||
@ -83,18 +127,32 @@ def test_edit_group_with_invalid_project_supervisor_id(test_app_with_context) ->
|
||||
yg = create_year_group()
|
||||
students = create_students(yg, 3)
|
||||
group = create_group(valid_data, yg)
|
||||
data['students'] = [student.index for student in students]
|
||||
data['project_supervisor_id'] = 10
|
||||
_test_case_client(client, f'/api/coordinator/groups/{group.id}/', data, 'Not found project supervisor!', 404,
|
||||
method='put', key='error')
|
||||
data["students"] = [student.index for student in students]
|
||||
data["project_supervisor_id"] = 10
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/groups/{group.id}/",
|
||||
data,
|
||||
"Not found project supervisor!",
|
||||
404,
|
||||
method="put",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_edit_group_with_invalid_data(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
group = create_group(valid_data, yg)
|
||||
data = {'students': [123_4356, 243_533, 434_343]}
|
||||
_test_case_client(client, f'/api/coordinator/groups/{group.id}/', data, 'Validation error', 400, method='put')
|
||||
data = {"students": [123_4356, 243_533, 434_343]}
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/groups/{group.id}/",
|
||||
data,
|
||||
"Validation error",
|
||||
400,
|
||||
method="put",
|
||||
)
|
||||
|
||||
|
||||
def test_edit_group_with_invalid_student_indexes(test_app_with_context) -> None:
|
||||
@ -102,21 +160,42 @@ def test_edit_group_with_invalid_student_indexes(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
group = create_group(valid_data, yg)
|
||||
data['students'] = [123_456, 243_533, 434_343]
|
||||
_test_case_client(client, f'/api/coordinator/groups/{group.id}/', data, 'Not found students!', 404,
|
||||
method='put', key='error')
|
||||
data["students"] = [123_456, 243_533, 434_343]
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/groups/{group.id}/",
|
||||
data,
|
||||
"Not found students!",
|
||||
404,
|
||||
method="put",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_edit_group_if_group_doesnt_exist(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/groups/333/', new_data, 'Not found group!', 404,
|
||||
method='put', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/groups/333/",
|
||||
new_data,
|
||||
"Not found group!",
|
||||
404,
|
||||
method="put",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_edit_group_if_you_pass_empty_data(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/groups/333/', {}, 'You have passed empty data!', 400,
|
||||
method='put', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/groups/333/",
|
||||
{},
|
||||
"You have passed empty data!",
|
||||
400,
|
||||
method="put",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_create_group(test_app_with_context) -> None:
|
||||
@ -125,26 +204,46 @@ def test_create_group(test_app_with_context) -> None:
|
||||
yg = create_year_group()
|
||||
students = create_students(yg, 3)
|
||||
ps = create_project_supervisors(yg, 1)[0]
|
||||
data['students'] = [student.index for student in students]
|
||||
data['project_supervisor_id'] = ps.id
|
||||
data["students"] = [student.index for student in students]
|
||||
data["project_supervisor_id"] = ps.id
|
||||
|
||||
_test_case_client(client, f'/api/coordinator/groups/{yg.id}/', data, 'Group was created!', 201,
|
||||
method='post')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/groups/{yg.id}/",
|
||||
data,
|
||||
"Group was created!",
|
||||
201,
|
||||
method="post",
|
||||
)
|
||||
assert Group.query.count() == 1
|
||||
_test_case_group(Group.query.first(), data)
|
||||
|
||||
|
||||
def test_create_group_if_year_group_doesnt_exist(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/groups/22/', invalid_data, 'Not found year group!', 404,
|
||||
method='post', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/groups/22/",
|
||||
invalid_data,
|
||||
"Not found year group!",
|
||||
404,
|
||||
method="post",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_create_group_if_project_supervisor_doesnt_exist(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
_test_case_client(client, f'/api/coordinator/groups/{yg.id}/', invalid_data, 'Not found project supervisor!',
|
||||
404, method='post', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/groups/{yg.id}/",
|
||||
invalid_data,
|
||||
"Not found project supervisor!",
|
||||
404,
|
||||
method="post",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_create_group_if_you_exceed_the_group_limit(test_app_with_context) -> None:
|
||||
@ -152,14 +251,21 @@ def test_create_group_if_you_exceed_the_group_limit(test_app_with_context) -> No
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
ps = create_project_supervisors(yg, 1)[0]
|
||||
data['project_supervisor_id'] = ps.id
|
||||
limit_group = current_app.config.get('LIMIT_STUDENTS_PER_GROUP')
|
||||
data["project_supervisor_id"] = ps.id
|
||||
limit_group = current_app.config.get("LIMIT_STUDENTS_PER_GROUP")
|
||||
|
||||
data['students'].extend([999_000 + i for i in range(limit_group + 4)])
|
||||
data["students"].extend([999_000 + i for i in range(limit_group + 4)])
|
||||
|
||||
_test_case_client(client, f'/api/coordinator/groups/{yg.id}/', data,
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/groups/{yg.id}/",
|
||||
data,
|
||||
f"Too much students you want add to group, The group can have only {limit_group}"
|
||||
" students", 400, method='post', key='error')
|
||||
" students",
|
||||
400,
|
||||
method="post",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_create_group_if_students_doesnt_exist(test_app_with_context) -> None:
|
||||
@ -167,36 +273,55 @@ def test_create_group_if_students_doesnt_exist(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
ps = create_project_supervisors(yg, 1)[0]
|
||||
data['project_supervisor_id'] = ps.id
|
||||
_test_case_client(client, f'/api/coordinator/groups/{yg.id}/', data, "Not found students!", 404, method='post',
|
||||
key='error')
|
||||
data["project_supervisor_id"] = ps.id
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/groups/{yg.id}/",
|
||||
data,
|
||||
"Not found students!",
|
||||
404,
|
||||
method="post",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_create_group_if_at_least_one_student_belong_to_other_group(test_app_with_context) -> None:
|
||||
def test_create_group_if_at_least_one_student_belong_to_other_group(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
data = copy.deepcopy(invalid_data)
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
ps = create_project_supervisors(yg, 1)[0]
|
||||
group = create_group(valid_data, yg)
|
||||
data['project_supervisor_id'] = ps.id
|
||||
data["project_supervisor_id"] = ps.id
|
||||
student = create_students(yg, 1)[0]
|
||||
group.students.append(student)
|
||||
db.session.commit()
|
||||
|
||||
data['students'].extend([student.index])
|
||||
_test_case_client(client, f'/api/coordinator/groups/{yg.id}/', data,
|
||||
"One or more students have already belonged to group!", 400, method='post', key='error')
|
||||
data["students"].extend([student.index])
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/groups/{yg.id}/",
|
||||
data,
|
||||
"One or more students have already belonged to group!",
|
||||
400,
|
||||
method="post",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_create_group_if_limit_of_group_was_exceed_for_project_supervisor(test_app_with_context) -> None:
|
||||
def test_create_group_if_limit_of_group_was_exceed_for_project_supervisor(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
data = copy.deepcopy(invalid_data)
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
ps = create_project_supervisors(yg, 1)[0]
|
||||
data['project_supervisor_id'] = ps.id
|
||||
data["project_supervisor_id"] = ps.id
|
||||
|
||||
ygps = YearGroupProjectSupervisors.query.filter_by(project_supervisor_id=ps.id, year_group_id=yg.id). \
|
||||
first()
|
||||
ygps = YearGroupProjectSupervisors.query.filter_by(
|
||||
project_supervisor_id=ps.id, year_group_id=yg.id
|
||||
).first()
|
||||
limit_group = ygps.limit_group
|
||||
|
||||
groups = create_groups(yg, limit_group)
|
||||
@ -204,6 +329,12 @@ def test_create_group_if_limit_of_group_was_exceed_for_project_supervisor(test_a
|
||||
group.project_supervisor_id = ps.id
|
||||
db.session.commit()
|
||||
|
||||
_test_case_client(client, f'/api/coordinator/groups/{yg.id}/', data,
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/groups/{yg.id}/",
|
||||
data,
|
||||
"Can't create new group, project supervisor achieved a limit of groups",
|
||||
400, method='post', key='error')
|
||||
400,
|
||||
method="post",
|
||||
key="error",
|
||||
)
|
||||
|
@ -1,27 +1,40 @@
|
||||
from ...utils import _test_case_client, _test_case_client_without_response, assert_model_changes
|
||||
from ...fake_data import create_project_supervisors, create_year_group, create_dummy_group, create_dummy_ps
|
||||
from app.dependencies import db
|
||||
from app.project_supervisor.models import YearGroupProjectSupervisors
|
||||
|
||||
from ...fake_data import (
|
||||
create_dummy_group,
|
||||
create_dummy_ps,
|
||||
create_project_supervisors,
|
||||
create_year_group,
|
||||
)
|
||||
from ...utils import (
|
||||
_test_case_client,
|
||||
_test_case_client_without_response,
|
||||
assert_model_changes,
|
||||
)
|
||||
|
||||
valid_data = {
|
||||
'first_name': 'John',
|
||||
'last_name': 'Smith',
|
||||
'email': 'johnsmith@gmail.com'
|
||||
"first_name": "John",
|
||||
"last_name": "Smith",
|
||||
"email": "johnsmith@gmail.com",
|
||||
}
|
||||
|
||||
year_group_ps_data = {
|
||||
'limit_group': 3
|
||||
}
|
||||
year_group_ps_data = {"limit_group": 3}
|
||||
|
||||
|
||||
def test_list_project_supervisors(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
year_group = create_year_group()
|
||||
create_project_supervisors(year_group, 25)
|
||||
data = _test_case_client_without_response(client, '/api/coordinator/project_supervisor/?per_page=10', None, 200,
|
||||
method='get')
|
||||
assert data.get('max_pages') == 3
|
||||
assert len(data.get('project_supervisors')) == 10
|
||||
data = _test_case_client_without_response(
|
||||
client,
|
||||
"/api/coordinator/project_supervisor/?per_page=10",
|
||||
None,
|
||||
200,
|
||||
method="get",
|
||||
)
|
||||
assert data.get("max_pages") == 3
|
||||
assert len(data.get("project_supervisors")) == 10
|
||||
|
||||
|
||||
def test_list_project_supervisors_by_year_group(test_app_with_context) -> None:
|
||||
@ -30,184 +43,343 @@ def test_list_project_supervisors_by_year_group(test_app_with_context) -> None:
|
||||
year_group_2 = create_year_group()
|
||||
create_project_supervisors(year_group, 12)
|
||||
create_project_supervisors(year_group_2, 24)
|
||||
data = _test_case_client_without_response(client,
|
||||
f'/api/coordinator/project_supervisor/{year_group.id}/?per_page=10',
|
||||
None, 200, method='get')
|
||||
assert data.get('max_pages') == 2
|
||||
assert len(data.get('project_supervisors')) == 10
|
||||
data = _test_case_client_without_response(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/{year_group.id}/?per_page=10",
|
||||
None,
|
||||
200,
|
||||
method="get",
|
||||
)
|
||||
assert data.get("max_pages") == 2
|
||||
assert len(data.get("project_supervisors")) == 10
|
||||
|
||||
|
||||
def test_create_project_supervisors(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/project_supervisor/', valid_data,
|
||||
'Project Supervisor was created!', 201, method='post')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/project_supervisor/",
|
||||
valid_data,
|
||||
"Project Supervisor was created!",
|
||||
201,
|
||||
method="post",
|
||||
)
|
||||
|
||||
|
||||
def test_create_project_supervisors_with_invalid_data(test_app_with_context) -> None:
|
||||
data = {
|
||||
'first_name': 'John',
|
||||
'last_name': 'Smith',
|
||||
'email': 'johnsmitl.com'
|
||||
}
|
||||
data = {"first_name": "John", "last_name": "Smith", "email": "johnsmitl.com"}
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/project_supervisor/', data,
|
||||
'Validation error', 400, method='post')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/project_supervisor/",
|
||||
data,
|
||||
"Validation error",
|
||||
400,
|
||||
method="post",
|
||||
)
|
||||
|
||||
|
||||
def test_create_project_supervisors_if_project_supervisor_has_already_exist(test_app_with_context) -> None:
|
||||
def test_create_project_supervisors_if_project_supervisor_has_already_exist(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
create_dummy_ps(valid_data)
|
||||
_test_case_client(client, '/api/coordinator/project_supervisor/', valid_data,
|
||||
'Project Supervisor has already exists!', 400, method='post', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/project_supervisor/",
|
||||
valid_data,
|
||||
"Project Supervisor has already exists!",
|
||||
400,
|
||||
method="post",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_detail_project_supervisor(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
ps = create_dummy_ps(valid_data)
|
||||
data = _test_case_client_without_response(client, f'/api/coordinator/project_supervisor/{ps.id}/detail/',
|
||||
None, 200, method='get')
|
||||
data = _test_case_client_without_response(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/{ps.id}/detail/",
|
||||
None,
|
||||
200,
|
||||
method="get",
|
||||
)
|
||||
assert_model_changes(ps, data)
|
||||
|
||||
|
||||
def test_detail_project_supervisor_if_project_supervisor_doesnt_exist(test_app_with_context) -> None:
|
||||
def test_detail_project_supervisor_if_project_supervisor_doesnt_exist(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/project_supervisor/23/detail/', None,
|
||||
'Not found project supervisor!', 404, method='get', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/project_supervisor/23/detail/",
|
||||
None,
|
||||
"Not found project supervisor!",
|
||||
404,
|
||||
method="get",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_delete_project_supervisor(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
ps = create_dummy_ps(valid_data)
|
||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/', None,
|
||||
'Project Supervisor was deleted!', 200, method='delete')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/{ps.id}/",
|
||||
None,
|
||||
"Project Supervisor was deleted!",
|
||||
200,
|
||||
method="delete",
|
||||
)
|
||||
|
||||
|
||||
def test_delete_project_supervisor_if_project_supervisor_doesnt_exist(test_app_with_context) -> None:
|
||||
def test_delete_project_supervisor_if_project_supervisor_doesnt_exist(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/project_supervisor/23/', None,
|
||||
'Not found project supervisor!', 404, method='delete', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/project_supervisor/23/",
|
||||
None,
|
||||
"Not found project supervisor!",
|
||||
404,
|
||||
method="delete",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_delete_project_supervisor_if_project_supervisor_has_got_at_least_one_group(test_app_with_context) -> None:
|
||||
def test_delete_project_supervisor_if_project_supervisor_has_got_at_least_one_group(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
ps = create_dummy_ps(valid_data)
|
||||
create_dummy_group({'name': 'new project'}, ps.id)
|
||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/', None,
|
||||
'Project Supervisor has at least one group!', 400, method='delete', key='error')
|
||||
create_dummy_group({"name": "new project"}, ps.id)
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/{ps.id}/",
|
||||
None,
|
||||
"Project Supervisor has at least one group!",
|
||||
400,
|
||||
method="delete",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_edit_project_supervisor(test_app_with_context) -> None:
|
||||
new_data = {
|
||||
'first_name': 'Albert',
|
||||
'last_name': 'Einstein',
|
||||
'email': 'albertmc2@gmail.com'
|
||||
"first_name": "Albert",
|
||||
"last_name": "Einstein",
|
||||
"email": "albertmc2@gmail.com",
|
||||
}
|
||||
with test_app_with_context.test_client() as client:
|
||||
ps = create_dummy_ps(valid_data)
|
||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/', new_data,
|
||||
'Project Supervisor was updated!', 200, method='put')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/{ps.id}/",
|
||||
new_data,
|
||||
"Project Supervisor was updated!",
|
||||
200,
|
||||
method="put",
|
||||
)
|
||||
assert_model_changes(ps, new_data)
|
||||
|
||||
|
||||
def test_edit_project_supervisor_with_invalid_data(test_app_with_context) -> None:
|
||||
invalid_data = {
|
||||
'first_name': 'Mark',
|
||||
'last_name': 'Smith',
|
||||
'email': 'invalidemail'
|
||||
}
|
||||
invalid_data = {"first_name": "Mark", "last_name": "Smith", "email": "invalidemail"}
|
||||
with test_app_with_context.test_client() as client:
|
||||
ps = create_dummy_ps(valid_data)
|
||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/', invalid_data,
|
||||
'Validation error', 400, method='put')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/{ps.id}/",
|
||||
invalid_data,
|
||||
"Validation error",
|
||||
400,
|
||||
method="put",
|
||||
)
|
||||
|
||||
|
||||
def test_edit_project_supervisor_if_project_supervisor_doesnt_exist(test_app_with_context) -> None:
|
||||
def test_edit_project_supervisor_if_project_supervisor_doesnt_exist(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/project_supervisor/2332/', valid_data,
|
||||
'Not found project supervisor!', 404, method='put', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/project_supervisor/2332/",
|
||||
valid_data,
|
||||
"Not found project supervisor!",
|
||||
404,
|
||||
method="put",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_add_project_supervisor_to_year_group(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
ps = create_dummy_ps(valid_data)
|
||||
yg = create_year_group()
|
||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/year-group/{yg.id}/',
|
||||
year_group_ps_data, "Project Supervisor was added to year group!", 201, method='post')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/{ps.id}/year-group/{yg.id}/",
|
||||
year_group_ps_data,
|
||||
"Project Supervisor was added to year group!",
|
||||
201,
|
||||
method="post",
|
||||
)
|
||||
|
||||
|
||||
def test_add_project_supervisor_to_year_group_if_project_supervisor_doesnt_exist(test_app_with_context) -> None:
|
||||
def test_add_project_supervisor_to_year_group_if_project_supervisor_doesnt_exist(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
_test_case_client(client, f'/api/coordinator/project_supervisor/454/year-group/{yg.id}/', year_group_ps_data,
|
||||
"Not found project supervisor!", 404, method='post', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/454/year-group/{yg.id}/",
|
||||
year_group_ps_data,
|
||||
"Not found project supervisor!",
|
||||
404,
|
||||
method="post",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_add_project_supervisor_to_year_group_if_year_group_doesnt_exist(test_app_with_context) -> None:
|
||||
def test_add_project_supervisor_to_year_group_if_year_group_doesnt_exist(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
ps = create_dummy_ps(valid_data)
|
||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/year-group/2/', year_group_ps_data,
|
||||
"Not found year group!", 404, method='post', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/{ps.id}/year-group/2/",
|
||||
year_group_ps_data,
|
||||
"Not found year group!",
|
||||
404,
|
||||
method="post",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_add_project_supervisor_to_year_group_if_project_supervisor_has_already_assigned_to_year_group(
|
||||
test_app_with_context) -> None:
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
ps = create_dummy_ps(valid_data)
|
||||
yg = create_year_group()
|
||||
ygps = YearGroupProjectSupervisors(project_supervisor_id=ps.id, year_group_id=yg.id, limit_group=2)
|
||||
ygps = YearGroupProjectSupervisors(
|
||||
project_supervisor_id=ps.id, year_group_id=yg.id, limit_group=2
|
||||
)
|
||||
db.session.add(ygps)
|
||||
db.session.commit()
|
||||
|
||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/year-group/{yg.id}/',
|
||||
year_group_ps_data, "Project supervisor is assigned to this year group!", 400, method='post',
|
||||
key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/{ps.id}/year-group/{yg.id}/",
|
||||
year_group_ps_data,
|
||||
"Project supervisor is assigned to this year group!",
|
||||
400,
|
||||
method="post",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_delete_project_supervisor_to_year_group(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
ps = create_dummy_ps(valid_data)
|
||||
yg = create_year_group()
|
||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/year-group/{yg.id}/', None,
|
||||
"Project Supervisor was removed from this year group!", 200, method='delete')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/{ps.id}/year-group/{yg.id}/",
|
||||
None,
|
||||
"Project Supervisor was removed from this year group!",
|
||||
200,
|
||||
method="delete",
|
||||
)
|
||||
assert len(YearGroupProjectSupervisors.query.all()) == 0
|
||||
|
||||
|
||||
def test_delete_project_supervisor_to_year_group_if_project_supervisor_doesnt_exist(test_app_with_context) -> None:
|
||||
def test_delete_project_supervisor_to_year_group_if_project_supervisor_doesnt_exist(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
_test_case_client(client, f'/api/coordinator/project_supervisor/5/year-group/{yg.id}/', None,
|
||||
"Not found project supervisor!", 404, method='delete', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/5/year-group/{yg.id}/",
|
||||
None,
|
||||
"Not found project supervisor!",
|
||||
404,
|
||||
method="delete",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_delete_project_supervisor_to_year_group_if_year_group_doesnt_exist(test_app_with_context) -> None:
|
||||
def test_delete_project_supervisor_to_year_group_if_year_group_doesnt_exist(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
ps = create_dummy_ps(valid_data)
|
||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/year-group/23/', None,
|
||||
"Not found year group!", 404, method='delete', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/{ps.id}/year-group/23/",
|
||||
None,
|
||||
"Not found year group!",
|
||||
404,
|
||||
method="delete",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_update_limit_of_group_for_project_supervisor(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
ps = create_dummy_ps(valid_data)
|
||||
yg = create_year_group()
|
||||
ygps = YearGroupProjectSupervisors(project_supervisor_id=ps.id, year_group_id=yg.id, limit_group=6)
|
||||
ygps = YearGroupProjectSupervisors(
|
||||
project_supervisor_id=ps.id, year_group_id=yg.id, limit_group=6
|
||||
)
|
||||
db.session.add(ygps)
|
||||
db.session.commit()
|
||||
|
||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/year-group/{yg.id}/',
|
||||
year_group_ps_data, "Limit of group was changed!", 200, method='put')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/{ps.id}/year-group/{yg.id}/",
|
||||
year_group_ps_data,
|
||||
"Limit of group was changed!",
|
||||
200,
|
||||
method="put",
|
||||
)
|
||||
assert_model_changes(ygps, year_group_ps_data)
|
||||
|
||||
|
||||
def test_update_limit_of_group_for_project_supervisor_if_project_supervisor_doesnt_exist(test_app_with_context) -> None:
|
||||
def test_update_limit_of_group_for_project_supervisor_if_project_supervisor_doesnt_exist(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
_test_case_client(client, f'/api/coordinator/project_supervisor/34/year-group/{yg.id}/',
|
||||
year_group_ps_data, "Not found project supervisor!", 404, method='put', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/34/year-group/{yg.id}/",
|
||||
year_group_ps_data,
|
||||
"Not found project supervisor!",
|
||||
404,
|
||||
method="put",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_update_limit_of_group_for_project_supervisor_if_year_group_doesnt_exist(test_app_with_context) -> None:
|
||||
def test_update_limit_of_group_for_project_supervisor_if_year_group_doesnt_exist(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
ps = create_dummy_ps(valid_data)
|
||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/year-group/34/',
|
||||
year_group_ps_data, "Not found year group!", 404, method='put', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/project_supervisor/{ps.id}/year-group/34/",
|
||||
year_group_ps_data,
|
||||
"Not found year group!",
|
||||
404,
|
||||
method="put",
|
||||
key="error",
|
||||
)
|
||||
|
@ -1,26 +1,26 @@
|
||||
import copy
|
||||
|
||||
from ...utils import _test_case_client, _test_case_client_without_response, assert_model_changes
|
||||
from ...fake_data import create_year_group, create_students, create_student
|
||||
from ...fake_data import create_student, create_students, create_year_group
|
||||
from ...utils import (
|
||||
_test_case_client,
|
||||
_test_case_client_without_response,
|
||||
assert_model_changes,
|
||||
)
|
||||
|
||||
valid_data = {
|
||||
'first_name': 'Albert',
|
||||
'last_name': 'Rose',
|
||||
'index': 234_343,
|
||||
'email': 'albert@gmail.com'
|
||||
"first_name": "Albert",
|
||||
"last_name": "Rose",
|
||||
"index": 234_343,
|
||||
"email": "albert@gmail.com",
|
||||
}
|
||||
|
||||
new_data = {
|
||||
'first_name': 'Martin',
|
||||
'last_name': 'Green',
|
||||
'pesel': '93030312894'
|
||||
}
|
||||
new_data = {"first_name": "Martin", "last_name": "Green", "pesel": "93030312894"}
|
||||
|
||||
data_to_create_student = {
|
||||
'first_name': 'Albert',
|
||||
'last_name': 'Marcus',
|
||||
'pesel': '93030312896',
|
||||
'index': 123_456
|
||||
"first_name": "Albert",
|
||||
"last_name": "Marcus",
|
||||
"pesel": "93030312896",
|
||||
"index": 123_456,
|
||||
}
|
||||
|
||||
|
||||
@ -28,94 +28,174 @@ def test_list_students(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
create_students(yg, 45)
|
||||
data = _test_case_client_without_response(client, f'/api/coordinator/students/{yg.id}/?per_page=10', None, 200,
|
||||
method='get')
|
||||
assert data.get('max_pages') == 5
|
||||
assert len(data.get('students')) == 10
|
||||
data = _test_case_client_without_response(
|
||||
client,
|
||||
f"/api/coordinator/students/{yg.id}/?per_page=10",
|
||||
None,
|
||||
200,
|
||||
method="get",
|
||||
)
|
||||
assert data.get("max_pages") == 5
|
||||
assert len(data.get("students")) == 10
|
||||
|
||||
|
||||
def test_detail_student(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
st = create_student(valid_data, yg.id)
|
||||
data = _test_case_client_without_response(client, f'/api/coordinator/students/{st.index}/detail/', None, 200,
|
||||
method='get')
|
||||
data = _test_case_client_without_response(
|
||||
client,
|
||||
f"/api/coordinator/students/{st.index}/detail/",
|
||||
None,
|
||||
200,
|
||||
method="get",
|
||||
)
|
||||
assert_model_changes(st, data)
|
||||
|
||||
|
||||
def test_detail_student_if_student_doesnt_exist(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/students/43/detail/', None, 'Not found student!', 404,
|
||||
method='get', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/students/43/detail/",
|
||||
None,
|
||||
"Not found student!",
|
||||
404,
|
||||
method="get",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_delete_student(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
st = create_student(valid_data, yg.id)
|
||||
_test_case_client(client, f'/api/coordinator/students/{st.index}/', None, 'Student was deleted!', 202,
|
||||
method='delete')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/students/{st.index}/",
|
||||
None,
|
||||
"Student was deleted!",
|
||||
202,
|
||||
method="delete",
|
||||
)
|
||||
|
||||
|
||||
def test_delete_student_if_student_doesnt_exist(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/students/43/', None, 'Not found student!', 404,
|
||||
method='delete', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/students/43/",
|
||||
None,
|
||||
"Not found student!",
|
||||
404,
|
||||
method="delete",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_edit_student(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
st = create_student(valid_data, yg.id)
|
||||
_test_case_client(client, f'/api/coordinator/students/{st.index}/', new_data, 'Student was updated!', 200,
|
||||
method='put')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/students/{st.index}/",
|
||||
new_data,
|
||||
"Student was updated!",
|
||||
200,
|
||||
method="put",
|
||||
)
|
||||
|
||||
|
||||
def test_edit_student_with_invalid_data(test_app_with_context) -> None:
|
||||
data = copy.copy(new_data)
|
||||
data['pesel'] = '43333333333433443'
|
||||
data["pesel"] = "43333333333433443"
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
st = create_student(valid_data, yg.id)
|
||||
_test_case_client(client, f'/api/coordinator/students/{st.index}/', data, 'Validation error', 400, method='put')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/students/{st.index}/",
|
||||
data,
|
||||
"Validation error",
|
||||
400,
|
||||
method="put",
|
||||
)
|
||||
|
||||
|
||||
def test_edit_student_if_student_doesnt_exist(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/students/54/', new_data, 'Not found student!', 404, method='put',
|
||||
key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/students/54/",
|
||||
new_data,
|
||||
"Not found student!",
|
||||
404,
|
||||
method="put",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_create_student(test_app_with_context) -> None:
|
||||
data = copy.copy(data_to_create_student)
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
data['year_group_id'] = yg.id
|
||||
_test_case_client(client, '/api/coordinator/students/', data, 'Student was created!', 200, method='post')
|
||||
data["year_group_id"] = yg.id
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/students/",
|
||||
data,
|
||||
"Student was created!",
|
||||
200,
|
||||
method="post",
|
||||
)
|
||||
|
||||
|
||||
def test_create_student_with_invalid_data(test_app_with_context) -> None:
|
||||
data = copy.copy(data_to_create_student)
|
||||
data['pesel'] = '434343434343344'
|
||||
data["pesel"] = "434343434343344"
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
data['year_group_id'] = yg.id
|
||||
_test_case_client(client, '/api/coordinator/students/', data, 'Validation error', 400, method='post')
|
||||
data["year_group_id"] = yg.id
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/students/",
|
||||
data,
|
||||
"Validation error",
|
||||
400,
|
||||
method="post",
|
||||
)
|
||||
|
||||
|
||||
def test_create_student_if_year_group_doesnt_exist(test_app_with_context) -> None:
|
||||
data = copy.copy(data_to_create_student)
|
||||
with test_app_with_context.test_client() as client:
|
||||
data['year_group_id'] = 34
|
||||
_test_case_client(client, '/api/coordinator/students/', data, 'Not found year group!', 404, method='post',
|
||||
key='error')
|
||||
data["year_group_id"] = 34
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/students/",
|
||||
data,
|
||||
"Not found year group!",
|
||||
404,
|
||||
method="post",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_create_student_if_student_has_already_assigned_to_this_group(test_app_with_context) -> None:
|
||||
def test_create_student_if_student_has_already_assigned_to_this_group(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
data = copy.copy(data_to_create_student)
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group()
|
||||
create_student(data, yg.id)
|
||||
data['year_group_id'] = yg.id
|
||||
_test_case_client(client, '/api/coordinator/students/', data, 'You are assigned to this year group!', 400,
|
||||
method='post', key='error')
|
||||
data["year_group_id"] = yg.id
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/students/",
|
||||
data,
|
||||
"You are assigned to this year group!",
|
||||
400,
|
||||
method="post",
|
||||
key="error",
|
||||
)
|
||||
|
@ -1,99 +1,154 @@
|
||||
from ...fake_data import create_year_group
|
||||
from ...utils import _test_case_client_without_response, _test_case_client, assert_model_changes
|
||||
from app.base.mode import ModeGroups
|
||||
|
||||
valid_data = {
|
||||
'mode': ModeGroups.STATIONARY.value,
|
||||
'name': '2022/2023'
|
||||
}
|
||||
from ...fake_data import create_year_group
|
||||
from ...utils import (
|
||||
_test_case_client,
|
||||
_test_case_client_without_response,
|
||||
assert_model_changes,
|
||||
)
|
||||
|
||||
new_data = {
|
||||
'mode': ModeGroups.NON_STATIONARY.value,
|
||||
'name': '2021/2022'
|
||||
}
|
||||
valid_data = {"mode": ModeGroups.STATIONARY.value, "name": "2022/2023"}
|
||||
|
||||
example_data = {
|
||||
'mode': ModeGroups.STATIONARY.value,
|
||||
'name': '2021/2022'
|
||||
}
|
||||
new_data = {"mode": ModeGroups.NON_STATIONARY.value, "name": "2021/2022"}
|
||||
|
||||
example_data = {"mode": ModeGroups.STATIONARY.value, "name": "2021/2022"}
|
||||
|
||||
|
||||
def test_create_year_group(test_client) -> None:
|
||||
_test_case_client(test_client, '/api/coordinator/year-group/', valid_data, 'Year group was created!', 201)
|
||||
_test_case_client(
|
||||
test_client,
|
||||
"/api/coordinator/year-group/",
|
||||
valid_data,
|
||||
"Year group was created!",
|
||||
201,
|
||||
)
|
||||
|
||||
|
||||
def test_create_year_group_with_invalid_name(test_client) -> None:
|
||||
data = {
|
||||
'mode': ModeGroups.STATIONARY.value,
|
||||
'name': '2022/203232a'
|
||||
}
|
||||
_test_case_client(test_client, '/api/coordinator/year-group/', data, 'Validation error', 400)
|
||||
data = {"mode": ModeGroups.STATIONARY.value, "name": "2022/203232a"}
|
||||
_test_case_client(
|
||||
test_client, "/api/coordinator/year-group/", data, "Validation error", 400
|
||||
)
|
||||
|
||||
|
||||
def test_create_year_group_with_invalid_mode(test_client) -> None:
|
||||
data = {
|
||||
'mode': 'xxxx',
|
||||
'name': '2022/2033'
|
||||
}
|
||||
_test_case_client(test_client, '/api/coordinator/year-group/', data, 'Validation error', 400)
|
||||
data = {"mode": "xxxx", "name": "2022/2033"}
|
||||
_test_case_client(
|
||||
test_client, "/api/coordinator/year-group/", data, "Validation error", 400
|
||||
)
|
||||
|
||||
|
||||
def test_create_year_group_if_year_group_already_exists(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
create_year_group(valid_data)
|
||||
_test_case_client(client, '/api/coordinator/year-group/', valid_data, 'Year group has already exists!', 400,
|
||||
'error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/year-group/",
|
||||
valid_data,
|
||||
"Year group has already exists!",
|
||||
400,
|
||||
"error",
|
||||
)
|
||||
|
||||
|
||||
def test_delete_year_group(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group(valid_data)
|
||||
_test_case_client(client, f'/api/coordinator/year-group/{yg.id}/', None, 'Year group was deleted!', 202,
|
||||
method='delete')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/year-group/{yg.id}/",
|
||||
None,
|
||||
"Year group was deleted!",
|
||||
202,
|
||||
method="delete",
|
||||
)
|
||||
|
||||
|
||||
def test_delete_year_group_if_year_group_not_exists(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/coordinator/year-group/1/', None, 'Year group doesn\'t exist!', 404,
|
||||
method='delete', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/coordinator/year-group/1/",
|
||||
None,
|
||||
"Year group doesn't exist!",
|
||||
404,
|
||||
method="delete",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_update_year_group(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group(valid_data)
|
||||
_test_case_client(client, f'/api/coordinator/year-group/{yg.id}/', new_data, "Year group was updated!", 200,
|
||||
method='put', key='message')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/year-group/{yg.id}/",
|
||||
new_data,
|
||||
"Year group was updated!",
|
||||
200,
|
||||
method="put",
|
||||
key="message",
|
||||
)
|
||||
assert_model_changes(yg, new_data)
|
||||
|
||||
|
||||
def test_update_year_group_with_invalid_data(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
yg = create_year_group(valid_data)
|
||||
_test_case_client(client, f'/api/coordinator/year-group/{yg.id}/', {'name': '', 'mode': ''}, 'Validation error',
|
||||
400, method='put', key='message')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/year-group/{yg.id}/",
|
||||
{"name": "", "mode": ""},
|
||||
"Validation error",
|
||||
400,
|
||||
method="put",
|
||||
key="message",
|
||||
)
|
||||
assert_model_changes(yg, valid_data)
|
||||
|
||||
|
||||
def test_update_year_group_with_invalid_route_param_year_group_id(test_app_with_context) -> None:
|
||||
def test_update_year_group_with_invalid_route_param_year_group_id(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, f'/api/coordinator/year-group/23/', new_data, 'Not found year group!',
|
||||
404, method='put', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/year-group/23/",
|
||||
new_data,
|
||||
"Not found year group!",
|
||||
404,
|
||||
method="put",
|
||||
key="error",
|
||||
)
|
||||
|
||||
|
||||
def test_update_year_group_with_valid_data_and_year_group_which_has_already_exist(test_app_with_context) -> None:
|
||||
def test_update_year_group_with_valid_data_and_year_group_which_has_already_exist(
|
||||
test_app_with_context,
|
||||
) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
create_year_group(new_data)
|
||||
yg = create_year_group(valid_data)
|
||||
_test_case_client(client, f'/api/coordinator/year-group/{yg.id}/', new_data, 'Year group has already exists!',
|
||||
400, method='put', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
f"/api/coordinator/year-group/{yg.id}/",
|
||||
new_data,
|
||||
"Year group has already exists!",
|
||||
400,
|
||||
method="put",
|
||||
key="error",
|
||||
)
|
||||
assert_model_changes(yg, valid_data)
|
||||
|
||||
|
||||
def test_list_year_group(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
ygs = [create_year_group(data) for data in (valid_data, new_data, example_data)]
|
||||
data = _test_case_client_without_response(client, '/api/coordinator/year-group/', None, 200, method='get')
|
||||
assert data.get('max_pages') == 1
|
||||
for year_group_data in data.get('year_groups'):
|
||||
yg_id = year_group_data.get('id')
|
||||
assert_model_changes(list(filter(lambda yg: yg.id == yg_id, ygs))[0], year_group_data)
|
||||
data = _test_case_client_without_response(
|
||||
client, "/api/coordinator/year-group/", None, 200, method="get"
|
||||
)
|
||||
assert data.get("max_pages") == 1
|
||||
for year_group_data in data.get("year_groups"):
|
||||
yg_id = year_group_data.get("id")
|
||||
assert_model_changes(
|
||||
list(filter(lambda yg: yg.id == yg_id, ygs))[0], year_group_data
|
||||
)
|
||||
|
@ -1,13 +1,16 @@
|
||||
from ...utils import _test_case_client_without_response, assert_model_changes
|
||||
from ...fake_data import create_year_group, create_project_supervisors, create_groups
|
||||
from app.dependencies import db
|
||||
|
||||
from ...fake_data import create_groups, create_project_supervisors, create_year_group
|
||||
from ...utils import _test_case_client_without_response, assert_model_changes
|
||||
|
||||
|
||||
def test_list_year_group_for_specific_student(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
year_group = create_year_group()
|
||||
amount_of_project_supervisors = 3
|
||||
project_supervisors = create_project_supervisors(year_group, amount_of_project_supervisors)
|
||||
project_supervisors = create_project_supervisors(
|
||||
year_group, amount_of_project_supervisors
|
||||
)
|
||||
groups = create_groups(year_group, 6)
|
||||
|
||||
for i in range(1, 4):
|
||||
@ -16,12 +19,14 @@ def test_list_year_group_for_specific_student(test_app_with_context) -> None:
|
||||
gr.project_supervisor_id = project_supervisors[i - 1].id
|
||||
db.session.commit()
|
||||
|
||||
url = f'/api/students/registrations/{year_group.id}/?per_page=10'
|
||||
data = _test_case_client_without_response(client, url, None, 200, method='get')
|
||||
assert data.get('max_pages') == 1
|
||||
project_supervisors_data = data.get('project_supervisors')
|
||||
url = f"/api/students/registrations/{year_group.id}/?per_page=10"
|
||||
data = _test_case_client_without_response(client, url, None, 200, method="get")
|
||||
assert data.get("max_pages") == 1
|
||||
project_supervisors_data = data.get("project_supervisors")
|
||||
assert len(project_supervisors_data) == amount_of_project_supervisors
|
||||
|
||||
for ps, expected_available_groups in zip(project_supervisors, [2, 1, 0]):
|
||||
ps_dict = list(filter(lambda p: p.get('email') == ps.email, project_supervisors_data))[0]
|
||||
assert ps_dict.get('available_groups') == expected_available_groups
|
||||
ps_dict = list(
|
||||
filter(lambda p: p.get("email") == ps.email, project_supervisors_data)
|
||||
)[0]
|
||||
assert ps_dict.get("available_groups") == expected_available_groups
|
||||
|
@ -1,32 +1,17 @@
|
||||
from ...utils import _test_case_client, _test_case_client_without_response
|
||||
from ...fake_data import create_year_group, create_student
|
||||
from app.base.mode import ModeGroups
|
||||
from app.dependencies import db
|
||||
from app.students.models import YearGroupStudents
|
||||
|
||||
valid_data = {
|
||||
'first_name': 'Dominic',
|
||||
'last_name': 'Mozart',
|
||||
'index': 123_345
|
||||
}
|
||||
from ...fake_data import create_student, create_year_group
|
||||
from ...utils import _test_case_client, _test_case_client_without_response
|
||||
|
||||
valid_data = {"first_name": "Dominic", "last_name": "Mozart", "index": 123_345}
|
||||
|
||||
year_group_data = [
|
||||
{
|
||||
'name': '2022/2023',
|
||||
'mode': ModeGroups.STATIONARY.value
|
||||
},
|
||||
{
|
||||
'name': '2021/2022',
|
||||
'mode': ModeGroups.STATIONARY.value
|
||||
},
|
||||
{
|
||||
'name': '2023/2024',
|
||||
'mode': ModeGroups.NON_STATIONARY.value
|
||||
},
|
||||
{
|
||||
'name': '1997/1998',
|
||||
'mode': ModeGroups.NON_STATIONARY.value
|
||||
},
|
||||
{"name": "2022/2023", "mode": ModeGroups.STATIONARY.value},
|
||||
{"name": "2021/2022", "mode": ModeGroups.STATIONARY.value},
|
||||
{"name": "2023/2024", "mode": ModeGroups.NON_STATIONARY.value},
|
||||
{"name": "1997/1998", "mode": ModeGroups.NON_STATIONARY.value},
|
||||
]
|
||||
|
||||
|
||||
@ -35,16 +20,25 @@ def test_list_year_group_for_specific_student(test_app_with_context) -> None:
|
||||
year_groups = [create_year_group(data) for data in year_group_data]
|
||||
student = create_student(valid_data)
|
||||
for yg in year_groups[:-1]:
|
||||
db.session.add(YearGroupStudents(year_group_id=yg.id, student_index=student.index))
|
||||
db.session.add(
|
||||
YearGroupStudents(year_group_id=yg.id, student_index=student.index)
|
||||
)
|
||||
db.session.commit()
|
||||
|
||||
url = f'/api/students/year-group/?per_page=10&index={student.index}'
|
||||
data = _test_case_client_without_response(client, url, None, 200, method='get')
|
||||
assert data.get('max_pages') == 1
|
||||
assert len(data.get('year_groups')) == len(year_groups) - 1
|
||||
url = f"/api/students/year-group/?per_page=10&index={student.index}"
|
||||
data = _test_case_client_without_response(client, url, None, 200, method="get")
|
||||
assert data.get("max_pages") == 1
|
||||
assert len(data.get("year_groups")) == len(year_groups) - 1
|
||||
|
||||
|
||||
def test_list_year_group_if_student_doesnt_exist(test_app_with_context) -> None:
|
||||
with test_app_with_context.test_client() as client:
|
||||
_test_case_client(client, '/api/students/year-group/?per_page=10&index=23', None, 'Not found student!', 404,
|
||||
method='get', key='error')
|
||||
_test_case_client(
|
||||
client,
|
||||
"/api/students/year-group/?per_page=10&index=23",
|
||||
None,
|
||||
"Not found student!",
|
||||
404,
|
||||
method="get",
|
||||
key="error",
|
||||
)
|
||||
|
@ -4,80 +4,107 @@ import pandas as pd
|
||||
import pytest
|
||||
from flask import current_app
|
||||
|
||||
from app.dependencies import db
|
||||
from app.base.utils import is_allowed_extensions, order_by_column_name, paginate_models
|
||||
from app.coordinator.utils import check_columns, parse_csv, generate_range_dates, generate_csv
|
||||
from app.coordinator.exceptions import InvalidNameOrTypeHeaderException
|
||||
from app.students.models import Student, Group
|
||||
from app.coordinator.utils import (
|
||||
check_columns,
|
||||
generate_csv,
|
||||
generate_range_dates,
|
||||
parse_csv,
|
||||
)
|
||||
from app.dependencies import db
|
||||
from app.students.models import Group, Student
|
||||
|
||||
|
||||
def test_is_allowed_extensions(test_app) -> None:
|
||||
with test_app.app_context():
|
||||
for ext in current_app.config.get('ALLOWED_EXTENSIONS'):
|
||||
assert is_allowed_extensions(f'file.{ext}') is True
|
||||
for ext in current_app.config.get("ALLOWED_EXTENSIONS"):
|
||||
assert is_allowed_extensions(f"file.{ext}") is True
|
||||
|
||||
|
||||
def test_is_allowed_extensions_with_invalid_extensions(test_app) -> None:
|
||||
with test_app.app_context():
|
||||
assert is_allowed_extensions('file.invalid_ext') is False
|
||||
assert is_allowed_extensions('file') is False
|
||||
assert is_allowed_extensions("file.invalid_ext") is False
|
||||
assert is_allowed_extensions("file") is False
|
||||
|
||||
|
||||
def test_order_by_column_name_ascending_mode(test_app) -> None:
|
||||
with test_app.app_context():
|
||||
query = order_by_column_name(Student.query, 'index', 'desc')
|
||||
query = order_by_column_name(Student.query, "index", "desc")
|
||||
assert 'ORDER BY students."index"' in str(query)
|
||||
|
||||
|
||||
def test_order_by_column_name_descending_mode(test_app) -> None:
|
||||
with test_app.app_context():
|
||||
query = order_by_column_name(Student.query, 'index', 'desc')
|
||||
query = order_by_column_name(Student.query, "index", "desc")
|
||||
assert 'ORDER BY students."index" DESC' in str(query)
|
||||
|
||||
|
||||
def test_paginate_models(test_app_ctx_with_db) -> None:
|
||||
with test_app_ctx_with_db:
|
||||
st = Student(index=123456, first_name='Dominic', last_name='Smith', pesel='99010109876', email='xxx@gmail.com')
|
||||
st1 = Student(index=123457, first_name='John', last_name='Newton', pesel='99010109871', email='zzz@gmail.com')
|
||||
st = Student(
|
||||
index=123456,
|
||||
first_name="Dominic",
|
||||
last_name="Smith",
|
||||
pesel="99010109876",
|
||||
email="xxx@gmail.com",
|
||||
)
|
||||
st1 = Student(
|
||||
index=123457,
|
||||
first_name="John",
|
||||
last_name="Newton",
|
||||
pesel="99010109871",
|
||||
email="zzz@gmail.com",
|
||||
)
|
||||
db.session.add_all([st, st1])
|
||||
db.session.commit()
|
||||
result = paginate_models(1, Student.query, 1)
|
||||
|
||||
items = result.get('items', [])
|
||||
max_pages = result.get('max_pages', 0)
|
||||
items = result.get("items", [])
|
||||
max_pages = result.get("max_pages", 0)
|
||||
|
||||
assert len(items) == 1
|
||||
assert max_pages == 2
|
||||
|
||||
|
||||
def test_check_columns() -> None:
|
||||
dummy_data = {'NAZWISKO': ['Smith'], 'IMIE': ['Dominic'], 'INDEKS': [343433], 'PESEL': [90020178654],
|
||||
'EMAIL': ['domsmi@gmail.com']}
|
||||
dummy_data = {
|
||||
"NAZWISKO": ["Smith"],
|
||||
"IMIE": ["Dominic"],
|
||||
"INDEKS": [343433],
|
||||
"PESEL": [90020178654],
|
||||
"EMAIL": ["domsmi@gmail.com"],
|
||||
}
|
||||
df = pd.DataFrame(data=dummy_data)
|
||||
assert check_columns(df) is True
|
||||
|
||||
|
||||
def test_check_columns_with_invalid_column_names() -> None:
|
||||
dummy_data = {'col1': [1, 2], 'col2': [2, 3]}
|
||||
dummy_data = {"col1": [1, 2], "col2": [2, 3]}
|
||||
df = pd.DataFrame(data=dummy_data)
|
||||
assert check_columns(df) is False
|
||||
|
||||
|
||||
def test_check_columns_with_invalid_column_types() -> None:
|
||||
dummy_data = {'NAZWISKO': [999], 'IMIE': ['Dominic'], 'INDEKS': [343433], 'PESEL': [90020178654],
|
||||
'EMAIL': ['domsmi@gmail.com']}
|
||||
dummy_data = {
|
||||
"NAZWISKO": [999],
|
||||
"IMIE": ["Dominic"],
|
||||
"INDEKS": [343433],
|
||||
"PESEL": [90020178654],
|
||||
"EMAIL": ["domsmi@gmail.com"],
|
||||
}
|
||||
df = pd.DataFrame(data=dummy_data)
|
||||
assert check_columns(df) is False
|
||||
|
||||
|
||||
def get_path_to_fake_data(filename: str) -> str:
|
||||
base_dir = current_app.config.get('BASE_DIR', '/')
|
||||
return base_dir / 'tmp_data' / filename
|
||||
base_dir = current_app.config.get("BASE_DIR", "/")
|
||||
return base_dir / "tmp_data" / filename
|
||||
|
||||
|
||||
def test_parse_csv(test_app) -> None:
|
||||
with test_app.app_context():
|
||||
with open(get_path_to_fake_data('students.csv')) as f:
|
||||
with open(get_path_to_fake_data("students.csv")) as f:
|
||||
students = sorted(list(parse_csv(f)), key=lambda s: s.index)
|
||||
indexes = [452790 + i for i in range(3)]
|
||||
assert len(students) == len(indexes)
|
||||
@ -87,14 +114,14 @@ def test_parse_csv(test_app) -> None:
|
||||
|
||||
def test_parse_csv_with_invalid_column_header_name_in_csv_file(test_app) -> None:
|
||||
with test_app.app_context():
|
||||
with open(get_path_to_fake_data('students_column_name.csv')) as f:
|
||||
with open(get_path_to_fake_data("students_column_name.csv")) as f:
|
||||
with pytest.raises(InvalidNameOrTypeHeaderException):
|
||||
parse_csv(f)
|
||||
|
||||
|
||||
def test_parse_csv_with_invalid_column_type_in_csv_file(test_app) -> None:
|
||||
with test_app.app_context():
|
||||
with open(get_path_to_fake_data('students_column_type.csv')) as f:
|
||||
with open(get_path_to_fake_data("students_column_type.csv")) as f:
|
||||
with pytest.raises(InvalidNameOrTypeHeaderException):
|
||||
parse_csv(f)
|
||||
|
||||
@ -114,12 +141,27 @@ def test_generate_range_dates() -> None:
|
||||
|
||||
def test_generate_csv(test_app_ctx_with_db) -> None:
|
||||
students_data = [
|
||||
{'first_name': 'Dominic', 'last_name': 'Smith', 'email': 'xxe@gmail.com', 'index': 123456,
|
||||
'pesel': '98070234293'},
|
||||
{'first_name': 'Matthew', 'last_name': 'Cash', 'email': 'zze@gmail.com', 'index': 123455,
|
||||
'pesel': '98070234291'},
|
||||
{'first_name': 'Martin', 'last_name': 'Rose', 'email': 'nne@gmail.com', 'index': 123446,
|
||||
'pesel': '98070234223'},
|
||||
{
|
||||
"first_name": "Dominic",
|
||||
"last_name": "Smith",
|
||||
"email": "xxe@gmail.com",
|
||||
"index": 123456,
|
||||
"pesel": "98070234293",
|
||||
},
|
||||
{
|
||||
"first_name": "Matthew",
|
||||
"last_name": "Cash",
|
||||
"email": "zze@gmail.com",
|
||||
"index": 123455,
|
||||
"pesel": "98070234291",
|
||||
},
|
||||
{
|
||||
"first_name": "Martin",
|
||||
"last_name": "Rose",
|
||||
"email": "nne@gmail.com",
|
||||
"index": 123446,
|
||||
"pesel": "98070234223",
|
||||
},
|
||||
]
|
||||
|
||||
with test_app_ctx_with_db:
|
||||
@ -135,7 +177,11 @@ def test_generate_csv(test_app_ctx_with_db) -> None:
|
||||
db.session.add_all([gr1, gr2])
|
||||
db.session.commit()
|
||||
|
||||
students_and_groups = [(students[0], gr1), (students[1], gr1), (students[2], gr2)]
|
||||
students_and_groups = [
|
||||
(students[0], gr1),
|
||||
(students[1], gr1),
|
||||
(students[2], gr2),
|
||||
]
|
||||
generated_csv = generate_csv(students_and_groups)
|
||||
for data in students_data:
|
||||
for value in data.values():
|
||||
|
@ -3,7 +3,10 @@ import datetime
|
||||
import pytest
|
||||
from marshmallow import ValidationError
|
||||
|
||||
from app.coordinator.validators import validate_index, validate_datetime_greater_than_now
|
||||
from app.coordinator.validators import (
|
||||
validate_datetime_greater_than_now,
|
||||
validate_index,
|
||||
)
|
||||
|
||||
|
||||
def test_validate_index() -> None:
|
||||
|
@ -15,8 +15,13 @@ def assert_model_changes(model: db.Model, expected_data: dict) -> None:
|
||||
assert value == val
|
||||
|
||||
|
||||
def _test_case_client_without_response(test_client: FlaskClient, url: str, data: Union[dict, None], status_code: int,
|
||||
method: str = 'post') -> dict:
|
||||
def _test_case_client_without_response(
|
||||
test_client: FlaskClient,
|
||||
url: str,
|
||||
data: Union[dict, None],
|
||||
status_code: int,
|
||||
method: str = "post",
|
||||
) -> dict:
|
||||
method_func = getattr(test_client, method)
|
||||
if data is not None:
|
||||
response = method_func(url, json=data)
|
||||
@ -27,16 +32,25 @@ def _test_case_client_without_response(test_client: FlaskClient, url: str, data:
|
||||
return response.json
|
||||
|
||||
|
||||
def _test_case_client(test_client: FlaskClient, url: str, data: Union[dict, None], message: str, status_code: int,
|
||||
key: str = 'message', method: str = 'post') -> None:
|
||||
response_data = _test_case_client_without_response(test_client, url, data, status_code, method)
|
||||
def _test_case_client(
|
||||
test_client: FlaskClient,
|
||||
url: str,
|
||||
data: Union[dict, None],
|
||||
message: str,
|
||||
status_code: int,
|
||||
key: str = "message",
|
||||
method: str = "post",
|
||||
) -> None:
|
||||
response_data = _test_case_client_without_response(
|
||||
test_client, url, data, status_code, method
|
||||
)
|
||||
assert key in response_data.keys()
|
||||
assert response_data.get(key) == message
|
||||
|
||||
|
||||
def _test_case_group(group: Group, data: dict) -> None:
|
||||
assert group.name == data['name']
|
||||
assert group.project_supervisor_id == data['project_supervisor_id']
|
||||
assert group.name == data["name"]
|
||||
assert group.project_supervisor_id == data["project_supervisor_id"]
|
||||
|
||||
for st in group.students:
|
||||
assert st.index in data['students']
|
||||
assert st.index in data["students"]
|
||||
|
Loading…
Reference in New Issue
Block a user