Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend/feature/db models #19

Merged
merged 36 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
e7778ed
Basic db definition in flask
JibrilExe Feb 20, 2024
12c3641
main.py
JibrilExe Feb 20, 2024
ef77e3b
Defined official db model in SQLalchemy
JibrilExe Feb 21, 2024
dfc8da0
db model definitions in sqlalchemy
JibrilExe Feb 21, 2024
fbee136
flask_sqlalchemy in requirements
JibrilExe Feb 21, 2024
6ab22a4
foutje
JibrilExe Feb 21, 2024
71830fc
fixed db_uri
JibrilExe Feb 21, 2024
bf8d988
db initialization inside create_app
JibrilExe Feb 21, 2024
3e95b1f
db_uri and code clean
JibrilExe Feb 21, 2024
fe2ff03
import order fix
JibrilExe Feb 21, 2024
2035e4a
database uri added
warreprovoost Feb 21, 2024
a57c9f9
.env added to ignore
JibrilExe Feb 22, 2024
16a0d38
Merge branch 'backend/feature/db-models' of https://github.com/SELab-…
JibrilExe Feb 22, 2024
ba36b8a
Updated docs and .gitignore
JibrilExe Feb 22, 2024
a54e712
A first succesfull test for user model
JibrilExe Feb 22, 2024
3214d65
Doc cleanup and test function for courses and course_relations models…
JibrilExe Feb 23, 2024
70a1232
Project and submission test added
JibrilExe Feb 23, 2024
35656a6
added psycopg to dependencies
AronBuzogany Feb 23, 2024
e8d0c5f
dockerized tests to host postgres server
AronBuzogany Feb 23, 2024
bbbb9e7
created test script
AronBuzogany Feb 23, 2024
0802c3d
created test directory to test models
AronBuzogany Feb 23, 2024
88757ae
Merge branch 'backend/feature/db-models' of github.com:SELab-2/UGent-…
AronBuzogany Feb 23, 2024
4b443f7
waiting for postgres service to start before running test scripts and…
AronBuzogany Feb 23, 2024
aa2edcd
changed github action to run test script instead
AronBuzogany Feb 23, 2024
2312254
constructing pytests for models
JibrilExe Feb 23, 2024
7913d7a
running test script with sudo
AronBuzogany Feb 23, 2024
1dbabf2
adding bash to run script
AronBuzogany Feb 23, 2024
763ec84
Merge branch 'backend/feature/db-models' of https://github.com/SELab-…
JibrilExe Feb 23, 2024
b162def
fixing pytest
JibrilExe Feb 23, 2024
f91ce9d
pytests fixed, 1 warning left
JibrilExe Feb 23, 2024
ad43b13
warning fix
JibrilExe Feb 23, 2024
5c18e3d
fixed: run github action job on self-hosted runner
AronBuzogany Feb 23, 2024
43a9f37
fixed: no longer running test script with privileges
AronBuzogany Feb 23, 2024
05a655e
added: installing docker-compose to run our backend tests
AronBuzogany Feb 23, 2024
769e77e
fixed: no longer running compose install with permissions
AronBuzogany Feb 23, 2024
df0d112
using ubuntu-latest runner until docker-compose is installed on our s…
AronBuzogany Feb 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
working-directory: ./frontend
run: npm run lint
Backend-tests:
runs-on: self-hosted
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

Expand All @@ -50,10 +50,10 @@ jobs:
- name: Install dependencies
working-directory: ./backend
run: pip3 install -r requirements.txt && pip3 install -r dev-requirements.txt

- name: Running tests
working-directory: ./backend
run: pytest
run: bash ./run_tests.sh

- name: Run linting
working-directory: ./backend
Expand Down
3 changes: 2 additions & 1 deletion backend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ __pycache__/
htmlcov/
docs/_build/
dist/
venv/
venv/
.env
15 changes: 15 additions & 0 deletions backend/Dockerfile.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM python:3.9-slim

# Set the working directory
WORKDIR /app

