From 8f64ed2736e4587bcde10479763534f8ba625a17 Mon Sep 17 00:00:00 2001 From: Aroy Date: Sat, 4 Feb 2023 14:37:05 +0530 Subject: [PATCH] student backend update --- studentBackend/.gitignore | 1 + studentBackend/__init__.py | 0 studentBackend/api/__init__.py | 0 studentBackend/api/model/__init__.py | 0 studentBackend/api/model/assignmentsmodel.py | 17 +++++++ studentBackend/api/model/noticeboardmodel.py | 12 +++++ studentBackend/api/model/welcome.py | 3 ++ studentBackend/api/routes/__init__.py | 0 studentBackend/api/routes/apyhub/__init__.py | 0 studentBackend/api/routes/apyhub/routes.py | 37 ++++++++++++++ .../api/routes/authentication/__init__.py | 0 .../api/routes/authentication/routes.py | 46 +++++++++++++++++ studentBackend/api/routes/home.py | 11 +++++ .../api/routes/students/__init__.py | 0 studentBackend/api/routes/students/routes.py | 26 ++++++++++ studentBackend/api/schema/__init__.py | 0 studentBackend/api/schema/assignments.py | 20 ++++++++ studentBackend/api/schema/noticeboard.py | 20 ++++++++ studentBackend/api/schema/welcome.py | 10 ++++ studentBackend/api/services/__init__.py | 4 ++ studentBackend/api/services/database.py | 41 ++++++++++++++++ studentBackend/app.py | 49 +++++++++++++++++++ studentBackend/config.py | 7 +++ studentBackend/requirements.txt | 33 +++++++++++++ studentBackend/vercel.json | 11 +++++ 25 files changed, 348 insertions(+) create mode 100644 studentBackend/.gitignore create mode 100644 studentBackend/__init__.py create mode 100644 studentBackend/api/__init__.py create mode 100644 studentBackend/api/model/__init__.py create mode 100644 studentBackend/api/model/assignmentsmodel.py create mode 100644 studentBackend/api/model/noticeboardmodel.py create mode 100644 studentBackend/api/model/welcome.py create mode 100644 studentBackend/api/routes/__init__.py create mode 100644 studentBackend/api/routes/apyhub/__init__.py create mode 100644 studentBackend/api/routes/apyhub/routes.py create mode 100644 studentBackend/api/routes/authentication/__init__.py create mode 100644 studentBackend/api/routes/authentication/routes.py create mode 100644 studentBackend/api/routes/home.py create mode 100644 studentBackend/api/routes/students/__init__.py create mode 100644 studentBackend/api/routes/students/routes.py create mode 100644 studentBackend/api/schema/__init__.py create mode 100644 studentBackend/api/schema/assignments.py create mode 100644 studentBackend/api/schema/noticeboard.py create mode 100644 studentBackend/api/schema/welcome.py create mode 100644 studentBackend/api/services/__init__.py create mode 100644 studentBackend/api/services/database.py create mode 100644 studentBackend/app.py create mode 100644 studentBackend/config.py create mode 100644 studentBackend/requirements.txt create mode 100644 studentBackend/vercel.json diff --git a/studentBackend/.gitignore b/studentBackend/.gitignore new file mode 100644 index 0000000..2eea525 --- /dev/null +++ b/studentBackend/.gitignore @@ -0,0 +1 @@ +.env \ No newline at end of file diff --git a/studentBackend/__init__.py b/studentBackend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/studentBackend/api/__init__.py b/studentBackend/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/studentBackend/api/model/__init__.py b/studentBackend/api/model/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/studentBackend/api/model/assignmentsmodel.py b/studentBackend/api/model/assignmentsmodel.py new file mode 100644 index 0000000..c5ca7d5 --- /dev/null +++ b/studentBackend/api/model/assignmentsmodel.py @@ -0,0 +1,17 @@ +class AssignmentList: + def __init__(self): + self.assignments = list() + + +class Assignment: + def __init__(self, assignedTo, assignedBy, data, date, time, assignmentID): + self.assignedTo = assignedTo + self.assignedBy = assignedBy + self.data = data + self.date = date + self.time = time + self.assignmentID = assignmentID + + def assignedToMod(self): + for obj in self.assignedTo: + obj['studentID'] = str(obj['studentID']) diff --git a/studentBackend/api/model/noticeboardmodel.py b/studentBackend/api/model/noticeboardmodel.py new file mode 100644 index 0000000..fee84cd --- /dev/null +++ b/studentBackend/api/model/noticeboardmodel.py @@ -0,0 +1,12 @@ +class NoticeBoardModel: + def __init__(self): + self.notices = list() + + +class NoticeModel: + def __init__(self, data, date, time, isFile, fileURL): + self.data = data + self.date = date + self.time = time + self.isFile = isFile + self.fileURL = fileURL diff --git a/studentBackend/api/model/welcome.py b/studentBackend/api/model/welcome.py new file mode 100644 index 0000000..4abc1f3 --- /dev/null +++ b/studentBackend/api/model/welcome.py @@ -0,0 +1,3 @@ +class WelcomeModel: + def __init__(self): + self.message = "The Ed360 Student Backend" diff --git a/studentBackend/api/routes/__init__.py b/studentBackend/api/routes/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/studentBackend/api/routes/apyhub/__init__.py b/studentBackend/api/routes/apyhub/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/studentBackend/api/routes/apyhub/routes.py b/studentBackend/api/routes/apyhub/routes.py new file mode 100644 index 0000000..b643af0 --- /dev/null +++ b/studentBackend/api/routes/apyhub/routes.py @@ -0,0 +1,37 @@ +import requests +from flask import Blueprint, request +from flask_cors import cross_origin + +apyHub_bp = Blueprint('apyHub', __name__) + + +@apyHub_bp.route("/getAttendanceChart", methods=['POST']) +@cross_origin() +def getAttendanceChart(): + if request.method == 'post' or request.method == 'POST': + data = request.get_json() + resp = requests.post('https://api.apyhub.com/generate/charts/pie/url', + headers= + { + 'apy-token': 'APT0ezbHwZe9HuBi5kXGjedIqMu4v4YrdbSerW8wszGK8E', + }, + + json={ + 'title': 'Attendance', + 'theme': 'Light', + 'data': [ + { + 'label': 'Present', + 'value': data['present'] + }, + { + 'label': 'Absent', + 'value': data['absent'] + }] + }, + ) + + return resp.text + + + diff --git a/studentBackend/api/routes/authentication/__init__.py b/studentBackend/api/routes/authentication/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/studentBackend/api/routes/authentication/routes.py b/studentBackend/api/routes/authentication/routes.py new file mode 100644 index 0000000..4352e12 --- /dev/null +++ b/studentBackend/api/routes/authentication/routes.py @@ -0,0 +1,46 @@ +from flask import Blueprint, url_for, session, redirect, request +from os import environ as env +from urllib.parse import quote_plus, urlencode + +auth_bp = Blueprint('auth', __name__) +state = ["", ""] + + +def register_auth_routes(oauth): + @auth_bp.route('/login/') + def login(): + redirect_uri = request.args.get("redirect_uri") + if redirect_uri is None: + redirect_uri = url_for("home_api.welcome") + + resp = oauth.auth0.authorize_redirect( + redirect_uri=url_for(".callback", _external=True) + ) + + url = resp.headers.get("Location") + + state[0] = url[url.rindex("state") + 6: url.rindex("&")] + state[1] = redirect_uri + + return redirect(url) + + @auth_bp.route('/callback/') + def callback(): + token = oauth.auth0.authorize_access_token() + session["user"] = token + return redirect(state[1]) + + @auth_bp.route('/logout/') + def logout(): + session.clear() + return redirect( + "https://" + env.get("AUTH0_DOMAIN") + + "/v2/logout?" + + urlencode( + { + "returnTo": url_for("home_api.welcome", _external=True), + "client_id": env.get("AUTH0_CLIENT_ID"), + }, + quote_via=quote_plus, + ) + ) diff --git a/studentBackend/api/routes/home.py b/studentBackend/api/routes/home.py new file mode 100644 index 0000000..eac061b --- /dev/null +++ b/studentBackend/api/routes/home.py @@ -0,0 +1,11 @@ +from flask import Blueprint +from studentBackend.api.model.welcome import WelcomeModel +from studentBackend.api.schema.welcome import WelcomeSchema + +home_api = Blueprint('home_api', __name__) + + +@home_api.route('/') +def welcome(): + result = WelcomeModel() + return WelcomeSchema().dump(result), 200 diff --git a/studentBackend/api/routes/students/__init__.py b/studentBackend/api/routes/students/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/studentBackend/api/routes/students/routes.py b/studentBackend/api/routes/students/routes.py new file mode 100644 index 0000000..657ec38 --- /dev/null +++ b/studentBackend/api/routes/students/routes.py @@ -0,0 +1,26 @@ +from flask import Blueprint, url_for, session, redirect + +from studentBackend.api import Notice +from studentBackend.api.model.noticeboardmodel import NoticeBoardModel, NoticeModel +from studentBackend.api.schema.noticeboard import NoticeBoardSchema + +student_bp = Blueprint('student', __name__) + + +@student_bp.route("/noticeboard/") +def get_notices(): + if session: + noticeBoard = NoticeBoardModel() + for notices in Notice.objects: + data = notices.data + date = notices.date + time = notices.time + isFile = notices.isFile + fileURL = notices.fileURL + + notice = NoticeModel(data, date, time, isFile, fileURL) + noticeBoard.notices.append(notice) + + return NoticeBoardSchema().dumps(noticeBoard), 200 + else: + return redirect(url_for("auth.login", redirect_uri=url_for(".get_notices"))) diff --git a/studentBackend/api/schema/__init__.py b/studentBackend/api/schema/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/studentBackend/api/schema/assignments.py b/studentBackend/api/schema/assignments.py new file mode 100644 index 0000000..6614de5 --- /dev/null +++ b/studentBackend/api/schema/assignments.py @@ -0,0 +1,20 @@ +from flask_marshmallow import Schema +from marshmallow.fields import Str, Nested, List, Dict + + +class AssignmentSchema(Schema): + class Meta: + fields = ['assignmentID', 'data', 'date', 'time', 'assignedTo'] + + assignedTo = List(Dict()) + assignmentID = Str() + data = Str() + date = Str() + time = Str() + + +class AssignmentListSchema(Schema): + class Meta: + fields = ['assignments'] + + assignments = List(Nested(AssignmentSchema)) diff --git a/studentBackend/api/schema/noticeboard.py b/studentBackend/api/schema/noticeboard.py new file mode 100644 index 0000000..73ab39c --- /dev/null +++ b/studentBackend/api/schema/noticeboard.py @@ -0,0 +1,20 @@ +from flask_marshmallow import Schema +from marshmallow.fields import Str, Boolean, URL, Nested, List + + +class NoticeSchema(Schema): + class Meta: + fields = ['data', 'date', 'time', 'isFile', 'fileURL'] + + data = Str() + date = Str() + time = Str() + isFile = Boolean() + fileURL = URL() + + +class NoticeBoardSchema(Schema): + class Meta: + fields = ["notices"] + + notices = List(Nested(NoticeSchema)) diff --git a/studentBackend/api/schema/welcome.py b/studentBackend/api/schema/welcome.py new file mode 100644 index 0000000..66e5c5e --- /dev/null +++ b/studentBackend/api/schema/welcome.py @@ -0,0 +1,10 @@ +from flask_marshmallow import Schema +from marshmallow.fields import Str + + +class WelcomeSchema(Schema): + class Meta: + # Fields to expose + fields = ["message"] + + message = Str() diff --git a/studentBackend/api/services/__init__.py b/studentBackend/api/services/__init__.py new file mode 100644 index 0000000..07f2542 --- /dev/null +++ b/studentBackend/api/services/__init__.py @@ -0,0 +1,4 @@ +import mongoengine as db +from os import environ as env + +db.connect(db="Ed360", username="im_still_thinking", password="zephyrus1234", host=env.get("MONGODB_CONNECTION_STRING")) diff --git a/studentBackend/api/services/database.py b/studentBackend/api/services/database.py new file mode 100644 index 0000000..6a735ce --- /dev/null +++ b/studentBackend/api/services/database.py @@ -0,0 +1,41 @@ +from studentBackend.api import db + + +class Assignments(db.Document): + meta = {'collection': 'Assignments'} + + assignedBy = db.ObjectIdField() + assignedTo = db.ListField(db.DictField()) + data = db.StringField() + date = db.StringField() + time = db.StringField() + assignmentID = db.StringField() + + +class Notice(db.Document): + meta = {'collection': 'Notice'} + + data = db.StringField() + date = db.StringField() + time = db.StringField() + isFile = db.BooleanField() + fileURL = db.URLField() + + +class Students(db.Document): + meta = {'collection': 'Students'} + + username = db.StringField() + password = db.StringField() + name = db.StringField() + points = db.IntField() + assignments = db.ListField(db.ObjectIdField()) + + +class Teachers(db.Document): + meta = {'collection': 'Teachers'} + + username = db.StringField() + password = db.StringField() + name = db.StringField() + assignments = db.ListField(db.ObjectIdField()) diff --git a/studentBackend/app.py b/studentBackend/app.py new file mode 100644 index 0000000..d5987db --- /dev/null +++ b/studentBackend/app.py @@ -0,0 +1,49 @@ +from os import environ as env + +from authlib.integrations.flask_client import OAuth + +from flask import Flask, redirect, url_for +from flask_cors import CORS + +app = Flask(__name__) +app.secret_key = env.get("APP_SECRET_KEY") +app.config.from_pyfile('config.py') + +CORS(app) + +from api.routes.authentication.routes import register_auth_routes, auth_bp +from api.routes.home import home_api +from api.routes.students.routes import student_bp + +oauth = OAuth(app) +oauth.register( + "auth0", + client_id=env.get("AUTH0_CLIENT_ID"), + client_secret=env.get("AUTH0_CLIENT_SECRET"), + client_kwargs={ + "scope": "openid profile email", + }, + server_metadata_url=f'https://{env.get("AUTH0_DOMAIN")}/.well-known/openid-configuration' +) + +register_auth_routes(oauth) + + +@app.route("/") +def root(): + return redirect(url_for("home_api.welcome")) + + +app.register_blueprint(home_api, url_prefix='/api') +app.register_blueprint(auth_bp, url_prefix="/api/auth") +app.register_blueprint(student_bp, url_prefix="/api/student") + +if __name__ == '__main__': + from argparse import ArgumentParser + + parser = ArgumentParser() + parser.add_argument('-p', '--port', default=3000, type=int) + args = parser.parse_args() + port = args.port + + app.run(host='0.0.0.0', port=port, debug=True) diff --git a/studentBackend/config.py b/studentBackend/config.py new file mode 100644 index 0000000..df26a97 --- /dev/null +++ b/studentBackend/config.py @@ -0,0 +1,7 @@ +from dotenv import load_dotenv +from os import path + +basedir = path.abspath(path.dirname(__file__)) +load_dotenv(path.join(basedir, '.env')) + + diff --git a/studentBackend/requirements.txt b/studentBackend/requirements.txt new file mode 100644 index 0000000..8d782ec --- /dev/null +++ b/studentBackend/requirements.txt @@ -0,0 +1,33 @@ +attrs==22.2.0 +Authlib==1.2.0 +certifi==2022.12.7 +cffi==1.15.1 +charset-normalizer==3.0.1 +click==8.1.3 +cryptography==39.0.0 +dnspython==2.3.0 +email-validator==1.3.0 +Flask==2.2.2 +Flask-Cors==3.0.10 +flask-marshmallow==0.14.0 +Flask-WTF==1.1.1 +idna==3.4 +itsdangerous==2.1.2 +Jinja2==3.1.2 +jsonschema==4.17.3 +MarkupSafe==2.1.1 +marshmallow==3.19.0 +mistune==2.0.4 +mongoengine==0.25.0 +oauthlib==3.2.2 +packaging==23.0 +pycparser==2.21 +pymongo==4.3.3 +pyrsistent==0.19.3 +python-dotenv==0.21.0 +PyYAML==6.0 +requests==2.28.2 +six==1.16.0 +urllib3==1.26.14 +Werkzeug==2.2.2 +WTForms==3.0.1 diff --git a/studentBackend/vercel.json b/studentBackend/vercel.json new file mode 100644 index 0000000..b60e7fc --- /dev/null +++ b/studentBackend/vercel.json @@ -0,0 +1,11 @@ +{ + "name": "Ed360", + "version": 2, + "builds": [{ + "src": "*py", + "use": "@vercel/python" + }], + "routes": [ + { "src": "/(.*)", "dest": "app.py" } + ] +} \ No newline at end of file