Skip to content
This repository has been archived by the owner on Jan 22, 2025. It is now read-only.

Backend/feature/projects endpoint #31

Merged
merged 83 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from 80 commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
91e6dd6
route /projects/ added
Gerwoud Feb 24, 2024
de332a7
added functionality for parsing the dict once the query is ran
Gerwoud Feb 25, 2024
b032e39
display json data at endpoint instead of dummy data
Gerwoud Feb 25, 2024
9f5e4f3
detail endpoint created
Gerwoud Feb 25, 2024
2dc1340
post functionality for projects
Gerwoud Feb 25, 2024
aed5d38
remove functionality for projects, only works with updated sql script
Gerwoud Feb 25, 2024
eeb38b5
added right exit codes
Gerwoud Feb 25, 2024
e1125c2
code reformat
Gerwoud Feb 25, 2024
6475ea5
added 404 page if you're trying to remove a non-existing project
Gerwoud Feb 25, 2024
c6fb5eb
404 function made
Gerwoud Feb 25, 2024
3399e6d
added basic add and remove test for project
Gerwoud Feb 25, 2024
100572a
wrote extra test for just getting the users
Gerwoud Feb 25, 2024
aa0269d
added put for a project
Gerwoud Feb 25, 2024
792ddd9
added test for put
Gerwoud Feb 25, 2024
28b82fa
testing working
Gerwoud Feb 25, 2024
5db9ded
added comments to project_test project and projects_detail
Gerwoud Feb 25, 2024
8bd67ae
added pytest fixture
Gerwoud Feb 26, 2024
3ec266d
added right dummy data for fixtures
Gerwoud Feb 26, 2024
f9295fc
linter fixes, project endpoint files now score 10/10
Gerwoud Feb 26, 2024
3cedf3e
more linter fixes
Gerwoud Feb 26, 2024
7206efa
linter import order fix
Gerwoud Feb 26, 2024
b3a53bd
added ingores for linter
Gerwoud Feb 26, 2024
5be4c0a
more linter
Gerwoud Feb 26, 2024
061dbd8
renamed is_existing_project function
Gerwoud Feb 26, 2024
5b544f9
changed arguments of get functions to not use **kwargs anymore
Gerwoud Feb 26, 2024
9f5033a
fixed jsonify issue for response
Gerwoud Feb 26, 2024
dacc4f6
added try catch blocks and changed Message to message
Gerwoud Feb 26, 2024
672aea8
applied jsonify on projects
Gerwoud Feb 26, 2024
167efd3
removed print statement
Gerwoud Feb 26, 2024
deaaebb
removed unnecessary session.commit
Gerwoud Feb 26, 2024
794a797
test if tests still work on git
Gerwoud Feb 26, 2024
3b3792f
added the commit messages again
Gerwoud Feb 26, 2024
af7d44d
better tests, pray for git tests
Gerwoud Feb 27, 2024
a9ade40
fixed TODO of path.append('.')
Gerwoud Feb 27, 2024
13554fa
fixed code duplication for parser (hopefully)
Gerwoud Feb 27, 2024
f41cd84
fixed non existing fields in testing bug
Gerwoud Feb 27, 2024
e27d270
fixed parse code duplication
Gerwoud Feb 27, 2024
56af6bc
linter fixes
Gerwoud Feb 27, 2024
f908303
more linter fixes
Gerwoud Feb 27, 2024
d10fcf6
removed linter disables
Gerwoud Feb 28, 2024
054f90d
fixed linter import order
Gerwoud Feb 28, 2024
dd0f7fe
removed unused imports
Gerwoud Feb 28, 2024
0b58bab
removed unused comment
Gerwoud Feb 28, 2024
0e73d09
removed print statement and unused comments
Gerwoud Feb 28, 2024
3b8aee3
changed put to patch
Gerwoud Feb 28, 2024
42f20f7
fixed wrong status code
Gerwoud Feb 28, 2024
d16b10f
removed useless comment
Gerwoud Feb 28, 2024
60ae98b
added message field to return json
Gerwoud Feb 28, 2024
ae817d6
removed all fields from /projects get except project_id, title and de…
Gerwoud Feb 28, 2024
f6d2157
added try catch block to post of projects endpoint
Gerwoud Feb 28, 2024
7a397f1
removed print statements
Gerwoud Feb 28, 2024
8a1f467
removed commented code
Gerwoud Feb 28, 2024
d5b07bb
changed the get from tuple to a json
Gerwoud Feb 28, 2024
de7a616
linter fix
Gerwoud Feb 28, 2024
7648d81
edited OpenAPI_Object
Gerwoud Feb 29, 2024
c2dfb3f
linter fix
Gerwoud Feb 29, 2024
1d23226
fixed no module named project error
Gerwoud Feb 29, 2024
320030e
added file sessionmaker for code duplication purposes
Gerwoud Feb 29, 2024
41400af
Thanks for this linter for helping me improve my code :)
Gerwoud Feb 29, 2024
04d8976
added root point conftest.py
Gerwoud Feb 29, 2024
d74f764
added root point conftest.py
Gerwoud Mar 1, 2024
a72ef10
added try catch block
Gerwoud Mar 1, 2024
15fa782
removed commented code
Gerwoud Mar 2, 2024
85cce0b
removed print statements
Gerwoud Mar 2, 2024
87255c1
return whole URL of project instead of just the id
Gerwoud Mar 2, 2024
c994225
small linter fixes :)
Gerwoud Mar 2, 2024
4b667bf
load the env variable at the start of file as constant
Gerwoud Mar 2, 2024
ec323bb
paths attribute should be an object, not a list
AronBuzogany Mar 2, 2024
09c2117
patched patch function
Gerwoud Mar 3, 2024
f992a55
fixed typo in patch
Gerwoud Mar 3, 2024
81b2740
fixed json return in 500 patch message
Gerwoud Mar 3, 2024
c68b01a
fixed url returns
Gerwoud Mar 3, 2024
3cfa66f
fix: wrapped project json with seperate message
Gerwoud Mar 3, 2024
eabcc85
fix: keyerror on tests with change of return json in projects POST me…
Gerwoud Mar 3, 2024
c90dfac
fix: return good json representation
Gerwoud Mar 3, 2024
604cd92
fixed typos in OpenAPI_Object.json
Gerwoud Mar 3, 2024
97f0866
fixed typos in project_detail
Gerwoud Mar 3, 2024
b89f5b3
fixed typos in model Projects
Gerwoud Mar 3, 2024
5c2b718
typo fixed
Gerwoud Mar 4, 2024
12b1a29
route -> routes
Gerwoud Mar 4, 2024
4425192
Merge branch 'development' into backend/feature/projects-endpoint
Gerwoud Mar 5, 2024
cdd94d2
fix: naming of new database schemes
Gerwoud Mar 5, 2024
e055344
i <3 linters
Gerwoud Mar 5, 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
5 changes: 3 additions & 2 deletions backend/project/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
"""

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from .db_in import db
from .endpoints.index.index import index_bp
from .endpoints.projects.project_endpoint import project_bp

db = SQLAlchemy()

def create_app():
"""
Expand All @@ -17,6 +17,7 @@ def create_app():

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

