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
|
```bash
|
||||||
pytest
|
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:
|
### Useful commands:
|
||||||
Add new package
|
Add new package
|
||||||
```bash
|
```bash
|
||||||
@ -45,15 +61,19 @@ flask startapp NAME_OF_APP
|
|||||||
```
|
```
|
||||||
Above command create package structure:
|
Above command create package structure:
|
||||||
\
|
\
|
||||||
Create serializer in `__schemas__.py` file:
|
Create serializer in `schemas.py` file:
|
||||||
```python3
|
```python3
|
||||||
class ExampleSchema(ma.SQLAlchemyAutoSchema):
|
from marshmallow import Schema, fields
|
||||||
class Meta:
|
|
||||||
model = MODEL_NAME
|
class ExampleSchema(Schema):
|
||||||
|
id = fields.Integer()
|
||||||
|
name = fields.Str()
|
||||||
```
|
```
|
||||||
\
|
\
|
||||||
Create models in `__models__.py` file:
|
Create models in `models.py` file:
|
||||||
```python3
|
```python3
|
||||||
|
from ..dependencies import db
|
||||||
|
|
||||||
class Example(db.Model):
|
class Example(db.Model):
|
||||||
__tablename__ = "examples"
|
__tablename__ = "examples"
|
||||||
|
|
||||||
@ -61,7 +81,7 @@ class Example(db.Model):
|
|||||||
title = db.Column(db.String(255), unique=True)
|
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
|
```python3
|
||||||
from flask import Blueprint, make_response, jsonify, Response
|
from flask import Blueprint, make_response, jsonify, Response
|
||||||
|
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from apiflask import APIFlask
|
from apiflask import APIFlask
|
||||||
from flask_migrate import Migrate
|
|
||||||
from flask_cors import CORS
|
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 .config import config
|
||||||
from .dependencies import db, ma
|
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 .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:
|
if config_name is None:
|
||||||
config_name = os.environ.get("FLASK_ENV")
|
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"))
|
app.config.from_object(config.get(config_name) or config.get("development"))
|
||||||
|
|
||||||
if app.config['ENABLE_CORS']:
|
if app.config["ENABLE_CORS"]:
|
||||||
CORS(app)
|
CORS(app)
|
||||||
|
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
from flask import Blueprint
|
from flask import Blueprint
|
||||||
|
|
||||||
from .coordinator.routes import bp as coordinator_bp
|
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 .project_supervisor.routes import bp as project_supervisor_bp
|
||||||
from .students.routes import bp as students_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
|
# register blueprints here
|
||||||
api_bp.register_blueprint(coordinator_bp)
|
api_bp.register_blueprint(coordinator_bp)
|
||||||
|
@ -2,6 +2,21 @@ from enum import Enum
|
|||||||
|
|
||||||
|
|
||||||
class ModeGroups(str, Enum):
|
class ModeGroups(str, Enum):
|
||||||
STATIONARY = 's'
|
STATIONARY = "s"
|
||||||
NON_STATIONARY = 'n'
|
NON_STATIONARY = "n"
|
||||||
ENGLISH_SPEAKING_STATIONARY = 'e'
|
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):
|
class MessageSchema(Schema):
|
||||||
|
@ -10,11 +10,13 @@ class PaginationResponse(TypedDict):
|
|||||||
max_pages: int
|
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 is not None:
|
||||||
if order_by_col_name == 'asc':
|
if order_by_col_name == "asc":
|
||||||
query = query.order_by(model_field)
|
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))
|
query = query.order_by(desc(model_field))
|
||||||
|
|
||||||
return query
|
return query
|
||||||
@ -27,12 +29,12 @@ def paginate_models(page: int, query: BaseQuery, per_page=10) -> PaginationRespo
|
|||||||
else:
|
else:
|
||||||
query = query.paginate(page=default_page, per_page=per_page, error_out=False)
|
query = query.paginate(page=default_page, per_page=per_page, error_out=False)
|
||||||
|
|
||||||
return {
|
return {"items": query.items, "max_pages": query.pages}
|
||||||
'items': query.items,
|
|
||||||
'max_pages': query.pages
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def is_allowed_extensions(filename: str):
|
def is_allowed_extensions(filename: str):
|
||||||
return '.' in filename and \
|
return (
|
||||||
filename.rsplit('.', 1)[1].lower() in current_app.config['ALLOWED_EXTENSIONS']
|
"." 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 click import command
|
||||||
|
from flask.cli import with_appcontext
|
||||||
|
|
||||||
from ..dependencies import db
|
from ..dependencies import db
|
||||||
|
|
||||||
|
|
||||||
@command('clear_db')
|
@command("clear_db")
|
||||||
@with_appcontext
|
@with_appcontext
|
||||||
def clear_db() -> None:
|
def clear_db() -> None:
|
||||||
"""Clear database"""
|
"""Clear database"""
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from flask import current_app
|
from click import argument, command
|
||||||
from click import command, argument
|
|
||||||
from click.exceptions import ClickException
|
from click.exceptions import ClickException
|
||||||
|
from flask import current_app
|
||||||
from flask.cli import with_appcontext
|
from flask.cli import with_appcontext
|
||||||
|
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ def startapp(name: str) -> None:
|
|||||||
"""Create the application structure"""
|
"""Create the application structure"""
|
||||||
|
|
||||||
if not re.match("^[a-zA-Z].*$", name):
|
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
|
app_dir = current_app.config["SRC_DIR"] / name
|
||||||
if os.path.exists(app_dir):
|
if os.path.exists(app_dir):
|
||||||
@ -26,12 +26,14 @@ def startapp(name: str) -> None:
|
|||||||
Below you write a schema of model
|
Below you write a schema of model
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
from marshmallow import Schema
|
||||||
|
|
||||||
class ExampleSchema(ma.SQLAlchemyAutoSchema):
|
class ExampleSchema(ma.SQLAlchemyAutoSchema):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = MODEL_NAME
|
model = MODEL_NAME
|
||||||
\'\'\'
|
\'\'\'
|
||||||
|
|
||||||
from ..dependencies import ma
|
from marshmallow import Schema
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model_content = """\'\'\'
|
model_content = """\'\'\'
|
||||||
@ -43,7 +45,6 @@ class Example(db.Model):
|
|||||||
|
|
||||||
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||||
title = db.Column(db.String(255), unique=True)
|
title = db.Column(db.String(255), unique=True)
|
||||||
|
|
||||||
\'\'\'
|
\'\'\'
|
||||||
|
|
||||||
from ..dependencies import db
|
from ..dependencies import db
|
||||||
|
@ -8,11 +8,11 @@ class Config:
|
|||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
SRC_DIR = BASE_DIR / "app"
|
SRC_DIR = BASE_DIR / "app"
|
||||||
EXCLUDED_DIRS = ["__pycache__", "commands"]
|
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
|
MAX_CONTENT_LENGTH = 10 * 1024 * 1024 # 10 MB
|
||||||
|
|
||||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
@ -20,8 +20,8 @@ class Config:
|
|||||||
LIMIT_STUDENTS_PER_GROUP = 5
|
LIMIT_STUDENTS_PER_GROUP = 5
|
||||||
LIMIT_MEMBERS_PER_COMMITTEE = 3
|
LIMIT_MEMBERS_PER_COMMITTEE = 3
|
||||||
|
|
||||||
DESCRIPTION = 'System PRI'
|
DESCRIPTION = "System PRI"
|
||||||
OPENAPI_VERSION = '3.0.2'
|
OPENAPI_VERSION = "3.0.2"
|
||||||
|
|
||||||
# Weights for project grade sheet
|
# Weights for project grade sheet
|
||||||
PRESENTATION_WEIGHT_FIRST_TERM = 1.5
|
PRESENTATION_WEIGHT_FIRST_TERM = 1.5
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
class CSVException(Exception):
|
class CSVException(Exception):
|
||||||
"""Main csv exception"""
|
"""Main csv exception"""
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidNameOrTypeHeaderException(CSVException):
|
class InvalidNameOrTypeHeaderException(CSVException):
|
||||||
"""Throw if csv file has invalid name or type of header"""
|
"""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 ...examination_schedule.models import ExaminationSchedule, TermOfDefence
|
||||||
|
from ...project_supervisor.models import ProjectSupervisor
|
||||||
from ...students.models import Group
|
from ...students.models import Group
|
||||||
|
|
||||||
|
|
||||||
def get_term_of_defence_by_id_and_examination_schedule_id(examination_schedule_id: int,
|
def get_term_of_defence_by_id_and_examination_schedule_id(
|
||||||
term_of_defence_id: int) -> ExaminationSchedule:
|
examination_schedule_id: int, term_of_defence_id: int
|
||||||
td = TermOfDefence.query.filter(TermOfDefence.id == term_of_defence_id,
|
) -> ExaminationSchedule:
|
||||||
TermOfDefence.examination_schedule_id == examination_schedule_id).first()
|
td = TermOfDefence.query.filter(
|
||||||
|
TermOfDefence.id == term_of_defence_id,
|
||||||
|
TermOfDefence.examination_schedule_id == examination_schedule_id,
|
||||||
|
).first()
|
||||||
if td is None:
|
if td is None:
|
||||||
abort(404, "Not found examination schedule or term of defence!")
|
abort(404, "Not found examination schedule or term of defence!")
|
||||||
return td
|
return td
|
||||||
@ -27,9 +37,12 @@ def check_the_group_has_assigned_to_term_of_defence(group_id: int) -> TermOfDefe
|
|||||||
return td
|
return td
|
||||||
|
|
||||||
|
|
||||||
def set_new_group_to_term_of_defence(examination_schedule_id: int, term_of_defence_id: int,
|
def set_new_group_to_term_of_defence(
|
||||||
group_id: int) -> TermOfDefence:
|
examination_schedule_id: int, term_of_defence_id: int, group_id: int
|
||||||
td = get_term_of_defence_by_id_and_examination_schedule_id(examination_schedule_id, term_of_defence_id)
|
) -> 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)
|
get_group_by_id(group_id)
|
||||||
check_the_group_has_assigned_to_term_of_defence(group_id)
|
check_the_group_has_assigned_to_term_of_defence(group_id)
|
||||||
td.group_id = 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:
|
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:
|
if ex is None:
|
||||||
abort(404, "Not found examination schedule!")
|
abort(404, "Not found examination schedule!")
|
||||||
return ex
|
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 flask import Blueprint
|
||||||
|
|
||||||
from .examination_schedule import bp as examination_schedule_bp
|
|
||||||
from .enrollments import bp as enrollments_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 .groups import bp as groups_bp
|
||||||
from .project_supervisor import bp as project_supervisor_bp
|
from .project_supervisor import bp as project_supervisor_bp
|
||||||
from .students import bp as students_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 .workloads import bp as workloads_bp
|
||||||
|
from .year_group import bp as year_group_bp
|
||||||
|
|
||||||
bp = Blueprint("coordinator", __name__, url_prefix="/coordinator")
|
bp = Blueprint("coordinator", __name__, url_prefix="/coordinator")
|
||||||
|
|
||||||
|
@ -1,68 +1,53 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from apiflask import APIBlueprint
|
from apiflask import APIBlueprint
|
||||||
from flask import abort, current_app
|
from flask import abort
|
||||||
from sqlalchemy import or_, and_
|
|
||||||
from flask_sqlalchemy import get_debug_queries
|
|
||||||
|
|
||||||
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 ...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 ..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 = APIBlueprint("enrollments", __name__, url_prefix="/enrollments")
|
||||||
|
|
||||||
|
|
||||||
@bp.post('/<int:examination_schedule_id>/add')
|
@bp.post("/<int:examination_schedule_id>/add")
|
||||||
@bp.input(TermOfDefenceSchema)
|
@bp.input(TermOfDefenceSchema)
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def create_term_of_defence(examination_schedule_id: int, data: dict) -> dict:
|
def create_term_of_defence(examination_schedule_id: int, data: dict) -> dict:
|
||||||
if not data:
|
chairman_of_committee_id = data.pop("chairman_of_committee")
|
||||||
abort(400, "You have passed empty data!")
|
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)
|
ex = get_examination_schedule_by_id(examination_schedule_id)
|
||||||
|
|
||||||
yg_id = ex.year_group_id
|
project_supervisors = get_and_check_the_project_supervisors_exists_in_db(
|
||||||
project_supervisors_ids = data.pop('project_supervisors')
|
ex.year_group_id, project_supervisors_ids
|
||||||
project_supervisors = ProjectSupervisor.query.filter(
|
)
|
||||||
or_(*[ProjectSupervisor.id == i for i in project_supervisors_ids])).filter(YearGroup.id == yg_id).all()
|
validate_enrollments_date(ex.start_date, ex.end_date, ex.duration_time, data)
|
||||||
|
check_the_term_of_defence_not_exists_in_chosen_date_range(
|
||||||
if len(project_supervisors) != len(project_supervisors_ids):
|
examination_schedule_id, data
|
||||||
abort(404, "Project Supervisors didn't exist!")
|
)
|
||||||
|
td = TermOfDefence(
|
||||||
start_date = data['start_date']
|
**data,
|
||||||
end_date = data['end_date']
|
examination_schedule_id=examination_schedule_id,
|
||||||
|
chairman_of_committee=chairman_of_committee_id
|
||||||
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)
|
|
||||||
db.session.add(td)
|
db.session.add(td)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
for p in project_supervisors:
|
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!"}
|
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.input(TermOfDefenceSchema)
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def create_many_term_of_defences(examination_schedule_id: int, data: dict) -> dict:
|
def create_many_term_of_defences(examination_schedule_id: int, data: dict) -> dict:
|
||||||
if not data:
|
chairman_of_committee_id = data.pop("chairman_of_committee")
|
||||||
abort(400, "You have passed empty data!")
|
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)
|
ex = get_examination_schedule_by_id(examination_schedule_id)
|
||||||
|
|
||||||
yg_id = ex.year_group_id
|
project_supervisors = get_and_check_the_project_supervisors_exists_in_db(
|
||||||
project_supervisors_ids = data.pop('project_supervisors')
|
ex.year_group_id, project_supervisors_ids
|
||||||
project_supervisors = ProjectSupervisor.query.filter(
|
)
|
||||||
or_(*[ProjectSupervisor.id == i for i in project_supervisors_ids])).filter(YearGroup.id == yg_id).all()
|
validate_enrollments_date(ex.start_date, ex.end_date, ex.duration_time, data)
|
||||||
|
check_the_term_of_defence_not_exists_in_chosen_date_range(
|
||||||
if len(project_supervisors) != len(project_supervisors_ids):
|
examination_schedule_id, data
|
||||||
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!")
|
|
||||||
|
|
||||||
# create many here
|
# 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)
|
dates = generate_range_dates(start_date, end_date, ex.duration_time)
|
||||||
for start_date in dates:
|
for start_date in dates:
|
||||||
end_date = start_date + datetime.timedelta(minutes=ex.duration_time)
|
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
|
td.members_of_committee = project_supervisors
|
||||||
db.session.add(td)
|
db.session.add(td)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return {"message": "Term of defences was created!"}
|
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.input(TermOfDefenceSchema)
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def update_term_of_defence(examination_schedule_id: int, term_of_defence_id: int, data: dict) -> dict:
|
def update_term_of_defence(
|
||||||
if not data:
|
examination_schedule_id: int, term_of_defence_id: int, data: dict
|
||||||
abort(400, "You have passed empty data!")
|
) -> 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,
|
td_query = TermOfDefence.query.filter(
|
||||||
TermOfDefence.examination_schedule_id == examination_schedule_id)
|
TermOfDefence.id == term_of_defence_id,
|
||||||
|
TermOfDefence.examination_schedule_id == examination_schedule_id,
|
||||||
|
)
|
||||||
td = td_query.first()
|
td = td_query.first()
|
||||||
if td is None:
|
if td is None:
|
||||||
abort(404, "Not found term of defence!")
|
abort(404, "Not found term of defence!")
|
||||||
|
|
||||||
ex = td.examination_schedule
|
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):
|
project_supervisors = get_and_check_the_project_supervisors_exists_in_db(
|
||||||
abort(404, "Project Supervisors didn't exist!")
|
ex.year_group_id, project_supervisors_ids
|
||||||
|
)
|
||||||
start_date = data['start_date']
|
validate_enrollments_date(ex.start_date, ex.end_date, ex.duration_time, data)
|
||||||
end_date = data['end_date']
|
check_the_term_of_defence_not_exists_in_chosen_date_range(
|
||||||
if not (ex.start_date.timestamp() <= start_date.timestamp() and ex.end_date.timestamp() >= end_date.timestamp()):
|
examination_schedule_id, data
|
||||||
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!")
|
|
||||||
|
|
||||||
td_query.update(data)
|
td_query.update(data)
|
||||||
td.members_of_committee = []
|
td.members_of_committee = []
|
||||||
|
td.chairman_of_committee = chairman_of_committee_id
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
for p in project_supervisors:
|
for p in project_supervisors:
|
||||||
td.members_of_committee.append(p)
|
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!"}
|
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)
|
@bp.output(MessageSchema)
|
||||||
def delete_term_of_defence(examination_schedule_id: int, term_of_defence_id: int) -> dict:
|
def delete_term_of_defence(
|
||||||
td = get_term_of_defence_by_id_and_examination_schedule_id(examination_schedule_id, term_of_defence_id)
|
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.delete(td)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return {"message": "Term of defence was deleted!"}
|
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)
|
@bp.output(AssignedGroupToTermOfDefenceListSchema)
|
||||||
def list_of_term_of_defences(examination_schedule_id: int) -> dict:
|
def list_of_term_of_defences(examination_schedule_id: int) -> dict:
|
||||||
get_examination_schedule_by_id(examination_schedule_id)
|
get_examination_schedule_by_id(examination_schedule_id)
|
||||||
|
|
||||||
td = TermOfDefence.query. \
|
td = (
|
||||||
join(TermOfDefence.members_of_committee, isouter=True). \
|
TermOfDefence.query.join(TermOfDefence.members_of_committee, isouter=True)
|
||||||
filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
|
.filter(TermOfDefence.examination_schedule_id == examination_schedule_id)
|
||||||
all()
|
.all()
|
||||||
|
)
|
||||||
return {"term_of_defences": td}
|
return {"term_of_defences": td}
|
||||||
|
|
||||||
|
|
||||||
@bp.get('/<int:examination_schedule_id>/temporary-availabilities/')
|
@bp.get("/<int:examination_schedule_id>/temporary-availabilities/")
|
||||||
@bp.output(TemporaryAvailabilityListSchema)
|
@bp.output(TemporaryAvailabilityListSchema)
|
||||||
def list_of_temporary_availability(examination_schedule_id: int) -> dict:
|
def list_of_temporary_availability(examination_schedule_id: int) -> dict:
|
||||||
get_examination_schedule_by_id(examination_schedule_id)
|
get_examination_schedule_by_id(examination_schedule_id)
|
||||||
|
|
||||||
td = TemporaryAvailability.query. \
|
td = (
|
||||||
filter(TemporaryAvailability.examination_schedule_id == examination_schedule_id). \
|
TemporaryAvailability.query.filter(
|
||||||
join(TemporaryAvailability.project_supervisor). \
|
TemporaryAvailability.examination_schedule_id == examination_schedule_id
|
||||||
all()
|
)
|
||||||
|
.join(TemporaryAvailability.project_supervisor)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
return {"temporary_availabilities": td}
|
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)
|
@bp.output(AssignedGroupToTermOfDefenceListSchema)
|
||||||
def list_of_assigned_group_to_term_of_defences(examination_schedule_id: int) -> dict:
|
def list_of_assigned_group_to_term_of_defences(examination_schedule_id: int) -> dict:
|
||||||
get_examination_schedule_by_id(examination_schedule_id)
|
get_examination_schedule_by_id(examination_schedule_id)
|
||||||
|
|
||||||
td = TermOfDefence.query. \
|
td = (
|
||||||
join(TermOfDefence.members_of_committee, isouter=True). \
|
TermOfDefence.query.join(TermOfDefence.members_of_committee, isouter=True)
|
||||||
join(TermOfDefence.group). \
|
.join(TermOfDefence.group)
|
||||||
filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
|
.filter(TermOfDefence.examination_schedule_id == examination_schedule_id)
|
||||||
filter(TermOfDefence.group_id.isnot(None)). \
|
.filter(TermOfDefence.group_id.isnot(None))
|
||||||
all()
|
.all()
|
||||||
|
)
|
||||||
return {"term_of_defences": td}
|
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.input(GroupIdSchema)
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def add_group_to_term_of_defence(examination_schedule_id: int, term_of_defence_id: int, data: dict) -> dict:
|
def add_group_to_term_of_defence(
|
||||||
set_new_group_to_term_of_defence(examination_schedule_id, term_of_defence_id, data.get("group_id"))
|
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()
|
db.session.commit()
|
||||||
return {"message": "Group was added to term of defences!"}
|
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)
|
@bp.output(MessageSchema)
|
||||||
def delete_group_to_term_of_defence(examination_schedule_id: int, term_of_defence_id: int) -> dict:
|
def delete_group_to_term_of_defence(
|
||||||
td = get_term_of_defence_by_id_and_examination_schedule_id(examination_schedule_id, term_of_defence_id)
|
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
|
td.group_id = None
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return {"message": "Group was deleted from term of defences!"}
|
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.input(GroupIdSchema)
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def update_group_for_term_of_defence(examination_schedule_id: int, term_of_defence_id: int, data: dict) -> dict:
|
def update_group_for_term_of_defence(
|
||||||
set_new_group_to_term_of_defence(examination_schedule_id, term_of_defence_id, data.get("group_id"))
|
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()
|
db.session.commit()
|
||||||
return {"message": "Group for term of defence was updated!"}
|
return {"message": "Group for term of defence was updated!"}
|
||||||
|
@ -1,34 +1,40 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from apiflask import APIBlueprint
|
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.utils import paginate_models
|
||||||
from ...base.mode import ModeGroups
|
|
||||||
from ...dependencies import db
|
from ...dependencies import db
|
||||||
from ...examination_schedule.models import ExaminationSchedule, TermOfDefence
|
from ...examination_schedule.models import ExaminationSchedule, TermOfDefence
|
||||||
from ...students.models import Group, YearGroup
|
|
||||||
from ...project_supervisor.models import ProjectSupervisor
|
from ...project_supervisor.models import ProjectSupervisor
|
||||||
from ..schemas import ExaminationScheduleSchema, ExaminationScheduleUpdateSchema, \
|
from ...students.models import Group, YearGroup
|
||||||
ExaminationSchedulesQuerySchema, ExaminationSchedulesPaginationSchema
|
from ..query.enrollments import set_enrollments_mode
|
||||||
from ..utils import generate_examination_schedule_pdf_file
|
from ..schemas.examination_schedule import (
|
||||||
from ...base.schemas import MessageSchema
|
ExaminationScheduleSchema,
|
||||||
|
ExaminationSchedulesPaginationSchema,
|
||||||
|
ExaminationSchedulesQuerySchema,
|
||||||
|
)
|
||||||
|
from ..utils import generate_examination_schedule_pdf_file, get_duration_time
|
||||||
|
|
||||||
bp = APIBlueprint("examination_schedule", __name__, url_prefix="/examination_schedule")
|
bp = APIBlueprint("examination_schedule", __name__, url_prefix="/examination_schedule")
|
||||||
|
|
||||||
|
|
||||||
@bp.get('/<int:year_group_id>/')
|
@bp.get("/<int:year_group_id>/")
|
||||||
@bp.input(ExaminationSchedulesQuerySchema, location='query')
|
@bp.input(ExaminationSchedulesQuerySchema, location="query")
|
||||||
@bp.output(ExaminationSchedulesPaginationSchema)
|
@bp.output(ExaminationSchedulesPaginationSchema)
|
||||||
def list_examination_schedule(year_group_id: int, query: dict) -> dict:
|
def list_examination_schedule(year_group_id: int, query: dict) -> dict:
|
||||||
page = query.get('page')
|
page = query.get("page")
|
||||||
per_page = query.get('per_page')
|
per_page = query.get("per_page")
|
||||||
es_query = ExaminationSchedule.query.filter(ExaminationSchedule.year_group_id == year_group_id)
|
es_query = ExaminationSchedule.query.filter(
|
||||||
|
ExaminationSchedule.year_group_id == year_group_id
|
||||||
|
)
|
||||||
data = paginate_models(page, es_query, per_page)
|
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.input(ExaminationScheduleSchema)
|
||||||
@bp.output(MessageSchema, status_code=201)
|
@bp.output(MessageSchema, status_code=201)
|
||||||
def create_examination_schedule(year_group_id: int, data: dict) -> dict:
|
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:
|
if yg is None:
|
||||||
abort(404, "Year group doesn't exist!")
|
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!")
|
abort(400, "Invalid data! End date must be greater than start date!")
|
||||||
|
|
||||||
duration_time = None
|
duration_time = get_duration_time(yg.mode)
|
||||||
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
|
|
||||||
|
|
||||||
if duration_time is None:
|
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.add(examination_schedule)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return {"message": "Examination schedule was created!"}
|
return {"message": "Examination schedule was created!"}
|
||||||
|
|
||||||
|
|
||||||
@bp.put('/<int:id>/')
|
@bp.put("/<int:examination_schedule_id>/")
|
||||||
@bp.input(ExaminationScheduleSchema)
|
@bp.input(ExaminationScheduleSchema)
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def update_examination_schedule(id: int, data: dict) -> dict:
|
def update_examination_schedule(examination_schedule_id: int, data: dict) -> dict:
|
||||||
examination_schedule_query = db.session.query(ExaminationSchedule).filter(ExaminationSchedule.id == id)
|
examination_schedule_query = db.session.query(ExaminationSchedule).filter(
|
||||||
|
ExaminationSchedule.id == examination_schedule_id
|
||||||
|
)
|
||||||
examination_schedule = examination_schedule_query.first()
|
examination_schedule = examination_schedule_query.first()
|
||||||
|
|
||||||
if examination_schedule is None:
|
if examination_schedule is None:
|
||||||
@ -68,10 +73,14 @@ def update_examination_schedule(id: int, data: dict) -> dict:
|
|||||||
return {"message": "Examination schedule was updated!"}
|
return {"message": "Examination schedule was updated!"}
|
||||||
|
|
||||||
|
|
||||||
@bp.delete('/<int:id>/')
|
@bp.delete("/<int:examination_schedule_id>/")
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def delete_examination_schedule(id: int) -> dict:
|
def delete_examination_schedule(examination_schedule_id: int) -> dict:
|
||||||
examination_schedule = db.session.query(ExaminationSchedule).filter(ExaminationSchedule.id == id).first()
|
examination_schedule = (
|
||||||
|
db.session.query(ExaminationSchedule)
|
||||||
|
.filter(ExaminationSchedule.id == examination_schedule_id)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
if examination_schedule is None:
|
if examination_schedule is None:
|
||||||
abort(404, "Examination schedule doesn't exist!")
|
abort(404, "Examination schedule doesn't exist!")
|
||||||
db.session.delete(examination_schedule)
|
db.session.delete(examination_schedule)
|
||||||
@ -79,52 +88,56 @@ def delete_examination_schedule(id: int) -> dict:
|
|||||||
return {"message": "Examination schedule was deleted!"}
|
return {"message": "Examination schedule was deleted!"}
|
||||||
|
|
||||||
|
|
||||||
@bp.put('/<int:id>/date/')
|
@bp.put("/<int:examination_schedule_id>/open-enrollments/")
|
||||||
@bp.input(ExaminationScheduleUpdateSchema)
|
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def set_date_of_examination_schedule(id: int, data: dict) -> dict:
|
def open_enrollments(examination_schedule_id: int) -> dict:
|
||||||
examination_schedule_query = db.session.query(ExaminationSchedule).filter(ExaminationSchedule.id == id)
|
return set_enrollments_mode(examination_schedule_id, EnrollmentsMode.OPEN, "open")
|
||||||
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!"}
|
|
||||||
|
|
||||||
|
|
||||||
@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:
|
def download_examination_schedule(examination_schedule_id: int) -> Response:
|
||||||
examination_schedule = db.session.query(ExaminationSchedule). \
|
examination_schedule = (
|
||||||
filter(ExaminationSchedule.id == examination_schedule_id).first()
|
db.session.query(ExaminationSchedule)
|
||||||
|
.filter(ExaminationSchedule.id == examination_schedule_id)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
if examination_schedule is None:
|
if examination_schedule is None:
|
||||||
abort(404, "Examination schedule doesn't exist!")
|
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 = []
|
nested_term_of_defences = []
|
||||||
for d in distinct_dates:
|
for d in distinct_dates:
|
||||||
date_tmp = datetime.datetime.strptime(d[0], "%Y-%m-%d").date()
|
date_tmp = datetime.datetime.strptime(d[0], "%Y-%m-%d").date()
|
||||||
term_of_defences = db.session.query(TermOfDefence). \
|
term_of_defences = (
|
||||||
join(Group, isouter=True).join(ProjectSupervisor, isouter=True). \
|
db.session.query(TermOfDefence)
|
||||||
filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
|
.join(Group, isouter=True)
|
||||||
filter(TermOfDefence.group_id.isnot(None)). \
|
.join(ProjectSupervisor, isouter=True)
|
||||||
filter(db.func.Date(TermOfDefence.start_date) == date_tmp). \
|
.filter(TermOfDefence.examination_schedule_id == examination_schedule_id)
|
||||||
all()
|
.filter(TermOfDefence.group_id.isnot(None))
|
||||||
|
.filter(db.func.Date(TermOfDefence.start_date) == date_tmp)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
if len(term_of_defences) > 0:
|
if len(term_of_defences) > 0:
|
||||||
nested_term_of_defences.append(term_of_defences)
|
nested_term_of_defences.append(term_of_defences)
|
||||||
# print(nested_term_of_defences)
|
# print(nested_term_of_defences)
|
||||||
base_dir = current_app.config.get('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)
|
pdf = generate_examination_schedule_pdf_file(
|
||||||
|
examination_schedule.title, nested_term_of_defences, base_dir
|
||||||
|
)
|
||||||
title = examination_schedule.title.replace("-", "_").split()
|
title = examination_schedule.title.replace("-", "_").split()
|
||||||
filename = "_".join(title)
|
filename = "_".join(title)
|
||||||
|
|
||||||
response = make_response(pdf)
|
response = make_response(pdf)
|
||||||
response.headers['Content-Type'] = 'application/pdf'
|
response.headers["Content-Type"] = "application/pdf"
|
||||||
response.headers['Content-Disposition'] = 'attachment; filename=%s.pdf' % filename
|
response.headers["Content-Disposition"] = "attachment; filename=%s.pdf" % filename
|
||||||
return response
|
return response
|
||||||
|
@ -1,61 +1,72 @@
|
|||||||
from flask import abort
|
|
||||||
from apiflask import APIBlueprint
|
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.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
|
from ..utils import attach_points_for_first_and_second_term_to_group_models
|
||||||
|
|
||||||
bp = APIBlueprint("groups", __name__, url_prefix="/groups")
|
bp = APIBlueprint("groups", __name__, url_prefix="/groups")
|
||||||
|
|
||||||
|
|
||||||
@bp.get("/<int:year_group_id>/")
|
@bp.get("/<int:year_group_id>/")
|
||||||
@bp.input(GroupQuerySchema, location='query')
|
@bp.input(GroupQuerySchema, location="query")
|
||||||
@bp.output(GroupsPaginationSchema)
|
@bp.output(GroupsPaginationSchema)
|
||||||
def list_groups(year_group_id: int, query: dict) -> dict:
|
def list_groups(year_group_id: int, query: dict) -> dict:
|
||||||
search_name = query.get('name')
|
search_name = query.get("name")
|
||||||
page = query.get('page')
|
page = query.get("page")
|
||||||
per_page = query.get('per_page')
|
per_page = query.get("per_page")
|
||||||
|
|
||||||
groups_query = Group.search_by_name(year_group_id, search_name)
|
groups_query = Group.search_by_name(year_group_id, search_name)
|
||||||
data = paginate_models(page, groups_query, per_page)
|
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)
|
attach_points_for_first_and_second_term_to_group_models(items)
|
||||||
|
|
||||||
return {
|
return {"groups": items, "max_pages": data["max_pages"]}
|
||||||
"groups": items,
|
|
||||||
"max_pages": data['max_pages']
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@bp.post("/<int:year_group_id>/")
|
@bp.post("/<int:year_group_id>/")
|
||||||
@bp.input(GroupCreateSchema)
|
@bp.input(GroupCreateSchema)
|
||||||
@bp.output(MessageSchema, status_code=201)
|
@bp.output(MessageSchema, status_code=201)
|
||||||
def create_group(year_group_id: int, data: dict) -> dict:
|
def create_group(year_group_id: int, data: dict) -> dict:
|
||||||
name = data['name']
|
name = data["name"]
|
||||||
students_ids = data['students']
|
students_ids = data["students"]
|
||||||
project_supervisor_id = data['project_supervisor_id']
|
project_supervisor_id = data["project_supervisor_id"]
|
||||||
|
|
||||||
yg = YearGroup.query.filter(YearGroup.id == year_group_id).first()
|
yg = YearGroup.query.filter(YearGroup.id == year_group_id).first()
|
||||||
if yg is None:
|
if yg is None:
|
||||||
abort(404, "Not found year group!")
|
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:
|
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). \
|
students_without_groups = (
|
||||||
join(Group, Student.groups). \
|
db.session.query(Student, Group)
|
||||||
filter(Group.year_group_id == year_group_id). \
|
.join(Group, Student.groups)
|
||||||
filter(db.or_(*[Student.id == st_id for st_id in students_ids])).all()
|
.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:
|
if len(students_without_groups) > 0:
|
||||||
abort(400, "One or more students have already belonged to group!")
|
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:
|
def detail_group(group_id: int) -> Group:
|
||||||
group = Group.query.filter_by(id=group_id).first()
|
group = Group.query.filter_by(id=group_id).first()
|
||||||
if group is None:
|
if group is None:
|
||||||
abort(404, f"Not found group!")
|
abort(404, "Not found group!")
|
||||||
return group
|
return group
|
||||||
|
|
||||||
|
|
||||||
@ -90,7 +101,7 @@ def detail_group(group_id: int) -> Group:
|
|||||||
def delete_group(group_id: int) -> dict:
|
def delete_group(group_id: int) -> dict:
|
||||||
group = Group.query.filter_by(id=group_id).first()
|
group = Group.query.filter_by(id=group_id).first()
|
||||||
if group is None:
|
if group is None:
|
||||||
abort(404, f"Not found group!")
|
abort(404, "Not found group!")
|
||||||
|
|
||||||
group.students = []
|
group.students = []
|
||||||
db.session.delete(group)
|
db.session.delete(group)
|
||||||
@ -103,29 +114,31 @@ def delete_group(group_id: int) -> dict:
|
|||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def edit_group(group_id: int, data: dict) -> dict:
|
def edit_group(group_id: int, data: dict) -> dict:
|
||||||
if not data:
|
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_query = Group.query.filter_by(id=group_id)
|
||||||
group = group_query.first()
|
group = group_query.first()
|
||||||
|
|
||||||
if group is None:
|
if group is None:
|
||||||
abort(404, f"Not found group!")
|
abort(404, "Not found group!")
|
||||||
|
|
||||||
students_ids = data.get('students')
|
students_ids = data.get("students")
|
||||||
name = data.get('name')
|
name = data.get("name")
|
||||||
project_supervisor_id = data.get('project_supervisor_id')
|
project_supervisor_id = data.get("project_supervisor_id")
|
||||||
|
|
||||||
if students_ids is not None:
|
if students_ids is not None:
|
||||||
students = db.session.query(Student).filter(Student.id.in_(students_ids)).all()
|
students = db.session.query(Student).filter(Student.id.in_(students_ids)).all()
|
||||||
if len(students_ids) != len(students):
|
if len(students_ids) != len(students):
|
||||||
abort(404, 'Not found students!')
|
abort(404, "Not found students!")
|
||||||
group.students = students
|
group.students = students
|
||||||
|
|
||||||
if name is not None:
|
if name is not None:
|
||||||
group.name = name
|
group.name = name
|
||||||
|
|
||||||
if project_supervisor_id is not None:
|
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:
|
if ps is None:
|
||||||
abort(404, "Not found project supervisor!")
|
abort(404, "Not found project supervisor!")
|
||||||
group.project_supervisor_id = project_supervisor_id
|
group.project_supervisor_id = project_supervisor_id
|
||||||
|
@ -1,37 +1,40 @@
|
|||||||
from flask import abort
|
|
||||||
from apiflask import APIBlueprint
|
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 ...project_supervisor.models import ProjectSupervisor
|
||||||
from ...students.models import Group, YearGroup
|
from ...students.models import Group, YearGroup
|
||||||
from ..schemas import ProjectSupervisorSchema, ProjectSupervisorEditSchema, ProjectSupervisorsPaginationSchema, \
|
from ..schemas.project_supervisor import (
|
||||||
ProjectSupervisorCreateSchema, MessageWithIdSchema, ProjectSupervisorQuerySchema
|
ProjectSupervisorCreateSchema,
|
||||||
from ...base.schemas import MessageSchema
|
ProjectSupervisorEditSchema,
|
||||||
from ...dependencies import db
|
ProjectSupervisorQuerySchema,
|
||||||
from ...base.utils import paginate_models
|
ProjectSupervisorSchema,
|
||||||
|
ProjectSupervisorsPaginationSchema,
|
||||||
|
)
|
||||||
|
from ..schemas.students import MessageWithIdSchema
|
||||||
|
|
||||||
bp = APIBlueprint("project_supervisor", __name__, url_prefix="/project_supervisor")
|
bp = APIBlueprint("project_supervisor", __name__, url_prefix="/project_supervisor")
|
||||||
|
|
||||||
|
|
||||||
@bp.get("/<int:year_group_id>/")
|
@bp.get("/<int:year_group_id>/")
|
||||||
@bp.input(ProjectSupervisorQuerySchema, location='query')
|
@bp.input(ProjectSupervisorQuerySchema, location="query")
|
||||||
@bp.output(ProjectSupervisorsPaginationSchema)
|
@bp.output(ProjectSupervisorsPaginationSchema)
|
||||||
def list_project_supervisors(year_group_id: int, query: dict) -> dict:
|
def list_project_supervisors(year_group_id: int, query: dict) -> dict:
|
||||||
fullname = query.get('fullname')
|
fullname = query.get("fullname")
|
||||||
order_by_first_name = query.get('order_by_first_name')
|
order_by_first_name = query.get("order_by_first_name")
|
||||||
order_by_last_name = query.get('order_by_last_name')
|
order_by_last_name = query.get("order_by_last_name")
|
||||||
page = query.get('page')
|
page = query.get("page")
|
||||||
per_page = query.get('per_page')
|
per_page = query.get("per_page")
|
||||||
|
|
||||||
project_supervisor_query = ProjectSupervisor.search_by_fullname_and_mode_and_order_by_first_name_or_last_name(
|
project_supervisor_query = ProjectSupervisor.search_by_fullname(
|
||||||
year_group_id, fullname, order_by_first_name, order_by_last_name)
|
year_group_id, fullname, order_by_first_name, order_by_last_name
|
||||||
|
)
|
||||||
|
|
||||||
data = paginate_models(page, project_supervisor_query, per_page)
|
data = paginate_models(page, project_supervisor_query, per_page)
|
||||||
# print(get_debug_queries()[0])
|
# print(get_debug_queries()[0])
|
||||||
return {
|
return {"project_supervisors": data["items"], "max_pages": data["max_pages"]}
|
||||||
"project_supervisors": data['items'],
|
|
||||||
"max_pages": data['max_pages']
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@bp.post("/<int:year_group_id>/")
|
@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:
|
if year_group is None:
|
||||||
abort(404, "Not found year group!")
|
abort(404, "Not found year group!")
|
||||||
|
|
||||||
email = data['email']
|
email = data["email"]
|
||||||
project_supervisor = ProjectSupervisor.query.filter(ProjectSupervisor.email == email).first()
|
project_supervisor = ProjectSupervisor.query.filter(
|
||||||
|
ProjectSupervisor.email == email,
|
||||||
|
ProjectSupervisor.year_group_id == year_group_id,
|
||||||
|
).first()
|
||||||
if project_supervisor is not None:
|
if project_supervisor is not None:
|
||||||
abort(400, "Project Supervisor has already exists!")
|
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.get("/<int:project_supervisor_id>/detail/")
|
||||||
@bp.output(ProjectSupervisorSchema)
|
@bp.output(ProjectSupervisorSchema)
|
||||||
def detail_project_supervisor(project_supervisor_id: int) -> ProjectSupervisor:
|
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:
|
if project_supervisor is None:
|
||||||
abort(404, 'Not found project supervisor!')
|
abort(404, "Not found project supervisor!")
|
||||||
return project_supervisor
|
return project_supervisor
|
||||||
|
|
||||||
|
|
||||||
@bp.delete("/<int:project_supervisor_id>/")
|
@bp.delete("/<int:project_supervisor_id>/")
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def delete_project_supervisor(project_supervisor_id: int) -> dict:
|
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:
|
if project_supervisor is None:
|
||||||
abort(404, "Not found project supervisor!")
|
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:
|
if count_groups > 0:
|
||||||
abort(400, "Project Supervisor has at least one group!")
|
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)
|
@bp.output(MessageSchema)
|
||||||
def edit_project_supervisor(project_supervisor_id: int, data: dict) -> dict:
|
def edit_project_supervisor(project_supervisor_id: int, data: dict) -> dict:
|
||||||
if not data:
|
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()
|
project_supervisor = project_supervisor_query.first()
|
||||||
|
|
||||||
if project_supervisor is None:
|
if project_supervisor is None:
|
||||||
abort(404, f"Not found project supervisor!")
|
abort(404, "Not found project supervisor!")
|
||||||
|
|
||||||
project_supervisor_query.update(data)
|
project_supervisor_query.update(data)
|
||||||
db.session.commit()
|
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:
|
if year_group is None:
|
||||||
abort(404, "Not found year group!")
|
abort(404, "Not found year group!")
|
||||||
|
|
||||||
last_year_group = YearGroup.query.filter(YearGroup.mode == year_group.mode). \
|
last_year_group = (
|
||||||
filter(YearGroup.id != year_group_id).filter(YearGroup.created_at < year_group.created_at). \
|
YearGroup.query.filter(YearGroup.mode == year_group.mode)
|
||||||
order_by(db.desc(YearGroup.created_at)).first()
|
.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:
|
if last_year_group is None:
|
||||||
abort(400, "The latest year group doesn't exist!")
|
abort(400, "The latest year group doesn't exist!")
|
||||||
|
|
||||||
project_supervisors = ProjectSupervisor.query.filter(ProjectSupervisor.year_group_id == last_year_group.id).all()
|
project_supervisors = ProjectSupervisor.query.filter(
|
||||||
current_project_supervisors_email_in_new_year_group = [ps.email for ps in ProjectSupervisor.query.filter(
|
ProjectSupervisor.year_group_id == last_year_group.id
|
||||||
ProjectSupervisor.year_group_id == year_group_id).all()]
|
).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:
|
for ps in project_supervisors:
|
||||||
if ps.email not in current_project_supervisors_email_in_new_year_group:
|
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,
|
new_ps = ProjectSupervisor(
|
||||||
limit_group=ps.limit_group, year_group_id=year_group_id)
|
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.add(new_ps)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
@ -1,44 +1,51 @@
|
|||||||
from random import randint
|
|
||||||
from itertools import islice
|
from itertools import islice
|
||||||
|
from random import randint
|
||||||
|
|
||||||
from flask import Response, abort
|
|
||||||
from apiflask import APIBlueprint
|
from apiflask import APIBlueprint
|
||||||
|
from flask import Response, abort
|
||||||
from sqlalchemy import or_
|
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.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 = APIBlueprint("students", __name__, url_prefix="/students")
|
||||||
|
|
||||||
|
|
||||||
@bp.get("/<int:year_group_id>/")
|
@bp.get("/<int:year_group_id>/")
|
||||||
@bp.input(StudentQuerySchema, location='query')
|
@bp.input(StudentQuerySchema, location="query")
|
||||||
@bp.output(StudentsPaginationSchema)
|
@bp.output(StudentsPaginationSchema)
|
||||||
def list_students(year_group_id: int, query: dict) -> dict:
|
def list_students(year_group_id: int, query: dict) -> dict:
|
||||||
# add filter by year group
|
# add filter by year group
|
||||||
fullname = query.get('fullname')
|
fullname = query.get("fullname")
|
||||||
order_by_first_name = query.get('order_by_first_name')
|
order_by_first_name = query.get("order_by_first_name")
|
||||||
order_by_last_name = query.get('order_by_last_name')
|
order_by_last_name = query.get("order_by_last_name")
|
||||||
page = query.get('page')
|
page = query.get("page")
|
||||||
per_page = query.get('per_page')
|
per_page = query.get("per_page")
|
||||||
|
|
||||||
student_query = Student.search_by_fullname_and_mode_and_order_by_first_name_or_last_name(
|
student_query = (
|
||||||
year_group_id, fullname, order_by_first_name, order_by_last_name)
|
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)
|
data = paginate_models(page, student_query, per_page)
|
||||||
# print(get_debug_queries()[0])
|
# print(get_debug_queries()[0])
|
||||||
return {
|
return {"students": data["items"], "max_pages": data["max_pages"]}
|
||||||
"students": data['items'],
|
|
||||||
"max_pages": data['max_pages']
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@bp.get("/<int:student_id>/detail/")
|
@bp.get("/<int:student_id>/detail/")
|
||||||
@ -66,13 +73,13 @@ def delete_student(student_id: int) -> dict:
|
|||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def edit_student(student_id: int, data: dict) -> dict:
|
def edit_student(student_id: int, data: dict) -> dict:
|
||||||
if not data:
|
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()
|
student = student_query.first()
|
||||||
|
|
||||||
if student is None:
|
if student is None:
|
||||||
abort(404, 'Not found student!')
|
abort(404, "Not found student!")
|
||||||
|
|
||||||
student_query.update(data)
|
student_query.update(data)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@ -84,20 +91,21 @@ def edit_student(student_id: int, data: dict) -> dict:
|
|||||||
@bp.input(StudentCreateSchema)
|
@bp.input(StudentCreateSchema)
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def create_student(data: dict) -> dict:
|
def create_student(data: dict) -> dict:
|
||||||
index = data['index']
|
index = data["index"]
|
||||||
yg_id = data['year_group_id']
|
yg_id = data["year_group_id"]
|
||||||
del 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:
|
if student is not None:
|
||||||
abort(400, "Student has already assigned to this year group!")
|
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()
|
year_group = YearGroup.query.filter(YearGroup.id == yg_id).first()
|
||||||
if year_group is None:
|
if year_group is None:
|
||||||
abort(404, "Not found year group!")
|
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)
|
student = Student(**data, email=dummy_email, year_group_id=yg_id)
|
||||||
db.session.add(student)
|
db.session.add(student)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@ -106,18 +114,18 @@ def create_student(data: dict) -> dict:
|
|||||||
|
|
||||||
|
|
||||||
@bp.post("/upload/")
|
@bp.post("/upload/")
|
||||||
@bp.input(YearGroupInfoQuery, location='query')
|
@bp.input(YearGroupInfoQuery, location="query")
|
||||||
@bp.input(FileSchema, location='form_and_files')
|
@bp.input(FileSchema, location="form_and_files")
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def upload_students(query: dict, file: dict) -> dict:
|
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,
|
"""Add only Students to chosen year group if students exist in db and
|
||||||
they will be omitted"""
|
assigned to correct year group, they will be omitted"""
|
||||||
year_group_id = query.get('year_group_id')
|
year_group_id = query.get("year_group_id")
|
||||||
yg = YearGroup.query.filter(YearGroup.id == year_group_id).first()
|
yg = YearGroup.query.filter(YearGroup.id == year_group_id).first()
|
||||||
if yg is None:
|
if yg is None:
|
||||||
abort(404, "Not found year group!")
|
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):
|
if uploaded_file and is_allowed_extensions(uploaded_file.filename):
|
||||||
try:
|
try:
|
||||||
students = parse_csv(uploaded_file, year_group_id)
|
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:
|
if len(list_of_students) == 0:
|
||||||
break
|
break
|
||||||
|
|
||||||
students_in_db = Student.query.filter(or_(Student.index == s.index for s in list_of_students)).\
|
students_in_db = (
|
||||||
filter(Student.year_group_id==year_group_id).all()
|
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]
|
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.add_all(students_not_exists_in_db)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
@ -144,17 +161,23 @@ def upload_students(query: dict, file: dict) -> dict:
|
|||||||
|
|
||||||
|
|
||||||
@bp.post("/download/")
|
@bp.post("/download/")
|
||||||
@bp.input(StudentListFileDownloaderSchema, location='query')
|
@bp.input(StudentListFileDownloaderSchema, location="query")
|
||||||
def download_students(query: dict) -> Response:
|
def download_students(query: dict) -> Response:
|
||||||
year_group_id = query.get('year_group_id')
|
year_group_id = query.get("year_group_id")
|
||||||
students_and_groups = db.session.query(Student, Group).join(Group, Student.groups). \
|
students_and_groups = (
|
||||||
filter(Group.year_group_id == year_group_id). \
|
db.session.query(Student, Group)
|
||||||
join(ProjectSupervisor).all()
|
.join(Group, Student.groups)
|
||||||
|
.filter(Group.year_group_id == year_group_id)
|
||||||
|
.join(ProjectSupervisor)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
if len(students_and_groups) == 0:
|
if len(students_and_groups) == 0:
|
||||||
abort(404, "Not found students!")
|
abort(404, "Not found students!")
|
||||||
|
|
||||||
csv_file = generate_csv(students_and_groups)
|
csv_file = generate_csv(students_and_groups)
|
||||||
response = Response(csv_file, mimetype='text/csv')
|
response = Response(csv_file, mimetype="text/csv")
|
||||||
response.headers.set("Content-Disposition", "attachment", filename="students_list.csv")
|
response.headers.set(
|
||||||
|
"Content-Disposition", "attachment", filename="students_list.csv"
|
||||||
|
)
|
||||||
return response
|
return response
|
||||||
|
@ -1,32 +1,38 @@
|
|||||||
from apiflask import APIBlueprint
|
from apiflask import APIBlueprint
|
||||||
from flask import abort
|
from flask import abort
|
||||||
from flask_sqlalchemy import get_debug_queries
|
|
||||||
|
|
||||||
from ...dependencies import db
|
from ...dependencies import db
|
||||||
from ...examination_schedule.models import ExaminationSchedule, TermOfDefence
|
from ...examination_schedule.models import ExaminationSchedule, TermOfDefence
|
||||||
from ...project_supervisor.models import ProjectSupervisor
|
from ...project_supervisor.models import ProjectSupervisor
|
||||||
from ..schemas import WorkloadSchema
|
from ..schemas.examination_schedule import WorkloadSchema
|
||||||
|
|
||||||
bp = APIBlueprint("workloads", __name__, url_prefix="/")
|
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)
|
@bp.output(WorkloadSchema)
|
||||||
def workloads_statistics(examination_schedule_id: int) -> dict:
|
def workloads_statistics(examination_schedule_id: int) -> dict:
|
||||||
es = ExaminationSchedule.query.filter_by(id=examination_schedule_id).first()
|
es = ExaminationSchedule.query.filter_by(id=examination_schedule_id).first()
|
||||||
if es is None:
|
if es is None:
|
||||||
abort(404, "Not found examination schedule!")
|
abort(404, "Not found examination schedule!")
|
||||||
|
|
||||||
statistics = db.session.query(
|
statistics = (
|
||||||
|
db.session.query(
|
||||||
ProjectSupervisor.first_name + " " + ProjectSupervisor.last_name,
|
ProjectSupervisor.first_name + " " + ProjectSupervisor.last_name,
|
||||||
db.func.count(TermOfDefence.group_id),
|
db.func.count(TermOfDefence.group_id),
|
||||||
db.func.count(TermOfDefence.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)
|
workloads = (
|
||||||
# print(len(statistics))
|
{
|
||||||
# print(get_debug_queries())
|
"full_name": s[0],
|
||||||
workloads = ({"full_name": s[0], "groups_assigned_to_his_committee": s[1],
|
"groups_assigned_to_his_committee": s[1],
|
||||||
"assigned_to_committee": s[2]} for s in statistics)
|
"assigned_to_committee": s[2],
|
||||||
return {'workloads': workloads}
|
}
|
||||||
|
for s in statistics
|
||||||
|
)
|
||||||
|
return {"workloads": workloads}
|
||||||
|
@ -1,22 +1,28 @@
|
|||||||
from flask import abort
|
|
||||||
from apiflask import APIBlueprint
|
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.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 = APIBlueprint("year_group", __name__, url_prefix="/year-group")
|
||||||
|
|
||||||
|
|
||||||
@bp.post('/')
|
@bp.post("/")
|
||||||
@bp.input(YearGroupSchema)
|
@bp.input(YearGroupSchema)
|
||||||
@bp.output(MessageSchema, status_code=201)
|
@bp.output(MessageSchema, status_code=201)
|
||||||
def create_year_group(data: dict) -> dict:
|
def create_year_group(data: dict) -> dict:
|
||||||
name = data['name']
|
name = data["name"]
|
||||||
mode = data['mode']
|
mode = data["mode"]
|
||||||
year_group = YearGroup.query.filter(YearGroup.name == name, YearGroup.mode == mode).first()
|
year_group = YearGroup.query.filter(
|
||||||
|
YearGroup.name == name, YearGroup.mode == mode
|
||||||
|
).first()
|
||||||
if year_group is not None:
|
if year_group is not None:
|
||||||
abort(400, "Year group has already exists!")
|
abort(400, "Year group has already exists!")
|
||||||
|
|
||||||
@ -27,38 +33,37 @@ def create_year_group(data: dict) -> dict:
|
|||||||
return {"message": "Year group was created!"}
|
return {"message": "Year group was created!"}
|
||||||
|
|
||||||
|
|
||||||
@bp.get('/')
|
@bp.get("/")
|
||||||
@bp.input(YearGroupQuerySchema, location='query')
|
@bp.input(YearGroupQuerySchema, location="query")
|
||||||
@bp.output(YearGroupPaginationSchema)
|
@bp.output(YearGroupPaginationSchema)
|
||||||
def list_of_year_groups(query: dict) -> dict:
|
def list_of_year_groups(query: dict) -> dict:
|
||||||
page = query.get('page')
|
page = query.get("page")
|
||||||
per_page = query.get('per_page')
|
per_page = query.get("per_page")
|
||||||
|
|
||||||
year_group_query = YearGroup.query.order_by(db.desc(YearGroup.created_at))
|
year_group_query = YearGroup.query.order_by(db.desc(YearGroup.created_at))
|
||||||
data = paginate_models(page, year_group_query, per_page)
|
data = paginate_models(page, year_group_query, per_page)
|
||||||
|
|
||||||
return {
|
return {"year_groups": data["items"], "max_pages": data["max_pages"]}
|
||||||
"year_groups": data['items'],
|
|
||||||
"max_pages": data['max_pages']
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@bp.put('/<int:id>/')
|
@bp.put("/<int:id>/")
|
||||||
@bp.input(YearGroupSchema)
|
@bp.input(YearGroupSchema)
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def update_year_of_group(id: int, data: dict) -> dict:
|
def update_year_of_group(id: int, data: dict) -> dict:
|
||||||
if not data:
|
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_query = YearGroup.query.filter(YearGroup.id == id)
|
||||||
year_group = year_group_query.first()
|
year_group = year_group_query.first()
|
||||||
|
|
||||||
if year_group is None:
|
if year_group is None:
|
||||||
abort(404, 'Not found year group!')
|
abort(404, "Not found year group!")
|
||||||
|
|
||||||
name = data['name']
|
name = data["name"]
|
||||||
mode = data['mode']
|
mode = data["mode"]
|
||||||
year_group = YearGroup.query.filter(YearGroup.name == name, YearGroup.mode == mode, YearGroup.id != id).first()
|
year_group = YearGroup.query.filter(
|
||||||
|
YearGroup.name == name, YearGroup.mode == mode, YearGroup.id != id
|
||||||
|
).first()
|
||||||
if year_group is not None:
|
if year_group is not None:
|
||||||
abort(400, "Year group has already exists!")
|
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!"}
|
return {"message": "Year group was updated!"}
|
||||||
|
|
||||||
|
|
||||||
@bp.delete('/<int:id>/')
|
@bp.delete("/<int:id>/")
|
||||||
@bp.output(MessageSchema, status_code=202)
|
@bp.output(MessageSchema, status_code=202)
|
||||||
def delete_year_of_group(id: int) -> dict:
|
def delete_year_of_group(id: int) -> dict:
|
||||||
year_group = YearGroup.query.filter_by(id=id).first()
|
year_group = YearGroup.query.filter_by(id=id).first()
|
||||||
if year_group is None:
|
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.delete(year_group)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return {"message": "Year group was deleted!"}
|
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):
|
class TermOfDefenceSchema(Schema):
|
||||||
start_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
|
start_date = fields.DateTime(
|
||||||
end_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
|
validate=validate_datetime_greater_than_now, required=True
|
||||||
project_supervisors = fields.List(fields.Integer(required=True), validate=validate.Length(3, 3))
|
)
|
||||||
|
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):
|
class ProjectSupervisorForTermOfDefenceSchema(Schema):
|
||||||
@ -19,30 +26,35 @@ class TermOfDefenceItemSchema(Schema):
|
|||||||
id = fields.Integer()
|
id = fields.Integer()
|
||||||
start_date = fields.DateTime()
|
start_date = fields.DateTime()
|
||||||
end_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):
|
class TermOfDefenceListSchema(Schema):
|
||||||
term_of_defences = fields.List(fields.Nested(TermOfDefenceItemSchema))
|
term_of_defences = fields.List(fields.Nested(TermOfDefenceItemSchema))
|
||||||
|
|
||||||
|
|
||||||
class StudentDataItemSchema(Schema):
|
class StudentDataItemAssignedGroupSchema(Schema):
|
||||||
index = fields.Integer()
|
index = fields.Integer()
|
||||||
first_name = fields.Str()
|
first_name = fields.Str()
|
||||||
last_name = fields.Str()
|
last_name = fields.Str()
|
||||||
|
|
||||||
|
|
||||||
class GroupDataItemSchema(Schema):
|
class GroupDataItemAssignedGroupSchema(Schema):
|
||||||
name = fields.Str()
|
name = fields.Str()
|
||||||
students = fields.List(fields.Nested(StudentDataItemSchema))
|
students = fields.List(fields.Nested(StudentDataItemAssignedGroupSchema))
|
||||||
|
|
||||||
|
|
||||||
class AssignedGroupToTermOfDefenceItemSchema(TermOfDefenceItemSchema):
|
class AssignedGroupToTermOfDefenceDataItemSchema(TermOfDefenceItemSchema):
|
||||||
group = fields.Nested(GroupDataItemSchema)
|
group = fields.Nested(GroupDataItemAssignedGroupSchema)
|
||||||
|
|
||||||
|
|
||||||
class AssignedGroupToTermOfDefenceListSchema(Schema):
|
class AssignedGroupToTermOfDefenceListSchema(Schema):
|
||||||
term_of_defences = fields.List(fields.Nested(AssignedGroupToTermOfDefenceItemSchema))
|
term_of_defences = fields.List(
|
||||||
|
fields.Nested(AssignedGroupToTermOfDefenceDataItemSchema)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ProjectSupervisorForTemporaryAvailabilitySchema(Schema):
|
class ProjectSupervisorForTemporaryAvailabilitySchema(Schema):
|
||||||
@ -58,4 +70,6 @@ class TemporaryAvailabilityItemSchema(Schema):
|
|||||||
|
|
||||||
|
|
||||||
class TemporaryAvailabilityListSchema(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
|
from ..validators import validate_datetime_greater_than_now
|
||||||
|
|
||||||
|
|
||||||
class ExaminationScheduleSchema(Schema):
|
class ExaminationScheduleSchema(Schema):
|
||||||
title = fields.Str(validate=validate.Length(min=1, max=100), required=True)
|
title = fields.Str(validate=validate.Length(min=1, max=100), required=True)
|
||||||
start_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
|
start_date = fields.DateTime(
|
||||||
end_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
|
validate=validate_datetime_greater_than_now, required=True
|
||||||
|
)
|
||||||
|
end_date = fields.DateTime(
|
||||||
class ExaminationScheduleUpdateSchema(Schema):
|
validate=validate_datetime_greater_than_now, required=True
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
class ExaminationScheduleListItemSchema(Schema):
|
class ExaminationScheduleListItemSchema(Schema):
|
||||||
id = fields.Integer()
|
id = fields.Integer()
|
||||||
title = fields.Str()
|
title = fields.Str()
|
||||||
|
open_enrollments = fields.String()
|
||||||
start_date = fields.DateTime()
|
start_date = fields.DateTime()
|
||||||
end_date = fields.DateTime()
|
end_date = fields.DateTime()
|
||||||
start_date_for_enrollment_students = fields.DateTime()
|
|
||||||
end_date_for_enrollment_students = fields.DateTime()
|
|
||||||
|
|
||||||
|
|
||||||
class ExaminationSchedulesPaginationSchema(Schema):
|
class ExaminationSchedulesPaginationSchema(Schema):
|
||||||
examination_schedules = fields.List(fields.Nested(ExaminationScheduleListItemSchema))
|
examination_schedules = fields.List(
|
||||||
|
fields.Nested(ExaminationScheduleListItemSchema)
|
||||||
|
)
|
||||||
max_pages = fields.Integer()
|
max_pages = fields.Integer()
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
from marshmallow import Schema, fields, validate
|
from marshmallow import Schema, fields, validate
|
||||||
|
|
||||||
from ..validators import validate_index
|
|
||||||
from .students import GroupSchema
|
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):
|
class ProjectSupervisorQuerySchema(Schema):
|
||||||
@ -19,7 +25,9 @@ class ProjectSupervisorsPaginationSchema(Schema):
|
|||||||
class ProjectSupervisorCreateSchema(Schema):
|
class ProjectSupervisorCreateSchema(Schema):
|
||||||
first_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
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)
|
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)
|
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 ...dependencies import ma
|
||||||
from ...students.models import Student, Group
|
from ...students.models import Group, Student
|
||||||
from ...project_supervisor.models import ProjectSupervisor
|
|
||||||
from ..validators import validate_index
|
from ..validators import validate_index
|
||||||
|
from .project_supervisor import ProjectSupervisorSchema
|
||||||
|
|
||||||
class ProjectSupervisorSchema(ma.SQLAlchemyAutoSchema):
|
|
||||||
class Meta:
|
|
||||||
model = ProjectSupervisor
|
|
||||||
include_relationships = False
|
|
||||||
|
|
||||||
|
|
||||||
class GroupSchema(ma.SQLAlchemyAutoSchema):
|
class GroupSchema(ma.SQLAlchemyAutoSchema):
|
||||||
@ -45,7 +39,6 @@ class StudentCreateSchema(ma.Schema):
|
|||||||
class StudentEditSchema(ma.Schema):
|
class StudentEditSchema(ma.Schema):
|
||||||
first_name = fields.Str(validate=validate.Length(min=1, max=255))
|
first_name = fields.Str(validate=validate.Length(min=1, max=255))
|
||||||
last_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)
|
index = fields.Integer(validate=validate_index)
|
||||||
|
|
||||||
|
|
||||||
@ -55,7 +48,7 @@ class MessageWithIdSchema(ma.Schema):
|
|||||||
|
|
||||||
|
|
||||||
class FileSchema(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):
|
class StudentQuerySchema(ma.Schema):
|
||||||
@ -69,8 +62,12 @@ class StudentQuerySchema(ma.Schema):
|
|||||||
class YearGroupInfoQuery(Schema):
|
class YearGroupInfoQuery(Schema):
|
||||||
year_group_id = fields.Integer(required=True)
|
year_group_id = fields.Integer(required=True)
|
||||||
|
|
||||||
|
|
||||||
class DetailGroupSchema(ma.SQLAlchemyAutoSchema):
|
class DetailGroupSchema(ma.SQLAlchemyAutoSchema):
|
||||||
project_supervisor = fields.Nested(ProjectSupervisorSchema)
|
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:
|
class Meta:
|
||||||
model = Group
|
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
|
from ...base.mode import ModeGroups
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ def validate_mode(value: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
class YearGroupSchema(Schema):
|
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)
|
mode = fields.Str(validate=validate_mode, required=True)
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,54 +3,85 @@ import json
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import Generator, Union, Any, List, Tuple, TextIO
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any, Generator, List, TextIO, Tuple, Union
|
||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from reportlab.lib import colors
|
from reportlab.lib import colors
|
||||||
from reportlab.lib.enums import TA_CENTER
|
from reportlab.lib.enums import TA_CENTER
|
||||||
from reportlab.lib.styles import getSampleStyleSheet
|
from reportlab.lib.styles import getSampleStyleSheet
|
||||||
from reportlab.lib.units import mm, inch
|
from reportlab.lib.units import inch, mm
|
||||||
from reportlab.platypus import SimpleDocTemplate, Paragraph, PageBreak, Table
|
|
||||||
from reportlab.pdfbase import pdfmetrics
|
from reportlab.pdfbase import pdfmetrics
|
||||||
from reportlab.pdfbase.ttfonts import TTFont
|
from reportlab.pdfbase.ttfonts import TTFont
|
||||||
|
from reportlab.platypus import PageBreak, Paragraph, SimpleDocTemplate, Table
|
||||||
from werkzeug.datastructures import FileStorage
|
from werkzeug.datastructures import FileStorage
|
||||||
|
|
||||||
from .exceptions import InvalidNameOrTypeHeaderException
|
from ..base.mode import ModeGroups
|
||||||
from ..students.models import Student, Group, ProjectGradeSheet
|
|
||||||
from ..examination_schedule.models import TermOfDefence
|
from ..examination_schedule.models import TermOfDefence
|
||||||
|
from ..students.models import Group, ProjectGradeSheet, Student
|
||||||
|
from .exceptions import InvalidNameOrTypeHeaderException
|
||||||
|
|
||||||
|
|
||||||
def check_columns(df: pd.DataFrame) -> bool:
|
def check_columns(df: pd.DataFrame) -> bool:
|
||||||
headers = set(df.keys().values)
|
headers = set(df.keys().values)
|
||||||
column_names = ['NAZWISKO', 'IMIE', 'INDEKS', 'EMAIL']
|
column_names = ["NAZWISKO", "IMIE", "INDEKS", "EMAIL"]
|
||||||
column_types = ['object', 'object', 'int', 'object']
|
column_types = ["object", "object", "int", "object"]
|
||||||
return all((column_name in headers for column_name in column_names)) and \
|
return all((column_name in headers for column_name in column_names)) and all(
|
||||||
all((str(df.dtypes[column_name]).startswith(column_type) for column_name, column_type in
|
(
|
||||||
zip(column_names, column_types)))
|
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)
|
df = pd.read_csv(file)
|
||||||
|
|
||||||
if not check_columns(df):
|
if not check_columns(df):
|
||||||
raise InvalidNameOrTypeHeaderException
|
raise InvalidNameOrTypeHeaderException
|
||||||
students = (Student(last_name=dict(item.items())['NAZWISKO'],
|
students = (
|
||||||
first_name=dict(item.items())['IMIE'],
|
Student(
|
||||||
index=dict(item.items())['INDEKS'],
|
last_name=dict(item.items())["NAZWISKO"],
|
||||||
email=dict(item.items())['EMAIL'],
|
first_name=dict(item.items())["IMIE"],
|
||||||
year_group_id=year_group_id)
|
index=dict(item.items())["INDEKS"],
|
||||||
for _, item in df.iterrows())
|
email=dict(item.items())["EMAIL"],
|
||||||
|
year_group_id=year_group_id,
|
||||||
|
)
|
||||||
|
for _, item in df.iterrows()
|
||||||
|
)
|
||||||
|
|
||||||
return students
|
return students
|
||||||
|
|
||||||
|
|
||||||
def generate_csv(students_and_groups: List[Tuple[Student, Group]]) -> str:
|
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']
|
headers = [
|
||||||
data = [(student.index, student.first_name, student.last_name, student.email,
|
"INDEKS",
|
||||||
group.cdyd_kod, group.prz_kod, group.tzaj_kod, group.project_supervisor_id,
|
"IMIE",
|
||||||
None) for student, group in students_and_groups]
|
"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)
|
dataframe = defaultdict(list)
|
||||||
for row in data:
|
for row in data:
|
||||||
for idx, item in enumerate(row):
|
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)
|
return df.to_csv(index=False)
|
||||||
|
|
||||||
|
|
||||||
def generate_range_dates(start_date: datetime, end_date: datetime, step_in_minutes: int) -> \
|
def generate_range_dates(
|
||||||
Generator[Union[datetime, timedelta], Any, None]:
|
start_date: datetime, end_date: datetime, step_in_minutes: int
|
||||||
|
) -> Generator[Union[datetime, timedelta], Any, None]:
|
||||||
current_date = copy.copy(start_date)
|
current_date = copy.copy(start_date)
|
||||||
while True:
|
while True:
|
||||||
next_date = current_date + timedelta(minutes=step_in_minutes)
|
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)
|
current_date = copy.copy(next_date)
|
||||||
|
|
||||||
|
|
||||||
def generate_examination_schedule_pdf_file(title: str, nested_term_of_defences: List[List[TermOfDefence]],
|
def generate_examination_schedule_pdf_file(
|
||||||
base_dir: Path) -> bytes:
|
title: str, nested_term_of_defences: List[List[TermOfDefence]], base_dir: Path
|
||||||
|
) -> bytes:
|
||||||
pagesize = (297 * mm, 210 * mm)
|
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()
|
pdf_buffer = BytesIO()
|
||||||
my_doc = SimpleDocTemplate(
|
my_doc = SimpleDocTemplate(
|
||||||
pdf_buffer,
|
pdf_buffer,
|
||||||
@ -84,13 +125,13 @@ def generate_examination_schedule_pdf_file(title: str, nested_term_of_defences:
|
|||||||
leftMargin=1 * inch,
|
leftMargin=1 * inch,
|
||||||
rightMargin=1 * inch,
|
rightMargin=1 * inch,
|
||||||
bottomMargin=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()
|
style = getSampleStyleSheet()
|
||||||
bodyText = style['BodyText']
|
bodyText = style["BodyText"]
|
||||||
bodyText.fontName = 'Lato'
|
bodyText.fontName = "Lato"
|
||||||
normal = style["Heading1"]
|
normal = style["Heading1"]
|
||||||
normal.alignment = TA_CENTER
|
normal.alignment = TA_CENTER
|
||||||
flowables = []
|
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:
|
for term_of_defences in nested_term_of_defences:
|
||||||
if len(term_of_defences) == 0:
|
if len(term_of_defences) == 0:
|
||||||
continue
|
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)
|
paragraph_1 = Paragraph(f"{title} ~ {date}", normal)
|
||||||
flowables.append(paragraph_1)
|
flowables.append(paragraph_1)
|
||||||
data = [headers]
|
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):
|
for idx, td in enumerate(term_of_defences, start=1):
|
||||||
new_date = td.start_date + timedelta(hours=2)
|
new_date = td.start_date + timedelta(hours=2)
|
||||||
group_name = td.group.name if td.group is not None else ""
|
group_name = td.group.name if td.group is not None else ""
|
||||||
if group_name != '':
|
if group_name != "":
|
||||||
ps = td.group.project_supervisor
|
ps = td.group.project_supervisor
|
||||||
project_supervisor_fullname = f"{ps.first_name[0]}. {ps.last_name}"
|
project_supervisor_fullname = f"{ps.first_name[0]}. {ps.last_name}"
|
||||||
students = td.group.students
|
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
|
members = td.members_of_committee
|
||||||
# print(members)
|
# print(members)
|
||||||
if len(members) == 0:
|
if len(members) == 0:
|
||||||
committee = ''
|
committee = ""
|
||||||
else:
|
else:
|
||||||
members_iter = (f"{m.first_name[0]} {m.last_name}" for m in members)
|
members_iter = (f"{m.first_name[0]} {m.last_name}" for m in members)
|
||||||
committee = ", ".join(members_iter)
|
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(group_name, bodyText),
|
||||||
Paragraph(project_supervisor_fullname, bodyText),
|
Paragraph(project_supervisor_fullname, bodyText),
|
||||||
Paragraph(team, bodyText),
|
Paragraph(team, bodyText),
|
||||||
Paragraph(committee, bodyText),
|
Paragraph(committee, bodyText),
|
||||||
])
|
]
|
||||||
|
)
|
||||||
# print(data)
|
# print(data)
|
||||||
|
|
||||||
table = Table(data=data,
|
table = Table(
|
||||||
|
data=data,
|
||||||
style=[
|
style=[
|
||||||
('GRID', (0, 0), (-1, -1), 0.5, colors.black),
|
("GRID", (0, 0), (-1, -1), 0.5, colors.black),
|
||||||
('BACKGROUND', (0, 0), (-1, 0), colors.HexColor("#A6F1A6")),
|
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#A6F1A6")),
|
||||||
('BACKGROUND', (0, 0), (1, -1), 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(table)
|
||||||
flowables.append(PageBreak())
|
flowables.append(PageBreak())
|
||||||
@ -150,8 +204,20 @@ def generate_examination_schedule_pdf_file(title: str, nested_term_of_defences:
|
|||||||
return pdf_value
|
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]:
|
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"
|
config_dir = base_dir / "config"
|
||||||
|
|
||||||
with open(config_dir / "weights_project_grade_sheet.json") as f:
|
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
|
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 = []
|
terms = []
|
||||||
for pgs in project_grade_sheets:
|
for pgs in project_grade_sheets:
|
||||||
if pgs is None:
|
if pgs is None:
|
||||||
@ -168,28 +236,30 @@ def calculate_points_for_one_term(weights: dict, project_grade_sheets: List[Proj
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
first_term_points = {
|
first_term_points = {
|
||||||
'nominator': 0,
|
"nominator": 0,
|
||||||
'denominator': 0,
|
"denominator": 0,
|
||||||
}
|
}
|
||||||
second_term_points = {
|
second_term_points = {
|
||||||
'nominator': 0,
|
"nominator": 0,
|
||||||
'denominator': 0,
|
"denominator": 0,
|
||||||
}
|
}
|
||||||
for weight_key, weight_value in weights.items():
|
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:
|
try:
|
||||||
attribute_value = getattr(pgs, weight_key)
|
attribute_value = getattr(pgs, weight_key)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
attribute_value = 0
|
attribute_value = 0
|
||||||
points['nominator'] += attribute_value * weight_value * 1 / 4
|
points["nominator"] += attribute_value * weight_value * 1 / 4
|
||||||
points['denominator'] += weight_value
|
points["denominator"] += weight_value
|
||||||
|
|
||||||
try:
|
try:
|
||||||
fp = first_term_points['nominator'] / first_term_points['denominator']
|
fp = first_term_points["nominator"] / first_term_points["denominator"]
|
||||||
except ZeroDivisionError:
|
except ZeroDivisionError:
|
||||||
fp = 0
|
fp = 0
|
||||||
try:
|
try:
|
||||||
sp = second_term_points['nominator'] / second_term_points['denominator']
|
sp = second_term_points["nominator"] / second_term_points["denominator"]
|
||||||
except ZeroDivisionError:
|
except ZeroDivisionError:
|
||||||
sp = 0
|
sp = 0
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
from flask_sqlalchemy import SQLAlchemy
|
|
||||||
from flask_marshmallow import Marshmallow
|
from flask_marshmallow import Marshmallow
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
|
||||||
ma = Marshmallow()
|
ma = Marshmallow()
|
||||||
|
|
||||||
|
@ -8,6 +8,6 @@ def register_error_handlers(app: APIFlask):
|
|||||||
@app.errorhandler(HTTPException)
|
@app.errorhandler(HTTPException)
|
||||||
def handle_http_exception(e):
|
def handle_http_exception(e):
|
||||||
response = e.get_response()
|
response = e.get_response()
|
||||||
response.data = json.dumps({'error': e.description})
|
response.data = json.dumps({"error": e.description})
|
||||||
response.content_type = 'application/json'
|
response.content_type = "application/json"
|
||||||
return response
|
return response
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
from ..dependencies import db
|
from ..base.mode import EnrollmentsMode
|
||||||
from ..base.models import Base
|
from ..base.models import Base
|
||||||
|
from ..dependencies import db
|
||||||
|
|
||||||
|
|
||||||
class ExaminationSchedule(Base):
|
class ExaminationSchedule(Base):
|
||||||
__tablename__ = 'examination_schedules'
|
__tablename__ = "examination_schedules"
|
||||||
|
|
||||||
title = db.Column(db.String(100), unique=True, nullable=False)
|
title = db.Column(db.String(100), unique=True, nullable=False)
|
||||||
duration_time = db.Column(db.Integer, nullable=False) # in minutes
|
duration_time = db.Column(db.Integer, nullable=False) # in minutes
|
||||||
start_date_for_enrollment_students = db.Column(db.DateTime)
|
open_enrollments = db.Column(
|
||||||
end_date_for_enrollment_students = db.Column(db.DateTime)
|
db.String(1), default=EnrollmentsMode.INIT.value, nullable=False
|
||||||
|
)
|
||||||
start_date = db.Column(db.DateTime, nullable=False)
|
start_date = db.Column(db.DateTime, nullable=False)
|
||||||
end_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_id = db.Column(
|
||||||
year_group = db.relationship('YearGroup', backref='examination_schedules')
|
db.Integer, db.ForeignKey("year_groups.id"), nullable=False
|
||||||
|
)
|
||||||
|
year_group = db.relationship("YearGroup", backref="examination_schedules")
|
||||||
|
|
||||||
|
|
||||||
committee = db.Table(
|
committee = db.Table(
|
||||||
@ -23,23 +27,42 @@ committee = db.Table(
|
|||||||
|
|
||||||
|
|
||||||
class TermOfDefence(Base):
|
class TermOfDefence(Base):
|
||||||
__tablename__ = 'term_of_defences'
|
__tablename__ = "term_of_defences"
|
||||||
|
|
||||||
start_date = db.Column(db.DateTime, nullable=False)
|
start_date = db.Column(db.DateTime, nullable=False)
|
||||||
end_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_id = db.Column(
|
||||||
examination_schedule = db.relationship('ExaminationSchedule', backref='term_of_defences')
|
db.Integer, db.ForeignKey("examination_schedules.id")
|
||||||
group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
|
)
|
||||||
group = db.relationship("Group", uselist=False, backref='term_of_defence', lazy='joined')
|
examination_schedule = db.relationship(
|
||||||
members_of_committee = db.relationship("ProjectSupervisor", secondary=committee, lazy='joined')
|
"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):
|
class TemporaryAvailability(Base):
|
||||||
__tablename__ = 'temporary_availabilities'
|
__tablename__ = "temporary_availabilities"
|
||||||
|
|
||||||
start_date = db.Column(db.DateTime, nullable=False)
|
start_date = db.Column(db.DateTime, nullable=False)
|
||||||
end_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_id = db.Column(
|
||||||
examination_schedule = db.relationship("ExaminationSchedule", backref='temporary_availabilities')
|
db.Integer, db.ForeignKey("examination_schedules.id"), nullable=False
|
||||||
project_supervisor_id = db.Column(db.Integer, db.ForeignKey('project_supervisors.id'), nullable=False)
|
)
|
||||||
project_supervisor = db.relationship("ProjectSupervisor", backref='temporary_availabilities')
|
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 flask_sqlalchemy import BaseQuery
|
||||||
|
|
||||||
from ..dependencies import db
|
from ..base.models import Base, Person
|
||||||
from ..base.models import Person, Base
|
|
||||||
from ..base.utils import order_by_column_name
|
from ..base.utils import order_by_column_name
|
||||||
|
from ..dependencies import db
|
||||||
from ..students.models import YearGroup
|
from ..students.models import YearGroup
|
||||||
|
|
||||||
|
|
||||||
@ -10,27 +10,41 @@ class ProjectSupervisor(Base, Person):
|
|||||||
__tablename__ = "project_supervisors"
|
__tablename__ = "project_supervisors"
|
||||||
|
|
||||||
limit_group = db.Column(db.Integer, default=3, nullable=False)
|
limit_group = db.Column(db.Integer, default=3, nullable=False)
|
||||||
year_group_id = db.Column(db.Integer, db.ForeignKey('year_groups.id'))
|
is_coordinator = db.Column(db.Boolean, default=False, nullable=False)
|
||||||
year_group = db.relationship('YearGroup', backref='project_supervisors')
|
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
|
@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,
|
fullname: str = None,
|
||||||
order_by_first_name: 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
|
project_supervisors_query = cls.query
|
||||||
|
|
||||||
if year_group_id is not None:
|
if year_group_id is not None:
|
||||||
project_supervisors_query = project_supervisors_query. \
|
project_supervisors_query = project_supervisors_query.filter(
|
||||||
filter(ProjectSupervisor.year_group_id == year_group_id)
|
ProjectSupervisor.year_group_id == year_group_id
|
||||||
|
)
|
||||||
|
|
||||||
if fullname is not None:
|
if fullname is not None:
|
||||||
project_supervisors_query = project_supervisors_query.filter(
|
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,
|
project_supervisors_query = order_by_column_name(
|
||||||
order_by_first_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.last_name, order_by_last_name
|
||||||
|
)
|
||||||
|
|
||||||
return project_supervisors_query
|
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 apiflask import APIBlueprint
|
||||||
from flask import abort
|
from flask import abort
|
||||||
from sqlalchemy import and_, or_
|
from sqlalchemy import and_, or_
|
||||||
from ..schemas import TimeAvailabilityCreateSchema, TemporaryProjectSupervisorSchema, \
|
|
||||||
ListOfFreeTimesSchema, ListOfTermOfDefenceSchema
|
from ...base.mode import EnrollmentsMode
|
||||||
from ...dependencies import db
|
|
||||||
from ..models import ProjectSupervisor
|
|
||||||
from ...examination_schedule.models import ExaminationSchedule, TemporaryAvailability, TermOfDefence
|
|
||||||
from ...base.schemas import MessageSchema
|
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 = APIBlueprint("enrollments", __name__, url_prefix="/")
|
||||||
|
|
||||||
|
|
||||||
@bp.post('/<int:examination_schedule_id>/enrollments/')
|
@bp.post("/<int:examination_schedule_id>/enrollments/")
|
||||||
@bp.input(TimeAvailabilityCreateSchema)
|
@bp.input(TimeAvailabilityCreateSchema)
|
||||||
@bp.output(MessageSchema)
|
@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
|
# 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:
|
if project_supervisor is None:
|
||||||
abort(404, "ProjectSupervisor doesn't exist!")
|
abort(404, "ProjectSupervisor doesn't exist!")
|
||||||
|
print(project_supervisor)
|
||||||
################
|
################
|
||||||
|
|
||||||
es = ExaminationSchedule.query.filter(ExaminationSchedule.id == examination_schedule_id).first()
|
examination_schedule = ExaminationSchedule.query.filter(
|
||||||
if es is None:
|
ExaminationSchedule.id == examination_schedule_id
|
||||||
|
).first()
|
||||||
|
if examination_schedule is None:
|
||||||
abort(404, "Examination schedule doesn't exist!")
|
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']
|
if examination_schedule.open_enrollments != EnrollmentsMode.INIT.value:
|
||||||
ed = data['end_date']
|
abort(400, "Enrollments has started or closed! You have been delayed!")
|
||||||
|
|
||||||
|
sd = data.get("start_date")
|
||||||
|
ed = data.get("end_date")
|
||||||
if sd > ed:
|
if sd > ed:
|
||||||
abort(400, "Invalid data! End date must be greater than start date!")
|
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()):
|
start_date = examination_schedule.start_date
|
||||||
abort(400, "Date range is not within the examination schedule!")
|
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()
|
ta = (
|
||||||
if es.start_date_for_enrollment_students is not None and \
|
TemporaryAvailability.query.filter(
|
||||||
es.start_date_for_enrollment_students.timestamp() < now.timestamp():
|
TemporaryAvailability.examination_schedule_id == examination_schedule_id
|
||||||
abort(403, "Enrollment has started! You cannot set your free time!")
|
)
|
||||||
|
.filter(TemporaryAvailability.project_supervisor_id == project_supervisor.id)
|
||||||
ta = TemporaryAvailability.query.filter(TemporaryAvailability.examination_schedule_id == examination_schedule_id). \
|
.filter(
|
||||||
filter(TemporaryAvailability.project_supervisor_id == project_supervisor.id). \
|
or_(
|
||||||
filter(or_(and_(TemporaryAvailability.start_date >= sd, TemporaryAvailability.start_date < ed,
|
and_(
|
||||||
TemporaryAvailability.end_date >= ed),
|
TemporaryAvailability.start_date >= sd,
|
||||||
and_(TemporaryAvailability.start_date <= sd, TemporaryAvailability.end_date > sd,
|
TemporaryAvailability.start_date < ed,
|
||||||
TemporaryAvailability.end_date <= ed))).first()
|
TemporaryAvailability.end_date >= ed,
|
||||||
|
),
|
||||||
|
and_(
|
||||||
|
TemporaryAvailability.start_date <= sd,
|
||||||
|
TemporaryAvailability.end_date > sd,
|
||||||
|
TemporaryAvailability.end_date <= ed,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
if ta is not None:
|
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)
|
ta = TemporaryAvailability(**data, examination_schedule_id=examination_schedule_id)
|
||||||
db.session.add(ta)
|
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!"}
|
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.input(TemporaryProjectSupervisorSchema)
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def delete_your_free_time_from_examination_schedule(examination_schedule_id: int, temporary_availability_id: int,
|
def delete_your_free_time_from_examination_schedule(
|
||||||
data: dict) -> dict:
|
examination_schedule_id: int, temporary_availability_id: int, data: dict
|
||||||
|
) -> dict:
|
||||||
# this code will be removed
|
# 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:
|
if project_supervisor is None:
|
||||||
abort(404, "ProjectSupervisor doesn't exist!")
|
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.project_supervisor_id == project_supervisor.id,
|
||||||
TemporaryAvailability.id == temporary_availability_id).first()
|
TemporaryAvailability.id == temporary_availability_id,
|
||||||
|
).first()
|
||||||
|
|
||||||
if ta is None:
|
if ta is None:
|
||||||
abort(404, "Your free time doesn't exist!")
|
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!"}
|
return {"message": "You have just removed your free time!"}
|
||||||
|
|
||||||
|
|
||||||
@bp.get('/<int:examination_schedule_id>/temporary-availabilities/')
|
@bp.get("/<int:examination_schedule_id>/temporary-availabilities/")
|
||||||
@bp.input(TemporaryProjectSupervisorSchema, location='query')
|
@bp.input(TemporaryProjectSupervisorSchema, location="query")
|
||||||
@bp.output(ListOfFreeTimesSchema)
|
@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
|
# 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:
|
if project_supervisor is None:
|
||||||
abort(404, "ProjectSupervisor doesn't exist!")
|
abort(404, "ProjectSupervisor doesn't exist!")
|
||||||
################
|
################
|
||||||
es = ExaminationSchedule.query.filter(ExaminationSchedule.id == examination_schedule_id,
|
examination_schedule = ExaminationSchedule.query.filter(
|
||||||
ExaminationSchedule.year_group_id).first()
|
ExaminationSchedule.id == examination_schedule_id
|
||||||
|
).first()
|
||||||
if es is None:
|
if examination_schedule is None:
|
||||||
abort(404, "Examination schedule doesn't exist!")
|
abort(404, "Examination schedule doesn't exist!")
|
||||||
|
|
||||||
now = datetime.utcnow()
|
if examination_schedule.open_enrollments != EnrollmentsMode.INIT.value:
|
||||||
start_date = es.start_date_for_enrollment_students
|
abort(400, "Enrollments has started or closed! You have been delayed!")
|
||||||
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!")
|
|
||||||
|
|
||||||
# list of your term of defences first enrollment
|
# list of your term of defences first enrollment
|
||||||
ta = TemporaryAvailability.query.filter(TemporaryAvailability.examination_schedule_id == examination_schedule_id,
|
ta = TemporaryAvailability.query.filter(
|
||||||
TemporaryAvailability.project_supervisor_id == project_supervisor.id).all()
|
TemporaryAvailability.examination_schedule_id == examination_schedule_id,
|
||||||
|
TemporaryAvailability.project_supervisor_id == project_supervisor.id,
|
||||||
|
).all()
|
||||||
return {"free_times": ta}
|
return {"free_times": ta}
|
||||||
|
|
||||||
|
|
||||||
@bp.get('/<int:examination_schedule_id>/term-of-defences/')
|
@bp.get("/<int:examination_schedule_id>/term-of-defences/")
|
||||||
@bp.input(TemporaryProjectSupervisorSchema, location='query')
|
@bp.input(TemporaryProjectSupervisorSchema, location="query")
|
||||||
@bp.output(ListOfTermOfDefenceSchema)
|
@bp.output(ListOfTermOfDefenceSchema)
|
||||||
def list_created_term_of_defences_by_coordinator_for_project_supervisor(examination_schedule_id: int,
|
def list_created_term_of_defences_by_coordinator_for_project_supervisor(
|
||||||
data: dict) -> dict:
|
examination_schedule_id: int, data: dict
|
||||||
|
) -> dict:
|
||||||
# this code will be removed
|
# 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:
|
if project_supervisor is None:
|
||||||
abort(404, "ProjectSupervisor doesn't exist!")
|
abort(404, "ProjectSupervisor doesn't exist!")
|
||||||
################
|
################
|
||||||
es = ExaminationSchedule.query.filter(ExaminationSchedule.id == examination_schedule_id,
|
es = ExaminationSchedule.query.filter(
|
||||||
ExaminationSchedule.year_group_id).first()
|
ExaminationSchedule.id == examination_schedule_id,
|
||||||
|
ExaminationSchedule.year_group_id,
|
||||||
|
).first()
|
||||||
if es is None:
|
if es is None:
|
||||||
abort(404, "Examination schedule doesn't exist!")
|
abort(404, "Examination schedule doesn't exist!")
|
||||||
|
|
||||||
# list of your free times first enrollment
|
# list of your free times first enrollment
|
||||||
td = TermOfDefence.query.join(TermOfDefence.members_of_committee). \
|
td = (
|
||||||
filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
|
TermOfDefence.query.join(TermOfDefence.members_of_committee)
|
||||||
filter_by(id=project_supervisor.id).all()
|
.filter(TermOfDefence.examination_schedule_id == examination_schedule_id)
|
||||||
|
.filter_by(id=project_supervisor.id)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
return {"term_of_defences": td}
|
return {"term_of_defences": td}
|
||||||
|
@ -1,29 +1,43 @@
|
|||||||
from apiflask import APIBlueprint
|
from apiflask import APIBlueprint
|
||||||
from flask import abort
|
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 ...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.get("/group/<int:group_id>/")
|
||||||
@bp.input(ProjectSupervisorTermQuerySchema, location='query')
|
@bp.input(ProjectSupervisorTermQuerySchema, location="query")
|
||||||
def detail_project_grade_sheet(group_id: int, query: dict) -> dict:
|
def detail_project_grade_sheet(group_id: int, query: dict) -> dict:
|
||||||
project_supervisor_id = query.get('id')
|
project_supervisor_id = query.get("id")
|
||||||
project_supervisor = ProjectSupervisor.query.filter(ProjectSupervisor.id == project_supervisor_id).first()
|
project_supervisor = ProjectSupervisor.query.filter(
|
||||||
|
ProjectSupervisor.id == project_supervisor_id
|
||||||
|
).first()
|
||||||
if project_supervisor is None:
|
if project_supervisor is None:
|
||||||
abort(404, "ProjectSupervisor doesn't exist!")
|
abort(404, "ProjectSupervisor doesn't exist!")
|
||||||
####################################
|
####################################
|
||||||
term = query.get('term')
|
term = query.get("term")
|
||||||
group = Group.query.filter(Group.project_supervisor_id == project_supervisor_id, Group.id == group_id).first()
|
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:
|
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]
|
pgs = group.project_grade_sheet[0]
|
||||||
if term == 1:
|
if term == 1:
|
||||||
@ -34,36 +48,23 @@ def detail_project_grade_sheet(group_id: int, query: dict) -> dict:
|
|||||||
return schema.dump(pgs)
|
return schema.dump(pgs)
|
||||||
|
|
||||||
|
|
||||||
def update_project_grade_sheet(group_id: int, query: dict, data: dict) -> None:
|
@bp.patch("/group/<int:group_id>/first-term/")
|
||||||
project_supervisor_id = query.get('id')
|
@bp.input(TemporaryProjectSupervisorSchema, location="query")
|
||||||
project_supervisor = ProjectSupervisor.query.filter(ProjectSupervisor.id == project_supervisor_id).first()
|
@bp.input(ProjectGradeSheetEditFirstTermSchema, location="json")
|
||||||
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.output(MessageSchema)
|
@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)
|
update_project_grade_sheet(group_id, query, data)
|
||||||
return {"message": "Your project grade sheet was updated!"}
|
return {"message": "Your project grade sheet was updated!"}
|
||||||
|
|
||||||
|
|
||||||
@bp.patch('/group/<int:group_id>/second-term/')
|
@bp.patch("/group/<int:group_id>/second-term/")
|
||||||
@bp.input(TemporaryProjectSupervisorSchema, location='query')
|
@bp.input(TemporaryProjectSupervisorSchema, location="query")
|
||||||
@bp.input(ProjectGradeSheetEditSecondTermSchema, location='json')
|
@bp.input(ProjectGradeSheetEditSecondTermSchema, location="json")
|
||||||
@bp.output(MessageSchema)
|
@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)
|
update_project_grade_sheet(group_id, query, data)
|
||||||
return {"message": "Your project grade sheet was updated!"}
|
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):
|
class FreeTimeSchema(Schema):
|
||||||
@ -18,7 +18,9 @@ class ListOfTermOfDefenceSchema(Schema):
|
|||||||
class TimeAvailabilityCreateSchema(Schema):
|
class TimeAvailabilityCreateSchema(Schema):
|
||||||
start_date = fields.DateTime(required=True)
|
start_date = fields.DateTime(required=True)
|
||||||
end_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
|
# temporary class it will be removed in the future
|
||||||
|
@ -2,59 +2,63 @@ from datetime import datetime
|
|||||||
|
|
||||||
from flask_sqlalchemy import BaseQuery
|
from flask_sqlalchemy import BaseQuery
|
||||||
|
|
||||||
from ..dependencies import db
|
from ..base.models import Base, Person
|
||||||
from ..base.models import Person, Base
|
|
||||||
from ..base.utils import order_by_column_name
|
from ..base.utils import order_by_column_name
|
||||||
|
from ..dependencies import db
|
||||||
from ..examination_schedule.models import TermOfDefence
|
from ..examination_schedule.models import TermOfDefence
|
||||||
|
|
||||||
|
|
||||||
class YearGroup(Base):
|
class YearGroup(Base):
|
||||||
__tablename__ = 'year_groups'
|
__tablename__ = "year_groups"
|
||||||
|
|
||||||
name = db.Column(db.String(50), nullable=False)
|
name = db.Column(db.String(50), nullable=False)
|
||||||
mode = db.Column(db.String(1), nullable=False)
|
mode = db.Column(db.String(1), nullable=False)
|
||||||
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
|
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
|
||||||
|
|
||||||
__table__args = (
|
__table__args = db.UniqueConstraint("name", "mode", name="uc_name_mode_year_group")
|
||||||
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):
|
class Group(Base):
|
||||||
__tablename__ = "groups"
|
__tablename__ = "groups"
|
||||||
|
|
||||||
name = db.Column(db.String(60), nullable=False)
|
name = db.Column(db.String(60), nullable=False)
|
||||||
cdyd_kod = db.Column(db.String(60), default='2022/SZ')
|
cdyd_kod = db.Column(db.String(60), default="2022/SZ")
|
||||||
prz_kod = db.Column(db.String(60), default='06-DPRILI0')
|
prz_kod = db.Column(db.String(60), default="06-DPRILI0")
|
||||||
tzaj_kod = db.Column(db.String(60), default='LAB')
|
tzaj_kod = db.Column(db.String(60), default="LAB")
|
||||||
project_supervisor_id = db.Column(db.Integer, db.ForeignKey('project_supervisors.id'))
|
project_supervisor_id = db.Column(
|
||||||
project_supervisor = db.relationship('ProjectSupervisor', backref='groups')
|
db.Integer, db.ForeignKey("project_supervisors.id")
|
||||||
year_group_id = db.Column(db.Integer, db.ForeignKey('year_groups.id'))
|
)
|
||||||
year_group = db.relationship('YearGroup', backref='groups', lazy='joined')
|
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_first_term = db.Column(db.Integer, default=0, nullable=False)
|
||||||
points_for_second_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
|
@classmethod
|
||||||
def search_by_name(cls, year_group_id: int, search_name: str = None) -> BaseQuery:
|
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)
|
group_query = cls.query.filter(Group.year_group_id == year_group_id)
|
||||||
|
|
||||||
if search_name is not None:
|
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
|
return group_query
|
||||||
|
|
||||||
|
|
||||||
class ProjectGradeSheet(Base):
|
class ProjectGradeSheet(Base):
|
||||||
__tablename__ = 'project_grade_sheets'
|
__tablename__ = "project_grade_sheets"
|
||||||
|
|
||||||
group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
|
group_id = db.Column(db.Integer, db.ForeignKey("groups.id"))
|
||||||
group = db.relationship('Group', backref='project_grade_sheet', uselist=False)
|
group = db.relationship("Group", backref="project_grade_sheet", uselist=False)
|
||||||
|
|
||||||
presentation_required_content_1 = db.Column(db.Integer, default=0)
|
presentation_required_content_1 = db.Column(db.Integer, default=0)
|
||||||
presentation_required_content_2 = 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_was_compatible_2 = db.Column(db.Integer, default=0)
|
||||||
presentation_showing_1 = 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_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_1 = db.Column(
|
||||||
presentation_answers_to_questions_from_committee_2 = db.Column(db.Integer, default=0)
|
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_1 = db.Column(db.Integer, default=0)
|
||||||
documentation_project_vision_2 = 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"
|
__tablename__ = "students"
|
||||||
|
|
||||||
index = db.Column(db.Integer, nullable=False)
|
index = db.Column(db.Integer, nullable=False)
|
||||||
groups = db.relationship('Group', secondary=students_groups, back_populates='students')
|
groups = db.relationship(
|
||||||
year_group_id = db.Column(db.Integer, db.ForeignKey('year_groups.id'))
|
"Group", secondary=students_groups, back_populates="students"
|
||||||
year_group = db.relationship('YearGroup', backref='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
|
@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_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)
|
student_query = cls.query.filter(Student.year_group_id == year_group_id)
|
||||||
|
|
||||||
if fullname is not None:
|
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 = order_by_column_name(student_query, Student.last_name, order_by_last_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
|
return student_query
|
||||||
|
@ -1,46 +1,69 @@
|
|||||||
import datetime
|
|
||||||
|
|
||||||
from apiflask import APIBlueprint
|
from apiflask import APIBlueprint
|
||||||
from flask import abort
|
from flask import abort
|
||||||
|
|
||||||
from ..schemas import TemporaryStudentSchema, ExaminationScheduleListSchema, \
|
from ...base.schemas import MessageSchema
|
||||||
TermOfDefenceStudentListSchema
|
|
||||||
from ...dependencies import db
|
from ...dependencies import db
|
||||||
from ..models import Student, Group, TermOfDefence
|
|
||||||
from ...examination_schedule.models import ExaminationSchedule
|
from ...examination_schedule.models import ExaminationSchedule
|
||||||
from ...project_supervisor.models import ProjectSupervisor
|
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 = 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.input(TemporaryStudentSchema)
|
||||||
@bp.output(MessageSchema)
|
@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
|
# 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:
|
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,
|
term_of_defence = (
|
||||||
TermOfDefence.examination_schedule_id == examination_schedule_id).first()
|
TermOfDefence.query.filter(
|
||||||
ex = term_of_defence.examination_schedule
|
TermOfDefence.id == term_of_defence_id,
|
||||||
if term_of_defence is None or ex is None:
|
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!")
|
abort(400, "Term of defence not found!")
|
||||||
|
|
||||||
g = Group.query.join(ProjectSupervisor).filter(Group.year_group_id == ex.year_group_id). \
|
g = (
|
||||||
join(Group.students).filter_by(index=student.index).first()
|
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:
|
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,
|
defence = TermOfDefence.query.filter(
|
||||||
TermOfDefence.examination_schedule_id == examination_schedule_id).first()
|
TermOfDefence.group_id == g.id,
|
||||||
|
TermOfDefence.examination_schedule_id == examination_schedule_id,
|
||||||
|
).first()
|
||||||
if defence is not None:
|
if defence is not None:
|
||||||
abort(400, "Your group has already assigned to any exam date!")
|
abort(400, "Your group has already assigned to any exam date!")
|
||||||
|
|
||||||
td = TermOfDefence.query.join(TermOfDefence.members_of_committee). \
|
td = (
|
||||||
filter_by(id=g.project_supervisor_id).first()
|
TermOfDefence.query.join(TermOfDefence.members_of_committee)
|
||||||
|
.filter_by(id=g.project_supervisor_id)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
if td is None:
|
if td is None:
|
||||||
abort(400, "Your project supervisor is not in committee!")
|
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!"}
|
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.input(TemporaryStudentSchema)
|
||||||
@bp.output(MessageSchema)
|
@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
|
# 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:
|
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). \
|
term_of_defence = (
|
||||||
filter(TermOfDefence.examination_schedule_id == examination_schedule_id).first()
|
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
|
ex = term_of_defence.examination_schedule
|
||||||
if term_of_defence is None:
|
if term_of_defence is None:
|
||||||
abort(404, "Term of defence doesn't exist!")
|
abort(404, "Term of defence doesn't exist!")
|
||||||
|
|
||||||
group = Group.query.filter(Group.year_group_id == ex.year_group_id). \
|
group = (
|
||||||
join(Group.students).filter_by(index=student.index).first()
|
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:
|
if group.id != term_of_defence.group_id:
|
||||||
abort(400, "You are not assigned to this group!")
|
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!"}
|
return {"message": "You have just removed the group for this exam date!"}
|
||||||
|
|
||||||
|
|
||||||
@bp.get('/examination-schedule/year-group/<int:year_group_id>/')
|
@bp.get("/examination-schedule/year-group/<int:year_group_id>/")
|
||||||
@bp.input(TemporaryStudentSchema, location='query')
|
@bp.input(TemporaryStudentSchema, location="query")
|
||||||
@bp.output(ExaminationScheduleListSchema)
|
@bp.output(ExaminationScheduleListSchema)
|
||||||
def list_examination_schedule(year_group_id: int, data: dict) -> dict:
|
def list_examination_schedule(year_group_id: int, data: dict) -> dict:
|
||||||
# this code will be removed
|
# 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:
|
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
|
examination_schedules = ExaminationSchedule.query.filter(
|
||||||
now = datetime.datetime.utcnow()
|
ExaminationSchedule.year_group_id == year_group_id
|
||||||
examination_schedules = ExaminationSchedule.query. \
|
).all()
|
||||||
filter(ExaminationSchedule.year_group_id == year_group_id). \
|
return {"examination_schedules": examination_schedules}
|
||||||
filter(ExaminationSchedule.start_date_for_enrollment_students < now). \
|
|
||||||
filter(ExaminationSchedule.end_date_for_enrollment_students > now).all()
|
|
||||||
return {'examination_schedules': examination_schedules}
|
|
||||||
|
|
||||||
|
|
||||||
@bp.get('/examination-schedule/<int:examination_schedule_id>/enrollments/')
|
@bp.get("/examination-schedule/<int:examination_schedule_id>/enrollments/")
|
||||||
@bp.input(TemporaryStudentSchema, location='query')
|
@bp.input(TemporaryStudentSchema, location="query")
|
||||||
@bp.output(TermOfDefenceStudentListSchema)
|
@bp.output(TermOfDefenceStudentListSchema)
|
||||||
def list_term_of_defences(examination_schedule_id: int, data: dict) -> dict:
|
def list_term_of_defences(examination_schedule_id: int, data: dict) -> dict:
|
||||||
# this code will be removed
|
# 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:
|
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
|
term_of_defences = (
|
||||||
now = datetime.datetime.utcnow()
|
TermOfDefence.query.filter(
|
||||||
term_of_defences = TermOfDefence.query.filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
|
TermOfDefence.examination_schedule_id == examination_schedule_id
|
||||||
join(ExaminationSchedule, isouter=True). \
|
)
|
||||||
filter(ExaminationSchedule.start_date_for_enrollment_students < now). \
|
.join(ExaminationSchedule, isouter=True)
|
||||||
filter(ExaminationSchedule.end_date_for_enrollment_students > now).all()
|
.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 apiflask import APIBlueprint
|
||||||
from flask import abort
|
from flask import abort
|
||||||
|
|
||||||
from ..schemas import StudentIndexQueryTempSchema, ProjectGradeSheetDetailFirstTermSchema, \
|
from ..models import ProjectGradeSheet, Student
|
||||||
ProjectGradeSheetDetailSecondTermSchema
|
from ..schemas import (
|
||||||
from ..models import Student, ProjectGradeSheet
|
ProjectGradeSheetDetailFirstTermSchema,
|
||||||
|
ProjectGradeSheetDetailSecondTermSchema,
|
||||||
|
StudentIndexQueryTempSchema,
|
||||||
|
)
|
||||||
|
|
||||||
bp = APIBlueprint("project_grade_sheet", __name__, url_prefix="/project-grade-sheet")
|
bp = APIBlueprint("project_grade_sheet", __name__, url_prefix="/project-grade-sheet")
|
||||||
|
|
||||||
|
|
||||||
@bp.get('/year-group/<int:year_group_id>/')
|
@bp.get("/year-group/<int:year_group_id>/")
|
||||||
@bp.input(StudentIndexQueryTempSchema, location='query')
|
@bp.input(StudentIndexQueryTempSchema, location="query")
|
||||||
def detail_project_grade_sheet(year_group_id: int, query: dict) -> dict:
|
def detail_project_grade_sheet(year_group_id: int, query: dict) -> dict:
|
||||||
index = query.get('index')
|
student_id = query.get("student_id")
|
||||||
st = Student.query.filter(Student.index == index).first()
|
st = Student.query.filter(Student.id == student_id).first()
|
||||||
if st is None:
|
if st is None:
|
||||||
abort(404, "Not found student!")
|
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]
|
groups = [g for g in st.groups if g.year_group_id == year_group_id]
|
||||||
if len(groups) == 0:
|
if len(groups) == 0:
|
||||||
|
@ -1,36 +1,34 @@
|
|||||||
from apiflask import APIBlueprint
|
from apiflask import APIBlueprint
|
||||||
|
|
||||||
|
from ...base.utils import paginate_models
|
||||||
|
from ...dependencies import db
|
||||||
from ...project_supervisor.models import ProjectSupervisor
|
from ...project_supervisor.models import ProjectSupervisor
|
||||||
from ..models import Group
|
from ..models import Group
|
||||||
from ...dependencies import db
|
from ..schemas import ProjectSupervisorPaginationSchema, ProjectSupervisorQuerySchema
|
||||||
from ..schemas import ProjectSupervisorQuerySchema, ProjectSupervisorPaginationSchema
|
|
||||||
from ...base.utils import paginate_models
|
|
||||||
|
|
||||||
bp = APIBlueprint("registrations", __name__, url_prefix="/registrations")
|
bp = APIBlueprint("registrations", __name__, url_prefix="/registrations")
|
||||||
|
|
||||||
|
|
||||||
@bp.get('/<int:year_group_id>/')
|
@bp.get("/<int:year_group_id>/")
|
||||||
@bp.input(ProjectSupervisorQuerySchema, location='query')
|
@bp.input(ProjectSupervisorQuerySchema, location="query")
|
||||||
@bp.output(ProjectSupervisorPaginationSchema)
|
@bp.output(ProjectSupervisorPaginationSchema)
|
||||||
def list_available_groups(year_group_id: int, query: dict) -> dict:
|
def list_available_groups(year_group_id: int, query: dict) -> dict:
|
||||||
page = query.get('page')
|
page = query.get("page")
|
||||||
per_page = query.get('per_page')
|
per_page = query.get("per_page")
|
||||||
|
|
||||||
available_groups = (ProjectSupervisor.limit_group - db.func.count(Group.id))
|
available_groups = ProjectSupervisor.limit_group - db.func.count(Group.id)
|
||||||
ps_query = db.session. \
|
ps_query = (
|
||||||
query(ProjectSupervisor, available_groups). \
|
db.session.query(ProjectSupervisor, available_groups)
|
||||||
join(Group, isouter=True). \
|
.join(Group, isouter=True)
|
||||||
filter(ProjectSupervisor.year_group_id == year_group_id).\
|
.filter(ProjectSupervisor.year_group_id == year_group_id)
|
||||||
group_by(ProjectSupervisor.id)
|
.group_by(ProjectSupervisor.id)
|
||||||
|
)
|
||||||
|
|
||||||
data = paginate_models(page, ps_query, per_page)
|
data = paginate_models(page, ps_query, per_page)
|
||||||
|
|
||||||
project_supervisors = []
|
project_supervisors = []
|
||||||
for project_supervisor, available_groups in data['items']:
|
for project_supervisor, available_groups in data["items"]:
|
||||||
setattr(project_supervisor, 'available_groups', available_groups)
|
setattr(project_supervisor, "available_groups", available_groups)
|
||||||
project_supervisors.append(project_supervisor)
|
project_supervisors.append(project_supervisor)
|
||||||
|
|
||||||
return {
|
return {"project_supervisors": project_supervisors, "max_pages": data["max_pages"]}
|
||||||
"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]
|
POINTS = [0, 1, 3, 4]
|
||||||
|
|
||||||
|
|
||||||
class ProjectSupervisorSchema(Schema):
|
class ProjectSupervisorWithAvailableGroupsSchema(Schema):
|
||||||
first_name = fields.Str()
|
first_name = fields.Str()
|
||||||
last_name = fields.Str()
|
last_name = fields.Str()
|
||||||
email = fields.Str()
|
email = fields.Str()
|
||||||
@ -11,7 +11,9 @@ class ProjectSupervisorSchema(Schema):
|
|||||||
|
|
||||||
|
|
||||||
class ProjectSupervisorPaginationSchema(Schema):
|
class ProjectSupervisorPaginationSchema(Schema):
|
||||||
project_supervisors = fields.List(fields.Nested(ProjectSupervisorSchema))
|
project_supervisors = fields.List(
|
||||||
|
fields.Nested(ProjectSupervisorWithAvailableGroupsSchema)
|
||||||
|
)
|
||||||
max_pages = fields.Integer()
|
max_pages = fields.Integer()
|
||||||
|
|
||||||
|
|
||||||
@ -21,18 +23,19 @@ class ProjectSupervisorQuerySchema(Schema):
|
|||||||
|
|
||||||
|
|
||||||
class TemporaryStudentSchema(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()
|
id = fields.Integer()
|
||||||
title = fields.Str()
|
title = fields.Str()
|
||||||
start_date = fields.DateTime()
|
start_date = fields.DateTime()
|
||||||
end_date = fields.DateTime()
|
end_date = fields.DateTime()
|
||||||
|
open_enrollments = fields.Boolean()
|
||||||
|
|
||||||
|
|
||||||
class ExaminationScheduleListSchema(Schema):
|
class ExaminationScheduleListSchema(Schema):
|
||||||
examination_schedules = fields.List(fields.Nested(ExaminationScheduleSchema))
|
examination_schedules = fields.List(fields.Nested(ExaminationScheduleStudentSchema))
|
||||||
|
|
||||||
|
|
||||||
class ProjectSupervisorCommitteeSchema(Schema):
|
class ProjectSupervisorCommitteeSchema(Schema):
|
||||||
@ -64,11 +67,13 @@ class AssignedGroupToTermOfDefenceItemSchema(TermOfDefenceStudentItemSchema):
|
|||||||
|
|
||||||
|
|
||||||
class TermOfDefenceStudentListSchema(Schema):
|
class TermOfDefenceStudentListSchema(Schema):
|
||||||
term_of_defences = fields.List(fields.Nested(AssignedGroupToTermOfDefenceItemSchema))
|
term_of_defences = fields.List(
|
||||||
|
fields.Nested(AssignedGroupToTermOfDefenceItemSchema)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class StudentIndexQueryTempSchema(Schema):
|
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]))
|
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_required_content_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||||
presentation_was_compatible_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_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_project_vision_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||||
documentation_requirements_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_contact_with_client_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||||
group_work_management_of_risk_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_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))
|
group_work_devops_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||||
|
|
||||||
products_project_complexity_of_product_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
products_project_complexity_of_product_1 = fields.Integer(
|
||||||
products_project_access_to_application_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
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_security_issues_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||||
products_project_access_to_test_application_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
products_project_access_to_test_application_1 = fields.Integer(
|
||||||
products_project_acceptance_criteria_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
validate=validate.OneOf(POINTS)
|
||||||
products_project_expected_functionality_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_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_is_useful_1 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||||
products_project_prototype_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))
|
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_required_content_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||||
presentation_was_compatible_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_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_project_vision_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||||
documentation_requirements_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_contact_with_client_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||||
group_work_management_of_risk_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_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))
|
group_work_devops_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||||
|
|
||||||
products_project_complexity_of_product_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
products_project_complexity_of_product_2 = fields.Integer(
|
||||||
products_project_access_to_application_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
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_security_issues_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||||
products_project_access_to_test_application_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
products_project_access_to_test_application_2 = fields.Integer(
|
||||||
products_project_acceptance_criteria_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
validate=validate.OneOf(POINTS)
|
||||||
products_project_expected_functionality_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_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_is_useful_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||||
products_project_prototype_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))
|
products_project_tests_2 = fields.Integer(validate=validate.OneOf(POINTS))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import os
|
|
||||||
import importlib
|
import importlib
|
||||||
|
import os
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
@ -7,8 +7,8 @@ from flask import current_app
|
|||||||
|
|
||||||
def get_app_directories() -> list:
|
def get_app_directories() -> list:
|
||||||
directories = []
|
directories = []
|
||||||
src_dir = current_app.config['SRC_DIR']
|
src_dir = current_app.config["SRC_DIR"]
|
||||||
excluded_dirs = current_app.config['EXCLUDED_DIRS']
|
excluded_dirs = current_app.config["EXCLUDED_DIRS"]
|
||||||
|
|
||||||
for dirname in os.listdir(src_dir):
|
for dirname in os.listdir(src_dir):
|
||||||
path = src_dir / dirname
|
path = src_dir / dirname
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
from app import create_app
|
from app import create_app
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
@ -3,9 +3,8 @@ from __future__ import with_statement
|
|||||||
import logging
|
import logging
|
||||||
from logging.config import fileConfig
|
from logging.config import fileConfig
|
||||||
|
|
||||||
from flask import current_app
|
|
||||||
|
|
||||||
from alembic import context
|
from alembic import context
|
||||||
|
from flask import current_app
|
||||||
|
|
||||||
# this is the Alembic Config object, which provides
|
# this is the Alembic Config object, which provides
|
||||||
# access to the values within the .ini file in use.
|
# access to the values within the .ini file in use.
|
||||||
@ -14,17 +13,17 @@ config = context.config
|
|||||||
# Interpret the config file for Python logging.
|
# Interpret the config file for Python logging.
|
||||||
# This line sets up loggers basically.
|
# This line sets up loggers basically.
|
||||||
fileConfig(config.config_file_name)
|
fileConfig(config.config_file_name)
|
||||||
logger = logging.getLogger('alembic.env')
|
logger = logging.getLogger("alembic.env")
|
||||||
|
|
||||||
# add your model's MetaData object here
|
# add your model's MetaData object here
|
||||||
# for 'autogenerate' support
|
# for 'autogenerate' support
|
||||||
# from myapp import mymodel
|
# from myapp import mymodel
|
||||||
# target_metadata = mymodel.Base.metadata
|
# target_metadata = mymodel.Base.metadata
|
||||||
config.set_main_option(
|
config.set_main_option(
|
||||||
'sqlalchemy.url',
|
"sqlalchemy.url",
|
||||||
str(current_app.extensions['migrate'].db.get_engine().url).replace(
|
str(current_app.extensions["migrate"].db.get_engine().url).replace("%", "%%"),
|
||||||
'%', '%%'))
|
)
|
||||||
target_metadata = current_app.extensions['migrate'].db.metadata
|
target_metadata = current_app.extensions["migrate"].db.metadata
|
||||||
|
|
||||||
# other values from the config, defined by the needs of env.py,
|
# other values from the config, defined by the needs of env.py,
|
||||||
# can be acquired:
|
# can be acquired:
|
||||||
@ -45,9 +44,7 @@ def run_migrations_offline():
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
url = config.get_main_option("sqlalchemy.url")
|
url = config.get_main_option("sqlalchemy.url")
|
||||||
context.configure(
|
context.configure(url=url, target_metadata=target_metadata, literal_binds=True)
|
||||||
url=url, target_metadata=target_metadata, literal_binds=True
|
|
||||||
)
|
|
||||||
|
|
||||||
with context.begin_transaction():
|
with context.begin_transaction():
|
||||||
context.run_migrations()
|
context.run_migrations()
|
||||||
@ -65,20 +62,20 @@ def run_migrations_online():
|
|||||||
# when there are no changes to the schema
|
# when there are no changes to the schema
|
||||||
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
|
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
|
||||||
def process_revision_directives(context, revision, directives):
|
def process_revision_directives(context, revision, directives):
|
||||||
if getattr(config.cmd_opts, 'autogenerate', False):
|
if getattr(config.cmd_opts, "autogenerate", False):
|
||||||
script = directives[0]
|
script = directives[0]
|
||||||
if script.upgrade_ops.is_empty():
|
if script.upgrade_ops.is_empty():
|
||||||
directives[:] = []
|
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:
|
with connectable.connect() as connection:
|
||||||
context.configure(
|
context.configure(
|
||||||
connection=connection,
|
connection=connection,
|
||||||
target_metadata=target_metadata,
|
target_metadata=target_metadata,
|
||||||
process_revision_directives=process_revision_directives,
|
process_revision_directives=process_revision_directives,
|
||||||
**current_app.extensions['migrate'].configure_args
|
**current_app.extensions["migrate"].configure_args
|
||||||
)
|
)
|
||||||
|
|
||||||
with context.begin_transaction():
|
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
|
factory_boy>=3.2.1,<3.3.0
|
||||||
reportlab>=3.6.12,<3.7.0
|
reportlab>=3.6.12,<3.7.0
|
||||||
gunicorn>=20.1.0,<20.2.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
|
import pytest
|
||||||
from apiflask import APIFlask
|
from apiflask import APIFlask
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask.testing import FlaskClient
|
|
||||||
from flask.ctx import AppContext
|
from flask.ctx import AppContext
|
||||||
|
from flask.testing import FlaskClient
|
||||||
|
|
||||||
from app import create_app
|
from app import create_app
|
||||||
from app.dependencies import db
|
from app.dependencies import db
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from factory import alchemy, Sequence
|
from factory import Sequence, alchemy
|
||||||
from factory.faker import Faker
|
from factory.faker import Faker
|
||||||
from factory.fuzzy import FuzzyInteger, FuzzyDateTime
|
from factory.fuzzy import FuzzyDateTime, FuzzyInteger
|
||||||
|
|
||||||
from app.dependencies import db
|
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.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):
|
class ProjectSupervisorFactory(alchemy.SQLAlchemyModelFactory):
|
||||||
@ -15,9 +15,9 @@ class ProjectSupervisorFactory(alchemy.SQLAlchemyModelFactory):
|
|||||||
model = ProjectSupervisor
|
model = ProjectSupervisor
|
||||||
sqlalchemy_session = db.session
|
sqlalchemy_session = db.session
|
||||||
|
|
||||||
first_name = Faker('first_name')
|
first_name = Faker("first_name")
|
||||||
last_name = Faker('last_name')
|
last_name = Faker("last_name")
|
||||||
email = Faker('email')
|
email = Faker("email")
|
||||||
|
|
||||||
|
|
||||||
class YearGroupProjectSupervisorsFactory(alchemy.SQLAlchemyModelFactory):
|
class YearGroupProjectSupervisorsFactory(alchemy.SQLAlchemyModelFactory):
|
||||||
@ -33,7 +33,7 @@ class GroupFactory(alchemy.SQLAlchemyModelFactory):
|
|||||||
model = Group
|
model = Group
|
||||||
sqlalchemy_session = db.session
|
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_first_term = FuzzyInteger(1, 5)
|
||||||
points_for_second_term = FuzzyInteger(1, 5)
|
points_for_second_term = FuzzyInteger(1, 5)
|
||||||
|
|
||||||
@ -43,9 +43,9 @@ class StudentFactory(alchemy.SQLAlchemyModelFactory):
|
|||||||
model = Student
|
model = Student
|
||||||
sqlalchemy_session = db.session
|
sqlalchemy_session = db.session
|
||||||
|
|
||||||
first_name = Faker('first_name')
|
first_name = Faker("first_name")
|
||||||
last_name = Faker('last_name')
|
last_name = Faker("last_name")
|
||||||
email = Faker('email')
|
email = Faker("email")
|
||||||
index = Sequence(lambda n: 400_000 + n)
|
index = Sequence(lambda n: 400_000 + n)
|
||||||
|
|
||||||
|
|
||||||
@ -60,9 +60,13 @@ class ExaminationScheduleFactory(alchemy.SQLAlchemyModelFactory):
|
|||||||
model = ExaminationSchedule
|
model = ExaminationSchedule
|
||||||
sqlalchemy_session = db.session
|
sqlalchemy_session = db.session
|
||||||
|
|
||||||
title = Sequence(lambda n: f'Examination schedule {n}')
|
title = Sequence(lambda n: f"Examination schedule {n}")
|
||||||
duration_time = 30
|
duration_time = 30
|
||||||
start_date = FuzzyDateTime(datetime.datetime(2020, 1, 1, tzinfo=datetime.timezone.utc),
|
start_date = FuzzyDateTime(
|
||||||
datetime.datetime(2020, 1, 5, tzinfo=datetime.timezone.utc))
|
datetime.datetime(2020, 1, 1, tzinfo=datetime.timezone.utc),
|
||||||
end_date = FuzzyDateTime(datetime.datetime(2020, 1, 10, tzinfo=datetime.timezone.utc),
|
datetime.datetime(2020, 1, 5, tzinfo=datetime.timezone.utc),
|
||||||
datetime.datetime(2020, 1, 20, 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 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.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:
|
def create_year_group(data: dict = None) -> YearGroup:
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {'mode': ModeGroups.STATIONARY.value, 'name': '2022/2023'}
|
data = {"mode": ModeGroups.STATIONARY.value, "name": "2022/2023"}
|
||||||
yg = YearGroup(**data)
|
yg = YearGroup(**data)
|
||||||
db.session.add(yg)
|
db.session.add(yg)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return yg
|
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)]
|
ps = [ProjectSupervisorFactory() for _ in range(amount)]
|
||||||
db.session.add_all(ps)
|
db.session.add_all(ps)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
db.session.add_all(
|
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()
|
db.session.commit()
|
||||||
return ps
|
return ps
|
||||||
|
|
||||||
@ -47,7 +61,12 @@ def create_students(yg: YearGroup, amount: int) -> List[StudentFactory]:
|
|||||||
students = [StudentFactory() for _ in range(amount)]
|
students = [StudentFactory() for _ in range(amount)]
|
||||||
db.session.add_all(students)
|
db.session.add_all(students)
|
||||||
db.session.commit()
|
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()
|
db.session.commit()
|
||||||
return students
|
return students
|
||||||
|
|
||||||
@ -57,7 +76,9 @@ def create_student(data: dict, year_group_id: int = None) -> Student:
|
|||||||
db.session.add(st)
|
db.session.add(st)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
if year_group_id is not None:
|
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()
|
db.session.commit()
|
||||||
return st
|
return st
|
||||||
|
|
||||||
@ -76,8 +97,12 @@ def create_group(data: dict, yg: YearGroup) -> Group:
|
|||||||
return group
|
return group
|
||||||
|
|
||||||
|
|
||||||
def create_examination_schedules(yg: YearGroup, amount: int) -> List[ExaminationScheduleFactory]:
|
def create_examination_schedules(
|
||||||
examination_schedules = [ExaminationScheduleFactory(year_group_id=yg.id) for _ in range(amount)]
|
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.add_all(examination_schedules)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return examination_schedules
|
return examination_schedules
|
||||||
|
@ -1,28 +1,42 @@
|
|||||||
import datetime
|
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
|
from app.dependencies import db
|
||||||
|
|
||||||
valid_data = {
|
from ...fake_data import (
|
||||||
'title': 'examination schedule summer',
|
create_examination_schedule,
|
||||||
'start_date': datetime.datetime.now() + datetime.timedelta(days=5),
|
create_examination_schedules,
|
||||||
'end_date': datetime.datetime.now() + datetime.timedelta(days=10),
|
create_year_group,
|
||||||
'duration_time': 30
|
)
|
||||||
|
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 = {
|
ex_data = {
|
||||||
'title': 'new title',
|
"title": "new title",
|
||||||
'start_date': (datetime.datetime.now() + datetime.timedelta(days=5)).strftime("%Y-%m-%dT%H:%M:%S.000Z"),
|
"start_date": (datetime.datetime.now() + datetime.timedelta(days=5)).strftime(
|
||||||
'end_date': (datetime.datetime.now() + datetime.timedelta(days=10)).strftime("%Y-%m-%dT%H:%M:%S.000Z")
|
"%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 = {
|
enrollments_data = {
|
||||||
'start_date_for_enrollment_students': (datetime.datetime.now() + datetime.timedelta(days=2)).strftime(
|
"start_date_for_enrollment_students": (
|
||||||
"%Y-%m-%dT%H:%M:%S.000Z"),
|
datetime.datetime.now() + datetime.timedelta(days=2)
|
||||||
'end_date_for_enrollment_students': (datetime.datetime.now() + datetime.timedelta(days=4)).strftime(
|
).strftime("%Y-%m-%dT%H:%M:%S.000Z"),
|
||||||
"%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()
|
year_group = create_year_group()
|
||||||
create_examination_schedules(year_group, 34)
|
create_examination_schedules(year_group, 34)
|
||||||
|
|
||||||
url = f'/api/coordinator/examination_schedule/{year_group.id}/?per_page=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')
|
data = _test_case_client_without_response(client, url, None, 200, method="get")
|
||||||
assert data.get('max_pages') == 4
|
assert data.get("max_pages") == 4
|
||||||
assert len(data.get('examination_schedules')) == 10
|
assert len(data.get("examination_schedules")) == 10
|
||||||
|
|
||||||
|
|
||||||
def test_delete_examination_schedule(test_app_with_context) -> None:
|
def test_delete_examination_schedule(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
year_group = create_year_group()
|
year_group = create_year_group()
|
||||||
ex = create_examination_schedules(year_group, 1)[0]
|
ex = create_examination_schedules(year_group, 1)[0]
|
||||||
_test_case_client(client, f'/api/coordinator/examination_schedule/{ex.id}/', None,
|
_test_case_client(
|
||||||
'Examination schedule was deleted!', 200, method='delete')
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
_test_case_client(client, '/api/coordinator/examination_schedule/32/', None,
|
_test_case_client(
|
||||||
"Examination schedule doesn't exist!", 404, method='delete', key='error')
|
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:
|
def test_update_examination_schedule(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
year_group = create_year_group()
|
year_group = create_year_group()
|
||||||
ex = create_examination_schedules(year_group, 1)[0]
|
ex = create_examination_schedules(year_group, 1)[0]
|
||||||
_test_case_client(client, f'/api/coordinator/examination_schedule/{ex.id}/', ex_data,
|
_test_case_client(
|
||||||
'Examination schedule was updated!', 200, method='put')
|
client,
|
||||||
|
f"/api/coordinator/examination_schedule/{ex.id}/",
|
||||||
|
ex_data,
|
||||||
|
"Examination schedule was updated!",
|
||||||
|
200,
|
||||||
|
method="put",
|
||||||
|
)
|
||||||
assert_model_changes(ex, ex_data)
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
_test_case_client(client, '/api/coordinator/examination_schedule/32/', ex_data,
|
_test_case_client(
|
||||||
"Examination schedule doesn't exist!", 404, method='put', key='error')
|
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:
|
def test_set_date_of_examination_schedule(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
year_group = create_year_group()
|
year_group = create_year_group()
|
||||||
ex = create_examination_schedule(valid_data, year_group)
|
ex = create_examination_schedule(valid_data, year_group)
|
||||||
_test_case_client(client, f'/api/coordinator/examination_schedule/{ex.id}/date/', enrollments_data,
|
_test_case_client(
|
||||||
'You set date of examination schedule!', 200, method='put')
|
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)
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
_test_case_client(client, '/api/coordinator/examination_schedule/43/date/', enrollments_data,
|
_test_case_client(
|
||||||
'Examination schedule doesn\'t exist!', 404, method='put', key='error')
|
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 = {
|
invalid_dates = {
|
||||||
'start_date_for_enrollment_students': enrollments_data['end_date_for_enrollment_students'],
|
"start_date_for_enrollment_students": enrollments_data[
|
||||||
'end_date_for_enrollment_students': enrollments_data['start_date_for_enrollment_students'],
|
"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:
|
with test_app_with_context.test_client() as client:
|
||||||
year_group = create_year_group()
|
year_group = create_year_group()
|
||||||
ex = create_examination_schedule(valid_data, year_group)
|
ex = create_examination_schedule(valid_data, year_group)
|
||||||
_test_case_client(client, f'/api/coordinator/examination_schedule/{ex.id}/date/', invalid_dates,
|
_test_case_client(
|
||||||
'Invalid data! End date must be greater than start date!', 400, method='put', key='error')
|
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:
|
def test_create_project_supervisors(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
year_group = create_year_group()
|
year_group = create_year_group()
|
||||||
_test_case_client(client, f'/api/coordinator/examination_schedule/{year_group.id}/', ex_data,
|
_test_case_client(
|
||||||
'Examination schedule was created!', 201, method='post')
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
_test_case_client(client, '/api/coordinator/examination_schedule/33/', ex_data,
|
_test_case_client(
|
||||||
'Year group doesn\'t exist!', 404, method='post', key='error')
|
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:
|
def test_create_project_supervisors_with_invalid_dates(test_app_with_context) -> None:
|
||||||
invalid_data = {
|
invalid_data = {
|
||||||
'title': 'examination schedule winter',
|
"title": "examination schedule winter",
|
||||||
'start_date': ex_data['end_date'],
|
"start_date": ex_data["end_date"],
|
||||||
'end_date': ex_data['start_date']
|
"end_date": ex_data["start_date"],
|
||||||
}
|
}
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
year_group = create_year_group()
|
year_group = create_year_group()
|
||||||
_test_case_client(client, f'/api/coordinator/examination_schedule/{year_group.id}/', invalid_data,
|
_test_case_client(
|
||||||
'Invalid data! End date must be greater than start date!', 400, method='post', key='error')
|
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 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.dependencies import db
|
||||||
from app.students.models import Group
|
|
||||||
from app.project_supervisor.models import YearGroupProjectSupervisors
|
from app.project_supervisor.models import YearGroupProjectSupervisors
|
||||||
|
from app.students.models import Group
|
||||||
|
|
||||||
valid_data = {
|
from ...fake_data import (
|
||||||
'name': 'System Pri'
|
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 = {
|
valid_data = {"name": "System Pri"}
|
||||||
'name': 'Mobile app'
|
|
||||||
}
|
new_data = {"name": "Mobile app"}
|
||||||
|
|
||||||
invalid_data = {
|
invalid_data = {
|
||||||
'name': 'Mobile app v2',
|
"name": "Mobile app v2",
|
||||||
'students': [123_344, 455_444],
|
"students": [123_344, 455_444],
|
||||||
'project_supervisor_id': 1
|
"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:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
create_groups(yg, 33)
|
create_groups(yg, 33)
|
||||||
data = _test_case_client_without_response(client, f'/api/coordinator/groups/{yg.id}/?per_page=10', None, 200,
|
data = _test_case_client_without_response(
|
||||||
method='get')
|
client,
|
||||||
assert data.get('max_pages') == 4
|
f"/api/coordinator/groups/{yg.id}/?per_page=10",
|
||||||
assert len(data.get('groups')) == 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:
|
def test_detail_group(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
group = create_group(valid_data, yg)
|
group = create_group(valid_data, yg)
|
||||||
data = _test_case_client_without_response(client, f'/api/coordinator/groups/{group.id}/detail/', None, 200,
|
data = _test_case_client_without_response(
|
||||||
method='get')
|
client,
|
||||||
|
f"/api/coordinator/groups/{group.id}/detail/",
|
||||||
|
None,
|
||||||
|
200,
|
||||||
|
method="get",
|
||||||
|
)
|
||||||
assert_model_changes(group, data)
|
assert_model_changes(group, data)
|
||||||
|
|
||||||
|
|
||||||
def test_detail_group_if_group_doesnt_exist(test_app_with_context) -> None:
|
def test_detail_group_if_group_doesnt_exist(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
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',
|
_test_case_client(
|
||||||
key='error')
|
client,
|
||||||
|
"/api/coordinator/groups/11/detail/",
|
||||||
|
None,
|
||||||
|
"Not found group!",
|
||||||
|
404,
|
||||||
|
method="get",
|
||||||
|
key="error",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_delete_group(test_app_with_context) -> None:
|
def test_delete_group(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
group = create_group(valid_data, yg)
|
group = create_group(valid_data, yg)
|
||||||
_test_case_client(client, f'/api/coordinator/groups/{group.id}/', None, 'Group was deleted!', 202,
|
_test_case_client(
|
||||||
method='delete')
|
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:
|
def test_delete_group_if_group_doesnt_exist(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
_test_case_client(client, '/api/coordinator/groups/32/', None, 'Not found group!', 404, method='delete',
|
_test_case_client(
|
||||||
key='error')
|
client,
|
||||||
|
"/api/coordinator/groups/32/",
|
||||||
|
None,
|
||||||
|
"Not found group!",
|
||||||
|
404,
|
||||||
|
method="delete",
|
||||||
|
key="error",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_edit_group(test_app_with_context) -> None:
|
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)
|
students = create_students(yg, 3)
|
||||||
ps = create_project_supervisors(yg, 1)[0]
|
ps = create_project_supervisors(yg, 1)[0]
|
||||||
group = create_group(valid_data, yg)
|
group = create_group(valid_data, yg)
|
||||||
data['students'] = [student.index for student in students]
|
data["students"] = [student.index for student in students]
|
||||||
data['project_supervisor_id'] = ps.id
|
data["project_supervisor_id"] = ps.id
|
||||||
|
|
||||||
_test_case_client(client, f'/api/coordinator/groups/{group.id}/', data, 'Group was updated!', 200,
|
_test_case_client(
|
||||||
method='put')
|
client,
|
||||||
|
f"/api/coordinator/groups/{group.id}/",
|
||||||
|
data,
|
||||||
|
"Group was updated!",
|
||||||
|
200,
|
||||||
|
method="put",
|
||||||
|
)
|
||||||
_test_case_group(group, data)
|
_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()
|
yg = create_year_group()
|
||||||
students = create_students(yg, 3)
|
students = create_students(yg, 3)
|
||||||
group = create_group(valid_data, yg)
|
group = create_group(valid_data, yg)
|
||||||
data['students'] = [student.index for student in students]
|
data["students"] = [student.index for student in students]
|
||||||
data['project_supervisor_id'] = 10
|
data["project_supervisor_id"] = 10
|
||||||
_test_case_client(client, f'/api/coordinator/groups/{group.id}/', data, 'Not found project supervisor!', 404,
|
_test_case_client(
|
||||||
method='put', key='error')
|
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:
|
def test_edit_group_with_invalid_data(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
group = create_group(valid_data, yg)
|
group = create_group(valid_data, yg)
|
||||||
data = {'students': [123_4356, 243_533, 434_343]}
|
data = {"students": [123_4356, 243_533, 434_343]}
|
||||||
_test_case_client(client, f'/api/coordinator/groups/{group.id}/', data, 'Validation error', 400, method='put')
|
_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:
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
group = create_group(valid_data, yg)
|
group = create_group(valid_data, yg)
|
||||||
data['students'] = [123_456, 243_533, 434_343]
|
data["students"] = [123_456, 243_533, 434_343]
|
||||||
_test_case_client(client, f'/api/coordinator/groups/{group.id}/', data, 'Not found students!', 404,
|
_test_case_client(
|
||||||
method='put', key='error')
|
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:
|
def test_edit_group_if_group_doesnt_exist(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
_test_case_client(client, '/api/coordinator/groups/333/', new_data, 'Not found group!', 404,
|
_test_case_client(
|
||||||
method='put', key='error')
|
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:
|
def test_edit_group_if_you_pass_empty_data(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
_test_case_client(client, '/api/coordinator/groups/333/', {}, 'You have passed empty data!', 400,
|
_test_case_client(
|
||||||
method='put', key='error')
|
client,
|
||||||
|
"/api/coordinator/groups/333/",
|
||||||
|
{},
|
||||||
|
"You have passed empty data!",
|
||||||
|
400,
|
||||||
|
method="put",
|
||||||
|
key="error",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_create_group(test_app_with_context) -> None:
|
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()
|
yg = create_year_group()
|
||||||
students = create_students(yg, 3)
|
students = create_students(yg, 3)
|
||||||
ps = create_project_supervisors(yg, 1)[0]
|
ps = create_project_supervisors(yg, 1)[0]
|
||||||
data['students'] = [student.index for student in students]
|
data["students"] = [student.index for student in students]
|
||||||
data['project_supervisor_id'] = ps.id
|
data["project_supervisor_id"] = ps.id
|
||||||
|
|
||||||
_test_case_client(client, f'/api/coordinator/groups/{yg.id}/', data, 'Group was created!', 201,
|
_test_case_client(
|
||||||
method='post')
|
client,
|
||||||
|
f"/api/coordinator/groups/{yg.id}/",
|
||||||
|
data,
|
||||||
|
"Group was created!",
|
||||||
|
201,
|
||||||
|
method="post",
|
||||||
|
)
|
||||||
assert Group.query.count() == 1
|
assert Group.query.count() == 1
|
||||||
_test_case_group(Group.query.first(), data)
|
_test_case_group(Group.query.first(), data)
|
||||||
|
|
||||||
|
|
||||||
def test_create_group_if_year_group_doesnt_exist(test_app_with_context) -> None:
|
def test_create_group_if_year_group_doesnt_exist(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
_test_case_client(client, '/api/coordinator/groups/22/', invalid_data, 'Not found year group!', 404,
|
_test_case_client(
|
||||||
method='post', key='error')
|
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:
|
def test_create_group_if_project_supervisor_doesnt_exist(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
_test_case_client(client, f'/api/coordinator/groups/{yg.id}/', invalid_data, 'Not found project supervisor!',
|
_test_case_client(
|
||||||
404, method='post', key='error')
|
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:
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
ps = create_project_supervisors(yg, 1)[0]
|
ps = create_project_supervisors(yg, 1)[0]
|
||||||
data['project_supervisor_id'] = ps.id
|
data["project_supervisor_id"] = ps.id
|
||||||
limit_group = current_app.config.get('LIMIT_STUDENTS_PER_GROUP')
|
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}"
|
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:
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
ps = create_project_supervisors(yg, 1)[0]
|
ps = create_project_supervisors(yg, 1)[0]
|
||||||
data['project_supervisor_id'] = ps.id
|
data["project_supervisor_id"] = ps.id
|
||||||
_test_case_client(client, f'/api/coordinator/groups/{yg.id}/', data, "Not found students!", 404, method='post',
|
_test_case_client(
|
||||||
key='error')
|
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)
|
data = copy.deepcopy(invalid_data)
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
ps = create_project_supervisors(yg, 1)[0]
|
ps = create_project_supervisors(yg, 1)[0]
|
||||||
group = create_group(valid_data, yg)
|
group = create_group(valid_data, yg)
|
||||||
data['project_supervisor_id'] = ps.id
|
data["project_supervisor_id"] = ps.id
|
||||||
student = create_students(yg, 1)[0]
|
student = create_students(yg, 1)[0]
|
||||||
group.students.append(student)
|
group.students.append(student)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
data['students'].extend([student.index])
|
data["students"].extend([student.index])
|
||||||
_test_case_client(client, f'/api/coordinator/groups/{yg.id}/', data,
|
_test_case_client(
|
||||||
"One or more students have already belonged to group!", 400, method='post', key='error')
|
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)
|
data = copy.deepcopy(invalid_data)
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
ps = create_project_supervisors(yg, 1)[0]
|
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). \
|
ygps = YearGroupProjectSupervisors.query.filter_by(
|
||||||
first()
|
project_supervisor_id=ps.id, year_group_id=yg.id
|
||||||
|
).first()
|
||||||
limit_group = ygps.limit_group
|
limit_group = ygps.limit_group
|
||||||
|
|
||||||
groups = create_groups(yg, 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
|
group.project_supervisor_id = ps.id
|
||||||
db.session.commit()
|
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",
|
"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.dependencies import db
|
||||||
from app.project_supervisor.models import YearGroupProjectSupervisors
|
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 = {
|
valid_data = {
|
||||||
'first_name': 'John',
|
"first_name": "John",
|
||||||
'last_name': 'Smith',
|
"last_name": "Smith",
|
||||||
'email': 'johnsmith@gmail.com'
|
"email": "johnsmith@gmail.com",
|
||||||
}
|
}
|
||||||
|
|
||||||
year_group_ps_data = {
|
year_group_ps_data = {"limit_group": 3}
|
||||||
'limit_group': 3
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def test_list_project_supervisors(test_app_with_context) -> None:
|
def test_list_project_supervisors(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
year_group = create_year_group()
|
year_group = create_year_group()
|
||||||
create_project_supervisors(year_group, 25)
|
create_project_supervisors(year_group, 25)
|
||||||
data = _test_case_client_without_response(client, '/api/coordinator/project_supervisor/?per_page=10', None, 200,
|
data = _test_case_client_without_response(
|
||||||
method='get')
|
client,
|
||||||
assert data.get('max_pages') == 3
|
"/api/coordinator/project_supervisor/?per_page=10",
|
||||||
assert len(data.get('project_supervisors')) == 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:
|
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()
|
year_group_2 = create_year_group()
|
||||||
create_project_supervisors(year_group, 12)
|
create_project_supervisors(year_group, 12)
|
||||||
create_project_supervisors(year_group_2, 24)
|
create_project_supervisors(year_group_2, 24)
|
||||||
data = _test_case_client_without_response(client,
|
data = _test_case_client_without_response(
|
||||||
f'/api/coordinator/project_supervisor/{year_group.id}/?per_page=10',
|
client,
|
||||||
None, 200, method='get')
|
f"/api/coordinator/project_supervisor/{year_group.id}/?per_page=10",
|
||||||
assert data.get('max_pages') == 2
|
None,
|
||||||
assert len(data.get('project_supervisors')) == 10
|
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:
|
def test_create_project_supervisors(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
_test_case_client(client, '/api/coordinator/project_supervisor/', valid_data,
|
_test_case_client(
|
||||||
'Project Supervisor was created!', 201, method='post')
|
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:
|
def test_create_project_supervisors_with_invalid_data(test_app_with_context) -> None:
|
||||||
data = {
|
data = {"first_name": "John", "last_name": "Smith", "email": "johnsmitl.com"}
|
||||||
'first_name': 'John',
|
|
||||||
'last_name': 'Smith',
|
|
||||||
'email': 'johnsmitl.com'
|
|
||||||
}
|
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
_test_case_client(client, '/api/coordinator/project_supervisor/', data,
|
_test_case_client(
|
||||||
'Validation error', 400, method='post')
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
create_dummy_ps(valid_data)
|
create_dummy_ps(valid_data)
|
||||||
_test_case_client(client, '/api/coordinator/project_supervisor/', valid_data,
|
_test_case_client(
|
||||||
'Project Supervisor has already exists!', 400, method='post', key='error')
|
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:
|
def test_detail_project_supervisor(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
ps = create_dummy_ps(valid_data)
|
ps = create_dummy_ps(valid_data)
|
||||||
data = _test_case_client_without_response(client, f'/api/coordinator/project_supervisor/{ps.id}/detail/',
|
data = _test_case_client_without_response(
|
||||||
None, 200, method='get')
|
client,
|
||||||
|
f"/api/coordinator/project_supervisor/{ps.id}/detail/",
|
||||||
|
None,
|
||||||
|
200,
|
||||||
|
method="get",
|
||||||
|
)
|
||||||
assert_model_changes(ps, data)
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
_test_case_client(client, '/api/coordinator/project_supervisor/23/detail/', None,
|
_test_case_client(
|
||||||
'Not found project supervisor!', 404, method='get', key='error')
|
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:
|
def test_delete_project_supervisor(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
ps = create_dummy_ps(valid_data)
|
ps = create_dummy_ps(valid_data)
|
||||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/', None,
|
_test_case_client(
|
||||||
'Project Supervisor was deleted!', 200, method='delete')
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
_test_case_client(client, '/api/coordinator/project_supervisor/23/', None,
|
_test_case_client(
|
||||||
'Not found project supervisor!', 404, method='delete', key='error')
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
ps = create_dummy_ps(valid_data)
|
ps = create_dummy_ps(valid_data)
|
||||||
create_dummy_group({'name': 'new project'}, ps.id)
|
create_dummy_group({"name": "new project"}, ps.id)
|
||||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/', None,
|
_test_case_client(
|
||||||
'Project Supervisor has at least one group!', 400, method='delete', key='error')
|
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:
|
def test_edit_project_supervisor(test_app_with_context) -> None:
|
||||||
new_data = {
|
new_data = {
|
||||||
'first_name': 'Albert',
|
"first_name": "Albert",
|
||||||
'last_name': 'Einstein',
|
"last_name": "Einstein",
|
||||||
'email': 'albertmc2@gmail.com'
|
"email": "albertmc2@gmail.com",
|
||||||
}
|
}
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
ps = create_dummy_ps(valid_data)
|
ps = create_dummy_ps(valid_data)
|
||||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/', new_data,
|
_test_case_client(
|
||||||
'Project Supervisor was updated!', 200, method='put')
|
client,
|
||||||
|
f"/api/coordinator/project_supervisor/{ps.id}/",
|
||||||
|
new_data,
|
||||||
|
"Project Supervisor was updated!",
|
||||||
|
200,
|
||||||
|
method="put",
|
||||||
|
)
|
||||||
assert_model_changes(ps, new_data)
|
assert_model_changes(ps, new_data)
|
||||||
|
|
||||||
|
|
||||||
def test_edit_project_supervisor_with_invalid_data(test_app_with_context) -> None:
|
def test_edit_project_supervisor_with_invalid_data(test_app_with_context) -> None:
|
||||||
invalid_data = {
|
invalid_data = {"first_name": "Mark", "last_name": "Smith", "email": "invalidemail"}
|
||||||
'first_name': 'Mark',
|
|
||||||
'last_name': 'Smith',
|
|
||||||
'email': 'invalidemail'
|
|
||||||
}
|
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
ps = create_dummy_ps(valid_data)
|
ps = create_dummy_ps(valid_data)
|
||||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/', invalid_data,
|
_test_case_client(
|
||||||
'Validation error', 400, method='put')
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
_test_case_client(client, '/api/coordinator/project_supervisor/2332/', valid_data,
|
_test_case_client(
|
||||||
'Not found project supervisor!', 404, method='put', key='error')
|
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:
|
def test_add_project_supervisor_to_year_group(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
ps = create_dummy_ps(valid_data)
|
ps = create_dummy_ps(valid_data)
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/year-group/{yg.id}/',
|
_test_case_client(
|
||||||
year_group_ps_data, "Project Supervisor was added to year group!", 201, method='post')
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
_test_case_client(client, f'/api/coordinator/project_supervisor/454/year-group/{yg.id}/', year_group_ps_data,
|
_test_case_client(
|
||||||
"Not found project supervisor!", 404, method='post', key='error')
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
ps = create_dummy_ps(valid_data)
|
ps = create_dummy_ps(valid_data)
|
||||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/year-group/2/', year_group_ps_data,
|
_test_case_client(
|
||||||
"Not found year group!", 404, method='post', key='error')
|
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(
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
ps = create_dummy_ps(valid_data)
|
ps = create_dummy_ps(valid_data)
|
||||||
yg = create_year_group()
|
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.add(ygps)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/year-group/{yg.id}/',
|
_test_case_client(
|
||||||
year_group_ps_data, "Project supervisor is assigned to this year group!", 400, method='post',
|
client,
|
||||||
key='error')
|
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:
|
def test_delete_project_supervisor_to_year_group(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
ps = create_dummy_ps(valid_data)
|
ps = create_dummy_ps(valid_data)
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/year-group/{yg.id}/', None,
|
_test_case_client(
|
||||||
"Project Supervisor was removed from this year group!", 200, method='delete')
|
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
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
_test_case_client(client, f'/api/coordinator/project_supervisor/5/year-group/{yg.id}/', None,
|
_test_case_client(
|
||||||
"Not found project supervisor!", 404, method='delete', key='error')
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
ps = create_dummy_ps(valid_data)
|
ps = create_dummy_ps(valid_data)
|
||||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/year-group/23/', None,
|
_test_case_client(
|
||||||
"Not found year group!", 404, method='delete', key='error')
|
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:
|
def test_update_limit_of_group_for_project_supervisor(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
ps = create_dummy_ps(valid_data)
|
ps = create_dummy_ps(valid_data)
|
||||||
yg = create_year_group()
|
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.add(ygps)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/year-group/{yg.id}/',
|
_test_case_client(
|
||||||
year_group_ps_data, "Limit of group was changed!", 200, method='put')
|
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)
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
_test_case_client(client, f'/api/coordinator/project_supervisor/34/year-group/{yg.id}/',
|
_test_case_client(
|
||||||
year_group_ps_data, "Not found project supervisor!", 404, method='put', key='error')
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
ps = create_dummy_ps(valid_data)
|
ps = create_dummy_ps(valid_data)
|
||||||
_test_case_client(client, f'/api/coordinator/project_supervisor/{ps.id}/year-group/34/',
|
_test_case_client(
|
||||||
year_group_ps_data, "Not found year group!", 404, method='put', key='error')
|
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
|
import copy
|
||||||
|
|
||||||
from ...utils import _test_case_client, _test_case_client_without_response, assert_model_changes
|
from ...fake_data import create_student, create_students, create_year_group
|
||||||
from ...fake_data import create_year_group, create_students, create_student
|
from ...utils import (
|
||||||
|
_test_case_client,
|
||||||
|
_test_case_client_without_response,
|
||||||
|
assert_model_changes,
|
||||||
|
)
|
||||||
|
|
||||||
valid_data = {
|
valid_data = {
|
||||||
'first_name': 'Albert',
|
"first_name": "Albert",
|
||||||
'last_name': 'Rose',
|
"last_name": "Rose",
|
||||||
'index': 234_343,
|
"index": 234_343,
|
||||||
'email': 'albert@gmail.com'
|
"email": "albert@gmail.com",
|
||||||
}
|
}
|
||||||
|
|
||||||
new_data = {
|
new_data = {"first_name": "Martin", "last_name": "Green", "pesel": "93030312894"}
|
||||||
'first_name': 'Martin',
|
|
||||||
'last_name': 'Green',
|
|
||||||
'pesel': '93030312894'
|
|
||||||
}
|
|
||||||
|
|
||||||
data_to_create_student = {
|
data_to_create_student = {
|
||||||
'first_name': 'Albert',
|
"first_name": "Albert",
|
||||||
'last_name': 'Marcus',
|
"last_name": "Marcus",
|
||||||
'pesel': '93030312896',
|
"pesel": "93030312896",
|
||||||
'index': 123_456
|
"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:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
create_students(yg, 45)
|
create_students(yg, 45)
|
||||||
data = _test_case_client_without_response(client, f'/api/coordinator/students/{yg.id}/?per_page=10', None, 200,
|
data = _test_case_client_without_response(
|
||||||
method='get')
|
client,
|
||||||
assert data.get('max_pages') == 5
|
f"/api/coordinator/students/{yg.id}/?per_page=10",
|
||||||
assert len(data.get('students')) == 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:
|
def test_detail_student(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
st = create_student(valid_data, yg.id)
|
st = create_student(valid_data, yg.id)
|
||||||
data = _test_case_client_without_response(client, f'/api/coordinator/students/{st.index}/detail/', None, 200,
|
data = _test_case_client_without_response(
|
||||||
method='get')
|
client,
|
||||||
|
f"/api/coordinator/students/{st.index}/detail/",
|
||||||
|
None,
|
||||||
|
200,
|
||||||
|
method="get",
|
||||||
|
)
|
||||||
assert_model_changes(st, data)
|
assert_model_changes(st, data)
|
||||||
|
|
||||||
|
|
||||||
def test_detail_student_if_student_doesnt_exist(test_app_with_context) -> None:
|
def test_detail_student_if_student_doesnt_exist(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
_test_case_client(client, '/api/coordinator/students/43/detail/', None, 'Not found student!', 404,
|
_test_case_client(
|
||||||
method='get', key='error')
|
client,
|
||||||
|
"/api/coordinator/students/43/detail/",
|
||||||
|
None,
|
||||||
|
"Not found student!",
|
||||||
|
404,
|
||||||
|
method="get",
|
||||||
|
key="error",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_delete_student(test_app_with_context) -> None:
|
def test_delete_student(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
st = create_student(valid_data, yg.id)
|
st = create_student(valid_data, yg.id)
|
||||||
_test_case_client(client, f'/api/coordinator/students/{st.index}/', None, 'Student was deleted!', 202,
|
_test_case_client(
|
||||||
method='delete')
|
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:
|
def test_delete_student_if_student_doesnt_exist(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
_test_case_client(client, '/api/coordinator/students/43/', None, 'Not found student!', 404,
|
_test_case_client(
|
||||||
method='delete', key='error')
|
client,
|
||||||
|
"/api/coordinator/students/43/",
|
||||||
|
None,
|
||||||
|
"Not found student!",
|
||||||
|
404,
|
||||||
|
method="delete",
|
||||||
|
key="error",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_edit_student(test_app_with_context) -> None:
|
def test_edit_student(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
st = create_student(valid_data, yg.id)
|
st = create_student(valid_data, yg.id)
|
||||||
_test_case_client(client, f'/api/coordinator/students/{st.index}/', new_data, 'Student was updated!', 200,
|
_test_case_client(
|
||||||
method='put')
|
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:
|
def test_edit_student_with_invalid_data(test_app_with_context) -> None:
|
||||||
data = copy.copy(new_data)
|
data = copy.copy(new_data)
|
||||||
data['pesel'] = '43333333333433443'
|
data["pesel"] = "43333333333433443"
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
st = create_student(valid_data, yg.id)
|
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:
|
def test_edit_student_if_student_doesnt_exist(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
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',
|
_test_case_client(
|
||||||
key='error')
|
client,
|
||||||
|
"/api/coordinator/students/54/",
|
||||||
|
new_data,
|
||||||
|
"Not found student!",
|
||||||
|
404,
|
||||||
|
method="put",
|
||||||
|
key="error",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_create_student(test_app_with_context) -> None:
|
def test_create_student(test_app_with_context) -> None:
|
||||||
data = copy.copy(data_to_create_student)
|
data = copy.copy(data_to_create_student)
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
data['year_group_id'] = yg.id
|
data["year_group_id"] = yg.id
|
||||||
_test_case_client(client, '/api/coordinator/students/', data, 'Student was created!', 200, method='post')
|
_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:
|
def test_create_student_with_invalid_data(test_app_with_context) -> None:
|
||||||
data = copy.copy(data_to_create_student)
|
data = copy.copy(data_to_create_student)
|
||||||
data['pesel'] = '434343434343344'
|
data["pesel"] = "434343434343344"
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
data['year_group_id'] = yg.id
|
data["year_group_id"] = yg.id
|
||||||
_test_case_client(client, '/api/coordinator/students/', data, 'Validation error', 400, method='post')
|
_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:
|
def test_create_student_if_year_group_doesnt_exist(test_app_with_context) -> None:
|
||||||
data = copy.copy(data_to_create_student)
|
data = copy.copy(data_to_create_student)
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
data['year_group_id'] = 34
|
data["year_group_id"] = 34
|
||||||
_test_case_client(client, '/api/coordinator/students/', data, 'Not found year group!', 404, method='post',
|
_test_case_client(
|
||||||
key='error')
|
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)
|
data = copy.copy(data_to_create_student)
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group()
|
yg = create_year_group()
|
||||||
create_student(data, yg.id)
|
create_student(data, yg.id)
|
||||||
data['year_group_id'] = yg.id
|
data["year_group_id"] = yg.id
|
||||||
_test_case_client(client, '/api/coordinator/students/', data, 'You are assigned to this year group!', 400,
|
_test_case_client(
|
||||||
method='post', key='error')
|
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
|
from app.base.mode import ModeGroups
|
||||||
|
|
||||||
valid_data = {
|
from ...fake_data import create_year_group
|
||||||
'mode': ModeGroups.STATIONARY.value,
|
from ...utils import (
|
||||||
'name': '2022/2023'
|
_test_case_client,
|
||||||
}
|
_test_case_client_without_response,
|
||||||
|
assert_model_changes,
|
||||||
|
)
|
||||||
|
|
||||||
new_data = {
|
valid_data = {"mode": ModeGroups.STATIONARY.value, "name": "2022/2023"}
|
||||||
'mode': ModeGroups.NON_STATIONARY.value,
|
|
||||||
'name': '2021/2022'
|
|
||||||
}
|
|
||||||
|
|
||||||
example_data = {
|
new_data = {"mode": ModeGroups.NON_STATIONARY.value, "name": "2021/2022"}
|
||||||
'mode': ModeGroups.STATIONARY.value,
|
|
||||||
'name': '2021/2022'
|
example_data = {"mode": ModeGroups.STATIONARY.value, "name": "2021/2022"}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def test_create_year_group(test_client) -> None:
|
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:
|
def test_create_year_group_with_invalid_name(test_client) -> None:
|
||||||
data = {
|
data = {"mode": ModeGroups.STATIONARY.value, "name": "2022/203232a"}
|
||||||
'mode': ModeGroups.STATIONARY.value,
|
_test_case_client(
|
||||||
'name': '2022/203232a'
|
test_client, "/api/coordinator/year-group/", data, "Validation error", 400
|
||||||
}
|
)
|
||||||
_test_case_client(test_client, '/api/coordinator/year-group/', data, 'Validation error', 400)
|
|
||||||
|
|
||||||
|
|
||||||
def test_create_year_group_with_invalid_mode(test_client) -> None:
|
def test_create_year_group_with_invalid_mode(test_client) -> None:
|
||||||
data = {
|
data = {"mode": "xxxx", "name": "2022/2033"}
|
||||||
'mode': 'xxxx',
|
_test_case_client(
|
||||||
'name': '2022/2033'
|
test_client, "/api/coordinator/year-group/", data, "Validation error", 400
|
||||||
}
|
)
|
||||||
_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:
|
def test_create_year_group_if_year_group_already_exists(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
create_year_group(valid_data)
|
create_year_group(valid_data)
|
||||||
_test_case_client(client, '/api/coordinator/year-group/', valid_data, 'Year group has already exists!', 400,
|
_test_case_client(
|
||||||
'error')
|
client,
|
||||||
|
"/api/coordinator/year-group/",
|
||||||
|
valid_data,
|
||||||
|
"Year group has already exists!",
|
||||||
|
400,
|
||||||
|
"error",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_delete_year_group(test_app_with_context) -> None:
|
def test_delete_year_group(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group(valid_data)
|
yg = create_year_group(valid_data)
|
||||||
_test_case_client(client, f'/api/coordinator/year-group/{yg.id}/', None, 'Year group was deleted!', 202,
|
_test_case_client(
|
||||||
method='delete')
|
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:
|
def test_delete_year_group_if_year_group_not_exists(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
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,
|
_test_case_client(
|
||||||
method='delete', key='error')
|
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:
|
def test_update_year_group(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group(valid_data)
|
yg = create_year_group(valid_data)
|
||||||
_test_case_client(client, f'/api/coordinator/year-group/{yg.id}/', new_data, "Year group was updated!", 200,
|
_test_case_client(
|
||||||
method='put', key='message')
|
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)
|
assert_model_changes(yg, new_data)
|
||||||
|
|
||||||
|
|
||||||
def test_update_year_group_with_invalid_data(test_app_with_context) -> None:
|
def test_update_year_group_with_invalid_data(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
yg = create_year_group(valid_data)
|
yg = create_year_group(valid_data)
|
||||||
_test_case_client(client, f'/api/coordinator/year-group/{yg.id}/', {'name': '', 'mode': ''}, 'Validation error',
|
_test_case_client(
|
||||||
400, method='put', key='message')
|
client,
|
||||||
|
f"/api/coordinator/year-group/{yg.id}/",
|
||||||
|
{"name": "", "mode": ""},
|
||||||
|
"Validation error",
|
||||||
|
400,
|
||||||
|
method="put",
|
||||||
|
key="message",
|
||||||
|
)
|
||||||
assert_model_changes(yg, valid_data)
|
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:
|
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!',
|
_test_case_client(
|
||||||
404, method='put', key='error')
|
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:
|
with test_app_with_context.test_client() as client:
|
||||||
create_year_group(new_data)
|
create_year_group(new_data)
|
||||||
yg = create_year_group(valid_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!',
|
_test_case_client(
|
||||||
400, method='put', key='error')
|
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)
|
assert_model_changes(yg, valid_data)
|
||||||
|
|
||||||
|
|
||||||
def test_list_year_group(test_app_with_context) -> None:
|
def test_list_year_group(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
ygs = [create_year_group(data) for data in (valid_data, new_data, example_data)]
|
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')
|
data = _test_case_client_without_response(
|
||||||
assert data.get('max_pages') == 1
|
client, "/api/coordinator/year-group/", None, 200, method="get"
|
||||||
for year_group_data in data.get('year_groups'):
|
)
|
||||||
yg_id = year_group_data.get('id')
|
assert data.get("max_pages") == 1
|
||||||
assert_model_changes(list(filter(lambda yg: yg.id == yg_id, ygs))[0], year_group_data)
|
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 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:
|
def test_list_year_group_for_specific_student(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
with test_app_with_context.test_client() as client:
|
||||||
year_group = create_year_group()
|
year_group = create_year_group()
|
||||||
amount_of_project_supervisors = 3
|
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)
|
groups = create_groups(year_group, 6)
|
||||||
|
|
||||||
for i in range(1, 4):
|
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
|
gr.project_supervisor_id = project_supervisors[i - 1].id
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
url = f'/api/students/registrations/{year_group.id}/?per_page=10'
|
url = f"/api/students/registrations/{year_group.id}/?per_page=10"
|
||||||
data = _test_case_client_without_response(client, url, None, 200, method='get')
|
data = _test_case_client_without_response(client, url, None, 200, method="get")
|
||||||
assert data.get('max_pages') == 1
|
assert data.get("max_pages") == 1
|
||||||
project_supervisors_data = data.get('project_supervisors')
|
project_supervisors_data = data.get("project_supervisors")
|
||||||
assert len(project_supervisors_data) == amount_of_project_supervisors
|
assert len(project_supervisors_data) == amount_of_project_supervisors
|
||||||
|
|
||||||
for ps, expected_available_groups in zip(project_supervisors, [2, 1, 0]):
|
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]
|
ps_dict = list(
|
||||||
assert ps_dict.get('available_groups') == expected_available_groups
|
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.base.mode import ModeGroups
|
||||||
from app.dependencies import db
|
from app.dependencies import db
|
||||||
from app.students.models import YearGroupStudents
|
from app.students.models import YearGroupStudents
|
||||||
|
|
||||||
valid_data = {
|
from ...fake_data import create_student, create_year_group
|
||||||
'first_name': 'Dominic',
|
from ...utils import _test_case_client, _test_case_client_without_response
|
||||||
'last_name': 'Mozart',
|
|
||||||
'index': 123_345
|
valid_data = {"first_name": "Dominic", "last_name": "Mozart", "index": 123_345}
|
||||||
}
|
|
||||||
|
|
||||||
year_group_data = [
|
year_group_data = [
|
||||||
{
|
{"name": "2022/2023", "mode": ModeGroups.STATIONARY.value},
|
||||||
'name': '2022/2023',
|
{"name": "2021/2022", "mode": ModeGroups.STATIONARY.value},
|
||||||
'mode': ModeGroups.STATIONARY.value
|
{"name": "2023/2024", "mode": ModeGroups.NON_STATIONARY.value},
|
||||||
},
|
{"name": "1997/1998", "mode": ModeGroups.NON_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]
|
year_groups = [create_year_group(data) for data in year_group_data]
|
||||||
student = create_student(valid_data)
|
student = create_student(valid_data)
|
||||||
for yg in year_groups[:-1]:
|
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()
|
db.session.commit()
|
||||||
|
|
||||||
url = f'/api/students/year-group/?per_page=10&index={student.index}'
|
url = f"/api/students/year-group/?per_page=10&index={student.index}"
|
||||||
data = _test_case_client_without_response(client, url, None, 200, method='get')
|
data = _test_case_client_without_response(client, url, None, 200, method="get")
|
||||||
assert data.get('max_pages') == 1
|
assert data.get("max_pages") == 1
|
||||||
assert len(data.get('year_groups')) == len(year_groups) - 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:
|
def test_list_year_group_if_student_doesnt_exist(test_app_with_context) -> None:
|
||||||
with test_app_with_context.test_client() as client:
|
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,
|
_test_case_client(
|
||||||
method='get', key='error')
|
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
|
import pytest
|
||||||
from flask import current_app
|
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.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.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:
|
def test_is_allowed_extensions(test_app) -> None:
|
||||||
with test_app.app_context():
|
with test_app.app_context():
|
||||||
for ext in current_app.config.get('ALLOWED_EXTENSIONS'):
|
for ext in current_app.config.get("ALLOWED_EXTENSIONS"):
|
||||||
assert is_allowed_extensions(f'file.{ext}') is True
|
assert is_allowed_extensions(f"file.{ext}") is True
|
||||||
|
|
||||||
|
|
||||||
def test_is_allowed_extensions_with_invalid_extensions(test_app) -> None:
|
def test_is_allowed_extensions_with_invalid_extensions(test_app) -> None:
|
||||||
with test_app.app_context():
|
with test_app.app_context():
|
||||||
assert is_allowed_extensions('file.invalid_ext') is False
|
assert is_allowed_extensions("file.invalid_ext") is False
|
||||||
assert is_allowed_extensions('file') is False
|
assert is_allowed_extensions("file") is False
|
||||||
|
|
||||||
|
|
||||||
def test_order_by_column_name_ascending_mode(test_app) -> None:
|
def test_order_by_column_name_ascending_mode(test_app) -> None:
|
||||||
with test_app.app_context():
|
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)
|
assert 'ORDER BY students."index"' in str(query)
|
||||||
|
|
||||||
|
|
||||||
def test_order_by_column_name_descending_mode(test_app) -> None:
|
def test_order_by_column_name_descending_mode(test_app) -> None:
|
||||||
with test_app.app_context():
|
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)
|
assert 'ORDER BY students."index" DESC' in str(query)
|
||||||
|
|
||||||
|
|
||||||
def test_paginate_models(test_app_ctx_with_db) -> None:
|
def test_paginate_models(test_app_ctx_with_db) -> None:
|
||||||
with test_app_ctx_with_db:
|
with test_app_ctx_with_db:
|
||||||
st = Student(index=123456, first_name='Dominic', last_name='Smith', pesel='99010109876', email='xxx@gmail.com')
|
st = Student(
|
||||||
st1 = Student(index=123457, first_name='John', last_name='Newton', pesel='99010109871', email='zzz@gmail.com')
|
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.add_all([st, st1])
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
result = paginate_models(1, Student.query, 1)
|
result = paginate_models(1, Student.query, 1)
|
||||||
|
|
||||||
items = result.get('items', [])
|
items = result.get("items", [])
|
||||||
max_pages = result.get('max_pages', 0)
|
max_pages = result.get("max_pages", 0)
|
||||||
|
|
||||||
assert len(items) == 1
|
assert len(items) == 1
|
||||||
assert max_pages == 2
|
assert max_pages == 2
|
||||||
|
|
||||||
|
|
||||||
def test_check_columns() -> None:
|
def test_check_columns() -> None:
|
||||||
dummy_data = {'NAZWISKO': ['Smith'], 'IMIE': ['Dominic'], 'INDEKS': [343433], 'PESEL': [90020178654],
|
dummy_data = {
|
||||||
'EMAIL': ['domsmi@gmail.com']}
|
"NAZWISKO": ["Smith"],
|
||||||
|
"IMIE": ["Dominic"],
|
||||||
|
"INDEKS": [343433],
|
||||||
|
"PESEL": [90020178654],
|
||||||
|
"EMAIL": ["domsmi@gmail.com"],
|
||||||
|
}
|
||||||
df = pd.DataFrame(data=dummy_data)
|
df = pd.DataFrame(data=dummy_data)
|
||||||
assert check_columns(df) is True
|
assert check_columns(df) is True
|
||||||
|
|
||||||
|
|
||||||
def test_check_columns_with_invalid_column_names() -> None:
|
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)
|
df = pd.DataFrame(data=dummy_data)
|
||||||
assert check_columns(df) is False
|
assert check_columns(df) is False
|
||||||
|
|
||||||
|
|
||||||
def test_check_columns_with_invalid_column_types() -> None:
|
def test_check_columns_with_invalid_column_types() -> None:
|
||||||
dummy_data = {'NAZWISKO': [999], 'IMIE': ['Dominic'], 'INDEKS': [343433], 'PESEL': [90020178654],
|
dummy_data = {
|
||||||
'EMAIL': ['domsmi@gmail.com']}
|
"NAZWISKO": [999],
|
||||||
|
"IMIE": ["Dominic"],
|
||||||
|
"INDEKS": [343433],
|
||||||
|
"PESEL": [90020178654],
|
||||||
|
"EMAIL": ["domsmi@gmail.com"],
|
||||||
|
}
|
||||||
df = pd.DataFrame(data=dummy_data)
|
df = pd.DataFrame(data=dummy_data)
|
||||||
assert check_columns(df) is False
|
assert check_columns(df) is False
|
||||||
|
|
||||||
|
|
||||||
def get_path_to_fake_data(filename: str) -> str:
|
def get_path_to_fake_data(filename: str) -> str:
|
||||||
base_dir = current_app.config.get('BASE_DIR', '/')
|
base_dir = current_app.config.get("BASE_DIR", "/")
|
||||||
return base_dir / 'tmp_data' / filename
|
return base_dir / "tmp_data" / filename
|
||||||
|
|
||||||
|
|
||||||
def test_parse_csv(test_app) -> None:
|
def test_parse_csv(test_app) -> None:
|
||||||
with test_app.app_context():
|
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)
|
students = sorted(list(parse_csv(f)), key=lambda s: s.index)
|
||||||
indexes = [452790 + i for i in range(3)]
|
indexes = [452790 + i for i in range(3)]
|
||||||
assert len(students) == len(indexes)
|
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:
|
def test_parse_csv_with_invalid_column_header_name_in_csv_file(test_app) -> None:
|
||||||
with test_app.app_context():
|
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):
|
with pytest.raises(InvalidNameOrTypeHeaderException):
|
||||||
parse_csv(f)
|
parse_csv(f)
|
||||||
|
|
||||||
|
|
||||||
def test_parse_csv_with_invalid_column_type_in_csv_file(test_app) -> None:
|
def test_parse_csv_with_invalid_column_type_in_csv_file(test_app) -> None:
|
||||||
with test_app.app_context():
|
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):
|
with pytest.raises(InvalidNameOrTypeHeaderException):
|
||||||
parse_csv(f)
|
parse_csv(f)
|
||||||
|
|
||||||
@ -114,12 +141,27 @@ def test_generate_range_dates() -> None:
|
|||||||
|
|
||||||
def test_generate_csv(test_app_ctx_with_db) -> None:
|
def test_generate_csv(test_app_ctx_with_db) -> None:
|
||||||
students_data = [
|
students_data = [
|
||||||
{'first_name': 'Dominic', 'last_name': 'Smith', 'email': 'xxe@gmail.com', 'index': 123456,
|
{
|
||||||
'pesel': '98070234293'},
|
"first_name": "Dominic",
|
||||||
{'first_name': 'Matthew', 'last_name': 'Cash', 'email': 'zze@gmail.com', 'index': 123455,
|
"last_name": "Smith",
|
||||||
'pesel': '98070234291'},
|
"email": "xxe@gmail.com",
|
||||||
{'first_name': 'Martin', 'last_name': 'Rose', 'email': 'nne@gmail.com', 'index': 123446,
|
"index": 123456,
|
||||||
'pesel': '98070234223'},
|
"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:
|
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.add_all([gr1, gr2])
|
||||||
db.session.commit()
|
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)
|
generated_csv = generate_csv(students_and_groups)
|
||||||
for data in students_data:
|
for data in students_data:
|
||||||
for value in data.values():
|
for value in data.values():
|
||||||
|
@ -3,7 +3,10 @@ import datetime
|
|||||||
import pytest
|
import pytest
|
||||||
from marshmallow import ValidationError
|
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:
|
def test_validate_index() -> None:
|
||||||
|
@ -15,8 +15,13 @@ def assert_model_changes(model: db.Model, expected_data: dict) -> None:
|
|||||||
assert value == val
|
assert value == val
|
||||||
|
|
||||||
|
|
||||||
def _test_case_client_without_response(test_client: FlaskClient, url: str, data: Union[dict, None], status_code: int,
|
def _test_case_client_without_response(
|
||||||
method: str = 'post') -> dict:
|
test_client: FlaskClient,
|
||||||
|
url: str,
|
||||||
|
data: Union[dict, None],
|
||||||
|
status_code: int,
|
||||||
|
method: str = "post",
|
||||||
|
) -> dict:
|
||||||
method_func = getattr(test_client, method)
|
method_func = getattr(test_client, method)
|
||||||
if data is not None:
|
if data is not None:
|
||||||
response = method_func(url, json=data)
|
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
|
return response.json
|
||||||
|
|
||||||
|
|
||||||
def _test_case_client(test_client: FlaskClient, url: str, data: Union[dict, None], message: str, status_code: int,
|
def _test_case_client(
|
||||||
key: str = 'message', method: str = 'post') -> None:
|
test_client: FlaskClient,
|
||||||
response_data = _test_case_client_without_response(test_client, url, data, status_code, method)
|
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 key in response_data.keys()
|
||||||
assert response_data.get(key) == message
|
assert response_data.get(key) == message
|
||||||
|
|
||||||
|
|
||||||
def _test_case_group(group: Group, data: dict) -> None:
|
def _test_case_group(group: Group, data: dict) -> None:
|
||||||
assert group.name == data['name']
|
assert group.name == data["name"]
|
||||||
assert group.project_supervisor_id == data['project_supervisor_id']
|
assert group.project_supervisor_id == data["project_supervisor_id"]
|
||||||
|
|
||||||
for st in group.students:
|
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