├── tests
├── __init__.py
├── view
│ ├── __init__.py
│ ├── items
│ │ ├── __init__.py
│ │ └── test_items.py
│ ├── crudapi
│ │ ├── __init__.py
│ │ └── test_crud_api.py
│ ├── table_shapes
│ │ └── test_table_shapes.py
│ ├── test_reservations.py
│ ├── test_generic_views.py
│ ├── floors
│ │ └── test_floors.py
│ └── tables
│ │ └── test_tables.py
├── integration
│ ├── sync
│ │ ├── __init__.py
│ │ ├── it_sync_location_test.py
│ │ └── it_sync_tables_test.py
│ ├── __init__.py
│ ├── resources
│ │ └── messages
│ │ │ ├── message_en_US.properties
│ │ │ └── message_pt_BR.properties
│ ├── fixtures
│ │ └── test_image.jpg
│ ├── it_app_test.py
│ ├── it_test_auth.py
│ ├── it_other_privilages_test.py
│ ├── it_administrator_privilages_test.py
│ ├── it_companies_test.py
│ ├── it_authorization_test.py
│ ├── it_poster_test.py
│ ├── it_comments_test.py
│ ├── it_property_resource_test.py
│ ├── it_reservations_test.py
│ ├── it_roles_test.py
│ ├── poster
│ │ ├── poster_server_mock_test.py
│ │ └── poster_server_mock.py
│ ├── it_scheme_types_test.py
│ ├── it_locations_test.py
│ ├── it_tables_test.py
│ ├── it_floors_test.py
│ └── it_reservation_settings_test.py
├── test_poster.py
├── test_sms.py
├── test_auth.py
└── conftest.py
├── timeless
├── items
│ ├── __init__.py
│ ├── forms.py
│ ├── views.py
│ └── models.py
├── message
│ ├── __init__.py
│ ├── message_resource.py
│ └── property_resource.py
├── poster
│ ├── __init__.py
│ ├── exceptions.py
│ ├── models.py
│ ├── tasks.py
│ └── api.py
├── roles
│ ├── __init__.py
│ ├── forms.py
│ ├── models.py
│ └── views.py
├── customers
│ ├── __init__.py
│ └── models.py
├── employees
│ ├── __init__.py
│ ├── forms.py
│ ├── models.py
│ └── views.py
├── reservations
│ ├── __init__.py
│ ├── forms.py
│ └── models.py
├── templates
│ ├── items
│ │ ├── create.html
│ │ ├── edit.html
│ │ └── list.html
│ ├── _formhelpers.html
│ ├── auth
│ │ ├── forgot_password_post.html
│ │ ├── activate.html
│ │ ├── forgot_password.html
│ │ └── login.html
│ ├── schemetypes
│ │ ├── schemeconditions
│ │ │ ├── create_edit.html
│ │ │ └── list.html
│ │ └── list.html
│ ├── roles
│ │ ├── create_edit.html
│ │ └── list.html
│ ├── reservations
│ │ ├── settings
│ │ │ ├── create_edit.html
│ │ │ └── list.html
│ │ ├── create_edit.html
│ │ └── list.html
│ ├── restaurants
│ │ ├── table_shapes
│ │ │ ├── create_edit.html
│ │ │ └── list.html
│ │ ├── floors
│ │ │ ├── create_edit.html
│ │ │ └── list.html
│ │ ├── tables
│ │ │ ├── create_edit.html
│ │ │ └── list.html
│ │ └── locations
│ │ │ ├── list.html
│ │ │ └── create_edit.html
│ ├── views.py
│ ├── base.html
│ └── employees
│ │ ├── create_edit.html
│ │ └── list.html
├── restaurants
│ ├── floors
│ │ ├── __init__.py
│ │ ├── forms.py
│ │ └── views.py
│ ├── tables
│ │ ├── __init__.py
│ │ ├── forms.py
│ │ └── views.py
│ ├── table_shapes
│ │ ├── __init__.py
│ │ ├── forms.py
│ │ └── views.py
│ ├── __init__.py
│ └── locations
│ │ ├── forms.py
│ │ └── views.py
├── companies
│ ├── __init__.py
│ ├── views.py
│ └── models.py
├── static
│ └── style.css
├── schemetypes
│ ├── __init__.py
│ └── forms.py
├── db
│ └── __init__.py
├── cache
│ └── __init__.py
├── csrf
│ └── __init__.py
├── access_control
│ ├── methods.py
│ ├── __init__.py
│ ├── unknown_privileges.py
│ ├── administrator_privileges.py
│ ├── other_privileges.py
│ ├── views.py
│ ├── location_admin_privileges.py
│ ├── director_privileges.py
│ ├── manager_privileges.py
│ ├── owner_privileges.py
│ └── authorization.py
├── mail
│ └── __init__.py
├── celery.py
├── models.py
├── uploads
│ └── __init__.py
├── forms.py
├── sync
│ └── synced_table.py
├── auth
│ ├── auth.py
│ └── views.py
└── sms.py
├── migrations
├── README
├── versions
│ ├── 2019-01-28T204834.py
│ ├── 2019-01-28T205517.py
│ ├── 2019-02-01T150645.py
│ ├── 2019-01-27T152248.py
│ ├── 2019-01-28T204833.py
│ ├── 2019-01-22T094339.py
│ ├── 2019-01-25T202746.py
│ ├── 2019-01-25T120716.py
│ ├── 2019-02-26T054508.py
│ ├── 2019-01-28T205516.py
│ ├── 2019-01-28T150634.py
│ ├── 2019-01-29T144639.py
│ ├── 2019-01-25T202745.py
│ ├── 2019-01-25T085210.py
│ ├── 2019-01-29T092044.py
│ └── 2019-02-10T185948.py
├── script.py.mako
├── alembic.ini
└── env.py
├── .pylintrc
├── entrypoint.sh
├── frontend
├── public
│ ├── favicon.ico
│ ├── manifest.json
│ └── index.html
├── src
│ ├── index.js
│ ├── App.test.js
│ ├── index.css
│ ├── App.css
│ ├── App.js
│ └── logo.svg
├── .gitignore
└── package.json
├── setup.cfg
├── Dockerfile
├── .gitignore
├── .codeclimate.yml
├── main.py
├── scripts
├── install
│ ├── installRedis.sh
│ ├── deploy
│ │ ├── redis.service
│ │ ├── install_python.sh
│ │ ├── install_dependencies.sh
│ │ ├── timeless_pg.service
│ │ ├── install_redis.sh
│ │ └── install_db.sh
│ └── install_db.sh
└── backup
│ ├── cron_add.sh
│ ├── pg_backup.config
│ └── pg_restore.sh
├── .pdd
├── manage.py
├── .travis.yml
├── check_pylint.py
├── credentials
├── staging.id_rsa.pub.asc
├── credentials.json.asc
└── staging.id_rsa.asc
├── checkstyle.py
├── .rultor.yml
├── docker-compose.yaml
├── requirements.txt
├── config.py
└── deploy.sh
/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/view/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/view/items/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/timeless/items/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/timeless/message/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/timeless/poster/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/timeless/roles/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/view/crudapi/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/timeless/customers/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/timeless/employees/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/timeless/reservations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/integration/sync/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/timeless/templates/items/create.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/timeless/templates/items/edit.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/timeless/restaurants/floors/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/timeless/restaurants/tables/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/timeless/restaurants/table_shapes/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/migrations/README:
--------------------------------------------------------------------------------
1 | Generic single-database configuration.
--------------------------------------------------------------------------------
/timeless/companies/__init__.py:
--------------------------------------------------------------------------------
1 | import timeless.items.models
2 |
--------------------------------------------------------------------------------
/timeless/static/style.css:
--------------------------------------------------------------------------------
1 | h1 { color: #377ba8; margin: 1rem 0; }
--------------------------------------------------------------------------------
/tests/integration/__init__.py:
--------------------------------------------------------------------------------
1 | """ Package for integration tests """
2 |
--------------------------------------------------------------------------------
/.pylintrc:
--------------------------------------------------------------------------------
1 | [pre-commit-hook]
2 | command=pylint
3 | params=timeless
4 | limit=8.0
5 |
--------------------------------------------------------------------------------
/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | sleep 5 # waiting while postgres is being started
3 | exec "$@"
4 |
--------------------------------------------------------------------------------
/timeless/schemetypes/__init__.py:
--------------------------------------------------------------------------------
1 | """Python package containing DB models for SchemeTypes"""
2 |
--------------------------------------------------------------------------------
/timeless/db/__init__.py:
--------------------------------------------------------------------------------
1 | from flask_sqlalchemy import SQLAlchemy
2 |
3 |
4 | DB = SQLAlchemy()
5 |
--------------------------------------------------------------------------------
/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horoscopes/timelessis/master/frontend/public/favicon.ico
--------------------------------------------------------------------------------
/tests/integration/resources/messages/message_en_US.properties:
--------------------------------------------------------------------------------
1 | #commentedkey=commentedvalue
2 | foundkey=thevalue
--------------------------------------------------------------------------------
/tests/integration/resources/messages/message_pt_BR.properties:
--------------------------------------------------------------------------------
1 | #commentedkey=valorcomentado
2 | foundkey=ovalor
--------------------------------------------------------------------------------
/timeless/cache/__init__.py:
--------------------------------------------------------------------------------
1 | """ CACHE module """
2 | from flask_caching import Cache
3 |
4 | CACHE = Cache()
5 |
--------------------------------------------------------------------------------
/timeless/csrf/__init__.py:
--------------------------------------------------------------------------------
1 | """ CSRF module """
2 | from flask_wtf.csrf import CSRFProtect
3 |
4 | CSRF = CSRFProtect()
5 |
--------------------------------------------------------------------------------
/tests/integration/fixtures/test_image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horoscopes/timelessis/master/tests/integration/fixtures/test_image.jpg
--------------------------------------------------------------------------------
/tests/integration/it_app_test.py:
--------------------------------------------------------------------------------
1 | def test_hello(client):
2 | response = client.get("/")
3 | assert response.data == b'Hello, World!'
4 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [tool:pytest]
2 | testpaths = tests
3 | mocked-sessions=timeless.DB.session
4 |
5 | [coverage:run]
6 | branch = True
7 | source = timeless
8 |
--------------------------------------------------------------------------------
/timeless/restaurants/__init__.py:
--------------------------------------------------------------------------------
1 | import timeless.companies.models
2 | import timeless.employees.models
3 | import timeless.roles.models
4 | import timeless.items.models
5 |
--------------------------------------------------------------------------------
/timeless/poster/exceptions.py:
--------------------------------------------------------------------------------
1 | """ Poster related exceptions """
2 |
3 |
4 | class PosterAPIError(Exception):
5 | """Exception class for poster module """
6 | pass
7 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.6
2 |
3 | COPY . /usr/app
4 | WORKDIR /usr/app
5 |
6 | RUN pip install -r requirements.txt
7 |
8 | EXPOSE 5000
9 | ENTRYPOINT ["./entrypoint.sh"]
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Python
2 | *.pyc
3 | __pycache__
4 |
5 | #Flask
6 | instance/
7 | .webassets-cache
8 |
9 | #Environment
10 | venv/
11 |
12 | .idea/
13 | .DS_Store
14 |
15 | .vscode/
--------------------------------------------------------------------------------
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | engines:
2 | radon:
3 | enabled: true
4 | config:
5 | threshold: "B"
6 | pep8:
7 | enabled: true
8 | ratings:
9 | paths:
10 | -"timeless/**.py"
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | """ Application Main module """
2 | import os
3 | from timeless import create_app
4 |
5 |
6 | app = create_app(
7 | os.environ.get("TIMELESSIS_CONFIG", "config.DevelopmentConfig")
8 | )
9 |
--------------------------------------------------------------------------------
/frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import "./index.css";
4 | import App from "./App";
5 |
6 | ReactDOM.render(
We've sent an e-mail to {{email}} with your new password.
9 |Please use it to log in and change it.
10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /timeless/templates/schemetypes/schemeconditions/create_edit.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block header %} 4 |You have to Log In fist.
15 | {% endblock %} 16 | {% endif %} 17 | 18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /tests/integration/it_test_auth.py: -------------------------------------------------------------------------------- 1 | from http import HTTPStatus 2 | 3 | 4 | def test_login(client, auth): 5 | assert client.get("/auth/login").status_code == HTTPStatus.OK 6 | response = auth.login() 7 | assert response.status_code == HTTPStatus.OK 8 | 9 | 10 | def test_forgot_password(client): 11 | assert client.get("/auth/forgotpassword").status_code == HTTPStatus.OK 12 | 13 | 14 | def test_activate(client): 15 | assert client.get("/auth/activate").status_code == HTTPStatus.METHOD_NOT_ALLOWED 16 | -------------------------------------------------------------------------------- /migrations/versions/2019-01-28T204834.py: -------------------------------------------------------------------------------- 1 | """empty message 2 | 3 | Revision ID: 6069798906d9 4 | Revises: 79f280c6c1f4, 4d7589fae495 5 | Create Date: 2019-01-27 16:04:29.390792 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = '6069798906d9' 14 | down_revision = ('79f280c6c1f4', '4d7589fae495') 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | pass 21 | 22 | 23 | def downgrade(): 24 | pass 25 | -------------------------------------------------------------------------------- /migrations/versions/2019-01-28T205517.py: -------------------------------------------------------------------------------- 1 | """empty message 2 | 3 | Revision ID: bbd99136a04d 4 | Revises: 9eee25222512, 8e4ed4542586 5 | Create Date: 2019-01-28 21:54:11.052298 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = 'bbd99136a04d' 14 | down_revision = ('9eee25222512', '8e4ed4542586') 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | pass 21 | 22 | 23 | def downgrade(): 24 | pass 25 | -------------------------------------------------------------------------------- /migrations/versions/2019-02-01T150645.py: -------------------------------------------------------------------------------- 1 | """empty message 2 | 3 | Revision ID: ce1494a8b1f3 4 | Revises: 4207a669d969, b15df456e2cd 5 | Create Date: 2019-02-01 15:53:34.832140 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = 'ce1494a8b1f3' 14 | down_revision = ('4207a669d969', 'b15df456e2cd') 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | pass 21 | 22 | 23 | def downgrade(): 24 | pass 25 | -------------------------------------------------------------------------------- /timeless/celery.py: -------------------------------------------------------------------------------- 1 | from celery import Celery 2 | 3 | 4 | def make_celery(app): 5 | celery = Celery( 6 | app.import_name, 7 | backend=app.config["RESULT_BACKEND"], 8 | broker=app.config["BROKER_URL"] 9 | ) 10 | celery.conf.update(app.config) 11 | 12 | class ContextTask(celery.Task): 13 | def __call__(self, *args, **kwargs): 14 | with app.app_context(): 15 | return self.run(*args, **kwargs) 16 | 17 | celery.Task = ContextTask 18 | return celery 19 | -------------------------------------------------------------------------------- /timeless/templates/auth/forgot_password.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block header %} 4 |Please put your e-mail on the textbox below and we will send you a new one
9 | {% endblock %} 10 | {% block content %} 11 | 16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.8.4", 7 | "react-dom": "^16.8.4", 8 | "react-scripts": "2.1.8" 9 | }, 10 | "scripts": { 11 | "start": "react-scripts start", 12 | "build": "react-scripts build", 13 | "test": "react-scripts test", 14 | "eject": "react-scripts eject" 15 | }, 16 | "eslintConfig": { 17 | "extends": "react-app" 18 | }, 19 | "browserslist": [ 20 | ">0.2%", 21 | "not dead", 22 | "not ie <= 11", 23 | "not op_mini all" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /timeless/templates/reservations/settings/create_edit.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% from "_formhelpers.html" import render_field %} 3 | 4 | {% block header %} 5 |
12 | Edit src/App.js and save to reload.
13 |
{{ setting['name']}} - {{ setting['value']}}
12 | Edit 13 | Delete 14 |{{ role['works_on_shifts'] }}
17 |{{ role['company'] }}
18 |Default value: {{ type['default_value'] }}
17 |Value type: {{ type['value_type'] }}
18 |{{ floor['location'] }}
18 |Priority: {{ type['priority'] }}
17 |Start time: {{ type['start_time'] }}
18 |End time: {{ type['end_time'] }}
19 |{{ table_shape['description'] }}
22 |ID: {{ reservation['id'] }}
18 |Start time: {{ reservation['start_time'] }}
19 |End time: {{ reservation['end_time'] }}
20 |Num of persons: {{ reservation['num_of_persons'] }}
21 |Comment: {{ reservation['comment'] }}
22 |Status: {{ reservation['status'] }}
23 |{{ floors[table['floor_id']] }}
17 |{{ table['x'] }}
18 |{{ table['y'] }}
19 |{{ table['width'] }}
20 |{{ table['height'] }}
21 |{{ table['status'] }}
22 |{{ table['max_capacity'] }}
23 |{{ table['min_capacity'] }}
24 |{{ table['multiple'] }}
25 |{{ table['playstation'] }}
26 |{{ shapes[table['shape_id']] }}
27 |{{ table['deposit_hour'] }}
28 |{{ location['code'] }}
19 |{{ location['country'] }}
20 |{{ location['region'] }}
21 |{{ location['city'] }}
22 |{{ location['address'] }}
23 |{{ location['longitude'] }}
24 |{{ location['latitude'] }}
25 |{{ location['type'] }}
26 |{{ location['status'] }}
27 |{{ location['comment'] }}
28 |{{ location['company'] }}
29 |{{ location['floors'] }}
30 |ID: {{ employee['id'] }}
17 |Name: {{ employee['first_name'] }} {{ employee['last_name'] }}
18 |Company name: {{ employee['company.name'] }}
19 |Registration date: {{ employee['registration_date'] }}
20 |Account status: {{ employee['account_status'] }}
21 |User status: {{ employee['user_status'] }}
22 |Birth date: {{ employee['birth_date'] }}
23 |Email: {{ employee['email'] }}
24 |Phone number: {{ employee['phone_number'] }}
25 |User name: {{ employee['username'] }}
26 |Password: {{ employee['password'] }}
27 |Pin code: {{ employee['pin_code'] }}
28 |Comment: {{ employee['comment'] }}
29 | 30 |1st Floor
" in response.data 23 | assert b"2nd Floor
" in response.data 24 | assert b"3rd Floor
" in response.data 25 | assert b"4th Floor
" in response.data 26 | 27 | 28 | def test_not_authenticated(client): 29 | """ Test if not authenticated user is redirected to login page """ 30 | 31 | response = client.get("/floors/") 32 | print(response.data) 33 | assert response.status_code == HTTPStatus.OK 34 | assert b"