return app

Expand Down
5 changes: 3 additions & 2 deletions backend/project/__main__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
"""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
from .sessionmaker import url

path.append(".")

if __name__ == "__main__":
load_dotenv()
app = create_app_with_db(getenv("DB_HOST"))

app = create_app_with_db(url)
app.run(debug=True)
5 changes: 5 additions & 0 deletions backend/project/db_in.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""db initialization"""
from flask_sqlalchemy import SQLAlchemy


db = SQLAlchemy()
189 changes: 188 additions & 1 deletion backend/project/endpoints/index/OpenAPI_Object.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,192 @@
}
]
},
"paths": []
"paths": {
"/projects": {
"get": {
"description": "Returns all projects from the database that the user has access to",
"responses": {
"200": {
"description": "A list of projects",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"project_id": {
"type": "int"
},
"descriptions": {
"type": "string"
},
"title": {
"type": "string"
}
}
}
}
}
}
}
}
},
"post": {
"description": "Upload a new project",
"responses": {
"201": {
"description": "Uploaded a new project succesfully",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": "string"
}
}
}
}
}
}
}
},
"/projects/{id}": {
"get": {
"description": "Return a project with corresponding id",
"responses": {
"200": {
"description": "A project with corresponding id",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"archieved": {
"type": "bool"
},
"assignment_file": {
"type": "string"
},
"course_id": {
"type": "int"
},
"deadline": {
"type": "date"
},
"descriptions": {
"type": "array",
"items": {
"description": "string"
}
},
"project_id": {
"type": "int"
},
"regex_expressions": {
"type": "array",
"items": {
"regex": "string"
}
},
"script_name": {
"type": "string"
},
"test_path": {
"type": "string"
},
"title": {
"type": "string"
},
"visible_for_students": {
"type": "bool"
}
}
}
}
}
},
"404": {
"description": "An id that doesn't correspond to an existing project",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
}
}
}
}
}
},
"patch": {
"description": "Patch certain fields of a project",
"responses": {
"200": {
"description": "Patched a project succesfully",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": "string"
}
}
}
}
},
"404": {
"description": "Tried to patch a project that is not present",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
}
}
}
}
}
},
"delete": {
"description": "Delete a project with given id",
"responses": {
"200": {
"description": "Removed a project succesfully",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": "string"
}
}
}
}
},
"404": {
"description": "Tried to remove a project that is not present",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": "string"
}
}
}
}
}
}
}
}
}
}
31 changes: 31 additions & 0 deletions backend/project/endpoints/projects/endpoint_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
Parser for the argument when posting or patching a project
"""

from flask_restful import reqparse

parser = reqparse.RequestParser()
parser.add_argument('title', type=str, help='Projects title')
parser.add_argument('descriptions', type=str, help='Projects description')
parser.add_argument('assignment_file', type=str, help='Projects assignment file')
parser.add_argument("deadline", type=str, help='Projects deadline')
parser.add_argument("course_id", type=str, help='Projects course_id')
parser.add_argument("visible_for_students", type=bool, help='Projects visibility for students')
parser.add_argument("archieved", type=bool, help='Projects')
parser.add_argument("test_path", type=str, help='Projects test path')
parser.add_argument("script_name", type=str, help='Projects test script path')
parser.add_argument("regex_expressions", type=str, help='Projects regex expressions')


def parse_project_params():
"""
Return a dict of every non None value in the param
"""
args = parser.parse_args()
result_dict = {}

for key, value in args.items():
if value is not None:
result_dict[key] = value

return result_dict
117 changes: 117 additions & 0 deletions backend/project/endpoints/projects/project_detail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
"""
Module for project details page
for example /projects/1 if the project id of
the corresponding project is 1
"""
from os import getenv
from dotenv import load_dotenv

from flask import jsonify
from flask_restful import Resource, abort
from sqlalchemy import exc
from project.endpoints.projects.endpoint_parser import parse_project_params

from project import db
from project.models.projects import Projects

load_dotenv()
API_URL = getenv('API_HOST')

class ProjectDetail(Resource):
"""
Class for projects/id endpoints
Inherits from flask_restful.Resource class
for implementing get, delete and put methods
"""

def abort_if_not_present(self, project):
"""
Check if the project exists in the database
and if not abort the request and give back a 404 not found
"""
if project is None:
abort(404)

def get(self, project_id):
"""
Get method for listing a specific project
filtered by id of that specific project
the id fetched from the url with the reaparse
"""

try:
# fetch the project with the id that is specified in the url
project = Projects.query.filter_by(project_id=project_id).first()
self.abort_if_not_present(project)

# return the fetched project and return 200 OK status
return {
"data": jsonify(project).json,
"url": f"{API_URL}/projects/{project_id}",
"message": "Got project successfully"
}, 200
except exc.SQLAlchemyError:
return {
"message": "Internal server error",
"url": f"{API_URL}/projects/{project_id}"
}, 500

def patch(self, project_id):
"""
Update method for updating a specific project
filtered by id of that specific project
"""

# get the project that need to be edited
project = Projects.query.filter_by(project_id=project_id).first()

# check which values are not None in the dict
# if it is not None it needs to be modified in the database

# commit the changes and return the 200 OK code if it succeeds, else 500
try:
var_dict = parse_project_params()
for key, value in var_dict.items():
setattr(project, key, value)
Gerwoud marked this conversation as resolved.
Show resolved Hide resolved
db.session.commit()
# get the updated version
return {
"message": f"Succesfully changed project with id: {id}",
"url": f"{API_URL}/projects/{id}",
"data": project
}, 200
except exc.SQLAlchemyError:
db.session.rollback()
return {
"message": f"Something unexpected happenend when trying to edit project {id}",
"url": f"{API_URL}/projects/{id}"
}, 500

def delete(self, project_id):
"""
Delete a project and all of its submissions in cascade
done by project id
"""

# fetch the project that needs to be removed
deleted_project = Projects.query.filter_by(project_id=project_id).first()

# check if its an existing one
self.abort_if_not_present(deleted_project)

# if it exists delete it and commit the changes in the database
try:
db.session.delete(deleted_project)
db.session.commit()

# return 200 if content is deleted succesfully
return {
"message": f"Project with id: {id} deleted successfully",
"url": f"{API_URL}/projects/{id} deleted successfully!",
"data": deleted_project
}, 200
except exc.SQLAlchemyError:
return {
"message": f"Something unexpected happened when removing project {project_id}",
"url": f"{API_URL}/projects/{id}"
}, 500
Loading