Skip to content

Commit

Permalink
adding the basic structures and functionalities for the user frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
ooemperor committed Dec 2, 2023
1 parent 84516e5 commit 706c504
Show file tree
Hide file tree
Showing 25 changed files with 674 additions and 40 deletions.
20 changes: 16 additions & 4 deletions codeGrader/backend/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
from flask import Flask, request, send_file
from codeGrader.backend.config import config
from codeGrader.backend.api.handlers import UserHandler, ProfileHandler, AdminUserHandler, SubjectHandler, \
ExerciseHandler, TaskHandler, FileHandler, SubmissionHandler, TestCaseHandler, AdminUserLoginHandler, authentication, AdminTypeHandler
ExerciseHandler, TaskHandler, FileHandler, SubmissionHandler, TestCaseHandler, AdminUserLoginHandler, \
authentication, AdminTypeHandler, UserLoginHandler
from codeGrader.backend.api.logger import Logger
import logging

Expand Down Expand Up @@ -38,17 +39,28 @@ def home():
return response


@app.route("/login", methods=['POST'])
def login():
@app.route("/admin/login", methods=['POST'])
def admin_login():
"""
Login for a provided user
Login for a provided Admin User
"""
data = request.get_json()
username = data["username"]
password = data["password"]
return AdminUserLoginHandler().login(username, password)


@app.route("/user/login", methods=['POST'])
def user_login():
"""
Login for a provided user
"""
data = request.get_json()
username = data["username"]
password = data["password"]
return UserLoginHandler().login(username, password)