# Copy the application code into the container
COPY . /app

# Install dependencies
RUN apt-get update
RUN apt-get install -y --no-install-recommends python3-pip
RUN pip3 install --no-cache-dir -r requirements.txt -r dev-requirements.txt

# Command to run the tests
CMD ["pytest"]
21 changes: 19 additions & 2 deletions backend/project/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,34 @@
This file is the base of the Flask API. It contains the basic structure of the API.
"""

from flask import Flask, jsonify
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from .endpoints.index import index_bp

db = SQLAlchemy()

def create_app():
"""
Create a Flask application instance.
Returns:
Flask -- A Flask application instance
"""
app = Flask(__name__)

app = Flask(__name__)
app.register_blueprint(index_bp)

return app

def create_app_with_db(db_uri:str):
"""
Initialize the database with the given uri
and connect it to the app made with create_app.
Parameters:
db_uri (str): The URI of the database to initialize.
Returns:
Flask -- A Flask application instance
"""
app = create_app()
app.config["SQLALCHEMY_DATABASE_URI"] = db_uri
db.init_app(app)
return app
7 changes: 5 additions & 2 deletions backend/project/__main__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
"""Main entry point for the application."""
from sys import path
from os import getenv
from dotenv import load_dotenv
from project import create_app_with_db

path.append(".")

if __name__ == "__main__":
from project import create_app
app = create_app()
load_dotenv()
app = create_app_with_db(getenv("DB_HOST"))
app.run(debug=True)
11 changes: 9 additions & 2 deletions backend/project/endpoints/index.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
"""Index api point"""
from flask import Blueprint
from flask_restful import Resource

index_bp = Blueprint("index", __name__)


class Index(Resource):
"""Api endpoint for the / route"""

def get(self):
"""Example of an api endpoint function that will respond to get requests made to /
return a json data structure with key Message and value Hello World!"""
return {"Message": "Hello World!"}

index_bp.add_url_rule("/", view_func=Index.as_view("index"))


index_bp.add_url_rule("/", view_func=Index.as_view("index"))
Empty file.
31 changes: 31 additions & 0 deletions backend/project/models/course_relations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""Models for relation between users and courses"""
# pylint: disable=too-few-public-methods

from sqlalchemy import Integer, Column, ForeignKey, PrimaryKeyConstraint, String
from project import db
from project.models.users import Users
from project.models.courses import Courses

class BaseCourseRelation(db.Model):
"""Base class for course relation models,
both course relation tables have a
course_id of the course to wich someone is related and
an uid of the related person"""

__abstract__ = True

course_id = Column(Integer, ForeignKey('courses.course_id'), nullable=False)
uid = Column(String(255), ForeignKey("users.uid"), nullable=False)
__table_args__ = (
PrimaryKeyConstraint("course_id", "uid"),
)

class CourseAdmins(BaseCourseRelation):
"""Admin to course relation model"""

__tablename__ = "course_admins"

class CourseStudents(BaseCourseRelation):
"""Student to course relation model"""

__tablename__ = "course_students"
15 changes: 15 additions & 0 deletions backend/project/models/courses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""The Courses model"""
# pylint: disable=too-few-public-methods
from sqlalchemy import Integer, Column, ForeignKey, String
from project import db
from project.models.users import Users

class Courses(db.Model):
"""This class described the courses table,
a course has an id, name, optional ufora id and the teacher that created it"""

__tablename__ = "courses"
course_id = Column(Integer, primary_key=True)
name = Column(String(50), nullable=False)
ufora_id = Column(String(50), nullable=True)
teacher = Column(String(255), ForeignKey("users.uid"), nullable=False)
28 changes: 28 additions & 0 deletions backend/project/models/projects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""Model for projects"""
# pylint: disable=too-few-public-methods
from sqlalchemy import ARRAY, Boolean, Column, DateTime, ForeignKey, Integer, String, Text
from project import db
from project.models.courses import Courses

