From 008efa1c24ee1aa2873f414dce1afa682bdb1d2f Mon Sep 17 00:00:00 2001
From: Stefano Pigozzi <256895@studenti.unimore.it>
Date: Fri, 7 May 2021 19:46:14 +0200
Subject: [PATCH] =?UTF-8?q?=F0=9F=92=A5=20Create=20test=20framework?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../runConfigurations/Backend__Run_tests.xml | 23 ++++
...config__.xml => Backend__Start_server.xml} | 15 +--
code/backend/.gitignore | 5 +
code/backend/backend.iml | 1 +
code/backend/nest_backend/__main__.py | 64 +++-------
code/backend/nest_backend/app.py | 111 ++++++++++++++++--
.../backend/nest_backend/database/__init__.py | 2 +-
code/backend/nest_backend/database/base.py | 6 +-
.../nest_backend/database/tables/Alert.py | 20 ++--
.../database/tables/Authorization.py | 12 +-
.../database/tables/BoolOperation.py | 31 ++---
.../nest_backend/database/tables/Composed.py | 12 +-
.../nest_backend/database/tables/Condition.py | 18 +--
.../nest_backend/database/tables/Contains.py | 12 +-
.../database/tables/Notification.py | 13 +-
.../database/tables/Repository.py | 28 ++---
.../nest_backend/database/tables/Tweet.py | 16 +--
.../nest_backend/database/tables/User.py | 16 +--
code/backend/nest_backend/gestione.py | 2 +-
.../routes/repository/conditions/condition.py | 6 +-
.../conditions/repository_conditions.py | 11 +-
.../routes/repository/repositories.py | 4 +-
.../routes/repository/repository.py | 16 +--
.../backend/nest_backend/routes/users/user.py | 8 +-
.../nest_backend/routes/users/users.py | 4 +-
code/backend/nest_backend/swagger.py | 3 +-
code/backend/nest_backend/test/conftest.py | 7 ++
.../test/fixtures/flask_client.py | 37 ++++++
code/backend/nest_backend/test/test_doa.py | 9 ++
.../nest_backend/tweet_explorer/__main__.py | 4 +-
.../test => old_unittest_tests}/login_test.py | 0
.../openapi_compliance_test.py | 0
.../repositories_test.py | 0
.../repository_conditions_test.py | 0
.../repository_test.py | 0
.../test => old_unittest_tests}/user_test.py | 0
.../test => old_unittest_tests}/users_test.py | 0
37 files changed, 324 insertions(+), 192 deletions(-)
create mode 100644 .idea/runConfigurations/Backend__Run_tests.xml
rename .idea/runConfigurations/{Backend___Make_your_own_run_config__.xml => Backend__Start_server.xml} (56%)
create mode 100644 code/backend/nest_backend/test/conftest.py
create mode 100644 code/backend/nest_backend/test/fixtures/flask_client.py
create mode 100644 code/backend/nest_backend/test/test_doa.py
rename code/backend/{nest_backend/test => old_unittest_tests}/login_test.py (100%)
rename code/backend/{nest_backend/test => old_unittest_tests}/openapi_compliance_test.py (100%)
rename code/backend/{nest_backend/test => old_unittest_tests}/repositories_test.py (100%)
rename code/backend/{nest_backend/test => old_unittest_tests}/repository_conditions_test.py (100%)
rename code/backend/{nest_backend/test => old_unittest_tests}/repository_test.py (100%)
rename code/backend/{nest_backend/test => old_unittest_tests}/user_test.py (100%)
rename code/backend/{nest_backend/test => old_unittest_tests}/users_test.py (100%)
diff --git a/.idea/runConfigurations/Backend__Run_tests.xml b/.idea/runConfigurations/Backend__Run_tests.xml
new file mode 100644
index 0000000..525e3b8
--- /dev/null
+++ b/.idea/runConfigurations/Backend__Run_tests.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/Backend___Make_your_own_run_config__.xml b/.idea/runConfigurations/Backend__Start_server.xml
similarity index 56%
rename from .idea/runConfigurations/Backend___Make_your_own_run_config__.xml
rename to .idea/runConfigurations/Backend__Start_server.xml
index 13fbfcc..b52a8fd 100644
--- a/.idea/runConfigurations/Backend___Make_your_own_run_config__.xml
+++ b/.idea/runConfigurations/Backend__Start_server.xml
@@ -1,22 +1,23 @@
-
-
+
+
+
-
-
-
+
+
+
-
+
-
+
diff --git a/code/backend/.gitignore b/code/backend/.gitignore
index 5391d87..ba7e575 100644
--- a/code/backend/.gitignore
+++ b/code/backend/.gitignore
@@ -1,3 +1,8 @@
+# Flask config
+
+config.py
+configtest.py
+
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
diff --git a/code/backend/backend.iml b/code/backend/backend.iml
index faeca50..8f95d85 100644
--- a/code/backend/backend.iml
+++ b/code/backend/backend.iml
@@ -5,6 +5,7 @@
+
diff --git a/code/backend/nest_backend/__main__.py b/code/backend/nest_backend/__main__.py
index c473990..aab0585 100644
--- a/code/backend/nest_backend/__main__.py
+++ b/code/backend/nest_backend/__main__.py
@@ -1,57 +1,23 @@
"""
This is the runner for the server.
"""
-import werkzeug.middleware.proxy_fix
-from .routes import *
+import os
+import sys
+
from .gestione import *
-from flask_cors import CORS
-from flask_jwt_extended import *
-from .app import app
-from .api_spec import spec
-from .swagger import swagger_ui_blueprint, SWAGGER_URL
-
-Base.init_app(app=app)
-jwt = JWTManager(app)
-cors = CORS(app)
-app.config['CORS_HEADERS'] = 'Content-Type'
-
-reverse_proxy_app = werkzeug.middleware.proxy_fix.ProxyFix(app=app, x_for=1, x_proto=0, x_host=1, x_port=0, x_prefix=0)
-# Routes setup
-
-app.add_url_rule("/doa", view_func=page_doa, methods=["GET", "POST"])
-app.add_url_rule("/api/v1/login", view_func=page_login, methods=["POST"])
-app.add_url_rule("/api/v1/users/", view_func=page_users, methods=["GET", "POST"])
-app.add_url_rule("/api/v1/users/", view_func=page_user, methods=["GET", "PATCH", "DELETE"])
-app.add_url_rule("/api/v1/repositories/", view_func=page_repositories, methods=["GET", "POST"])
-app.add_url_rule("/api/v1/repositories/", view_func=page_repository, methods=["GET", "PATCH", "DELETE", "PUT"])
-app.add_url_rule("/api/v1/repositories//conditions", view_func=page_repository_conditions,
- methods=["GET", "POST"])
-app.add_url_rule("/api/v1/conditions/", view_func=page_condition, methods=["GET", "PATCH", "DELETE"])
-
-app.register_error_handler(Exception, error_handler)
-app.register_blueprint(swagger_ui_blueprint, url_prefix=SWAGGER_URL)
+from .app import app, extension_sqlalchemy
-with app.test_request_context():
- print(" * Getting docs ready...")
- for fn_name in app.view_functions:
- if fn_name == 'static':
- continue
- view_fn = app.view_functions[fn_name]
- spec.path(view=view_fn)
- print(" * Docs have been compiled on http://127.0.0.1:5000/docs")
+print(" * Swagger docs will be available at http://127.0.0.1:5000/docs")
+with app.app_context():
+ print(" * Creating database tables...")
+ extension_sqlalchemy.create_all(app=app)
+ if not User.query.filter_by(isAdmin=True).all():
+ print(" * Creating default admin account...")
+ extension_sqlalchemy.session.add(
+ User(email="admin@admin.com", password=gen_password("password"), username="admin", isAdmin=True))
+ extension_sqlalchemy.session.commit()
+ print(" * Created! Username: admin | Password: password")
-@app.route("/docs/swagger.json")
-def create_swagger_doc():
- return jsonify(spec.to_dict())
-
-
-if __name__ == "__main__":
- with app.app_context():
- Base.create_all(app=app)
- if not User.query.filter_by(isAdmin=True).all():
- Base.session.add(
- User(email="admin@admin.com", password=gen_password("password"), username="admin", isAdmin=True))
- Base.session.commit()
- app.run(debug=__debug__)
+app.run(debug=__debug__)
diff --git a/code/backend/nest_backend/app.py b/code/backend/nest_backend/app.py
index 3bca49e..3573d79 100644
--- a/code/backend/nest_backend/app.py
+++ b/code/backend/nest_backend/app.py
@@ -1,16 +1,101 @@
from flask import Flask
-import os
+from flask_cors import CORS as FlaskCORS
+from flask_jwt_extended import JWTManager as FlaskJWTManager
+from flask_sqlalchemy import SQLAlchemy as FlaskSQLAlchemy
+from werkzeug.middleware.proxy_fix import ProxyFix as MiddlewareProxyFix
+
+from . import database, routes, gestione, swagger
+from .api_spec import spec
+
+# --- MAIN APP ---
app = Flask(__name__)
-if os.getenv('COOKIE_SECRET'):
- app.secret_key = os.getenv('COOKIE_SECRET')
-else:
- app.secret_key = "testing"
-if os.getenv("JWT_SECRET_KEY"):
- app.config["JWT_SECRET_KEY"] = os.getenv("JWT_SECRET_KEY")
-else:
- app.config["JWT_SECRET_KEY"] = "testing"
-if os.getenv("DATABASE_URI"):
- app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URI')
-else:
- app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:password@localhost:5432/PdSDev'
+
+# --- APP CONFIG
+
+app.config.from_envvar("FLASK_CONFIG")
+
+# --- EXTENSIONS ---
+
+app.config['CORS_HEADERS'] = 'Content-Type'
+extension_cors = FlaskCORS(app=app)
+
+extension_jwt = FlaskJWTManager(app=app)
+
+extension_sqlalchemy = database.ext
+extension_sqlalchemy.init_app(app=app)
+
+# --- API ROUTES ---
+
+app.add_url_rule(
+ "/doa",
+ view_func=routes.page_doa,
+ methods=["GET", "POST"],
+)
+app.add_url_rule(
+ "/api/v1/login",
+ view_func=routes.page_login,
+ methods=["POST"],
+)
+app.add_url_rule(
+ "/api/v1/users/",
+ view_func=routes.page_users,
+ methods=["GET", "POST"],
+)
+app.add_url_rule(
+ "/api/v1/users/",
+ view_func=routes.page_user,
+ methods=["GET", "PATCH", "DELETE"],
+)
+app.add_url_rule(
+ "/api/v1/repositories/",
+ view_func=routes.page_repositories,
+ methods=["GET", "POST"],
+)
+app.add_url_rule(
+ "/api/v1/repositories/",
+ view_func=routes.page_repository,
+ methods=["GET", "PATCH", "DELETE", "PUT"],
+)
+app.add_url_rule(
+ "/api/v1/repositories//conditions",
+ view_func=routes.page_repository_conditions,
+ methods=["GET", "POST"],
+)
+app.add_url_rule(
+ "/api/v1/conditions/",
+ view_func=routes.page_condition,
+ methods=["GET", "PATCH", "DELETE"],
+)
+
+# --- SWAGGER DOCS ---
+
+app.register_blueprint(
+ swagger.swagger_ui_blueprint,
+ url_prefix=swagger.SWAGGER_URL
+)
+
+with app.test_request_context():
+ for fn_name in app.view_functions:
+ if fn_name == 'static':
+ continue
+ view_fn = app.view_functions[fn_name]
+ spec.path(view=view_fn)
+
+app.add_url_rule(
+ "/docs/swagger.json",
+ view_func=lambda: gestione.jsonify(spec.to_dict()),
+ methods=["GET"],
+)
+
+# --- ERROR HANDLER ---
+
+app.register_error_handler(
+ Exception,
+ gestione.error_handler
+)
+
+# --- REVERSE PROXY ---
+
+if not __debug__:
+ app = MiddlewareProxyFix(app=app, x_for=1, x_proto=0, x_host=1, x_port=0, x_prefix=0)
diff --git a/code/backend/nest_backend/database/__init__.py b/code/backend/nest_backend/database/__init__.py
index 2498170..a4592ad 100644
--- a/code/backend/nest_backend/database/__init__.py
+++ b/code/backend/nest_backend/database/__init__.py
@@ -3,4 +3,4 @@ This module imports all the tables and the declarative base
"""
from .tables import *
-from .base import Base
\ No newline at end of file
+from .base import ext
diff --git a/code/backend/nest_backend/database/base.py b/code/backend/nest_backend/database/base.py
index fafa769..4147398 100644
--- a/code/backend/nest_backend/database/base.py
+++ b/code/backend/nest_backend/database/base.py
@@ -1,7 +1,3 @@
-"""
-This module creates the declarative base
-"""
import flask_sqlalchemy
-from sqlalchemy.orm import backref
-Base = flask_sqlalchemy.SQLAlchemy()
+ext = flask_sqlalchemy.SQLAlchemy()
diff --git a/code/backend/nest_backend/database/tables/Alert.py b/code/backend/nest_backend/database/tables/Alert.py
index fccfb75..188ea14 100644
--- a/code/backend/nest_backend/database/tables/Alert.py
+++ b/code/backend/nest_backend/database/tables/Alert.py
@@ -2,18 +2,18 @@
This module defines the Alert database class.
"""
-from ..base import Base
+from ..base import ext
-class Alert(Base.Model):
+class Alert(ext.Model):
__tablename__ = "alert"
- id = Base.Column(Base.Integer, primary_key=True)
- name = Base.Column(Base.String, nullable=False)
- limit = Base.Column(Base.Integer, nullable=False)
- window_size = Base.Column(Base.Integer, nullable=False)
+ id = ext.Column(ext.Integer, primary_key=True)
+ name = ext.Column(ext.String, nullable=False)
+ limit = ext.Column(ext.Integer, nullable=False)
+ window_size = ext.Column(ext.Integer, nullable=False)
# Foreign Keys
- repository_id = Base.Column(Base.Integer, Base.ForeignKey("repository.id", ondelete="CASCADE"), nullable=False)
+ repository_id = ext.Column(ext.Integer, ext.ForeignKey("repository.id", ondelete="CASCADE"), nullable=False)
# Relationships
- repository = Base.relationship("Repository", back_populates="alerts")
- notifications = Base.relationship("Notification", back_populates="alert", cascade="all, delete")
- operations = Base.relationship("BoolOperation", back_populates="alert", cascade="all, delete")
\ No newline at end of file
+ repository = ext.relationship("Repository", back_populates="alerts")
+ notifications = ext.relationship("Notification", back_populates="alert", cascade="all, delete")
+ operations = ext.relationship("BoolOperation", back_populates="alert", cascade="all, delete")
\ No newline at end of file
diff --git a/code/backend/nest_backend/database/tables/Authorization.py b/code/backend/nest_backend/database/tables/Authorization.py
index 64de68e..978aabe 100644
--- a/code/backend/nest_backend/database/tables/Authorization.py
+++ b/code/backend/nest_backend/database/tables/Authorization.py
@@ -2,12 +2,12 @@
This module defines the Authorization database class.
"""
-from ..base import Base
+from ..base import ext
-class Authorization(Base.Model):
- rid = Base.Column(Base.Integer, Base.ForeignKey("repository.id", ondelete="CASCADE"), primary_key=True)
- email = Base.Column(Base.String, Base.ForeignKey("user.email", ondelete="CASCADE"), primary_key=True)
+class Authorization(ext.Model):
+ rid = ext.Column(ext.Integer, ext.ForeignKey("repository.id", ondelete="CASCADE"), primary_key=True)
+ email = ext.Column(ext.String, ext.ForeignKey("user.email", ondelete="CASCADE"), primary_key=True)
# Relationships
- repository = Base.relationship("Repository", back_populates="authorizations")
- user = Base.relationship("User", back_populates="authorizations")
\ No newline at end of file
+ repository = ext.relationship("Repository", back_populates="authorizations")
+ user = ext.relationship("User", back_populates="authorizations")
\ No newline at end of file
diff --git a/code/backend/nest_backend/database/tables/BoolOperation.py b/code/backend/nest_backend/database/tables/BoolOperation.py
index 927feae..52d4df5 100644
--- a/code/backend/nest_backend/database/tables/BoolOperation.py
+++ b/code/backend/nest_backend/database/tables/BoolOperation.py
@@ -2,24 +2,25 @@
This module defines the BoolOperation database class.
"""
-from ..base import Base, backref
+from ..base import ext
from .Enums import OperationType
+from sqlalchemy.orm import backref
-class BoolOperation(Base.Model):
+class BoolOperation(ext.Model):
__tablename__ = "bool_operation"
- id = Base.Column(Base.Integer, primary_key=True)
- operation = Base.Column(Base.Enum(OperationType), nullable=False)
- isRoot = Base.Column(Base.Boolean, default=False, nullable=False)
+ id = ext.Column(ext.Integer, primary_key=True)
+ operation = ext.Column(ext.Enum(OperationType), nullable=False)
+ isRoot = ext.Column(ext.Boolean, default=False, nullable=False)
# Foreign Keys
- condition_id = Base.Column(Base.Integer, Base.ForeignKey("condition.id"))
- node_1_id = Base.Column(Base.Integer, Base.ForeignKey("bool_operation.id"))
- node_2_id = Base.Column(Base.Integer, Base.ForeignKey("bool_operation.id"))
- alert_id = Base.Column(Base.Integer, Base.ForeignKey("alert.id"))
+ condition_id = ext.Column(ext.Integer, ext.ForeignKey("condition.id"))
+ node_1_id = ext.Column(ext.Integer, ext.ForeignKey("bool_operation.id"))
+ node_2_id = ext.Column(ext.Integer, ext.ForeignKey("bool_operation.id"))
+ alert_id = ext.Column(ext.Integer, ext.ForeignKey("alert.id"))
# Relationships
- condition = Base.relationship("Condition", back_populates="operations")
- node_1 = Base.relationship("BoolOperation", primaryjoin=("bool_operation.c.node_1_id==bool_operation.c.id"),
- remote_side="BoolOperation.id", backref=backref("father_1", uselist=False))
- node_2 = Base.relationship("BoolOperation", primaryjoin=("bool_operation.c.node_2_id==bool_operation.c.id"),
- remote_side="BoolOperation.id", backref=backref("father_2", uselist=False))
- alert = Base.relationship("Alert", back_populates="operations")
+ condition = ext.relationship("Condition", back_populates="operations")
+ node_1 = ext.relationship("BoolOperation", primaryjoin=("bool_operation.c.node_1_id==bool_operation.c.id"),
+ remote_side="BoolOperation.id", backref=backref("father_1", uselist=False))
+ node_2 = ext.relationship("BoolOperation", primaryjoin=("bool_operation.c.node_2_id==bool_operation.c.id"),
+ remote_side="BoolOperation.id", backref=backref("father_2", uselist=False))
+ alert = ext.relationship("Alert", back_populates="operations")
diff --git a/code/backend/nest_backend/database/tables/Composed.py b/code/backend/nest_backend/database/tables/Composed.py
index 98564de..9da3d0a 100644
--- a/code/backend/nest_backend/database/tables/Composed.py
+++ b/code/backend/nest_backend/database/tables/Composed.py
@@ -2,13 +2,13 @@
This module defines the Composed database class.
"""
-from ..base import Base
+from ..base import ext
-class Composed(Base.Model):
+class Composed(ext.Model):
__tablename__ = "composed"
- rid = Base.Column(Base.Integer, Base.ForeignKey("repository.id"), primary_key=True)
- snowflake = Base.Column(Base.String, Base.ForeignKey("tweet.snowflake"), primary_key=True)
+ rid = ext.Column(ext.Integer, ext.ForeignKey("repository.id"), primary_key=True)
+ snowflake = ext.Column(ext.String, ext.ForeignKey("tweet.snowflake"), primary_key=True)
# Relationships
- repository = Base.relationship("Repository", back_populates="tweets")
- tweet = Base.relationship("Tweet", back_populates="repositories")
\ No newline at end of file
+ repository = ext.relationship("Repository", back_populates="tweets")
+ tweet = ext.relationship("Tweet", back_populates="repositories")
\ No newline at end of file
diff --git a/code/backend/nest_backend/database/tables/Condition.py b/code/backend/nest_backend/database/tables/Condition.py
index 2c99193..ff15aba 100644
--- a/code/backend/nest_backend/database/tables/Condition.py
+++ b/code/backend/nest_backend/database/tables/Condition.py
@@ -2,21 +2,21 @@
This module defines the Condition database class.
"""
-from ..base import Base
+from ..base import ext
from .Enums import ConditionType
-class Condition(Base.Model):
+class Condition(ext.Model):
__tablename__ = "condition"
- id = Base.Column(Base.Integer, primary_key=True)
- type = Base.Column(Base.Enum(ConditionType), nullable=False)
- content = Base.Column(Base.String, nullable=False)
+ id = ext.Column(ext.Integer, primary_key=True)
+ type = ext.Column(ext.Enum(ConditionType), nullable=False)
+ content = ext.Column(ext.String, nullable=False)
# FK
- repository_id = Base.Column(Base.Integer, Base.ForeignKey("repository.id", ondelete="CASCADE"))
+ repository_id = ext.Column(ext.Integer, ext.ForeignKey("repository.id", ondelete="CASCADE"))
# Relationships
- repository = Base.relationship("Repository", back_populates="conditions", cascade="all, delete")
- tweets = Base.relationship("Contains", back_populates="condition")
- operations = Base.relationship("BoolOperation", back_populates="condition")
+ repository = ext.relationship("Repository", back_populates="conditions", cascade="all, delete")
+ tweets = ext.relationship("Contains", back_populates="condition")
+ operations = ext.relationship("BoolOperation", back_populates="condition")
def to_json(self):
return {
diff --git a/code/backend/nest_backend/database/tables/Contains.py b/code/backend/nest_backend/database/tables/Contains.py
index 7ddbaae..dbbaf50 100644
--- a/code/backend/nest_backend/database/tables/Contains.py
+++ b/code/backend/nest_backend/database/tables/Contains.py
@@ -2,13 +2,13 @@
This module defines the Contains database class.
"""
-from ..base import Base
+from ..base import ext
-class Contains(Base.Model):
+class Contains(ext.Model):
__tablename__ = "contains"
- cid = Base.Column(Base.Integer, Base.ForeignKey("condition.id"), primary_key=True)
- snowflake = Base.Column(Base.String, Base.ForeignKey("tweet.snowflake"), primary_key=True)
+ cid = ext.Column(ext.Integer, ext.ForeignKey("condition.id"), primary_key=True)
+ snowflake = ext.Column(ext.String, ext.ForeignKey("tweet.snowflake"), primary_key=True)
# Relationships
- condition = Base.relationship("Condition", back_populates="tweets")
- tweet = Base.relationship("Tweet", back_populates="conditions")
\ No newline at end of file
+ condition = ext.relationship("Condition", back_populates="tweets")
+ tweet = ext.relationship("Tweet", back_populates="conditions")
\ No newline at end of file
diff --git a/code/backend/nest_backend/database/tables/Notification.py b/code/backend/nest_backend/database/tables/Notification.py
index ae751b4..881be58 100644
--- a/code/backend/nest_backend/database/tables/Notification.py
+++ b/code/backend/nest_backend/database/tables/Notification.py
@@ -2,13 +2,14 @@
This module defines the Notification database class.
"""
-from ..base import Base
+from ..base import ext
-class Notification(Base.Model):
+
+class Notification(ext.Model):
__tablename__ = "notification"
- id = Base.Column(Base.Integer, primary_key=True)
- ora = Base.Column(Base.DateTime, nullable=False)
+ id = ext.Column(ext.Integer, primary_key=True)
+ ora = ext.Column(ext.DateTime, nullable=False)
# Foreign Key
- alert_id = Base.Column(Base.Integer, Base.ForeignKey("alert.id"), nullable=False)
+ alert_id = ext.Column(ext.Integer, ext.ForeignKey("alert.id"), nullable=False)
# Relationships
- alert = Base.relationship("Alert", back_populates="notifications")
\ No newline at end of file
+ alert = ext.relationship("Alert", back_populates="notifications")
diff --git a/code/backend/nest_backend/database/tables/Repository.py b/code/backend/nest_backend/database/tables/Repository.py
index 44015b3..06a3410 100644
--- a/code/backend/nest_backend/database/tables/Repository.py
+++ b/code/backend/nest_backend/database/tables/Repository.py
@@ -2,30 +2,30 @@
This module defines the :class:`.Repository` database class.
"""
-from ..base import Base
+from ..base import ext
from .Enums import ConditionMode
-class Repository(Base.Model):
+class Repository(ext.Model):
__tablename__ = "repository"
# Columns
- id = Base.Column(Base.Integer, primary_key=True)
- name = Base.Column(Base.String, nullable=False)
- start = Base.Column(Base.DateTime, nullable=True)
- end = Base.Column(Base.DateTime, nullable=True)
- is_active = Base.Column(Base.Boolean, nullable=False, default=False)
- evaluation_mode = Base.Column(Base.Enum(ConditionMode), default=ConditionMode.all_or.value)
+ id = ext.Column(ext.Integer, primary_key=True)
+ name = ext.Column(ext.String, nullable=False)
+ start = ext.Column(ext.DateTime, nullable=True)
+ end = ext.Column(ext.DateTime, nullable=True)
+ is_active = ext.Column(ext.Boolean, nullable=False, default=False)
+ evaluation_mode = ext.Column(ext.Enum(ConditionMode), default=ConditionMode.all_or.value)
# Foreign Keys
- owner_id = Base.Column(Base.String, Base.ForeignKey("user.email", ondelete="CASCADE"), nullable=False)
+ owner_id = ext.Column(ext.String, ext.ForeignKey("user.email", ondelete="CASCADE"), nullable=False)
# Relationships
- owner = Base.relationship("User", back_populates="owner_of")
- authorizations = Base.relationship("Authorization", back_populates="repository", cascade="all, delete")
- tweets = Base.relationship("Composed", back_populates="repository", cascade="all, delete")
- alerts = Base.relationship("Alert", back_populates="repository", cascade="all, delete")
- conditions = Base.relationship("Condition", back_populates="repository")
+ owner = ext.relationship("User", back_populates="owner_of")
+ authorizations = ext.relationship("Authorization", back_populates="repository", cascade="all, delete")
+ tweets = ext.relationship("Composed", back_populates="repository", cascade="all, delete")
+ alerts = ext.relationship("Alert", back_populates="repository", cascade="all, delete")
+ conditions = ext.relationship("Condition", back_populates="repository")
def to_json(self):
return {
diff --git a/code/backend/nest_backend/database/tables/Tweet.py b/code/backend/nest_backend/database/tables/Tweet.py
index 333875c..f858179 100644
--- a/code/backend/nest_backend/database/tables/Tweet.py
+++ b/code/backend/nest_backend/database/tables/Tweet.py
@@ -2,15 +2,15 @@
This module defines the Tweet database class.
"""
-from ..base import Base
+from ..base import ext
-class Tweet(Base.Model):
+class Tweet(ext.Model):
__tablename__ = "tweet"
- snowflake = Base.Column(Base.String, primary_key=True)
- content = Base.Column(Base.String)
- location = Base.Column(Base.String) # Todo: see if a dedicated class for locations is needed. This is likely.
- poster = Base.Column(Base.String) # Todo: see if a dedicated class for posters is needed.
+ snowflake = ext.Column(ext.String, primary_key=True)
+ content = ext.Column(ext.String)
+ location = ext.Column(ext.String) # Todo: see if a dedicated class for locations is needed. This is likely.
+ poster = ext.Column(ext.String) # Todo: see if a dedicated class for posters is needed.
# Relationships
- repositories = Base.relationship("Composed", back_populates="tweet", cascade="all, delete")
- conditions = Base.relationship("Contains", back_populates="tweet", cascade="all, delete")
\ No newline at end of file
+ repositories = ext.relationship("Composed", back_populates="tweet", cascade="all, delete")
+ conditions = ext.relationship("Contains", back_populates="tweet", cascade="all, delete")
diff --git a/code/backend/nest_backend/database/tables/User.py b/code/backend/nest_backend/database/tables/User.py
index f5695ad..c6bc0cf 100644
--- a/code/backend/nest_backend/database/tables/User.py
+++ b/code/backend/nest_backend/database/tables/User.py
@@ -2,18 +2,18 @@
This module defines the User database class.
"""
-from ..base import Base
+from ..base import ext
-class User(Base.Model):
+class User(ext.Model):
__tablename__ = "user"
- email = Base.Column(Base.String, primary_key=True)
- username = Base.Column(Base.String, nullable=False)
- password = Base.Column(Base.LargeBinary, nullable=False)
- isAdmin = Base.Column(Base.Boolean, default=False)
+ email = ext.Column(ext.String, primary_key=True)
+ username = ext.Column(ext.String, nullable=False)
+ password = ext.Column(ext.LargeBinary, nullable=False)
+ isAdmin = ext.Column(ext.Boolean, default=False)
# Relationships
- owner_of = Base.relationship("Repository", back_populates="owner", cascade="all, delete")
- authorizations = Base.relationship("Authorization", back_populates="user", cascade="all, delete")
+ owner_of = ext.relationship("Repository", back_populates="owner", cascade="all, delete")
+ authorizations = ext.relationship("Authorization", back_populates="user", cascade="all, delete")
def to_json(self):
return {'email': self.email, 'username': self.username, 'isAdmin': self.isAdmin}
diff --git a/code/backend/nest_backend/gestione.py b/code/backend/nest_backend/gestione.py
index 5164257..4e38949 100644
--- a/code/backend/nest_backend/gestione.py
+++ b/code/backend/nest_backend/gestione.py
@@ -9,7 +9,7 @@ from .database import *
import bcrypt
import functools
from flask_jwt_extended import get_jwt_identity
-from flask import request, jsonify
+from flask import jsonify
def authenticate(username, password):
diff --git a/code/backend/nest_backend/routes/repository/conditions/condition.py b/code/backend/nest_backend/routes/repository/conditions/condition.py
index 0c429dd..3754abb 100644
--- a/code/backend/nest_backend/routes/repository/conditions/condition.py
+++ b/code/backend/nest_backend/routes/repository/conditions/condition.py
@@ -123,9 +123,9 @@ def page_condition(cid):
if content := request.json.get("content"):
condition.content = content
- Base.session.commit()
+ ext.session.commit()
return json_success(condition.to_json()), 200
if request.method == "DELETE":
- Base.session.delete(condition)
- Base.session.commit()
+ ext.session.delete(condition)
+ ext.session.commit()
return json_success("Deleted."), 200
diff --git a/code/backend/nest_backend/routes/repository/conditions/repository_conditions.py b/code/backend/nest_backend/routes/repository/conditions/repository_conditions.py
index 9ce279f..5ed9e03 100644
--- a/code/backend/nest_backend/routes/repository/conditions/repository_conditions.py
+++ b/code/backend/nest_backend/routes/repository/conditions/repository_conditions.py
@@ -1,7 +1,8 @@
-from flask import render_template, abort, jsonify, request
-from nest_backend.database import *
+from flask import request
from flask_jwt_extended import jwt_required
-from nest_backend.gestione import *
+from nest_backend.gestione import repository_auth, json_error, json_success, ConditionType, Condition, Repository, \
+ find_user, get_jwt_identity
+from nest_backend.database import ext as extension_sqlalchemy
from flask_cors import cross_origin
@@ -91,7 +92,7 @@ def page_repository_conditions(rid):
return json_error("Missing `content` parameter."), 400
condition = Condition(content=content, type=type_, repository_id=rid)
- Base.session.add(condition)
- Base.session.commit()
+ extension_sqlalchemy.session.add(condition)
+ extension_sqlalchemy.session.commit()
return json_success(condition.to_json()), 200
diff --git a/code/backend/nest_backend/routes/repository/repositories.py b/code/backend/nest_backend/routes/repository/repositories.py
index 6e4417d..630c1bf 100644
--- a/code/backend/nest_backend/routes/repository/repositories.py
+++ b/code/backend/nest_backend/routes/repository/repositories.py
@@ -77,6 +77,6 @@ def page_repositories():
if not name:
return json_error("Missing one or more parameters"), 400
repository = Repository(name=name, owner_id=user.email)
- Base.session.add(repository)
- Base.session.commit()
+ ext.session.add(repository)
+ ext.session.commit()
return json_success(repository.to_json()), 200
diff --git a/code/backend/nest_backend/routes/repository/repository.py b/code/backend/nest_backend/routes/repository/repository.py
index 9f0abe2..f4b81a1 100644
--- a/code/backend/nest_backend/routes/repository/repository.py
+++ b/code/backend/nest_backend/routes/repository/repository.py
@@ -174,16 +174,16 @@ def page_repository(rid):
except KeyError:
return json_error("Unknown `type` specified."), 400
repository.evaluation_mode = evaluation_mode
- Base.session.commit()
+ ext.session.commit()
return json_success(repository.to_json()), 200
elif request.method == "DELETE":
if repository.owner_id != user.email and not user.isAdmin:
return json_error("You are not the owner of this repository."), 403
try:
- Base.session.delete(repository)
- Base.session.commit()
+ ext.session.delete(repository)
+ ext.session.commit()
except Exception as e:
- Base.session.rollback()
+ ext.session.rollback()
return json_error("Cant delete repository because of dependencies."), 500
return json_success("Success"), 200
elif request.method == "PUT":
@@ -200,8 +200,8 @@ def page_repository(rid):
# Delete no longer needed conditions.
for c in repository.conditions:
if c.id not in ids:
- Base.session.delete(c)
- Base.session.commit()
+ ext.session.delete(c)
+ ext.session.commit()
# Create brand new conditions
for c in request.json['conditions']:
if not c['id']:
@@ -210,6 +210,6 @@ def page_repository(rid):
type_ = ConditionType(type_)
except KeyError:
return json_error("Unknown `type` specified."), 400
- Base.session.add(Condition(type=type_, content=c['content'], repository_id=rid))
- Base.session.commit()
+ ext.session.add(Condition(type=type_, content=c['content'], repository_id=rid))
+ ext.session.commit()
return json_success(repository.to_json()), 200
diff --git a/code/backend/nest_backend/routes/users/user.py b/code/backend/nest_backend/routes/users/user.py
index 9ba4802..b8895f4 100644
--- a/code/backend/nest_backend/routes/users/user.py
+++ b/code/backend/nest_backend/routes/users/user.py
@@ -127,11 +127,11 @@ def page_user(email):
return json_error("User is not admin."), 403
if user == target:
return json_error("The user cant delete himself. Its a sin."), 406
- Base.session.delete(target)
+ ext.session.delete(target)
try:
- Base.session.commit()
+ ext.session.commit()
except Exception:
- Base.session.rollback()
+ ext.session.rollback()
return json_error("Could not delete the user."), 500
return json_success("The user has been deleted.")
elif request.method == "PATCH":
@@ -142,5 +142,5 @@ def page_user(email):
target.username = request.json.get("username")
if request.json.get("password"):
target.password = gen_password(request.json.get("password"))
- Base.session.commit()
+ ext.session.commit()
return json_success(target.to_json())
diff --git a/code/backend/nest_backend/routes/users/users.py b/code/backend/nest_backend/routes/users/users.py
index aa2c3e2..e8764c4 100644
--- a/code/backend/nest_backend/routes/users/users.py
+++ b/code/backend/nest_backend/routes/users/users.py
@@ -68,6 +68,6 @@ def page_users():
return json_error("User is not admin. Thou art not authorized."), 403
new_user = User(email=request.json.get("email"), password=gen_password(request.json.get("password")),
username=request.json.get("username"))
- Base.session.add(new_user)
- Base.session.commit()
+ ext.session.add(new_user)
+ ext.session.commit()
return json_success(new_user.to_json())
diff --git a/code/backend/nest_backend/swagger.py b/code/backend/nest_backend/swagger.py
index 15aab56..619aea7 100644
--- a/code/backend/nest_backend/swagger.py
+++ b/code/backend/nest_backend/swagger.py
@@ -2,8 +2,7 @@
from flask_swagger_ui import get_swaggerui_blueprint
-SWAGGER_URL = '/docs/'
-# FIXME: this will break if the website root isn't /, use url_for() instead!
+SWAGGER_URL = '/docs'
API_URL = "/docs/swagger.json"
# Call factory function to create our blueprint
diff --git a/code/backend/nest_backend/test/conftest.py b/code/backend/nest_backend/test/conftest.py
new file mode 100644
index 0000000..edf569d
--- /dev/null
+++ b/code/backend/nest_backend/test/conftest.py
@@ -0,0 +1,7 @@
+"""
+Pytest configuration file.
+
+Import global fixtures here.
+"""
+
+from fixtures.flask_client import flask_client
diff --git a/code/backend/nest_backend/test/fixtures/flask_client.py b/code/backend/nest_backend/test/fixtures/flask_client.py
new file mode 100644
index 0000000..e1022cc
--- /dev/null
+++ b/code/backend/nest_backend/test/fixtures/flask_client.py
@@ -0,0 +1,37 @@
+import pytest
+import uuid
+from nest_backend.app import app
+from nest_backend.gestione import gen_password
+from nest_backend.database import ext
+from nest_backend.database.tables import User
+
+
+@pytest.fixture(scope="package", autouse=True)
+def flask_client():
+ # Enter testing mode
+ app.config["TESTING"] = True
+
+ # Get environment variables
+ app.config.from_envvar("FLASK_CONFIG")
+
+ # Initialize database
+ with app.app_context():
+ # Use unique db schemas for each test session
+ uniq_schema = f"test_{uuid.uuid4()}"
+ ext.engine.execute(f"""CREATE SCHEMA "{uniq_schema}";""")
+ for table in ext.Model.metadata.tables.values():
+ table.schema = uniq_schema
+
+ ext.create_all(app=app)
+ if not User.query.filter_by(isAdmin=True).all():
+ ext.session.add(
+ User(email="admin@admin.com", password=gen_password("password"), username="admin", isAdmin=True))
+ ext.session.commit()
+
+ # Prepare test client
+ with app.test_client(use_cookies=False) as client:
+ yield client
+
+ # Teardown schema
+ with app.app_context():
+ ext.engine.execute(f"""DROP SCHEMA "{uniq_schema}" CASCADE;""")
diff --git a/code/backend/nest_backend/test/test_doa.py b/code/backend/nest_backend/test/test_doa.py
new file mode 100644
index 0000000..7180f65
--- /dev/null
+++ b/code/backend/nest_backend/test/test_doa.py
@@ -0,0 +1,9 @@
+import pytest
+from flask.testing import Client
+from nest_backend.test.fixtures import flask_client
+
+
+# noinspection PyShadowingNames
+def test_doa(flask_client: Client):
+ response = flask_client.get("/doa")
+ assert b"If you see this, the server is fine." in response.data
diff --git a/code/backend/nest_backend/tweet_explorer/__main__.py b/code/backend/nest_backend/tweet_explorer/__main__.py
index bf4c8c5..6fd0186 100644
--- a/code/backend/nest_backend/tweet_explorer/__main__.py
+++ b/code/backend/nest_backend/tweet_explorer/__main__.py
@@ -7,7 +7,7 @@ from nltk.corpus import stopwords
-Base.init_app(app=app)
+ext.init_app(app=app)
def authenticate():
c_k = "GEhtSyP9e98mzFeiOCSW0lvQX"
@@ -81,5 +81,5 @@ if __name__ == "__main__":
search_repo_conditions()
#print(stopwords.words('italian'))
with app.app_context():
- Base.create_all(app=app)
+ ext.create_all(app=app)
#start_exploring()
diff --git a/code/backend/nest_backend/test/login_test.py b/code/backend/old_unittest_tests/login_test.py
similarity index 100%
rename from code/backend/nest_backend/test/login_test.py
rename to code/backend/old_unittest_tests/login_test.py
diff --git a/code/backend/nest_backend/test/openapi_compliance_test.py b/code/backend/old_unittest_tests/openapi_compliance_test.py
similarity index 100%
rename from code/backend/nest_backend/test/openapi_compliance_test.py
rename to code/backend/old_unittest_tests/openapi_compliance_test.py
diff --git a/code/backend/nest_backend/test/repositories_test.py b/code/backend/old_unittest_tests/repositories_test.py
similarity index 100%
rename from code/backend/nest_backend/test/repositories_test.py
rename to code/backend/old_unittest_tests/repositories_test.py
diff --git a/code/backend/nest_backend/test/repository_conditions_test.py b/code/backend/old_unittest_tests/repository_conditions_test.py
similarity index 100%
rename from code/backend/nest_backend/test/repository_conditions_test.py
rename to code/backend/old_unittest_tests/repository_conditions_test.py
diff --git a/code/backend/nest_backend/test/repository_test.py b/code/backend/old_unittest_tests/repository_test.py
similarity index 100%
rename from code/backend/nest_backend/test/repository_test.py
rename to code/backend/old_unittest_tests/repository_test.py
diff --git a/code/backend/nest_backend/test/user_test.py b/code/backend/old_unittest_tests/user_test.py
similarity index 100%
rename from code/backend/nest_backend/test/user_test.py
rename to code/backend/old_unittest_tests/user_test.py
diff --git a/code/backend/nest_backend/test/users_test.py b/code/backend/old_unittest_tests/users_test.py
similarity index 100%
rename from code/backend/nest_backend/test/users_test.py
rename to code/backend/old_unittest_tests/users_test.py