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

Commit

Permalink
Merge pull request #30 from SELab-2/backend/feature/user-endpoint
Browse files Browse the repository at this point in the history
Backend/feature/user endpoint
  • Loading branch information
Vucis authored Mar 9, 2024
2 parents a394736 + 4f3fbdb commit f2dd5da
Show file tree
Hide file tree
Showing 10 changed files with 517 additions and 10 deletions.
1 change: 1 addition & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ docs/_build/
dist/
venv/
.env
.run/
7 changes: 5 additions & 2 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
FROM python:3.9
RUN mkdir /app
WORKDIR /app/
WORKDIR /app
ADD ./project /app/
COPY requirements.txt /app/requirements.txt
RUN pip3 install -r requirements.txt
CMD ["python3", "/app"]
COPY . /app
ENTRYPOINT ["python"]
CMD ["__main__.py"]
2 changes: 2 additions & 0 deletions backend/project/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from .endpoints.index.index import index_bp
from .endpoints.projects.project_endpoint import project_bp
from .endpoints.courses.courses_config import courses_bp
from .endpoints.users import users_bp


def create_app():
Expand All @@ -20,6 +21,7 @@ def create_app():
app.register_blueprint(index_bp)
app.register_blueprint(project_bp)
app.register_blueprint(courses_bp)
app.register_blueprint(users_bp)

return app

Expand Down
184 changes: 184 additions & 0 deletions backend/project/endpoints/index/OpenAPI_Object.json
Original file line number Diff line number Diff line change
Expand Up @@ -1357,7 +1357,191 @@
}
}
}
},
"/users": {
"get": {
"summary": "Get all users",
"responses": {
"200": {
"description": "A list of users",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"uid": {
"type": "string"
},
"is_teacher": {
"type": "boolean"
},
"is_admin": {
"type": "boolean"
}
},
"required": ["uid", "is_teacher", "is_admin"]
}
}
}
}
}}},
"post": {
"summary": "Create a new user",
"requestBody": {
"required": true,
"content":{
"application/json": {
"schema": {
"type": "object",
"properties": {
"uid": {
"type": "string"
},
"is_teacher": {
"type": "boolean"
},
"is_admin": {
"type": "boolean"
}
},
"required": ["uid", "is_teacher", "is_admin"]
}
}
}
},
"responses": {
"201": {
"description": "User created successfully"
},
"400": {
"description": "Invalid request data"
},
"415": {
"description": "Unsupported Media Type. Expected JSON."
},
"500": {
"description": "An error occurred while creating the user"
}
}

},
"/users/{user_id}": {
"get": {
"summary": "Get a user by ID",
"parameters": [
{
"name": "user_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "A user",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"uid": {
"type": "string"
},
"is_teacher": {
"type": "boolean"
},
"is_admin": {
"type": "boolean"
}
},
"required": ["uid", "is_teacher", "is_admin"]
}
}
}
},
"404": {
"description": "User not found"
}
}
},
"patch": {
"summary": "Update a user's information",
"parameters": [
{
"name": "user_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"is_teacher": {
"type": "boolean"
},
"is_admin": {
"type": "boolean"
}
},
"required": ["is_teacher", "is_admin"]
}
}
}
},
"responses": {
"200": {
"description": "User updated successfully"
},
"404": {
"description": "User not found"
},
"415": {
"description": "Unsupported Media Type. Expected JSON."
},
"500": {
"description": "An error occurred while patching the user"
}
}
},
"delete": {
"summary": "Delete a user",
"parameters": [
{
"name": "user_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "User deleted successfully"
},
"404": {
"description": "User not found"
},
"500": {
"description": "An error occurred while deleting the user"
}
}
}
}
}

}


}
155 changes: 155 additions & 0 deletions backend/project/endpoints/users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
"""Users api endpoint"""
from os import getenv

from dotenv import load_dotenv
from flask import Blueprint, request, jsonify
from flask_restful import Resource, Api
from sqlalchemy.exc import SQLAlchemyError

from project import db
from project.models.users import User as userModel

users_bp = Blueprint("users", __name__)
users_api = Api(users_bp)

load_dotenv()
API_URL = getenv("API_HOST")

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