class Projects(db.Model):
"""This class describes the projects table,
a projects has an id, a title, a description,
an optional assignment file that can contain more explanation of the projects,
an optional deadline,
the course id of the course to which the project belongs,
visible for students variable so a teacher can decide if the students can see it yet,
archieved var so we can implement the archiving functionality,
a test path,script name and regex experssions for automated testing"""

__tablename__ = "projects"
project_id = Column(Integer, primary_key=True)
title = Column(String(50), nullable=False, unique=False)
descriptions = Column(Text, nullable=False)
assignment_file = Column(String(50))
deadline = Column(DateTime(timezone=True))
course_id = Column(Integer, ForeignKey("courses.course_id"), nullable=False)
visible_for_students = Column(Boolean, nullable=False)
archieved = Column(Boolean, nullable=False)
test_path = Column(String(50))
script_name = Column(String(50))
regex_expressions = Column(ARRAY(String(50)))
25 changes: 25 additions & 0 deletions backend/project/models/submissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""Model for submissions"""
# pylint: disable=too-few-public-methods
from sqlalchemy import Column,String,ForeignKey,Integer,CheckConstraint,DateTime,Boolean
from project import db
from project.models.users import Users

class Submissions(db.Model):
"""This class describes the submissions table,
submissions can be made to a project, a submission has
and id, a uid from the user that uploaded it,
the project id of the related project,
an optional grading,
the submission time,
submission path,
and finally the submission status
so we can easily present in a list which submission succeeded the automated checks"""

__tablename__ = "submissions"
submission_id = Column(Integer, nullable=False, primary_key=True)
uid = Column(String(255), ForeignKey("users.uid"), nullable=False)
project_id = Column(Integer, ForeignKey("projects.project_id"), nullable=False)
grading = Column(Integer, CheckConstraint("grading >= 0 AND grading <= 20"))
submission_time = Column(DateTime(timezone=True), nullable=False)
submission_path = Column(String(50), nullable=False)
submission_status = Column(Boolean, nullable=False)
16 changes: 16 additions & 0 deletions backend/project/models/users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Model for users"""
# pylint: disable=too-few-public-methods
from sqlalchemy import Boolean, Column, String
from project import db


class Users(db.Model):
"""This class defines the users table,
a user has an uid,
is_teacher and is_admin booleans because a user
can be either a student,admin or teacher"""

__tablename__ = "users"
uid = Column(String(255), primary_key=True)
is_teacher = Column(Boolean)
is_admin = Column(Boolean)
3 changes: 3 additions & 0 deletions backend/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
flask
flask-restful
flask-sqlalchemy
python-dotenv
psycopg2-binary
20 changes: 20 additions & 0 deletions backend/run_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/bash

# Run Docker Compose to build and start the services, and capture the exit code from the test runner service
docker-compose -f tests.yaml up --build --exit-code-from test-runner

# Store the exit code in a variable
exit_code=$?

# After the tests are finished, stop and remove the containers
docker-compose -f tests.yaml down

# Check the exit code to determine whether the tests passed or failed
if [ $exit_code -eq 0 ]; then
echo "Tests passed!"
else
echo "Tests failed!"
fi

# Exit with the same exit code as the test runner service
exit $exit_code
31 changes: 31 additions & 0 deletions backend/tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
version: '3.8'

services:
postgres:
image: postgres:latest
environment:
POSTGRES_USER: test_user
POSTGRES_PASSWORD: test_password
POSTGRES_DB: test_database
healthcheck:
test: ["CMD-SHELL", "pg_isready -U test_user -d test_database"]
interval: 5s
timeout: 3s
retries: 3
start_period: 5s

test-runner:
build:
context: .
dockerfile: Dockerfile.test
depends_on:
postgres:
condition: service_healthy
environment:
POSTGRES_HOST: postgres # Use the service name defined in Docker Compose
POSTGRES_USER: test_user
POSTGRES_PASSWORD: test_password
POSTGRES_DB: test_database
volumes:
- .:/app
command: ["pytest"]
Loading
Loading