From 59a32e4c633d341e7871eb650ec247c9d30954a0 Mon Sep 17 00:00:00 2001 From: mohamed Date: Tue, 5 Jan 2021 11:48:12 +0100 Subject: [PATCH 1/3] first version v1.0 --- README.md | 8 + app.py | 18 ++ config.py | 29 +++ create-db.py | 81 ++++++++ specification/api.yml | 382 ++++++++++++++++++++++++++++++++++++++ vms/__init__.py | 0 vms/api/__init__.py | 0 vms/api/employee.py | 54 ++++++ vms/api/vacation.py | 96 ++++++++++ vms/core/__init__.py | 0 vms/core/helpers.py | 24 +++ vms/core/session.py | 28 +++ vms/model/__init__.py | 0 vms/model/dependencies.py | 2 + vms/model/employee.py | 33 ++++ vms/model/team.py | 15 ++ vms/model/vacation.py | 30 +++ 17 files changed, 800 insertions(+) create mode 100644 app.py create mode 100644 config.py create mode 100644 create-db.py create mode 100644 specification/api.yml create mode 100644 vms/__init__.py create mode 100644 vms/api/__init__.py create mode 100644 vms/api/employee.py create mode 100644 vms/api/vacation.py create mode 100644 vms/core/__init__.py create mode 100644 vms/core/helpers.py create mode 100644 vms/core/session.py create mode 100644 vms/model/__init__.py create mode 100644 vms/model/dependencies.py create mode 100644 vms/model/employee.py create mode 100644 vms/model/team.py create mode 100644 vms/model/vacation.py diff --git a/README.md b/README.md index eb87b21..0eb03ba 100644 --- a/README.md +++ b/README.md @@ -57,3 +57,11 @@ Your answer to this test should be a repository. Please refrain from forking thi Feel free to implement this project in whatever way you feel like, we do not impose any limitations/requirements. You can choose any framework (or no framework), any design pattern (or none), any database (or none) for this. + +`` +## Getting Started + +* First start by creating a environment with the requirements from requirements.txt file. +* Then run the create-db script to create a initialize the database and populate it with some fake data. +* Set the FLASK_APP environment variable with the name of the app +* Run the flask app with the command `flask run` \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000..f7a6a7e --- /dev/null +++ b/app.py @@ -0,0 +1,18 @@ +from flask import redirect +import os +import config + +connexion_app = config.connexion_app + +connexion_app.add_api('api.yml') + +app = config.app + + +@app.route('/') +def doc_root(): + return redirect("/api/ui") + + +if __name__ == "__main__": + connexion_app.run(debug=True) \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000..ed0d0ce --- /dev/null +++ b/config.py @@ -0,0 +1,29 @@ +import connexion +import os +from flask_sqlalchemy import SQLAlchemy +from flask_marshmallow import Marshmallow +from sqlalchemy.orm import sessionmaker +from sqlalchemy import create_engine + +Session = sessionmaker() + +basedir = os.path.abspath(os.path.dirname(__file__)) +connexion_app = connexion.App(__name__, specification_dir='specification') + +app = connexion_app.app + +db_url = "sqlite:////" + os.path.join(basedir, 'vms.db') + +engine = create_engine(db_url) +Session.configure(bind=engine) +session = Session() + +# Configure the SQLAlchemy +app.config["SQLALCHEMY_ECHO"] = False +app.config["SQLALCHEMY_DATABASE_URI"] = db_url +app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False + +db = SQLAlchemy(app) + +ma = Marshmallow(app) + diff --git a/create-db.py b/create-db.py new file mode 100644 index 0000000..84c7d41 --- /dev/null +++ b/create-db.py @@ -0,0 +1,81 @@ +import datetime +import os +import random + +from config import db +from vms.model.employee import Employee +from vms.model.team import Team, team_employee +from vms.model.vacation import Vacation +from faker import Faker + + +fake = Faker() + +if os.path.exists('vms.db'): + os.remove('vms.db') + +db.create_all() + + +def add_team(): + for _ in range(3): + team = Team( + name=fake.color_name() + ) + db.session.add(team) + + +def add_employees(): + for _ in range(10): + customer = Employee( + first_name=fake.first_name(), + last_name=fake.last_name(), + address=fake.street_address(), + postcode=fake.postcode(), + email=fake.email(), + phone=fake.phone_number() + ) + db.session.add(customer) + + +def add_team_employee(): + teams = Team.query.all() + employees = Employee.query.all() + + for team in teams: + k = random.randint(1, 3) + employee = random.sample(employees, k) + team.employees.extend(employee) + + db.session.commit() + + +def add_vacations(): + employees = Employee.query.all() + for _ in range(5): + employee = random.choice(employees) + start_dates = [] + for i in range(1,10): + if len(start_dates) > 0: + start = start_dates.pop() + start_date = fake.date_between_dates(date_start=start+datetime.timedelta(days=1), date_end=start+datetime.timedelta(days=15)) + else: + start_date = fake.date_between(start_date='-1y', end_date='today') + end_date = fake.date_between_dates(date_start=start_date, date_end=start_date+datetime.timedelta(days=10)) + start_dates.append(end_date) + vacation_type = random.choices(['NORMALE', 'UNPAID', 'RTT'], [60, 5, 25])[0] + + vacation = Vacation( + employee_id=employee.id, + start_date=start_date, + end_date=end_date, + type=vacation_type + ) + db.session.add(vacation) + + +add_team() +add_employees() +add_team_employee() +add_vacations() +db.session.commit() diff --git a/specification/api.yml b/specification/api.yml new file mode 100644 index 0000000..7820afe --- /dev/null +++ b/specification/api.yml @@ -0,0 +1,382 @@ +openapi: 3.0.0 +info: + title: Vacation managing system api + description: An api to helpe managing employee's vacations + version: 1.0 +servers: + - url: /api + +paths: + + /employees: + parameters: + - name: first_name + description: first_name + in: query + schema: + type: string + - name: last_name + description: last_name + in: query + schema: + type: string + - name: address + description: address + in: query + schema: + type: string + - name: postcode + description: postcode + in: query + schema: + type: string + format: int64 + - name: email + description: email + in: query + schema: + type: string + format: email + - name: phone + description: phone + in: query + schema: + type: string + pattern: ^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\./0-9]*$ + get: + tags: + - Employee + summary: Returns a list of employee. + description: Returns a list of employee. + operationId: employees_get_list + x-openapi-router-controller: vms.api.employee + + responses: + '200': # status code + description: A JSON array of employees + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Employee' + post: + tags: + - Employee + summary: Create employee. + description: Create employee. + operationId: employees_post + x-openapi-router-controller: vms.api.employee + responses: + '200': # status code + description: A JSON object of the created employee + content: + application/json: + schema: + $ref: '#/components/schemas/Employee' + /employee/{id}: + parameters: + - name: id + description: id + required: true + in: path + schema: + type: integer + get: + tags: + - Employee + summary: Get employee by id. + description: Get employee by id. + operationId: employee_get_by_id + x-openapi-router-controller: vms.api.employee + responses: + '200': # status code + description: A JSON object of the updated employee + content: + application/json: + schema: + $ref: '#/components/schemas/Employee' + patch: + tags: + - Employee + summary: update employee. + description: Update employee. + operationId: employee_patch + x-openapi-router-controller: vms.api.employee + parameters: + - name: first_name + description: first_name + in: query + schema: + type: string + - name: last_name + description: last_name + in: query + schema: + type: string + - name: address + description: address + in: query + schema: + type: string + - name: postcode + description: postcode + in: query + schema: + type: integer + format: int64 + - name: email + description: email + in: query + schema: + type: string + format: email + - name: phone + description: phone + in: query + schema: + type: string + pattern: ^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\./0-9]*$ + responses: + '200': # status code + description: A JSON object of the updated employee + content: + application/json: + schema: + $ref: '#/components/schemas/Employee' + delete: + tags: + - Employee + summary: delete employee by id. + description: delete employee by id. + operationId: employee_delete + x-openapi-router-controller: vms.api.employee + responses: + '200': # status code + description: A JSON object of the updated employee + content: + application/json: + schema: + $ref: '#/components/schemas/Employee' + + /vacations: + get: + tags: + - Vacation + summary: Returns a list of vacation. + description: Returns a list of vacation. + operationId: vacations_get_list + x-openapi-router-controller: vms.api.vacation + parameters: + - name: start_date + description: start_date + in: query + schema: + type: string + format: date + example: 2020-01-01 + - name: end_date + description: end_date + in: query + schema: + type: string + format: date + example: 2020-12-31 + - name: type + description: type + in: query + schema: + type: string + enum: + - 'NORMAL' + - 'UNPAID' + - 'RTT' + - name: employee_id + description: employee_id + in: query + schema: + type: array + items: + type: integer + format: int64 + responses: + '200': # status code + description: A JSON array of vacations + content: + application/json: + schema: + type: object + properties: + count: + type: integer + results: + type: array + items: + $ref: '#/components/schemas/Vacation' + post: + tags: + - Vacation + summary: Create vacation. + description: Create vacation. + operationId: vacations_post + x-openapi-router-controller: vms.api.vacation + parameters: + - name: start_date + description: start_date + in: query + required: true + schema: + type: string + format: date + example: 2020-01-01 + - name: end_date + description: end_date + in: query + required: true + schema: + type: string + format: date + example: 2020-12-31 + - name: type + description: type + in: query + required: true + schema: + type: string + enum: + - 'NORMAL' + - 'UNPAID' + - 'RTT' + - name: employee_id + description: employee_id + in: query + required: true + schema: + type: integer + format: int64 + responses: + '200': # status code + description: A JSON array of vacations + content: + application/json: + schema: + $ref: '#/components/schemas/Vacation' + '400': # Bad Request + description: Bad Request + /vacation/{id}: + parameters: + - name: id + description: id + required: true + in: path + schema: + type: integer + get: + tags: + - Vacation + summary: Get vacation by id. + description: Get vacation by id. + operationId: vacation_get_by_id + x-openapi-router-controller: vms.api.vacation + responses: + '200': # status code + description: Employee deleted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Vacation' + patch: + tags: + - Vacation + summary: update vacation. + description: Update vacation. + operationId: vacation_patch + x-openapi-router-controller: vms.api.vacation + parameters: + - name: start_date + description: start_date + in: query + required: true + schema: + type: string + format: date + example: 2020-01-01 + - name: end_date + description: end_date + in: query + required: true + schema: + type: string + format: date + example: 2020-01-02 + - name: type + description: type + in: query + required: true + schema: + type: string + enum: + - 'NORMAL' + - 'UNPAID' + - 'RTT' + - name: employee_id + description: employee_id + in: query + required: true + schema: + type: integer + format: int64 + responses: + '200': # status code + description: A JSON object of the updated vacation + content: + application/json: + schema: + $ref: '#/components/schemas/Vacation' + delete: + tags: + - Vacation + summary: delete vacation by id. + description: delete vacation by id. + operationId: vacation_delete + x-openapi-router-controller: vms.api.vacation + responses: + '200': # status code + description: Vacation deleted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Vacation' + +components: + schemas: + Employee: + type: object + properties: + id: + type: integer + first_name: + type: string + last_name: + type: string + address: + type: string + postcode: + type: string + email: + type: string + phone: + type: string + Vacation: + type: object + properties: + id: + type: integer + start_date: + type: string + end_date: + type: string + type: + type: string + employee_id: + type: string diff --git a/vms/__init__.py b/vms/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vms/api/__init__.py b/vms/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vms/api/employee.py b/vms/api/employee.py new file mode 100644 index 0000000..0c5e78e --- /dev/null +++ b/vms/api/employee.py @@ -0,0 +1,54 @@ +from config import db, session +from vms.core.session import get_all +from vms.model.employee import Employee, EmployeeSchema +from sqlalchemy.sql import text + +from vms.model.vacation import Vacation + + +def employees_get_list(**kwargs): + employees = get_all(Employee, kwargs) + employee_schema = EmployeeSchema(many=True) + data = employee_schema.dump(employees) + return data + + +def employee_get_by_id(id): + employee = Employee.query.get(id) + employee_schema = EmployeeSchema() + data = employee_schema.dump(employee) + return data + + +def employees_post(**kwargs): + del(kwargs['body']) + employee = Employee(**kwargs) + db.session.add(employee) + db.session.commit() + employee_schema = EmployeeSchema() + data = employee_schema.dump(employee) + return data + + +def employee_patch(id, **kwargs): + employee_updated = Employee.query.get(id) + del (kwargs['body']) + for att, value in kwargs.items(): + setattr(employee_updated, att, value) + db.session.commit() + employee_schema = EmployeeSchema() + data = employee_schema.dump(Employee.query.get(id)) + return data + + +def employee_delete(id): + employee = Employee.query.get(id) + employee_vacations_list = Vacation.query.filter_by(employee_id=id) + result = Employee.query.filter_by(id=id).delete() + if result: + employee_vacations_list.delete() + # db.session.query(Employee).filter(Employee.id == id).delete() + employee_schema = EmployeeSchema() + data = employee_schema.dump(employee) + db.session.commit() + return data diff --git a/vms/api/vacation.py b/vms/api/vacation.py new file mode 100644 index 0000000..930e9e6 --- /dev/null +++ b/vms/api/vacation.py @@ -0,0 +1,96 @@ +from werkzeug.exceptions import Forbidden, BadRequest, Conflict + +from config import db +from vms.core.helpers import format_date, verify_dates, get_periods_intersection +from vms.model.vacation import Vacation, VacationSchema +from vms.core.session import get_all, get_specific_instance + + +def vacations_get_list(*args, **kwargs): + vacations = get_all(Vacation, kwargs, "start_date") + if "employee_id" in kwargs and len(kwargs['employee_id']) > 1: + vacations_intersect = [] + for i in range(len(vacations) - 1): + period = get_periods_intersection([[vacations[i].start_date, vacations[i].end_date], + [vacations[i + 1].start_date, vacations[i + 1].end_date]]) + if period and [i for i in period]: + vacations_intersect.append(period) + return {'count': len(vacations_intersect), 'results': vacations_intersect} + vacation_schema = VacationSchema(many=True) + data = vacation_schema.dump(vacations) + response = {'count': len(data), 'results': data} + return response + + +def vacations_post(**kwargs): + del (kwargs['body']) + kwargs['start_date'] = format_date(kwargs['start_date']) + kwargs['end_date'] = format_date(kwargs['end_date']) + verify_dates([kwargs['start_date'], kwargs['end_date']]) + if get_specific_instance(Vacation, kwargs): + raise Conflict("Vacation already exist !") + vacation_post = Vacation() + vacations = get_all(Vacation, {"employee_id": [kwargs['employee_id']]}) + create_new_vacation = len(vacations) == 0 + for vacation in vacations: + if vacation.start_date > kwargs['end_date'] or kwargs['start_date'] > vacation.end_date: + create_new_vacation = True + elif vacation.type == kwargs['type']: + create_new_vacation = False + start_date = min(vacation.start_date, kwargs['start_date']) + end_date = max(vacation.end_date, kwargs['end_date']) + if vacation.start_date == start_date and vacation.end_date == end_date: + vacation_post = vacation + if vacation.start_date == start_date: + if vacation.end_date == end_date: + vacation_post = vacation + else: + vac = Vacation.query.get(vacation.id) + vac.end_date = kwargs['end_date'] + vacation_post = vac + elif vacation.end_date == end_date: + vac = Vacation.query.get(vacation.id) + vac.start_date = kwargs['start_date'] + vacation_post = vac + else: + create_new_vacation = True + break + else: + raise Forbidden("Two overlapped vacations must have the same type") + if create_new_vacation: + vacation_post = Vacation(**kwargs) + db.session.add(vacation_post) + db.session.commit() + employee_schema = VacationSchema() + data = employee_schema.dump(vacation_post) + return data + + +def vacation_get_by_id(id): + vacation = Vacation.query.get(id) + vacation_schema = VacationSchema() + data = vacation_schema.dump(vacation) + return data + + +def vacation_patch(id, **kwargs): + vacation_updated = Vacation.query.get(id) + del (kwargs['body']) + kwargs['start_date'] = format_date(kwargs['start_date']) + kwargs['end_date'] = format_date(kwargs['end_date']) + verify_dates([kwargs['start_date'], kwargs['end_date']]) + for att, value in kwargs.items(): + setattr(vacation_updated, att, value) + db.session.commit() + vacation_schema = VacationSchema() + data = vacation_schema.dump(Vacation.query.get(id)) + return data + + +def vacation_delete(id): + vacation = Vacation.query.get(id) + result = Vacation.query.filter_by(id=id).delete() + vacation_schema = VacationSchema() + data = vacation_schema.dump(vacation) + db.session.commit() + return data diff --git a/vms/core/__init__.py b/vms/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vms/core/helpers.py b/vms/core/helpers.py new file mode 100644 index 0000000..e3d446b --- /dev/null +++ b/vms/core/helpers.py @@ -0,0 +1,24 @@ +import dateutil.parser +from werkzeug.exceptions import BadRequest + + +def format_date(date): + return dateutil.parser.isoparse(date).date() + + +def verify_dates(dates): + if dates[0].weekday() > 4: + raise BadRequest("The start date must be not in the weekend") + if dates[1].weekday() > 4: + raise BadRequest("The end date must be not in the weekend") + if dates[0] > dates[1]: + raise BadRequest("The start date must be earlier than end date") + + +def get_periods_intersection(period): + if period[1][0] > period[0][1] or period[0][0] > period[1][1]: + return None + else: + maximum = max(period[0][0], period[1][0]) + minimum = min(period[0][1], period[1][1]) + return [maximum, minimum] if maximum != minimum else [maximum] diff --git a/vms/core/session.py b/vms/core/session.py new file mode 100644 index 0000000..7dc94b6 --- /dev/null +++ b/vms/core/session.py @@ -0,0 +1,28 @@ +from config import db +from vms.core.helpers import format_date + + +def get_all(model, filter, order_by=None): + query = db.session.query(model) + for attr, value in filter.items(): + if attr == "start_date": + query = query.filter(getattr(model, attr) >= format_date(value)) + elif attr == "end_date": + query = query.filter(getattr(model, attr) <= format_date(value)) + elif attr == "employee_id": + query = query.filter(getattr(model, attr).in_(value)) + else: + query = query.filter(getattr(model, attr) == value) + if order_by: + results = query.order_by(getattr(model, order_by)).all() + else: + results = query.all() + return results + + +def get_specific_instance(model, filter): + query = db.session.query(model) + for attr, value in filter.items(): + query = query.filter(getattr(model, attr) == value) + results = query.all() + return results diff --git a/vms/model/__init__.py b/vms/model/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vms/model/dependencies.py b/vms/model/dependencies.py new file mode 100644 index 0000000..bdd6f8d --- /dev/null +++ b/vms/model/dependencies.py @@ -0,0 +1,2 @@ +from vms.model.employee import Employee +from vms.model.vacation import Vacation \ No newline at end of file diff --git a/vms/model/employee.py b/vms/model/employee.py new file mode 100644 index 0000000..516569f --- /dev/null +++ b/vms/model/employee.py @@ -0,0 +1,33 @@ +from config import db, ma +from vms.model.vacation import Vacation +from marshmallow import fields + + +class Employee(db.Model): + + id = db.Column(db.Integer, primary_key=True) + first_name = db.Column(db.String(50), nullable=False) + last_name = db.Column(db.String(50), nullable=False) + address = db.Column(db.String(500), nullable=False) + postcode = db.Column(db.String(50), nullable=False) + email = db.Column(db.String(50), nullable=False, unique=True) + phone = db.Column(db.String(50), nullable=False, unique=True) + + vacations = db.relationship('Vacation', backref='employee', cascade='all, delete, delete-orphan', passive_deletes=True) + + +class EmployeeSchema(ma.SQLAlchemyAutoSchema): + class Meta: + model = Employee + sqla_session = db.session + + vacations = fields.Nested("EmployeeVacationSchema", default=[], many=True) + + +class EmployeeVacationSchema(ma.SQLAlchemyAutoSchema): + + id = fields.Int() + start_date = fields.Date() + end_date = fields.Date() + type = fields.Str() + employee_id = fields.Int() diff --git a/vms/model/team.py b/vms/model/team.py new file mode 100644 index 0000000..135631e --- /dev/null +++ b/vms/model/team.py @@ -0,0 +1,15 @@ +from config import db +from vms.model.employee import Employee + +team_employee = db.Table('team_employee', + db.Column('team_id', db.Integer, db.ForeignKey('team.id'), primary_key=True), + db.Column('employee_id', db.Integer, db.ForeignKey('employee.id'), primary_key=True) + ) + + +class Team(db.Model): + + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(50), nullable=False) + + employees = db.relationship('Employee', secondary=team_employee) diff --git a/vms/model/vacation.py b/vms/model/vacation.py new file mode 100644 index 0000000..b7add11 --- /dev/null +++ b/vms/model/vacation.py @@ -0,0 +1,30 @@ +from config import db, ma +from marshmallow import fields + + +class Vacation(db.Model): + + id = db.Column(db.Integer, primary_key=True) + start_date = db.Column(db.Date, nullable=False) + end_date = db.Column(db.Date, nullable=False) + type = db.Column(db.String(50), nullable=False) + employee_id = db.Column(db.Integer, db.ForeignKey('employee.id', ondelete='CASCADE')) + + +class VacationSchema(ma.SQLAlchemyAutoSchema): + class Meta: + model = Vacation + sqla_session = db.session + + employee = fields.Nested("VacationEmployeeSchema", default=[]) + + +class VacationEmployeeSchema(ma.SQLAlchemyAutoSchema): + + id = fields.Int() + first_name = fields.Str() + last_name = fields.Str() + address = fields.Str() + postcode = fields.Str() + email = fields.Str() + phone = fields.Str() \ No newline at end of file From 71a3622725c6b392a38ccc96eaace4b6a854e9d5 Mon Sep 17 00:00:00 2001 From: mohamed Date: Tue, 5 Jan 2021 11:48:27 +0100 Subject: [PATCH 2/3] add requirements --- requirements.txt | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..bf2d6b6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,30 @@ +attrs==20.3.0 +certifi==2020.12.5 +chardet==3.0.4 +click==7.1.2 +clickclick==20.10.2 +connexion==2.7.0 +Faker==5.0.0 +Flask==1.1.2 +flask-marshmallow==0.14.0 +Flask-SQLAlchemy==2.4.4 +idna==2.10 +inflection==0.5.1 +install==1.3.4 +itsdangerous==1.1.0 +Jinja2==2.11.2 +jsonschema==3.2.0 +MarkupSafe==1.1.1 +marshmallow==3.9.1 +marshmallow-sqlalchemy==0.24.1 +openapi-spec-validator==0.2.9 +pyrsistent==0.17.3 +python-dateutil==2.8.1 +PyYAML==5.3.1 +requests==2.25.0 +six==1.15.0 +SQLAlchemy==1.3.20 +swagger-ui-bundle==0.0.8 +text-unidecode==1.3 +urllib3==1.26.2 +Werkzeug==1.0.1 From 391ddf04a4f28d6748bfda5215615ca29f70eea2 Mon Sep 17 00:00:00 2001 From: mohamed Date: Tue, 5 Jan 2021 12:09:27 +0100 Subject: [PATCH 3/3] linting code --- specification/api.yml | 2 +- vms/api/employee.py | 4 +--- vms/api/vacation.py | 22 ++++++++++++++-------- vms/model/dependencies.py | 2 -- vms/model/employee.py | 4 +++- vms/model/team.py | 9 +++++---- vms/model/vacation.py | 5 +++-- 7 files changed, 27 insertions(+), 21 deletions(-) delete mode 100644 vms/model/dependencies.py diff --git a/specification/api.yml b/specification/api.yml index 7820afe..1908dc6 100644 --- a/specification/api.yml +++ b/specification/api.yml @@ -2,7 +2,7 @@ openapi: 3.0.0 info: title: Vacation managing system api description: An api to helpe managing employee's vacations - version: 1.0 + version: 1.0.0 servers: - url: /api diff --git a/vms/api/employee.py b/vms/api/employee.py index 0c5e78e..cc8acff 100644 --- a/vms/api/employee.py +++ b/vms/api/employee.py @@ -1,7 +1,6 @@ -from config import db, session +from config import db from vms.core.session import get_all from vms.model.employee import Employee, EmployeeSchema -from sqlalchemy.sql import text from vms.model.vacation import Vacation @@ -47,7 +46,6 @@ def employee_delete(id): result = Employee.query.filter_by(id=id).delete() if result: employee_vacations_list.delete() - # db.session.query(Employee).filter(Employee.id == id).delete() employee_schema = EmployeeSchema() data = employee_schema.dump(employee) db.session.commit() diff --git a/vms/api/vacation.py b/vms/api/vacation.py index 930e9e6..d3fdfc1 100644 --- a/vms/api/vacation.py +++ b/vms/api/vacation.py @@ -1,7 +1,8 @@ -from werkzeug.exceptions import Forbidden, BadRequest, Conflict +from werkzeug.exceptions import Forbidden, Conflict from config import db -from vms.core.helpers import format_date, verify_dates, get_periods_intersection +from vms.core.helpers import format_date, verify_dates, \ + get_periods_intersection from vms.model.vacation import Vacation, VacationSchema from vms.core.session import get_all, get_specific_instance @@ -11,11 +12,14 @@ def vacations_get_list(*args, **kwargs): if "employee_id" in kwargs and len(kwargs['employee_id']) > 1: vacations_intersect = [] for i in range(len(vacations) - 1): - period = get_periods_intersection([[vacations[i].start_date, vacations[i].end_date], - [vacations[i + 1].start_date, vacations[i + 1].end_date]]) + period = get_periods_intersection([[vacations[i].start_date, + vacations[i].end_date], + [vacations[i + 1].start_date, + vacations[i + 1].end_date]]) if period and [i for i in period]: vacations_intersect.append(period) - return {'count': len(vacations_intersect), 'results': vacations_intersect} + return {'count': len(vacations_intersect), + 'results': vacations_intersect} vacation_schema = VacationSchema(many=True) data = vacation_schema.dump(vacations) response = {'count': len(data), 'results': data} @@ -33,13 +37,15 @@ def vacations_post(**kwargs): vacations = get_all(Vacation, {"employee_id": [kwargs['employee_id']]}) create_new_vacation = len(vacations) == 0 for vacation in vacations: - if vacation.start_date > kwargs['end_date'] or kwargs['start_date'] > vacation.end_date: + if vacation.start_date > kwargs['end_date'] or \ + kwargs['start_date'] > vacation.end_date: create_new_vacation = True elif vacation.type == kwargs['type']: create_new_vacation = False start_date = min(vacation.start_date, kwargs['start_date']) end_date = max(vacation.end_date, kwargs['end_date']) - if vacation.start_date == start_date and vacation.end_date == end_date: + if vacation.start_date == start_date and \ + vacation.end_date == end_date: vacation_post = vacation if vacation.start_date == start_date: if vacation.end_date == end_date: @@ -89,7 +95,7 @@ def vacation_patch(id, **kwargs): def vacation_delete(id): vacation = Vacation.query.get(id) - result = Vacation.query.filter_by(id=id).delete() + Vacation.query.filter_by(id=id).delete() vacation_schema = VacationSchema() data = vacation_schema.dump(vacation) db.session.commit() diff --git a/vms/model/dependencies.py b/vms/model/dependencies.py deleted file mode 100644 index bdd6f8d..0000000 --- a/vms/model/dependencies.py +++ /dev/null @@ -1,2 +0,0 @@ -from vms.model.employee import Employee -from vms.model.vacation import Vacation \ No newline at end of file diff --git a/vms/model/employee.py b/vms/model/employee.py index 516569f..5711de8 100644 --- a/vms/model/employee.py +++ b/vms/model/employee.py @@ -13,7 +13,9 @@ class Employee(db.Model): email = db.Column(db.String(50), nullable=False, unique=True) phone = db.Column(db.String(50), nullable=False, unique=True) - vacations = db.relationship('Vacation', backref='employee', cascade='all, delete, delete-orphan', passive_deletes=True) + vacations = db.relationship('Vacation', backref='employee', + cascade='all, delete, delete-orphan', + passive_deletes=True) class EmployeeSchema(ma.SQLAlchemyAutoSchema): diff --git a/vms/model/team.py b/vms/model/team.py index 135631e..7128c31 100644 --- a/vms/model/team.py +++ b/vms/model/team.py @@ -1,10 +1,11 @@ from config import db -from vms.model.employee import Employee team_employee = db.Table('team_employee', - db.Column('team_id', db.Integer, db.ForeignKey('team.id'), primary_key=True), - db.Column('employee_id', db.Integer, db.ForeignKey('employee.id'), primary_key=True) - ) + db.Column('team_id', db.Integer, + db.ForeignKey('team.id'), primary_key=True), + db.Column('employee_id', db.Integer, + db.ForeignKey('employee.id'), + primary_key=True)) class Team(db.Model): diff --git a/vms/model/vacation.py b/vms/model/vacation.py index b7add11..3d3715e 100644 --- a/vms/model/vacation.py +++ b/vms/model/vacation.py @@ -8,7 +8,8 @@ class Vacation(db.Model): start_date = db.Column(db.Date, nullable=False) end_date = db.Column(db.Date, nullable=False) type = db.Column(db.String(50), nullable=False) - employee_id = db.Column(db.Integer, db.ForeignKey('employee.id', ondelete='CASCADE')) + employee_id = db.Column(db.Integer, db.ForeignKey('employee.id', + ondelete='CASCADE')) class VacationSchema(ma.SQLAlchemyAutoSchema): @@ -27,4 +28,4 @@ class VacationEmployeeSchema(ma.SQLAlchemyAutoSchema): address = fields.Str() postcode = fields.Str() email = fields.Str() - phone = fields.Str() \ No newline at end of file + phone = fields.Str()