def get(self):
"""
This function will respond to get requests made to /users.
It should return all users from the database.
"""
try:
query = userModel.query
is_teacher = request.args.get('is_teacher')
is_admin = request.args.get('is_admin')

if is_teacher is not None:
query = query.filter(userModel.is_teacher == (is_teacher.lower() == 'true'))

if is_admin is not None:
query = query.filter(userModel.is_admin == (is_admin.lower() == 'true'))

users = query.all()

result = jsonify({"message": "Queried all users", "data": users,
"url":f"{API_URL}/users", "status_code": 200})
return result
except SQLAlchemyError:
return {"message": "An error occurred while fetching the users",
"url": f"{API_URL}/users"}, 500

def post(self):
"""
This function will respond to post requests made to /users.
It should create a new user and return a success message.
"""
uid = request.json.get('uid')
is_teacher = request.json.get('is_teacher')
is_admin = request.json.get('is_admin')

if is_teacher is None or is_admin is None or uid is None:
return {
"message": "Invalid request data!",
"correct_format": {
"uid": "User ID (string)",
"is_teacher": "Teacher status (boolean)",
"is_admin": "Admin status (boolean)"
},"url": f"{API_URL}/users"
}, 400
try:
user = db.session.get(userModel, uid)
if user is not None:
# bad request, error code could be 409 but is rarely used
return {"message": f"User {uid} already exists"}, 400
# Code to create a new user in the database using the uid, is_teacher, and is_admin
new_user = userModel(uid=uid, is_teacher=is_teacher, is_admin=is_admin)
db.session.add(new_user)
db.session.commit()
return jsonify({"message": "User created successfully!",
"data": user, "url": f"{API_URL}/users/{user.uid}", "status_code": 201})

except SQLAlchemyError:
# every exception should result in a rollback
db.session.rollback()
return {"message": "An error occurred while creating the user",
"url": f"{API_URL}/users"}, 500



class User(Resource):
"""Api endpoint for the /users/{user_id} route"""

def get(self, user_id):
"""
This function will respond to GET requests made to /users/<user_id>.
It should return the user with the given user_id from the database.
"""
try:
user = db.session.get(userModel, user_id)
if user is None:
return {"message": "User not found!","url": f"{API_URL}/users"}, 404

return jsonify({"message": "User queried","data":user,
"url": f"{API_URL}/users/{user.uid}", "status_code": 200})
except SQLAlchemyError:
return {"message": "An error occurred while fetching the user",
"url": f"{API_URL}/users"}, 500

def patch(self, user_id):
"""
Update the user's information.
Returns:
dict: A dictionary containing the message indicating the success
or failure of the update.
"""
is_teacher = request.json.get('is_teacher')
is_admin = request.json.get('is_admin')
try:
user = db.session.get(userModel, user_id)
if user is None:
return {"message": "User not found!","url": f"{API_URL}/users"}, 404

if is_teacher is not None:
user.is_teacher = is_teacher
if is_admin is not None:
user.is_admin = is_admin

# Save the changes to the database
db.session.commit()
return jsonify({"message": "User updated successfully!",
"data": user, "url": f"{API_URL}/users/{user.uid}", "status_code": 200})
except SQLAlchemyError:
# every exception should result in a rollback
db.session.rollback()
return {"message": "An error occurred while patching the user",
"url": f"{API_URL}/users"}, 500


def delete(self, user_id):
"""
This function will respond to DELETE requests made to /users/<user_id>.
It should delete the user with the given user_id from the database.
"""
try:
user = db.session.get(userModel, user_id)
if user is None:
return {"message": "User not found!", "url": f"{API_URL}/users"}, 404

db.session.delete(user)
db.session.commit()
return {"message": "User deleted successfully!", "url": f"{API_URL}/users"}, 200
except SQLAlchemyError:
# every exception should result in a rollback
db.session.rollback()
return {"message": "An error occurred while deleting the user",
"url": f"{API_URL}/users"}, 500


users_api.add_resource(Users, "/users")
users_api.add_resource(User, "/users/<string:user_id>")
Loading

0 comments on commit f2dd5da

Please sign in to comment.