@app.route("/user/<int:id_>", methods=['GET', 'PUT', 'DELETE'])
def user(id_: int):
"""
Expand Down
42 changes: 37 additions & 5 deletions codeGrader/backend/api/handlers/LoginHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,27 @@

from .Base import BaseHandler
from codeGrader.backend.db.Admin import AdminUser
from codeGrader.backend.db.User import User
from .Exceptions import AuthorizationException
from sqlalchemy import select
import hashlib


class AdminUserLoginHandler(BaseHandler):
class LoginHandler(BaseHandler):
"""
Class for the login Handler
Specific User Login Handlers will then inherit from this class.
Used by the frontend to check the login status of a AdminUser.
"""

# instance variables that are not set in this parent class

def __init__(self):
"""
Constructor of the
Constructor of the LoginHandler Partent Class.
Uses the Basehandler
"""
super().__init__()
self.dbClass = AdminUser

def login(self, username: str, password: str):
"""
Expand All @@ -36,9 +40,9 @@ def login(self, username: str, password: str):
"""
try:
with self.sql_session.session.begin() as session:
adminUser_id = session.scalars(select(AdminUser.id).where(AdminUser.username == username)).one()
user_id = session.scalars(select(self.dbClass.id).where(self.dbClass.username == username)).one()

user = self.sql_session.get_object(AdminUser, adminUser_id)
user = self.sql_session.get_object(self.dbClass, user_id)
password = password.encode('utf-8')
password = hashlib.sha256(password)
password = password.hexdigest()
Expand All @@ -50,3 +54,31 @@ def login(self, username: str, password: str):
except sqlalchemy.exc.NoResultFound as err:
# incase we do not find a user with the given credentials
return self.create_generic_response('GET', "Authentication failed for User")


class AdminUserLoginHandler(LoginHandler):
"""
Class for the login Handler
Used by the frontend to check the login status of a AdminUser.
"""

def __init__(self):
"""
Constructor of the AdminUserLoginHandler
"""
super().__init__()
self.dbClass = AdminUser


class UserLoginHandler(LoginHandler):
"""
Class for the Login Handler of a normal user.
Used in frontend to check the login status of a normal User
"""

def __init__(self):
"""
Constructor of the
"""
super().__init__()
self.dbClass = User
4 changes: 2 additions & 2 deletions codeGrader/backend/api/handlers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
from .Exceptions import AuthorizationFail
from .Authentication import authentication
from .TestCase import TestCaseHandler
from .LoginHandler import AdminUserLoginHandler
from .LoginHandler import AdminUserLoginHandler, UserLoginHandler

__all__ = ["BaseHandler", "UserHandler", "AdminUserHandler", "ProfileHandler", "SubjectHandler", "TaskHandler",
"ExerciseHandler", "FileHandler", "SubmissionHandler", "authentication", "AuthorizationFail",
"TestCaseHandler", "AdminUserLoginHandler", "AdminTypeHandler"]
"TestCaseHandler", "AdminUserLoginHandler", "AdminTypeHandler", "UserLoginHandler"]
3 changes: 1 addition & 2 deletions codeGrader/frontend/admin/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
@author: mkaiser
@version: 1.0
"""
import flask_login
from flask import Flask, request, render_template, url_for, redirect, flash, session
from flask_login import LoginManager, login_user, login_required, logout_user
from codeGrader.frontend.config import config
Expand All @@ -27,7 +26,7 @@
def adminUser_login(admin_id):
"""
User load of the login_manager
Returns the frontend represenation of the user
Returns the frontend represenation of the admin user
@param admin_id: the id of the user
@type admin_id: int
@return: The frontend User Object
Expand Down
7 changes: 4 additions & 3 deletions codeGrader/frontend/admin/handlers/Base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

from codeGrader.frontend.config import config
from codeGrader.frontend.util import ApiHandler
from flask import request


class BaseHandler:
Expand All @@ -22,12 +21,14 @@ def __init__(self, requests: flask.Request):
self.request = requests
self.api = ApiHandler(config.apiHost, config.apiAuthentication, config.apiToken)

def get_value(self, value: str):
def get_value(self, value: str, default: str = ""):
"""
Get a value from the form that has been provided by the user identified by a given key.
The key is defined by the name in the html form
@param value: Name of the object in the request
@type value: str
@param default: The default value that shall be returned when no value is found. Optional parameter
@type default: str
@return: The value of the requested key
@rtype: str
"""
Expand All @@ -39,4 +40,4 @@ def get_value(self, value: str):
return value
except Exception as err:
print(err)
return '' # TODO: check if this makes sense.
return default
2 changes: 1 addition & 1 deletion codeGrader/frontend/admin/handlers/Home.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Handler Classes for the Users
Handler Classes for the home site of the admin panel.
"""
import flask
import flask_login
Expand Down
4 changes: 2 additions & 2 deletions codeGrader/frontend/admin/handlers/Login.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ def post(self):
body = dict()
body["password"] = password
body["username"] = username
response = self.api.post('/login', body)
id_ = response["response"]["id"] # is None when the Authentication failed
response = self.api.post('/admin/login', body)
id_ = response["response"]["id"] # is None when the Authentication failed
return id_
Binary file added codeGrader/frontend/admin/static/img/phbern.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions codeGrader/frontend/admin/templates/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ <h1 class="header1 core_content">Home</h1>
<br>
<br>
<img src="{{ url_for('static', filename='img/belearn.png') }}" alt="BeLearn" width="500">
<br>
<br>
<img src="{{ url_for('static', filename='img/phbern.png') }}" alt="PH Bern" width="500">
</div>


Expand Down
1 change: 0 additions & 1 deletion codeGrader/frontend/config/Config.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ def __init__(self):

self.config = configparser.ConfigParser()
self.config.read(configFile)
print(self.config.sections())


self.adminPort = self.config["Admin"]["Port"]
Expand Down
4 changes: 2 additions & 2 deletions codeGrader/frontend/config/config.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Secret_Key = <ADD_A_GOOD_SECRET_KEY_HERE>
Port = 8101

[User]
Name = AdminCodeGrader
Secret_Key = <ADD_A_GOOD_SECRET_KEY_HERE>
Name = CodeGrader
Secret_Key = <ADD_ANOTHER_GOOD_SECRET_KEY_HERE>
Port = 8102

[API]
Expand Down
18 changes: 0 additions & 18 deletions codeGrader/frontend/config/config.json

This file was deleted.

88 changes: 88 additions & 0 deletions codeGrader/frontend/user/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""
Route defintion of the User Frontend of the CodeGrader
@author: mkaiser
@version: 1.0
"""

import flask_login
from flask import Flask, request, render_template, url_for, redirect, flash, session
from flask_login import LoginManager, login_user, login_required, logout_user
from codeGrader.frontend.config import config
from codeGrader.frontend.user import templates
from codeGrader.frontend.user.handlers import UserSessionHandler, SessionUser, UserLoginHandler, HomeHandler

app = Flask(config.adminAppName, template_folder=templates.__path__[0])

# configuration of the login_manager and attaching it to the app
app.secret_key = config.userSecretKey
login_manager = LoginManager()
login_manager.init_app(app)


@login_manager.user_loader
def user_login(user_id: int):
"""
User Load of the Login Manager
Returns the Frontend Representation of a User
@param user_id: The id of the user
@type user_id: int
@return: The frontend user object
@rtype: SessionUser
"""
user = SessionUser(user_id)
return user


@login_manager.unauthorized_handler
def unauthorized():
"""
Returns to login page if you are not properly logged in
@return: Redirection to the login site.
"""
return redirect(url_for("login"))


@app.route("/login", methods=['GET', 'POST'])
def login():
"""
Renders the login page on GET
Tries to log the user in on POST
@return: Rendered template or a redirection
"""
if request.method == 'GET':
return render_template("login.html")

elif request.method == 'POST':
# try to log the user in
user_id = UserLoginHandler(request).post()
if user_id:
user = user_login(user_id)
login_user(user)
else:
flash("The provided Credentials are not valid")
return redirect(url_for("home"))


@app.route("/logout", methods=['GET', 'POST'])
@login_required
def logout():
"""
Logout a user so he needs to reauthenticate
@return: Redirect to the login page
"""
logout_user()
return redirect(url_for("login"))


@app.route("/")
@login_required
def home():
"""
The Home site of the user frontend
@return: Rendered Home Template
"""
return HomeHandler(request).get()


if __name__ == "__main__":
app.run(port=config.userPort)
43 changes: 43 additions & 0 deletions codeGrader/frontend/user/handlers/Base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
Base Handler for the User part of the CodeGrader Frontend
@author: mkaiser
"""
import flask

from codeGrader.frontend.config import config
from codeGrader.frontend.util import ApiHandler


class BaseHandler:
"""
Base Handler Class
Other Handlers will inherit from this class
"""

def __init__(self, requests: flask.Request):
"""
Constructor of the BaseHandler
"""
self.request = requests
self.api = ApiHandler(config.apiHost, config.apiAuthentication, config.apiToken)

def get_value(self, value: str, default: str = ""):
"""
Get a value from the form that has been provided by the user identified by a given key.
The key is defined by the name in the html form
@param value: Name of the object in the request
@type value: str
@param default: The default value that shall be returned when no value is found. Optional parameter
@type default: str
@return: The value of the requested key
@rtype: str
"""
try:
value = self.request.form[value]
if value == '':
return None
else:
return value
except Exception as err:
print(err)
return default
24 changes: 24 additions & 0 deletions codeGrader/frontend/user/handlers/Home.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""
Handler Classes for the Home site of the user panel
"""
import flask
import flask_login
from flask import request, render_template, redirect
from .Base import BaseHandler


class HomeHandler(BaseHandler):
"""
Handles Operations for the Home site
"""

def __init__(self, request: flask.Request):
"""
Constructor of the Home Handler
@param request: The request from the app route of flask
@type request: flask.request
"""
super().__init__(request)

def get(self):
return render_template("home.html")
Loading

0 comments on commit 706c504

Please sign in to comment.