diff --git a/server/app.py b/server/app.py new file mode 100644 index 0000000..2dddbd1 --- /dev/null +++ b/server/app.py @@ -0,0 +1,15 @@ +from fastapi import Depends, FastAPI +from .models import Base, engine, SessionLocal + +Base.metadata.create_all(bind=engine) + +app = FastAPI() + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() + +@app.post("/login") \ No newline at end of file diff --git a/server/app_old.py b/server/app_old.py index 3b75985..25d2ff1 100644 --- a/server/app_old.py +++ b/server/app_old.py @@ -1,364 +1,364 @@ -from flask import Flask, request, jsonify -from flask_cors import CORS -from server.database_old import Database - -app = Flask(__name__) -#app = Flask(__name__) -app.secret_key = "super_secret_key" -app.config["APPLICATION_ROOT"] = '/api' -CORS(app) -database = Database(app) - - -# Authentication -# ================================================== -# /login : Login -@app.route("/login", methods=["POST"]) -def login(): - data = request.get_json() - return jsonify(database.login( - data.get("email", ""), - data.get("password", "") - )) - -# /register : Registration -@app.route("/register", methods=["POST"]) -def register(): - data = request.get_json() - print(data) - isTeacher = data.get("isTeacher", None) - if isTeacher is None: - return { - "result": False, - "user": None, - "message": "Unknown Registration Method!" - } - if isTeacher: - return database.registerTeacher( - data.get("email", ""), data.get("password", ""), - data.get("name", ""), data.get("deptId", ""), - ) - return database.registerStudent( - data.get("email", ""), data.get("password", ""), - data.get("name", ""), data.get("gradYear", 0) - ) - - -# /update/password : Update Password -@app.route("/update/password", methods=["POST"]) -def updatePassword(): - data = request.get_json() - return jsonify( - database.changePassword( - data.get("email", ""), data.get("oldPw", ""), data.get("newPw", "") - ) - ) - -# ================================================== +# from flask import Flask, request, jsonify +# from flask_cors import CORS +# from server.database_old import Database + +# app = Flask(__name__) +# #app = Flask(__name__) +# app.secret_key = "super_secret_key" +# app.config["APPLICATION_ROOT"] = '/api' +# CORS(app) +# database = Database(app) + + +# # Authentication +# # ================================================== +# # /login : Login +# @app.route("/login", methods=["POST"]) +# def login(): +# data = request.get_json() +# return jsonify(database.login( +# data.get("email", ""), +# data.get("password", "") +# )) + +# # /register : Registration +# @app.route("/register", methods=["POST"]) +# def register(): +# data = request.get_json() +# print(data) +# isTeacher = data.get("isTeacher", None) +# if isTeacher is None: +# return { +# "result": False, +# "user": None, +# "message": "Unknown Registration Method!" +# } +# if isTeacher: +# return database.registerTeacher( +# data.get("email", ""), data.get("password", ""), +# data.get("name", ""), data.get("deptId", ""), +# ) +# return database.registerStudent( +# data.get("email", ""), data.get("password", ""), +# data.get("name", ""), data.get("gradYear", 0) +# ) + + +# # /update/password : Update Password +# @app.route("/update/password", methods=["POST"]) +# def updatePassword(): +# data = request.get_json() +# return jsonify( +# database.changePassword( +# data.get("email", ""), data.get("oldPw", ""), data.get("newPw", "") +# ) +# ) + +# # ================================================== -# Projects -# ================================================== -# /create/project : Project Creation -@app.route("/create/project", methods=["POST"]) -def createProject(): - data = request.get_json() - return jsonify(database.createProject( - data.get("pcode", ""), - data.get("year", 0), - data.get("deptId", ""), - data.get("title", ""), - data.get("abstract", ""), - data.get("teacherEmail", ""), - data.get("authorEmails", []) - )) - -# /update/project : Project Update -@app.route("/update/project", methods=["POST"]) -def updateProject(): - data = request.get_json() - res = database.updateProject( - data.get("pcode", ""), - data.get("title", ""), - data.get("abstract", ""), - data.get("reportPdf", "") - ) - return jsonify(res) - -# /delete/project : Project Deletion -@app.route("/delete/project", methods=["POST"]) -def deleteProject(): - data = request.get_json() - return jsonify(database.deleteProject( - data.get("pcode", "") - )) - -# ================================================== - - -# Submissions -# ================================================== -# /create/submission : Submission Creation -@app.route("/create/submission", methods=["POST"]) -def createSubmission(): - data = request.get_json() - return jsonify(database.createSubmission( - data.get("eventId", ""), - data.get("year", 0), - data.get("code", ""), - data.get("subTitle", ""), - data.get("subAbstract", ""), - data.get("pcodes", []), - data.get("authorEmails", []) - )) - - - -# /delete/submission : Submission Deletion -@app.route("/delete/submission", methods=["POST"]) -def deleteSubmission(): - data = request.get_json() - return jsonify(database.deleteSubmission( - data.get("eventId", ""), - data.get("year", 0), - data.get("code", "") - )) - - - -@app.route("/stats/", methods=["GET"]) -def stats(id): - email = (("h1810124" if id == "" else id) + "@nushigh.edu.sg") if "@" not in id else id - return jsonify({ - "projectStats": database.projectStats(email), - "submissionStats": database.submissionStats(email), - "awardStats": database.awardStats(email), - "projectAwardStats": database.projectAwardStats(email) - }) - - - -@app.route("/search/students", methods=["GET"]) -def searchStudents(): - res = jsonify(database.searchAllStudents()) - return res - -@app.route("/search/teachers", methods=["GET"]) -def searchTeachers(): - res = jsonify(database.searchAllTeachers()) - return res - -@app.route("/student/", methods=["GET"]) -def student(id): - email = (("h1810124" if id == "" else id) + "@nushigh.edu.sg") if "@" not in id else id - res = jsonify(database.student(email)) - return res - -@app.route("/teacher/", methods=["GET"]) -def teacher(email): - email = "nhscsp@nushigh.edu.sg" if email == "" else email - # email = request.args.get("email", "nhscsp@nushigh.edu.sg", str) +# # Projects +# # ================================================== +# # /create/project : Project Creation +# @app.route("/create/project", methods=["POST"]) +# def createProject(): +# data = request.get_json() +# return jsonify(database.createProject( +# data.get("pcode", ""), +# data.get("year", 0), +# data.get("deptId", ""), +# data.get("title", ""), +# data.get("abstract", ""), +# data.get("teacherEmail", ""), +# data.get("authorEmails", []) +# )) + +# # /update/project : Project Update +# @app.route("/update/project", methods=["POST"]) +# def updateProject(): +# data = request.get_json() +# res = database.updateProject( +# data.get("pcode", ""), +# data.get("title", ""), +# data.get("abstract", ""), +# data.get("reportPdf", "") +# ) +# return jsonify(res) + +# # /delete/project : Project Deletion +# @app.route("/delete/project", methods=["POST"]) +# def deleteProject(): +# data = request.get_json() +# return jsonify(database.deleteProject( +# data.get("pcode", "") +# )) + +# # ================================================== + + +# # Submissions +# # ================================================== +# # /create/submission : Submission Creation +# @app.route("/create/submission", methods=["POST"]) +# def createSubmission(): +# data = request.get_json() +# return jsonify(database.createSubmission( +# data.get("eventId", ""), +# data.get("year", 0), +# data.get("code", ""), +# data.get("subTitle", ""), +# data.get("subAbstract", ""), +# data.get("pcodes", []), +# data.get("authorEmails", []) +# )) + + + +# # /delete/submission : Submission Deletion +# @app.route("/delete/submission", methods=["POST"]) +# def deleteSubmission(): +# data = request.get_json() +# return jsonify(database.deleteSubmission( +# data.get("eventId", ""), +# data.get("year", 0), +# data.get("code", "") +# )) + + + +# @app.route("/stats/", methods=["GET"]) +# def stats(id): +# email = (("h1810124" if id == "" else id) + "@nushigh.edu.sg") if "@" not in id else id +# return jsonify({ +# "projectStats": database.projectStats(email), +# "submissionStats": database.submissionStats(email), +# "awardStats": database.awardStats(email), +# "projectAwardStats": database.projectAwardStats(email) +# }) + + + +# @app.route("/search/students", methods=["GET"]) +# def searchStudents(): +# res = jsonify(database.searchAllStudents()) +# return res + +# @app.route("/search/teachers", methods=["GET"]) +# def searchTeachers(): +# res = jsonify(database.searchAllTeachers()) +# return res + +# @app.route("/student/", methods=["GET"]) +# def student(id): +# email = (("h1810124" if id == "" else id) + "@nushigh.edu.sg") if "@" not in id else id +# res = jsonify(database.student(email)) +# return res + +# @app.route("/teacher/", methods=["GET"]) +# def teacher(email): +# email = "nhscsp@nushigh.edu.sg" if email == "" else email +# # email = request.args.get("email", "nhscsp@nushigh.edu.sg", str) - res = jsonify(database.teacher(email)) - return res - - -@app.route("/institute/", methods=["GET"]) -def institute(id): - id = "NUS" if id == "" else id - res = jsonify(database.institute(id)) - return res - -@app.route("/projects/", methods=["GET"]) -def getProjects(id): - if("@" not in id): id += "@nushigh.edu.sg" - if(database.isStudent(id)): res = jsonify(database.studentProjects(id)) - elif(database.isMentor(id)): res = jsonify(database.projectsByMentor(id)) - else: res = jsonify(database.teacherProjects(id)) - return res - -@app.route("/mentorStudents/", methods=["GET"]) -def getMentorStudents(email): - return jsonify(database.mentorStudents(email)) - -@app.route("/bestStudents/", methods=["GET"]) -def getBestStudents(email): - email = "nhscsp@nushigh.edu.sg" if email == "" else email - return jsonify(database.best_students(email)) - -@app.route("/extTeacherStudents/", methods=["GET"]) -def getExtTeacherStudents(email): - return jsonify(database.extTeacherStudents(email)) +# res = jsonify(database.teacher(email)) +# return res + + +# @app.route("/institute/", methods=["GET"]) +# def institute(id): +# id = "NUS" if id == "" else id +# res = jsonify(database.institute(id)) +# return res + +# @app.route("/projects/", methods=["GET"]) +# def getProjects(id): +# if("@" not in id): id += "@nushigh.edu.sg" +# if(database.isStudent(id)): res = jsonify(database.studentProjects(id)) +# elif(database.isMentor(id)): res = jsonify(database.projectsByMentor(id)) +# else: res = jsonify(database.teacherProjects(id)) +# return res + +# @app.route("/mentorStudents/", methods=["GET"]) +# def getMentorStudents(email): +# return jsonify(database.mentorStudents(email)) + +# @app.route("/bestStudents/", methods=["GET"]) +# def getBestStudents(email): +# email = "nhscsp@nushigh.edu.sg" if email == "" else email +# return jsonify(database.best_students(email)) + +# @app.route("/extTeacherStudents/", methods=["GET"]) +# def getExtTeacherStudents(email): +# return jsonify(database.extTeacherStudents(email)) -@app.route("/mentor/", methods=["GET"]) -def getMentors(email): - return jsonify(database.mentor(email)) +# @app.route("/mentor/", methods=["GET"]) +# def getMentors(email): +# return jsonify(database.mentor(email)) -@app.route("/projectsByMentor/", methods=["GET"]) -def getMentorProjects(email): - return jsonify(database.projectsByMentor(email)) +# @app.route("/projectsByMentor/", methods=["GET"]) +# def getMentorProjects(email): +# return jsonify(database.projectsByMentor(email)) -@app.route("/event//", methods=["GET"]) -def getEvent(eventId, year): - return jsonify(database.event(eventId, year)) +# @app.route("/event//", methods=["GET"]) +# def getEvent(eventId, year): +# return jsonify(database.event(eventId, year)) -@app.route("/events", methods=["GET"]) -def getEvents(): - return jsonify(database.events()) +# @app.route("/events", methods=["GET"]) +# def getEvents(): +# return jsonify(database.events()) -@app.route("/otherProjects/", methods=["GET"]) -def getOtherProjects(email): - return jsonify(database.otherProjects(email)) +# @app.route("/otherProjects/", methods=["GET"]) +# def getOtherProjects(email): +# return jsonify(database.otherProjects(email)) -@app.route("/otherEvents/", methods=["GET"]) -def getOtherEvents(email): - return jsonify(database.otherEvents(email)) - -@app.route("/project/", methods=["GET"]) -def project(pcode): - pcode = "23.018.NUSH.CS" if pcode == "" else pcode - res = jsonify(database.project(pcode)) - return res - -@app.route("/authors/", methods=["GET"]) -def authors(pcode): - pcode = "23.018.NUSH.CS" if pcode == "" else pcode - res = jsonify(database.projectMembers(pcode)) - return res - -@app.route("/update/student", methods=["POST"]) -def updateStudent(): - data = request.get_json() - email = data.get("sid", "")+"@nushigh.edu.sg" - about = data.get("about", "") - pfp = data.get("pfp", "") - print(len(pfp)) - res = database.updateStudent(email, pfp, about) - return jsonify(res) - -@app.route("/submission///", methods=["GET"]) -def submission(eventId, year, code): - return database.submission(eventId, year, code) - -@app.route("/submissions/", methods=["GET"]) -def submissions(pcode): - res = jsonify(database.submissionsByProject(pcode)) - return res - -@app.route("/submissions/user/", methods=["GET"]) -def submissionsByUser(email): - if("@" not in email): email += "@nushigh.edu.sg" - res = jsonify(database.submissionsByUser(email)) - return res - -@app.route("/submissions/all/", methods=["GET"]) -def getEverySubmission(email): - if("@" not in email): email += "@nushigh.edu.sg" - res = jsonify(database.strongSubmissions(email)) - return res - -@app.route("/coauthors/", methods=["GET"]) -def coauthors(id): - if(id == ""): id = "h1810124" - res = jsonify(database.coauthors(id+"@nushigh.edu.sg")) - return res - -@app.route("/removeStudent", methods=["POST"]) -def removeStudent(): - data = request.get_json() - res = jsonify(database.removeStudentFromProject(data.get("email", ""), data.get("pcode", ""))) - return res - -@app.route("/submission/remove", methods=["POST"]) -def removeStudentFromSubmission(): - data = request.get_json() - res = jsonify(database.removeStudentFromSubmission( - data.get("email", ""), data.get("eventId", ""), data.get("year", 0), data.get("code", "") - )) - return res - - -@app.route("/addExtStudent", methods=["POST"]) -def addExtStudent(): - data = request.get_json() - database.createExternalStudent( - data.get("email", ""), data.get("name", ""), data.get("teacherEmail", ""), - data.get("teacherName", ""), data.get("instId", "") - ) - return jsonify({"result": "Success"}) - -@app.route("/addStudents", methods=["POST"]) -def addStudents(): - data = request.get_json() - # Assume that the data is formatted as follows: {students: ["email1", "email2"], pcode: ""} - pcode = data.get("pcode", "") - students = [student for student in data.get("students", []) if database.student(student)] - database.addStudentsToProject(students, pcode) - return jsonify({"result": "Success"}) - -@app.route("/submissions/add", methods=["POST"]) -def addStudentsToSubmission(): - data = request.get_json() - eventId = data.get("eventId", "") - year = data.get("year", 0) - code = data.get("code", "") - students = [student for student in data.get("students", []) if database.student(student)] - database.addStudentsToSubmission(students, eventId, year, code) - return jsonify({"result": "Success"}) - -@app.route("/search/schools", methods=["GET"]) -def searchSchools(): - res = jsonify(database.searchSchools()) - return res - -@app.route("/search/organisers", methods=["GET"]) -def searchOrganisers(): - res = jsonify(database.searchOrganisers()) - return res - -@app.route("/create/researchEvent", methods=["POST"]) -def createEvent(): - data = request.get_json() - return jsonify(database.createResearchEvent( - data.get("eventId", ""), data.get("year", 0), data.get("name", ""), - data.get("start_date", ""), data.get("end_date", ""), data.get("format", ""), - data.get("about", ""), data.get("isCompetition", False), data.get("isConference", False), - data.get("organisers", []), data.get("awardTypes", []), data.get("confDoi", "") - )) - - -@app.route("/update/researchEvent", methods=["POST"]) -def updateEvent(): - data = request.get_json() - return jsonify(database.updateResearchEvent( - data.get("eventId", ""), data.get("year", 0), data.get("name", ""), - data.get("start_date", ""), data.get("end_date", ""), data.get("format", ""), - data.get("about", ""), data.get("isCompetition", False), data.get("isConference", False), - data.get("organisers", []), data.get("awardTypes", []), data.get("confDoi", "") - )) - -@app.route("/update/submission", methods=["POST"]) -def updateSubmission(): - data = request.get_json() - return jsonify(database.updateSubmission( - data.get("eventId", ""), data.get("year", 0), data.get("code", ""), - data.get("subTitle", ""), data.get("subAbstract", "") - )) +# @app.route("/otherEvents/", methods=["GET"]) +# def getOtherEvents(email): +# return jsonify(database.otherEvents(email)) + +# @app.route("/project/", methods=["GET"]) +# def project(pcode): +# pcode = "23.018.NUSH.CS" if pcode == "" else pcode +# res = jsonify(database.project(pcode)) +# return res + +# @app.route("/authors/", methods=["GET"]) +# def authors(pcode): +# pcode = "23.018.NUSH.CS" if pcode == "" else pcode +# res = jsonify(database.projectMembers(pcode)) +# return res + +# @app.route("/update/student", methods=["POST"]) +# def updateStudent(): +# data = request.get_json() +# email = data.get("sid", "")+"@nushigh.edu.sg" +# about = data.get("about", "") +# pfp = data.get("pfp", "") +# print(len(pfp)) +# res = database.updateStudent(email, pfp, about) +# return jsonify(res) + +# @app.route("/submission///", methods=["GET"]) +# def submission(eventId, year, code): +# return database.submission(eventId, year, code) + +# @app.route("/submissions/", methods=["GET"]) +# def submissions(pcode): +# res = jsonify(database.submissionsByProject(pcode)) +# return res + +# @app.route("/submissions/user/", methods=["GET"]) +# def submissionsByUser(email): +# if("@" not in email): email += "@nushigh.edu.sg" +# res = jsonify(database.submissionsByUser(email)) +# return res + +# @app.route("/submissions/all/", methods=["GET"]) +# def getEverySubmission(email): +# if("@" not in email): email += "@nushigh.edu.sg" +# res = jsonify(database.strongSubmissions(email)) +# return res + +# @app.route("/coauthors/", methods=["GET"]) +# def coauthors(id): +# if(id == ""): id = "h1810124" +# res = jsonify(database.coauthors(id+"@nushigh.edu.sg")) +# return res + +# @app.route("/removeStudent", methods=["POST"]) +# def removeStudent(): +# data = request.get_json() +# res = jsonify(database.removeStudentFromProject(data.get("email", ""), data.get("pcode", ""))) +# return res + +# @app.route("/submission/remove", methods=["POST"]) +# def removeStudentFromSubmission(): +# data = request.get_json() +# res = jsonify(database.removeStudentFromSubmission( +# data.get("email", ""), data.get("eventId", ""), data.get("year", 0), data.get("code", "") +# )) +# return res + + +# @app.route("/addExtStudent", methods=["POST"]) +# def addExtStudent(): +# data = request.get_json() +# database.createExternalStudent( +# data.get("email", ""), data.get("name", ""), data.get("teacherEmail", ""), +# data.get("teacherName", ""), data.get("instId", "") +# ) +# return jsonify({"result": "Success"}) + +# @app.route("/addStudents", methods=["POST"]) +# def addStudents(): +# data = request.get_json() +# # Assume that the data is formatted as follows: {students: ["email1", "email2"], pcode: ""} +# pcode = data.get("pcode", "") +# students = [student for student in data.get("students", []) if database.student(student)] +# database.addStudentsToProject(students, pcode) +# return jsonify({"result": "Success"}) + +# @app.route("/submissions/add", methods=["POST"]) +# def addStudentsToSubmission(): +# data = request.get_json() +# eventId = data.get("eventId", "") +# year = data.get("year", 0) +# code = data.get("code", "") +# students = [student for student in data.get("students", []) if database.student(student)] +# database.addStudentsToSubmission(students, eventId, year, code) +# return jsonify({"result": "Success"}) + +# @app.route("/search/schools", methods=["GET"]) +# def searchSchools(): +# res = jsonify(database.searchSchools()) +# return res + +# @app.route("/search/organisers", methods=["GET"]) +# def searchOrganisers(): +# res = jsonify(database.searchOrganisers()) +# return res + +# @app.route("/create/researchEvent", methods=["POST"]) +# def createEvent(): +# data = request.get_json() +# return jsonify(database.createResearchEvent( +# data.get("eventId", ""), data.get("year", 0), data.get("name", ""), +# data.get("start_date", ""), data.get("end_date", ""), data.get("format", ""), +# data.get("about", ""), data.get("isCompetition", False), data.get("isConference", False), +# data.get("organisers", []), data.get("awardTypes", []), data.get("confDoi", "") +# )) + + +# @app.route("/update/researchEvent", methods=["POST"]) +# def updateEvent(): +# data = request.get_json() +# return jsonify(database.updateResearchEvent( +# data.get("eventId", ""), data.get("year", 0), data.get("name", ""), +# data.get("start_date", ""), data.get("end_date", ""), data.get("format", ""), +# data.get("about", ""), data.get("isCompetition", False), data.get("isConference", False), +# data.get("organisers", []), data.get("awardTypes", []), data.get("confDoi", "") +# )) + +# @app.route("/update/submission", methods=["POST"]) +# def updateSubmission(): +# data = request.get_json() +# return jsonify(database.updateSubmission( +# data.get("eventId", ""), data.get("year", 0), data.get("code", ""), +# data.get("subTitle", ""), data.get("subAbstract", "") +# )) -# @app.route("/search/teachers", methods=["GET"]) +# # @app.route("/search/teachers", methods=["GET"]) -@app.route("/search/journals", methods=["GET"]) -def getJournals(): - return jsonify(database.journals()) +# @app.route("/search/journals", methods=["GET"]) +# def getJournals(): +# return jsonify(database.journals()) -@app.route('/') -def hello_world(): - return '

Hello World!

' +# @app.route('/') +# def hello_world(): +# return '

Hello World!

' -if __name__ == '__main__': - app.run(host="0.0.0.0", port=5000, debug=True) +# if __name__ == '__main__': +# app.run(host="0.0.0.0", port=5000, debug=True) diff --git a/server/database.py b/server/database.py index c3debb0..0cd1b88 100644 --- a/server/database.py +++ b/server/database.py @@ -1,660 +1,595 @@ -from typing import Optional, List -from sqlalchemy import ForeignKey, MetaData, UniqueConstraint, create_engine, Index -from sqlalchemy.sql.expression import false -from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship -from sqlalchemy.dialects.postgresql import BIGINT, VARCHAR, BOOLEAN, DATE, INTEGER, BYTEA -from datetime import date - -engine = create_engine('postgresql+asyncpg://postgres:admin@database/arxiv') -metadata_obj = MetaData(schema="arxiv") - -class Base(DeclarativeBase): - metadata = metadata_obj - -""" -Table "arxiv.researchevent" - Column | Type | Collation | Nullable | Default ----------------+-------------------------+-----------+----------+--------------------------------------------------- - numeventid | bigint | | not null | nextval('researchevent_numeventid_seq'::regclass) - eventid | character varying(15) | | not null | - year | integer | | not null | - name | character varying(100) | | not null | - about | character varying(5000) | | | - start_date | date | | not null | - end_date | date | | not null | - format | character varying(10) | | | - iscompetition | boolean | | not null | false - isconference | boolean | | not null | false - confdoi | character varying(200) | | | -Indexes: - "idx_16464_primary" PRIMARY KEY, btree (numeventid) - "idx_16464_eventid_2" UNIQUE, btree (eventid, year) -Referenced by: - TABLE "awardtypes" CONSTRAINT "awardtypes_ibfk_1" FOREIGN KEY (numeventid) REFERENCES researchevent(numeventid) ON UPDATE CASCADE ON DELETE CASCADE - TABLE "organises" CONSTRAINT "organises_ibfk_3" FOREIGN KEY (numeventid) REFERENCES researchevent(numeventid) ON UPDATE CASCADE ON DELETE CASCADE - TABLE "submission" CONSTRAINT "submission_ibfk_1" FOREIGN KEY (numeventid) REFERENCES researchevent(numeventid) ON UPDATE CASCADE ON DELETE CASCADE -""" -class ResearchEvent(Base): - __tablename__ = 'researchevent' - - num_event_id: Mapped[int] = mapped_column("numeventid", BIGINT, primary_key=True) - event_id: Mapped[str] = mapped_column("eventid", VARCHAR(15)) - year: Mapped[int] = mapped_column("year", INTEGER) - name: Mapped[str] = mapped_column("name", VARCHAR(100)) - about: Mapped[Optional[str]] = mapped_column("about", VARCHAR(5000)) - start_date: Mapped[date] = mapped_column("start_date", DATE) - end_date: Mapped[date] = mapped_column("end_date", DATE) - format: Mapped[Optional[str]] = mapped_column("format", VARCHAR(10)) - is_competition: Mapped[bool] = mapped_column("iscompetition", BOOLEAN, server_default=false(), default=False) - is_conference: Mapped[bool] = mapped_column("isconference", BOOLEAN, server_default=false(), default=False) - conf_doi: Mapped[Optional[str]] = mapped_column("confdoi", VARCHAR(200)) - - submissions: Mapped[List["Submission"]] = relationship(back_populates="event", cascade="all, delete-orphan", passive_deletes=True) - award_types: Mapped[List["AwardTypes"]] = relationship(back_populates="event", cascade="all, delete-orphan", passive_deletes=True) - organisers: Mapped[List["Organises"]] = relationship(back_populates="event", cascade="all, delete-orphan", passive_deletes=True) - - __table_args__ = (UniqueConstraint('eventid', 'year', name='idx_16464_eventid_2'),) - -""" -Table "arxiv.submission" - Column | Type | Collation | Nullable | Default --------------+-------------------------+-----------+----------+------------------------------------------- - subid | bigint | | not null | nextval('submission_subid_seq'::regclass) - numeventid | bigint | | not null | - code | character varying(20) | | not null | - subtitle | character varying(200) | | not null | - subabstract | character varying(2000) | | not null | -Indexes: - "idx_16479_primary" PRIMARY KEY, btree (subid) - "idx_16479_numeventid" UNIQUE, btree (numeventid, code) -Foreign-key constraints: - "submission_ibfk_1" FOREIGN KEY (numeventid) REFERENCES researchevent(numeventid) ON UPDATE CASCADE ON DELETE CASCADE -Referenced by: - TABLE "accomplishment" CONSTRAINT "accomplishment_ibfk_1" FOREIGN KEY (subid) REFERENCES submission(subid) ON UPDATE CASCADE ON DELETE SET NULL - TABLE "submits" CONSTRAINT "submits_ibfk_3" FOREIGN KEY (subid) REFERENCES submission(subid) ON UPDATE CASCADE ON DELETE CASCADE -""" -class Submission(Base): - __tablename__ = 'submission' - - sub_id: Mapped[int] = mapped_column("subid", BIGINT, primary_key=True) - num_event_id: Mapped[int] = mapped_column("numeventid", ForeignKey("researchevent.numeventid", name="submission_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) - code: Mapped[str] = mapped_column("code", VARCHAR(20)) - sub_title: Mapped[str] = mapped_column("subtitle", VARCHAR(200)) - sub_abstract: Mapped[str] = mapped_column("subabstract", VARCHAR(2000)) - - event: Mapped[ResearchEvent] = relationship("ResearchEvent", back_populates="submissions") - - accomplishments: Mapped[List["Accomplishment"]] = relationship("Accomplishment", back_populates="submission") - submits: Mapped[List["Submits"]] = relationship("Submits", back_populates="submission", cascade="all, delete-orphan", passive_deletes=True) - - __table_args__ = (UniqueConstraint('numeventid', 'code', name='idx_16479_numeventid'),) - -""" -Table "arxiv.accomplishment" - Column | Type | Collation | Nullable | Default ----------+------------------------+-----------+----------+--------- - accid | integer | | not null | - isaward | boolean | | not null | false - name | character varying(100) | | | - prize | character varying(100) | | | - subid | bigint | | | -Indexes: - "idx_16386_primary" PRIMARY KEY, btree (accid) - "idx_16386_subid" btree (subid) -Foreign-key constraints: - "accomplishment_ibfk_1" FOREIGN KEY (subid) REFERENCES submission(subid) ON UPDATE CASCADE ON DELETE SET NULL -Referenced by: - TABLE "publication" CONSTRAINT "publication_ibfk_1" FOREIGN KEY (accid) REFERENCES accomplishment(accid) ON UPDATE CASCADE ON DELETE CASCADE -""" -class Accomplishment(Base): - __tablename__ = 'accomplishment' - - acc_id: Mapped[int] = mapped_column("accid", INTEGER, primary_key=True) - is_award: Mapped[bool] = mapped_column("isaward", BOOLEAN, server_default=false(), default=False) - name: Mapped[Optional[str]] = mapped_column("name", VARCHAR(100)) - prize: Mapped[Optional[str]] = mapped_column("prize", VARCHAR(100)) - sub_id: Mapped[Optional[int]] = mapped_column("subid", ForeignKey("submission.subid", name="accomplishment_ibfk_1", onupdate="CASCADE", ondelete="SET NULL")) - - submission: Mapped[Submission] = relationship("Submission", back_populates="accomplishments") - publication: Mapped["Publication"] = relationship("Publication", back_populates="accomplishment", cascade="all, delete-orphan", passive_deletes=True) - - __table_args__ = (Index('idx_16386_subid', 'subid'),) - -""" -Table "arxiv.awardtypes" - Column | Type | Collation | Nullable | Default -------------+------------------------+-----------+----------+---------------------------------------- - id | bigint | | not null | nextval('awardtypes_id_seq'::regclass) - numeventid | bigint | | not null | - awardtype | character varying(100) | | not null | -Indexes: - "idx_16391_primary" PRIMARY KEY, btree (id) - "idx_16391_numeventid" UNIQUE, btree (numeventid, awardtype) -Foreign-key constraints: - "awardtypes_ibfk_1" FOREIGN KEY (numeventid) REFERENCES researchevent(numeventid) ON UPDATE CASCADE ON DELETE CASCADE -""" -class AwardTypes(Base): - __tablename__ = 'awardtypes' - - id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) - num_event_id: Mapped[int] = mapped_column("numeventid", ForeignKey("researchevent.numeventid", name="awardtypes_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) - award_type: Mapped[str] = mapped_column("awardtype", VARCHAR(100)) - - event: Mapped[ResearchEvent] = relationship("ResearchEvent", back_populates="award_types") - - __table_args__ = (UniqueConstraint('numeventid', 'awardtype', name='idx_16391_numeventid'),) - -""" -Table "arxiv.department" - Column | Type | Collation | Nullable | Default ---------+-----------------------+-----------+----------+----------------------- - deptid | character(2) | | not null | - name | character varying(50) | | not null | ''::character varying -Indexes: - "idx_16395_primary" PRIMARY KEY, btree (deptid) -Referenced by: - TABLE "nushteacher" CONSTRAINT "nushteacher_ibfk_1" FOREIGN KEY (deptid) REFERENCES department(deptid) ON UPDATE CASCADE ON DELETE SET NULL - TABLE "project" CONSTRAINT "project_ibfk_1" FOREIGN KEY (deptid) REFERENCES department(deptid) ON UPDATE CASCADE ON DELETE SET NULL -""" -class Department(Base): - __tablename__ = 'department' - - dept_id: Mapped[str] = mapped_column("deptid", VARCHAR(2), primary_key=True) - name: Mapped[str] = mapped_column("name", VARCHAR(50), server_default="", default="") - - teachers: Mapped[List["NUSHTeacher"]] = relationship("NUSHTeacher", back_populates="department") - projects: Mapped[List["Project"]] = relationship("Project", back_populates="department") - -""" -Table "arxiv.student" - Column | Type | Collation | Nullable | Default ---------+------------------------+-----------+----------+--------- - email | character varying(255) | | not null | - name | character varying(100) | | | -Indexes: - "idx_16475_primary" PRIMARY KEY, btree (email) -Referenced by: - TABLE "externalstudent" CONSTRAINT "externalstudent_ibfk_1" FOREIGN KEY (email) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE - TABLE "nushstudent" CONSTRAINT "nushstudent_ibfk_1" FOREIGN KEY (email) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE - TABLE "submits" CONSTRAINT "submits_ibfk_1" FOREIGN KEY (studentemail) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE - TABLE "works_on" CONSTRAINT "works_on_ibfk_2" FOREIGN KEY (studentemail) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE -""" -class Student(Base): - __tablename__ = 'student' - - email: Mapped[str] = mapped_column("email", VARCHAR(255), primary_key=True) - name: Mapped[Optional[str]] = mapped_column("name", VARCHAR(100)) - - external_student: Mapped["ExternalStudent"] = relationship("ExternalStudent", back_populates="student", cascade="all, delete-orphan", passive_deletes=True) - nush_student: Mapped["NUSHStudent"] = relationship("NUSHStudent", back_populates="student", cascade="all, delete-orphan", passive_deletes=True) - submits: Mapped[List["Submits"]] = relationship("Submits", back_populates="student", cascade="all, delete-orphan", passive_deletes=True) - projects: Mapped[List["WorksOn"]] = relationship("WorksOn", back_populates="student", cascade="all, delete-orphan", passive_deletes=True) - -""" -Table "arxiv.institution" - Column | Type | Collation | Nullable | Default --------------+------------------------+-----------+----------+----------------------- - instid | character varying(10) | | not null | - name | character varying(100) | | not null | ''::character varying - address | character varying(150) | | not null | ''::character varying - isschool | boolean | | not null | false - isinstitute | boolean | | not null | false - isorganiser | boolean | | not null | false - ispublisher | boolean | | not null | false -Indexes: - "idx_16407_primary" PRIMARY KEY, btree (instid) -Referenced by: - TABLE "externalteacher" CONSTRAINT "externalteacher_ibfk_1" FOREIGN KEY (schid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE SET NULL - TABLE "organises" CONSTRAINT "organises_ibfk_2" FOREIGN KEY (instid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE CASCADE - TABLE "publishedby" CONSTRAINT "publishedby_ibfk_2" FOREIGN KEY (instid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE CASCADE - TABLE "works_at" CONSTRAINT "works_at_ibfk_2" FOREIGN KEY (instid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE CASCADE -""" -class Institution(Base): - __tablename__ = 'institution' - - inst_id: Mapped[str] = mapped_column("instid", VARCHAR(10), primary_key=True) - name: Mapped[str] = mapped_column("name", VARCHAR(100), server_default="", default="") - address: Mapped[str] = mapped_column("address", VARCHAR(150), server_default="", default="") - is_school: Mapped[bool] = mapped_column("isschool", BOOLEAN, server_default=false(), default=False) - is_institute: Mapped[bool] = mapped_column("isinstitute", BOOLEAN, server_default=false(), default=False) - is_organiser: Mapped[bool] = mapped_column("isorganiser", BOOLEAN, server_default=false(), default=False) - is_publisher: Mapped[bool] = mapped_column("ispublisher", BOOLEAN, server_default=false(), default=False) - - teachers: Mapped[List["ExternalTeacher"]] = relationship("ExternalTeacher", back_populates="institution") - events: Mapped[List["Organises"]] = relationship("Organises", back_populates="institution", cascade="all, delete-orphan", passive_deletes=True) - publishes: Mapped[List["PublishedBy"]] = relationship("PublishedBy", back_populates="institution", cascade="all, delete-orphan", passive_deletes=True) - members: Mapped[List["WorksAt"]] = relationship("WorksAt", back_populates="institution", cascade="all, delete-orphan", passive_deletes=True) - -""" -Table "arxiv.externalteacher" - Column | Type | Collation | Nullable | Default ---------+------------------------+-----------+----------+--------- - email | character varying(255) | | not null | - name | character varying(100) | | | - schid | character varying(10) | | | -Indexes: - "idx_16404_primary" PRIMARY KEY, btree (email) - "idx_16404_schid" btree (schid) -Foreign-key constraints: - "externalteacher_ibfk_1" FOREIGN KEY (schid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE SET NULL -Referenced by: - TABLE "externalstudent" CONSTRAINT "externalstudent_ibfk_2" FOREIGN KEY (emergencyemail) REFERENCES externalteacher(email) ON UPDATE CASCADE ON DELETE SET NULL -""" -class ExternalTeacher(Base): - __tablename__ = 'externalteacher' - - email: Mapped[str] = mapped_column("email", VARCHAR(255), primary_key=True) - name: Mapped[Optional[str]] = mapped_column("name", VARCHAR(100)) - sch_id: Mapped[Optional[str]] = mapped_column("schid", ForeignKey("institution.instid", name="externalteacher_ibfk_1", onupdate="CASCADE", ondelete="SET NULL")) - - institution: Mapped[Institution] = relationship("Institution", back_populates="teachers") - students: Mapped[List["ExternalStudent"]] = relationship("ExternalStudent", back_populates="teacher") - - __table_args__ = (Index('idx_16404_schid', 'schid'),) - -""" -Table "arxiv.externalstudent" - Column | Type | Collation | Nullable | Default -----------------+------------------------+-----------+----------+--------- - email | character varying(255) | | not null | - emergencyemail | character varying(255) | | | -Indexes: - "idx_16399_primary" PRIMARY KEY, btree (email) - "idx_16399_emergencyemail" btree (emergencyemail) -Foreign-key constraints: - "externalstudent_ibfk_1" FOREIGN KEY (email) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE - "externalstudent_ibfk_2" FOREIGN KEY (emergencyemail) REFERENCES externalteacher(email) ON UPDATE CASCADE ON DELETE SET NULL -""" -class ExternalStudent(Base): - __tablename__ = 'externalstudent' - - email: Mapped[str] = mapped_column("email", ForeignKey("student.email", name="externalstudent_ibfk_1", onupdate="CASCADE", ondelete="CASCADE"), primary_key=True) - emergency_email: Mapped[Optional[str]] = mapped_column("emergencyemail", ForeignKey("externalteacher.email", name="externalstudent_ibfk_2", onupdate="CASCADE", ondelete="SET NULL")) - - student: Mapped[Student] = relationship("Student", back_populates="external_student") - teacher: Mapped[ExternalTeacher] = relationship("ExternalTeacher", back_populates="students") - - __table_args__ = (Index('idx_16399_emergencyemail', 'emergencyemail'),) - -""" -Table "arxiv.journal" - Column | Type | Collation | Nullable | Default ---------+------------------------+-----------+----------+--------- - issn | integer | | not null | - name | character varying(100) | | not null | -Indexes: - "idx_16416_primary" PRIMARY KEY, btree (issn) -Referenced by: - TABLE "publication" CONSTRAINT "publication_ibfk_2" FOREIGN KEY (journissn) REFERENCES journal(issn) ON UPDATE CASCADE ON DELETE CASCADE - TABLE "publishedby" CONSTRAINT "publishedby_ibfk_1" FOREIGN KEY (issn) REFERENCES journal(issn) ON UPDATE CASCADE ON DELETE CASCADE -""" -class Journal(Base): - __tablename__ = 'journal' - - issn: Mapped[int] = mapped_column("issn", INTEGER, autoincrement=False, primary_key=True) - name: Mapped[str] = mapped_column("name", VARCHAR(100)) - - publications: Mapped[List["Publication"]] = relationship("Publication", back_populates="journal", cascade="all, delete-orphan", passive_deletes=True) - publishers: Mapped[List["PublishedBy"]] = relationship("PublishedBy", back_populates="journal", cascade="all, delete-orphan", passive_deletes=True) - -""" -Table "arxiv.researchmentor" - Column | Type | Collation | Nullable | Default ---------+------------------------+-----------+----------+--------- - email | character varying(255) | | not null | - name | character varying(100) | | | -Indexes: - "idx_16472_primary" PRIMARY KEY, btree (email) -Referenced by: - TABLE "mentors" CONSTRAINT "mentors_ibfk_2" FOREIGN KEY (mentoremail) REFERENCES researchmentor(email) ON UPDATE CASCADE ON DELETE CASCADE - TABLE "works_at" CONSTRAINT "works_at_ibfk_1" FOREIGN KEY (mentoremail) REFERENCES researchmentor(email) ON UPDATE CASCADE ON DELETE CASCADE -""" -class ResearchMentor(Base): - __tablename__ = 'researchmentor' - - email: Mapped[str] = mapped_column("email", VARCHAR(255), primary_key=True) - name: Mapped[Optional[str]] = mapped_column("name", VARCHAR(100)) - - projects: Mapped[List["Mentors"]] = relationship("Mentors", back_populates="mentor", cascade="all, delete-orphan", passive_deletes=True) - workplaces: Mapped[List["WorksAt"]] = relationship("WorksAt", back_populates="mentor", cascade="all, delete-orphan", passive_deletes=True) - -""" -Table "arxiv.nushteacher" - Column | Type | Collation | Nullable | Default -----------+------------------------+-----------+----------+----------------------- - email | character varying(255) | | not null | - pwd | character varying(20) | | | - name | character varying(100) | | not null | ''::character varying - pfp | bytea | | | - isadmin | boolean | | not null | false - ismentor | boolean | | not null | false - deptid | character(2) | | | -Indexes: - "idx_16429_primary" PRIMARY KEY, btree (email) - "idx_16429_deptid" btree (deptid) -Foreign-key constraints: - "nushteacher_ibfk_1" FOREIGN KEY (deptid) REFERENCES department(deptid) ON UPDATE CASCADE ON DELETE SET NULL -Referenced by: - TABLE "project" CONSTRAINT "project_ibfk_2" FOREIGN KEY (teacheremail) REFERENCES nushteacher(email) ON UPDATE CASCADE ON DELETE SET NULL -""" -class NUSHTeacher(Base): - __tablename__ = 'nushteacher' - - email: Mapped[str] = mapped_column("email", VARCHAR(255), primary_key=True) - pwd: Mapped[Optional[str]] = mapped_column("pwd", VARCHAR(20)) - name: Mapped[str] = mapped_column("name", VARCHAR(100), server_default="", default="") - pfp: Mapped[Optional[bytes]] = mapped_column("pfp", BYTEA) - is_admin: Mapped[bool] = mapped_column("isadmin", BOOLEAN, server_default=false(), default=False) - is_mentor: Mapped[bool] = mapped_column("ismentor", BOOLEAN, server_default=false(), default=False) - dept_id: Mapped[Optional[str]] = mapped_column("deptid", ForeignKey("department.deptid", name="nushteacher_ibfk_1", onupdate="CASCADE", ondelete="SET NULL")) - - department: Mapped[Department] = relationship("Department", back_populates="teachers") - projects: Mapped[List["Project"]] = relationship("Project", back_populates="teacher") - - __table_args__ = (Index('idx_16429_deptid', 'deptid'),) - -""" -Table "arxiv.project" - Column | Type | Collation | Nullable | Default ---------------+-------------------------+-----------+----------+--------- - pcode | character varying(20) | | not null | - title | character varying(200) | | not null | - abstract | character varying(2000) | | | - reportpdf | bytea | | | - year | integer | | | - deptid | character(2) | | | - teacheremail | character varying(255) | | | -Indexes: - "idx_16442_primary" PRIMARY KEY, btree (pcode) - "idx_16442_deptid" btree (deptid) - "idx_16442_teacheremail" btree (teacheremail) -Foreign-key constraints: - "project_ibfk_1" FOREIGN KEY (deptid) REFERENCES department(deptid) ON UPDATE CASCADE ON DELETE SET NULL - "project_ibfk_2" FOREIGN KEY (teacheremail) REFERENCES nushteacher(email) ON UPDATE CASCADE ON DELETE SET NULL -Referenced by: - TABLE "mentors" CONSTRAINT "mentors_ibfk_1" FOREIGN KEY (pcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE - TABLE "projectcontinuation" CONSTRAINT "projectcontinuation_ibfk_1" FOREIGN KEY (prevpcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE - TABLE "projectcontinuation" CONSTRAINT "projectcontinuation_ibfk_2" FOREIGN KEY (nextpcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE - TABLE "submits" CONSTRAINT "submits_ibfk_2" FOREIGN KEY (pcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE - TABLE "works_on" CONSTRAINT "works_on_ibfk_1" FOREIGN KEY (pcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE -""" -class Project(Base): - __tablename__ = 'project' - - p_code: Mapped[str] = mapped_column("pcode", VARCHAR(20), primary_key=True) - title: Mapped[str] = mapped_column("title", VARCHAR(200)) - abstract: Mapped[Optional[str]] = mapped_column("abstract", VARCHAR(2000)) - report_pdf: Mapped[Optional[bytes]] = mapped_column("reportpdf", BYTEA) - year: Mapped[Optional[int]] = mapped_column("year", INTEGER) - dept_id: Mapped[Optional[str]] = mapped_column("deptid", ForeignKey("department.deptid", name="project_ibfk_1", onupdate="CASCADE", ondelete="SET NULL")) - teacher_email: Mapped[Optional[str]] = mapped_column("teacheremail", ForeignKey("nushteacher.email", name="project_ibfk_2", onupdate="CASCADE", ondelete="SET NULL")) - - department: Mapped[Department] = relationship("Department", back_populates="projects") - teacher: Mapped[NUSHTeacher] = relationship("NUSHTeacher", back_populates="projects") - - mentors: Mapped[List["Mentors"]] = relationship("Mentors", back_populates="project", cascade="all, delete-orphan", passive_deletes=True) - continuations: Mapped[List["ProjectContinuation"]] = relationship("ProjectContinuation", back_populates="prev_project", cascade="all, delete-orphan", passive_deletes=True) - prev_projects: Mapped[List["ProjectContinuation"]] = relationship("ProjectContinuation", back_populates="next_project", cascade="all, delete-orphan", passive_deletes=True) - submits: Mapped[List["Submits"]] = relationship("Submits", back_populates="project", cascade="all, delete-orphan", passive_deletes=True) - students: Mapped[List["WorksOn"]] = relationship("WorksOn", back_populates="project", cascade="all, delete-orphan", passive_deletes=True) - - __table_args__ = (Index('idx_16442_deptid', 'deptid'), Index('idx_16442_teacheremail', 'teacheremail'),) - -""" -Table "arxiv.mentors" - Column | Type | Collation | Nullable | Default --------------+------------------------+-----------+----------+------------------------------------- - id | bigint | | not null | nextval('mentors_id_seq'::regclass) - mentoremail | character varying(255) | | not null | - pcode | character varying(20) | | not null | -Indexes: - "idx_16420_primary" PRIMARY KEY, btree (id) - "idx_16420_mentoremail" btree (mentoremail) - "idx_16420_pcode_2" UNIQUE, btree (pcode, mentoremail) -Foreign-key constraints: - "mentors_ibfk_1" FOREIGN KEY (pcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE - "mentors_ibfk_2" FOREIGN KEY (mentoremail) REFERENCES researchmentor(email) ON UPDATE CASCADE ON DELETE CASCADE -""" -class Mentors(Base): - __tablename__ = 'mentors' - - id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) - mentor_email: Mapped[str] = mapped_column("mentoremail", ForeignKey("researchmentor.email", name="mentors_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) - p_code: Mapped[str] = mapped_column("pcode", ForeignKey("project.pcode", name="mentors_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) - - project: Mapped[Project] = relationship("Project", back_populates="mentors") - mentor: Mapped[ResearchMentor] = relationship("ResearchMentor", back_populates="projects") - - __table_args__ = (UniqueConstraint('pcode', 'mentoremail', name='idx_16420_pcode_2'), Index('idx_16420_mentoremail', 'mentoremail'),) - -""" -Table "arxiv.nushstudent" - Column | Type | Collation | Nullable | Default -----------+-------------------------+-----------+----------+--------- - email | character varying(255) | | not null | - pwd | character varying(20) | | | - pfp | bytea | | | - about | character varying(1000) | | | - gradyear | integer | | | - nush_sid | character varying(8) | | | -Indexes: - "idx_16424_primary" PRIMARY KEY, btree (email) -Foreign-key constraints: - "nushstudent_ibfk_1" FOREIGN KEY (email) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE -""" -class NUSHStudent(Base): - __tablename__ = 'nushstudent' - - email: Mapped[str] = mapped_column("email", ForeignKey("student.email", name="nushstudent_ibfk_1", onupdate="CASCADE", ondelete="CASCADE"), primary_key=True) - pwd: Mapped[Optional[str]] = mapped_column("pwd", VARCHAR(20)) - pfp: Mapped[Optional[bytes]] = mapped_column("pfp", BYTEA) - about: Mapped[Optional[str]] = mapped_column("about", VARCHAR(1000)) - grad_year: Mapped[Optional[int]] = mapped_column("gradyear", INTEGER) - nush_sid: Mapped[Optional[str]] = mapped_column("nush_sid", VARCHAR(8)) - - student: Mapped[Student] = relationship("Student", back_populates="nush_student") - -""" -Table "arxiv.organises" - Column | Type | Collation | Nullable | Default -------------+-----------------------+-----------+----------+--------------------------------------- - id | bigint | | not null | nextval('organises_id_seq'::regclass) - numeventid | bigint | | not null | - instid | character varying(10) | | not null | -Indexes: - "idx_16438_primary" PRIMARY KEY, btree (id) - "idx_16438_instid" btree (instid) - "idx_16438_numeventid" UNIQUE, btree (numeventid, instid) -Foreign-key constraints: - "organises_ibfk_2" FOREIGN KEY (instid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE CASCADE - "organises_ibfk_3" FOREIGN KEY (numeventid) REFERENCES researchevent(numeventid) ON UPDATE CASCADE ON DELETE CASCADE -""" -class Organises(Base): - __tablename__ = 'organises' - - id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) - num_event_id: Mapped[int] = mapped_column("numeventid", ForeignKey("researchevent.numeventid", name="organises_ibfk_3", onupdate="CASCADE", ondelete="CASCADE")) - inst_id: Mapped[str] = mapped_column("instid", ForeignKey("institution.instid", name="organises_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) - - event: Mapped[ResearchEvent] = relationship("ResearchEvent", back_populates="organisers") - institution: Mapped[Institution] = relationship("Institution", back_populates="events") - - __table_args__ = (UniqueConstraint('numeventid', 'instid', name='idx_16438_numeventid'), Index('idx_16438_instid', 'instid'),) - -""" -Table "arxiv.projectcontinuation" - Column | Type | Collation | Nullable | Default ------------+-----------------------+-----------+----------+------------------------------------------------- - id | bigint | | not null | nextval('projectcontinuation_id_seq'::regclass) - prevpcode | character varying(20) | | not null | - nextpcode | character varying(20) | | not null | -Indexes: - "idx_16448_primary" PRIMARY KEY, btree (id) - "idx_16448_nextpcode" btree (nextpcode) - "idx_16448_prevpcode_2" UNIQUE, btree (prevpcode, nextpcode) -Foreign-key constraints: - "projectcontinuation_ibfk_1" FOREIGN KEY (prevpcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE - "projectcontinuation_ibfk_2" FOREIGN KEY (nextpcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE -""" -class ProjectContinuation(Base): - __tablename__ = 'projectcontinuation' - - id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) - prev_p_code: Mapped[str] = mapped_column("prevpcode", ForeignKey("project.pcode", name="projectcontinuation_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) - next_p_code: Mapped[str] = mapped_column("nextpcode", ForeignKey("project.pcode", name="projectcontinuation_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) - - prev_project: Mapped["Project"] = relationship("Project", foreign_keys=[prev_p_code], back_populates="continuations") - next_project: Mapped["Project"] = relationship("Project", foreign_keys=[next_p_code], back_populates="prev_projects") - - __table_args__ = (UniqueConstraint('prevpcode', 'nextpcode', name='idx_16448_prevpcode_2'), Index('idx_16448_nextpcode', 'nextpcode'),) - -""" -Table "arxiv.publication" - Column | Type | Collation | Nullable | Default ------------+------------------------+-----------+----------+--------- - accid | integer | | not null | - pubtitle | character varying(200) | | not null | - doi | character varying(200) | | | - isjournal | boolean | | not null | false - url | character varying(300) | | | - journissn | integer | | | -Indexes: - "idx_16452_primary" PRIMARY KEY, btree (accid) - "idx_16452_journissn" btree (journissn) -Foreign-key constraints: - "publication_ibfk_1" FOREIGN KEY (accid) REFERENCES accomplishment(accid) ON UPDATE CASCADE ON DELETE CASCADE - "publication_ibfk_2" FOREIGN KEY (journissn) REFERENCES journal(issn) ON UPDATE CASCADE ON DELETE CASCADE -""" -class Publication(Base): - __tablename__ = 'publication' - - acc_id: Mapped[int] = mapped_column("accid", ForeignKey("accomplishment.accid", name="publication_ibfk_1", onupdate="CASCADE", ondelete="CASCADE"), primary_key=True) - pub_title: Mapped[str] = mapped_column("pubtitle", VARCHAR(200)) - doi: Mapped[Optional[str]] = mapped_column("doi", VARCHAR(200)) - is_journal: Mapped[bool] = mapped_column("isjournal", BOOLEAN, server_default=false(), default=False) - url: Mapped[Optional[str]] = mapped_column("url", VARCHAR(300)) - journ_issn: Mapped[Optional[int]] = mapped_column("journissn", ForeignKey("journal.issn", name="publication_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) - - accomplishment: Mapped[Accomplishment] = relationship("Accomplishment", back_populates="publication") - journal: Mapped[Journal] = relationship("Journal", back_populates="publications") - - __table_args__ = (Index('idx_16452_journissn', 'journissn'),) - -""" -Table "arxiv.publishedby" - Column | Type | Collation | Nullable | Default ---------+-----------------------+-----------+----------+----------------------------------------- - id | bigint | | not null | nextval('publishedby_id_seq'::regclass) - issn | integer | | not null | - instid | character varying(10) | | not null | -Indexes: - "idx_16459_primary" PRIMARY KEY, btree (id) - "idx_16459_instid" btree (instid) - "idx_16459_issn_2" UNIQUE, btree (issn, instid) -Foreign-key constraints: - "publishedby_ibfk_1" FOREIGN KEY (issn) REFERENCES journal(issn) ON UPDATE CASCADE ON DELETE CASCADE - "publishedby_ibfk_2" FOREIGN KEY (instid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE CASCADE -""" -class PublishedBy(Base): - __tablename__ = 'publishedby' - - id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) - issn: Mapped[int] = mapped_column("issn", ForeignKey("journal.issn", name="publishedby_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) - inst_id: Mapped[str] = mapped_column("instid", ForeignKey("institution.instid", name="publishedby_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) - - journal: Mapped[Journal] = relationship("Journal", back_populates="publishers") - institution: Mapped[Institution] = relationship("Institution", back_populates="publishes") - - __table_args__ = (UniqueConstraint('issn', 'instid', name='idx_16459_issn_2'), Index('idx_16459_instid', 'instid'),) - -""" -Table "arxiv.submits" - Column | Type | Collation | Nullable | Default ---------------+------------------------+-----------+----------+------------------------------------- - id | bigint | | not null | nextval('submits_id_seq'::regclass) - studentemail | character varying(255) | | not null | - pcode | character varying(20) | | not null | - subid | bigint | | not null | -Indexes: - "idx_16486_primary" PRIMARY KEY, btree (id) - "idx_16486_pcode" btree (pcode) - "idx_16486_studentemail_2" UNIQUE, btree (studentemail, pcode, subid) - "idx_16486_subid" btree (subid) -Foreign-key constraints: - "submits_ibfk_1" FOREIGN KEY (studentemail) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE - "submits_ibfk_2" FOREIGN KEY (pcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE - "submits_ibfk_3" FOREIGN KEY (subid) REFERENCES submission(subid) ON UPDATE CASCADE ON DELETE CASCADE -""" -class Submits(Base): - __tablename__ = 'submits' - - id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) - student_email: Mapped[str] = mapped_column("studentemail", ForeignKey("student.email", name="submits_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) - p_code: Mapped[str] = mapped_column("pcode", ForeignKey("project.pcode", name="submits_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) - sub_id: Mapped[int] = mapped_column("subid", ForeignKey("submission.subid", name="submits_ibfk_3", onupdate="CASCADE", ondelete="CASCADE")) - - student: Mapped[Student] = relationship("Student", back_populates="submits") - project: Mapped[Project] = relationship("Project", back_populates="submits") - submission: Mapped[Submission] = relationship("Submission", back_populates="submits") - - __table_args__ = (UniqueConstraint('studentemail', 'pcode', 'subid', name='idx_16486_studentemail_2'), Index('idx_16486_pcode', 'pcode'), Index('idx_16486_subid', 'subid'),) - -""" -Table "arxiv.works_at" - Column | Type | Collation | Nullable | Default --------------+------------------------+-----------+----------+-------------------------------------- - id | bigint | | not null | nextval('works_at_id_seq'::regclass) - mentoremail | character varying(255) | | not null | - instid | character varying(10) | | not null | - dept | character varying(100) | | | - role | character varying(100) | | | - officeaddr | character varying(100) | | | -Indexes: - "idx_16491_primary" PRIMARY KEY, btree (id) - "idx_16491_instid" btree (instid) - "idx_16491_mentoremail" UNIQUE, btree (mentoremail, instid) -Foreign-key constraints: - "works_at_ibfk_1" FOREIGN KEY (mentoremail) REFERENCES researchmentor(email) ON UPDATE CASCADE ON DELETE CASCADE - "works_at_ibfk_2" FOREIGN KEY (instid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE CASCADE -""" -class WorksAt(Base): - __tablename__ = 'works_at' - - id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) - mentor_email: Mapped[str] = mapped_column("mentoremail", ForeignKey("researchmentor.email", name="works_at_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) - inst_id: Mapped[str] = mapped_column("instid", ForeignKey("institution.instid", name="works_at_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) - dept: Mapped[Optional[str]] = mapped_column("dept", VARCHAR(100)) - role: Mapped[Optional[str]] = mapped_column("role", VARCHAR(100)) - office_addr: Mapped[Optional[str]] = mapped_column("officeaddr", VARCHAR(100)) - - mentor: Mapped[ResearchMentor] = relationship("ResearchMentor", back_populates="workplaces") - institution: Mapped[Institution] = relationship("Institution", back_populates="members") - - __table_args__ = (UniqueConstraint('mentoremail', 'instid', name='idx_16491_mentoremail'), Index('idx_16491_instid', 'instid'),) - -""" -Table "arxiv.works_on" - Column | Type | Collation | Nullable | Default ---------------+------------------------+-----------+----------+-------------------------------------- - id | bigint | | not null | nextval('works_on_id_seq'::regclass) - studentemail | character varying(255) | | not null | - pcode | character varying(20) | | not null | -Indexes: - "idx_16498_primary" PRIMARY KEY, btree (id) - "idx_16498_pcode" btree (pcode) - "idx_16498_studentemail" UNIQUE, btree (studentemail, pcode) -Foreign-key constraints: - "works_on_ibfk_1" FOREIGN KEY (pcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE - "works_on_ibfk_2" FOREIGN KEY (studentemail) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE -""" -class WorksOn(Base): - __tablename__ = 'works_on' - - id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) - student_email: Mapped[str] = mapped_column("studentemail", ForeignKey("student.email", name="works_on_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) - p_code: Mapped[str] = mapped_column("pcode", ForeignKey("project.pcode", name="works_on_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) - - project: Mapped[Project] = relationship("Project", back_populates="students") - student: Mapped[Student] = relationship("Student", back_populates="projects") - - __table_args__ = (UniqueConstraint('studentemail', 'pcode', name='idx_16498_studentemail'), Index('idx_16498_pcode', 'pcode'),) \ No newline at end of file +import base64 + +from sqlalchemy import select, union, update +from util import remove_nulls +import random +import itertools +from sqlalchemy.orm import Session, Bundle +from . import models, schemas +from functools import cache + +@cache +def get_default_pfp() -> bytes: + with open("assets/default.png", "rb") as f: + pfp = f.read() + + return pfp + +# ==================================== EXISTS FUNCTIONALITY ==================================== + +def is_student(db: Session, email: str) -> bool: + return db.execute(select(models.Student).filter(models.Student.email == email)).first() != None + +def is_mentor(db: Session, email: str) -> bool: + return db.execute(select(models.ResearchMentor).filter(models.ResearchMentor.email == email)).first() != None + +def is_nush_teacher(db: Session, email: str) -> bool: + return db.execute(select(models.NUSHTeacher).filter(models.NUSHTeacher.email == email)).first() != None + +def is_nush_student(db: Session, email: str) -> bool: + return db.execute(select(models.NUSHStudent).filter(models.NUSHStudent.email == email)).first() != None + + +# ================================ AUTHENTICATION FUNCTIONALITY ================================ + +def student_login(db: Session, email: str, pwd: str) -> bool: + return db.execute(select(models.NUSHStudent).filter(models.NUSHStudent.email == email, models.NUSHStudent.pwd == pwd)).first() != None + +def teacher_login(db: Session, email: str, pwd: str) -> bool: + return db.execute(select(models.NUSHTeacher).filter(models.NUSHTeacher.email == email, models.NUSHTeacher.pwd == pwd)).first() != None + +# FIXME +def login(db: Session, email: str, password: str) -> schemas.LoginResult: + is_student = is_nush_student(db, email) + + if is_student: + is_student_auth = student_login(db, email, password) + if is_student_auth: + return schemas.LoginResult(result=True, user=get_nush_student(db, email), message="Logged in successfully!") + return schemas.LoginResult(result=False, message="Incorrect password provided!") + + is_teacher = is_nush_teacher(db, email) + + if is_teacher: + is_teacher_auth = teacher_login(db, email, password) + if is_teacher_auth: + return schemas.LoginResult(result=True, user=get_nush_teacher(db, email), message="Logged in successfully!") + return schemas.LoginResult(result=False, message="Incorrect password provided!") + + return schemas.LoginResult(result=False, message="Account does not exist!") + +def register_student( + db: Session, email: str, password: str, name: str, grad_year: int +) -> schemas.RegisterStudentResult: + if not(email.endswith("@nushigh.edu.sg") and email[0] == 'h' and email[1:8].isnumeric()): + return schemas.RegisterStudentResult(result=False, error="Please give a valid email of form `hXXXXXXX@nushigh.edu.sg`.") + + # additional grad year check + join_yr = int(email[1:3]) + join_lvl = int(email[3]) + if (grad_year % 100) != ((join_yr + 6 - join_lvl) % 100): + return schemas.RegisterStudentResult(result=False, error="Graduation year appears invalid.") + + existing = is_nush_student(db, email) + if existing: + if(student_login(db, email, password)): + return schemas.RegisterStudentResult(result=True, user=get_nush_student(db, email), message="Account already exists, successfully logged in with details provided.") + return schemas.RegisterStudentResult(result=False, error="Account already exists!") + try: + db_nush_student = models.NUSHStudent( + email=email, pwd=password, pfp=get_default_pfp(), grad_year=grad_year, nush_sid=email[1:8] + ) + db_student = models.Student(email=email, name=name, nush_student=db_nush_student) + db.add(db_student) + db.commit() + + return schemas.RegisterStudentResult(result=True, user=get_nush_student(db, email), message="Registered Successfully!") + except Exception as e: + return schemas.RegisterStudentResult(result=False, error=str(e)) + +def register_teacher( + db: Session, email: str, password: str, name: str, dept_id: str +) -> schemas.RegisterTeacherResult: + if not(email.endswith("@nushigh.edu.sg")): + return schemas.RegisterTeacherResult(result=False, error="Please give a valid email ending with `@nushigh.edu.sg`.") + existing = is_nush_teacher(db, email) + if existing: + if(teacher_login(db, email, password)): + return schemas.RegisterTeacherResult(result=True, user=get_nush_teacher(db, email), message="Account already exists, successfully logged in with details provided.") + return schemas.RegisterTeacherResult(result=False, error="Account already exists!") + try: + db_nush_teacher = models.NUSHTeacher( + email=email, pwd=password, name=name, pfp=get_default_pfp(), dept_id=dept_id + ) + db.add(db_nush_teacher) + db.commit() + + return schemas.RegisterTeacherResult(result=True, user=get_nush_teacher(db, email), message="Registered Successfully!") + except Exception as e: + return schemas.RegisterTeacherResult(result=False, error=str(e)) + +def change_password(db: Session, email: str, old_pwd: str, new_pwd: str) -> schemas.ChangePasswordResult: + union_std_tcr = union(select(models.NUSHTeacher.email, models.NUSHTeacher.pwd), select(models.NUSHStudent.email, models.NUSHStudent.pwd)).subquery() + stmt = select(union_std_tcr).where(union_std_tcr.c.email == "h1910090@nushigh.edu.sg") + pwd_in_db = db.execute(stmt).one().pwd + + if(old_pwd != pwd_in_db): + return schemas.ChangePasswordResult(response="Current password is not correct!") + + if(is_student(db, email)): + db.execute(update(models.NUSHStudent).where(models.NUSHStudent.email == email).values(pwd=new_pwd)) + else: + db.execute(update(models.NUSHTeacher).where(models.NUSHTeacher.email == email).values(pwd=new_pwd)) + + return schemas.ChangePasswordResult(response="Success!") + + + +# ==================================== GETTER FUNCTIONALITY ==================================== + +def get_institution(db: Session, inst_id: str) -> models.Institution | None: + return db.execute(select(models.Institution).filter(models.Institution.inst_id == inst_id)).scalar_one_or_none() + +def get_nush_teacher_raw(db: Session, email: str) -> models.NUSHTeacher | None: + return db.execute(select(models.NUSHTeacher).filter(models.NUSHTeacher.email == email)).scalar_one_or_none() + +def get_nush_teacher(db: Session, email: str) -> schemas.NUSHTeacher | None: + teacher = get_nush_teacher_raw(db, email) + if not teacher: return None + pfp = base64.b64encode(teacher.pfp_bytes).decode("ascii") if teacher.pfp_bytes != None else "" + ret_teacher = schemas.NUSHTeacher.model_validate(teacher) + ret_teacher.pfp = pfp + return ret_teacher + +def get_ext_teacher(db: Session, email: str) -> models.ExternalTeacher | None: + return db.execute(select(models.ExternalTeacher).filter(models.ExternalTeacher.email == email)).scalar_one_or_none() + +def get_teacher(db: Session, email: str) -> models.NUSHTeacher | models.ExternalTeacher | None: + if(is_nush_teacher(db, email)): return get_nush_teacher_raw(db, email) + else: return get_ext_teacher(db, email) + +def get_nush_student_raw(db: Session, email: str) -> models.NUSHStudent | None: + return db.execute(select(models.NUSHStudent).filter(models.NUSHStudent.email == email)).scalar_one_or_none() + +def get_nush_student(db: Session, email: str) -> schemas.NUSHStudent | None: + student = get_nush_student_raw(db, email) + if not student: return None + pfp = base64.b64encode(student.pfp_bytes).decode("ascii") if student.pfp_bytes != None else "" + ret_student = schemas.NUSHStudent.model_validate(student) + ret_student.pfp = pfp + return ret_student + +def get_ext_student(db: Session, email: str) -> schemas.ExternalStudent | None: + stmt = select(models.ExternalStudent, models.Student, models.ExternalTeacher).join(models.Student).join(models.ExternalTeacher).filter(models.ExternalStudent.email == email) + row = db.execute(stmt).one_or_none() + if not row: + return None + + # we want the external teacher email and name + the institution + return schemas.ExternalStudent( + email=row.ExternalStudent.email, + name=row.Student.name, + emergency_email=row.ExternalStudent.emergency_email, + teacher_name=row.ExternalTeacher.name, + sch_id=row.ExternalTeacher.sch_id + ) + +def get_student(db: Session, email: str) -> schemas.NUSHStudent | schemas.ExternalStudent | None: + return get_nush_student(db, email) if is_nush_student(db, email) else get_ext_student(db, email) + +def get_mentor(db: Session, email: str) -> schemas.ResearchMentor | None: + mentor = db.execute(select(models.ResearchMentor).filter(models.ResearchMentor.email == email)).scalar_one_or_none() + if not mentor: + return None + return schemas.ResearchMentor( + email=mentor.email, + name=mentor.name, + jobs=[schemas.WorksAt.model_validate(job) for job in mentor.workplaces] + ) + +def event(self, eventId, year): + query = "SELECT * FROM ResearchEvent WHERE eventId=%s AND year=%s" + event = queryOne(query, (eventId, year)) + event["awardTypes"] = [i["awardType"] for i in queryAll("SELECT awardType FROM AwardTypes WHERE eventId=%s AND year=%s", (eventId, year))] if(event["isCompetition"]) else [] + instIds = queryAll("SELECT instId FROM Organises WHERE eventId = %s and year = %s", (eventId, year)) + event["organisers"] = [get_institution(instId["instId"]) for instId in instIds] + event["submissions"] = submissions(eventId, year) + return event + +def project(self, pcode): + # print(pcode) + project = queryOne("SELECT * FROM Project WHERE pcode = %s", (pcode, )) + if not project: return None + # print(project) + project["members"] = projectMembers(pcode) + project["teacher"] = get_nush_teacher(project["teacherEmail"]) + project["reportPdf"] = base64.b64encode(project.get("reportPdf", b'')).decode("utf-8") if project.get("reportPdf", b'') != None else "" + project["mentors"] = mentorsByProject(pcode) + del project["teacherEmail"] + return project + +def submission(self, eventId, year, code): + event = queryOne("SELECT name, about, isCompetition, isConference, start_date, end_date FROM ResearchEvent WHERE eventId = %s AND year = %s", (eventId, year, )) + submission = queryOne("SELECT * FROM Submission where eventId=%s AND year=%s AND code=%s", (eventId, year, code)) # returns None if no match found. + if not(submission): return submission + pcodes = queryAll("SELECT distinct pcode FROM Submits where eventId=%s AND year=%s AND code=%s", (eventId, year, code)) + submission["projects"] = remove_nulls([project(pcode["pcode"]) for pcode in pcodes if pcode]) + authors = queryAll("SELECT distinct studentEmail FROM Submits where eventId=%s AND year=%s AND code=%s", (eventId, year, code)) + submission["members"] = remove_nulls([get_student(email["studentEmail"]) for email in authors if email]) + submission["accs"] = accBySubmission(eventId, year, code) + return {**event, **submission} + +def strongSubmissions(self, email): + query = "SELECT distinct eventId, year, code FROM Submits WHERE studentEmail = %s" + codes = remove_nulls(queryAll(query, (email, ))) + return remove_nulls([submission(**kw) for kw in codes]) + + + +# ==================================== CREATE FUNCTIONALITY ==================================== + +def createExternalStudent(self, email, name, teacherEmail, teacherName, instId): + if get_nush_student(email): # Student is already in + return + + if not get_ext_teacher(teacherEmail): # Teacher is not in + execute("INSERT INTO ExternalTeacher (email, name, schId) VALUES (%s,%s, %s)", (teacherEmail, teacherName, instId)) + + execute("INSERT INTO Student (email, name) VALUES (%s, %s)", (email, name)) + execute("INSERT INTO ExternalStudent (email, emergencyEmail) VALUES (%s, %s)", (email, teacherEmail)) + +def createSubmission(self, eventId, year, code, subTitle, subAbstract, pcodes, authorEmails): + # print(eventId, year, code) + query = "INSERT INTO Submission(eventId, year, code, subTitle, subAbstract) VALUES (%s, %s, %s, %s, %s)" + execute(query, (eventId, year, code, subTitle, subAbstract), commit=False) + # print(pcodes) + # print(authorEmails) + query = "INSERT INTO Submits(eventId, year, code, studentEmail, pcode) VALUES (%s, %s, %s, %s, %s)" + executemany(query, [ + (eventId, year, code, email, pcode) for (email, pcode) in itertools.product(authorEmails, pcodes) + ]) + return submission(eventId, year, code) + +def createResearchEvent( + self, eventId, year, name, start_date, end_date, + format, about, isCompetition, isConference, + organisers, awardTypes, confDoi +): + query = "INSERT INTO ResearchEvent(eventId, year, name, start_date, end_date, format, about, isCompetition, isConference, confDoi) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" + execute(query, ( + eventId, year, name, start_date, end_date, + format, about, isCompetition, isConference, confDoi + ), commit=False) + executemany("INSERT INTO AwardTypes(eventId, year, awardType) VALUES (%s, %s, %s)", [ + (eventId, year, awardType) for awardType in awardTypes + ], commit=False) + executemany("INSERT INTO Organises(eventId, year, instId) VALUES (%s, %s, %s)", [ + (eventId, year, instId) for instId in organisers + ]) + return event(eventId, year) + +def createProject( + self, pcode, year, deptId, title, abstract, teacherEmail, authorEmails +): + query = "INSERT INTO Project(pcode, year, deptId, title, abstract, teacherEmail) VALUES (%s, %s, %s, %s, %s, %s)" + execute(query, ( + pcode, year, deptId, title, abstract, teacherEmail + ), commit=False) + executemany("INSERT INTO Works_On(studentEmail, pcode) VALUES (%s, %s)", [ + (authorEmail, pcode) for authorEmail in authorEmails + ]) + return project(pcode) + +# ==================================== UPDATE FUNCTIONALITY ==================================== + +def addStudentsToProject(self, emails, pcode): + emails = [email for email in emails if not queryOne("SELECT studentEmail FROM Works_On WHERE studentEmail = %s AND pcode = %s", (email, pcode))] + executemany("INSERT INTO Works_On (studentEmail, pcode) VALUES (%s, %s)", [(email, pcode) for email in emails]) + +def addStudentsToSubmission(self, emails, eventId, year, code): + pcodes = [i["pcode"] for i in remove_nulls(queryAll("SELECT distinct pcode FROM Submits WHERE eventId = %s AND year = %s AND code = %s", (eventId, year, code)))] + print(pcodes) + emails = [email for email in emails if not queryOne("SELECT distinct studentEmail FROM Submits WHERE studentEmail = %s AND eventId = %s AND year = %s AND code = %s", (email, eventId, year, code))] + executemany("INSERT INTO Submits (studentEmail, pcode, eventId, year, code) VALUES (%s, %s, %s, %s, %s)", [ + (email, pcode, eventId, year, code) for email, pcode in itertools.product(emails, pcodes) + ]) + +def updateSubmission(self, eventId, year, code, subTitle, subAbstract): + print(eventId, year, code) + query = "UPDATE Submission SET subTitle = %s, subAbstract = %s WHERE eventId = %s AND year = %s AND code = %s" + execute(query, (subTitle, subAbstract, eventId, year, code)) + res = submission(eventId, year, code) + print(res) + print(repr(res)) + return res + +def updateResearchEvent( + self, eventId, year, name, start_date, end_date, + format, about, isCompetition, isConference, + organisers, awardTypes, confDoi +): + query = "UPDATE ResearchEvent SET name = %s, start_date = %s, end_date = %s, format = %s, about = %s, isCompetition = %s, isConference = %s, confDoi = %s WHERE eventId = %s AND year = %s" + execute(query, ( + name, start_date, end_date, format, about, + isCompetition, isConference, confDoi, eventId, year + ), commit=False) + execute("DELETE FROM AwardTypes WHERE eventId = %s AND year = %s", (eventId, year), commit=False) + executemany("INSERT INTO AwardTypes(eventId, year, awardType) VALUES (%s, %s, %s)", [ + (eventId, year, awardType) for awardType in awardTypes + ], commit=False) + execute("DELETE FROM Organises WHERE eventId = %s AND year = %s", (eventId, year), commit=False) + executemany("INSERT INTO Organises(eventId, year, instId) VALUES (%s, %s, %s)", [ + (eventId, year, instId) for instId in organisers + ]) + return event(eventId, year) + +# ==================================== DELETE FUNCTIONALITY ==================================== + +def removeStudentFromProject(self, email, pcode): + query = "DELETE FROM Works_On WHERE studentEmail = %s AND pcode = %s" + execute(query, (email, pcode, )) + return project(pcode) + +def removeStudentFromSubmission(self, email, eventId, year, code): + query = "DELETE FROM Submits WHERE studentEmail = %s AND eventId = %s AND year = %s AND code = %s" + execute(query, (email, eventId, year, code, )) + return submission(eventId, year, code) + +def deleteProject(self, pcode): + query = "DELETE FROM Project WHERE pcode = %s" + try: + execute(query, (pcode,)) + return {"result": True, "message": "Project Deleted Successfully!"} + except Exception as e: + return {"result": False, "message": str(e)} + +def deleteSubmission(self, eventId, year, code): + query = "DELETE FROM Submission WHERE eventId = %s AND year = %s AND code = %s" + try: + execute(query, (eventId, year, code)) + return {"result": True, "message": "Submission Deleted Successfully!"} + except Exception as e: + return {"result": False, "message": str(e)} + + + + +# ==================================== SEARCH FUNCTIONALITY ==================================== + +def searchSchools(self): + return queryAll("SELECT instId, name FROM Institution WHERE isSchool = TRUE") + +def searchOrganisers(self): + return queryAll("SELECT instId, name FROM Institution WHERE isOrganiser = TRUE") + +def searchAllStudents(self): + query = "SELECT email, name FROM ExternalStudent NATURAL INNER JOIN Student" + external_students = [{**i, 'pfp': ''} for i in queryAll(query)] + query = "SELECT email, name, pfp FROM NUSHStudent NATURAL INNER JOIN Student" + students = queryAll(query) + for student in students: + if(student): student["pfp"] = base64.b64encode(student.get("pfp", b'')).decode("utf-8") if student.get("pfp", b'') != None else "" + return list(students) + list(external_students) + +def searchAllTeachers(self): + query = "SELECT email, name, pfp FROM NUSHTeacher" + students = queryAll(query) + for student in students: + if(student): student["pfp"] = base64.b64encode(student.get("pfp", b'')).decode("utf-8") if student.get("pfp", b'') != None else "" + return students + +def events(self): + query = "SELECT eventId, year, name, about, isConference, isCompetition, start_date, end_date FROM ResearchEvent" + return queryAll(query) + +def best_students(self, email): + query = "SELECT studentEmail FROM Works_On NATURAL INNER JOIN Project WHERE teacherEmail = %s GROUP BY teacherEmail, studentEmail ORDER BY COUNT(studentEmail) DESC LIMIT 5" + studentEmails = queryAll(query, (email, )) + return [get_student(email["studentEmail"]) for email in studentEmails] + +def teacherProjects(self, email): + query = "SELECT pcode FROM Project WHERE teacherEmail = %s" + pcodes = queryAll(query, (email, )) + return [project(pcode["pcode"]) for pcode in pcodes] + +def extTeacherStudents(self, email): + query = "SELECT email FROM ExternalStudent WHERE emergencyEmail = %s LIMIT 5" + emails = queryAll(query, (email, )) + return [get_ext_student(email["email"]) for email in emails] + +def _processAcc(self, result): + if result["isAward"]: + return { + "accId": result.get("accId", ""), + "name": result.get("name", ""), + "prize": result.get("prize", "") + } + else: + return queryOne("SELECT accId, pubTitle, doi FROM Publication WHERE accId = %s", (result.get("accId", ""), )) + +def accBySubmission(self, eventId, year, code): + # print("you chose", eventId, year, code) # , pubTitle, doi + query = "SELECT accId, isAward, name, prize FROM Accomplishment WHERE eventId = %s AND year = %s AND code = %s" + results = queryAll(query, (eventId, year, code, )) + return remove_nulls([_processAcc(result) for result in results]) + +def submissionsByProject(self, pcode): + query = "SELECT * FROM Submits WHERE pcode = %s" + submission_query_pairs = queryAll(query, (pcode, )) + query = "SELECT distinct eventId, year, code, subTitle, subAbstract FROM Submits NATURAL JOIN Submission WHERE pcode = %s" + submissions = queryAll(query, (pcode, )) + return [ + { + **submission, + "members": [ + get_student(i.get("studentEmail", "")) + for i in submission_query_pairs + if i.get("eventId", "") == submission.get("eventId", "") + and i.get("year", 0) == submission.get("year", 0) + and i.get("code", "") == submission.get("code", "") + ], + "accs": accBySubmission(submission.get("eventId", ""), submission.get("year", 0), submission.get("code", "")) + } + for submission in submissions + ] + +def submissionsByUser(self, email): + query = "SELECT * FROM Submits WHERE studentEmail = %s" + submission_query_pairs = queryAll(query, (email, )) + query = "SELECT distinct eventId, year, code, subTitle, subAbstract FROM Submits NATURAL JOIN Submission WHERE studentEmail = %s" + submissions = queryAll(query, (email, )) + return [ + { + **submission, + "projects": [ + i.get("pcode", "") + for i in submission_query_pairs + if i.get("eventId", "") == submission.get("eventId", "") + and i.get("year", 0) == submission.get("year", 0) + and i.get("code", "") == submission.get("code", "") + ], + # "accs": accBySubmission(submission.get("eventId", ""), submission.get("year", 0), submission.get("code", "")) + } + for submission in submissions + ] + +def mentorsByProject(self, pcode): + query = "SELECT email FROM ResearchMentor INNER JOIN Mentors ON ResearchMentor.email = Mentors.mentorEmail WHERE pcode = %s" + emails = queryAll(query, (pcode, )) + return [get_mentor(email["email"]) for email in emails] + + +def projectsByMentor(self, email): + query = "SELECT pcode FROM ResearchMentor INNER JOIN Mentors ON ResearchMentor.email = Mentors.mentorEmail WHERE email = %s" + pcodes = queryAll(query, (email, )) + return [project(pcode["pcode"]) for pcode in pcodes] + +def mentorStudents(self, email): + query = "SELECT studentEmail FROM Works_On NATURAL INNER JOIN Project NATURAL INNER JOIN Mentors WHERE mentorEmail = %s GROUP BY mentorEmail, studentEmail ORDER BY COUNT(studentEmail) DESC LIMIT 5" + emails = queryAll(query, (email, )) + return [get_student(email["studentEmail"]) for email in emails] + +def _processSub(self, eventId, year, sub): + if not sub: return sub + query = "SELECT distinct pcode FROM Submits WHERE eventId = %s and year = %s and code = %s" + pcode = queryOne(query, (eventId, year, sub["code"])) + pcode = pcode if pcode else dict(pcode="") + students = remove_nulls([get_student(email["studentEmail"]) for email in queryAll("SELECT distinct studentEmail FROM Submits WHERE eventId = %s and year = %s and code = %s", (eventId, year, sub["code"]))]) + return {**sub, **pcode, "members": students} + +def submissions(self, eventId, year): + query = "SELECT distinct code, subTitle title FROM Submission WHERE eventId = %s AND year = %s" + submissions = queryAll(query, (eventId, year, )) + return [_processSub(eventId, year, submission) for submission in submissions] + +def otherProjects(self, email): + query = "SELECT pcode FROM Project p WHERE %s <> ALL (SELECT studentEmail FROM Works_On wo where wo.pcode = p.pcode)" + pcodes = [i["pcode"] for i in queryAll(query, (email, ))] + random.shuffle(pcodes) + return remove_nulls([project(pcode) for pcode in pcodes if pcode]) + +def otherEvents(self, email): + query = "SELECT eventId, year FROM ResearchEvent re WHERE %s <> ALL (SELECT studentEmail FROM Submits s WHERE s.eventId = re.eventId AND s.year = re.year)" + ids = queryAll(query, (email, )) + return remove_nulls([event(**id) for id in ids]) + +def projectMembers(self, pcode): + query = "SELECT studentEmail email FROM Works_On WHERE pcode = %s" + return [get_nush_student(i["email"]) if is_nush_student(i["email"]) else get_ext_student(i["email"]) for i in queryAll(query, (pcode,))] + +def studentProjects(self, email): + pcodes = queryAll("SELECT pcode FROM Works_On WHERE studentEmail = %s", (email, )) + return remove_nulls([project(pcode["pcode"]) for pcode in pcodes]) + +def coauthors(self, email): + query = "SELECT other.studentEmail email, COUNT(pcode) num FROM Works_On self, Works_On other WHERE pcode = other.pcode AND studentEmail = %s AND other.studentEmail <> studentEmail GROUP BY other.studentEmail ORDER BY COUNT(pcode) DESC LIMIT 5" + return [{**(i[0]), "count": i[1]} for i in [(get_nush_student(i["email"]), i["num"]) for i in queryAll(query, (email,)) if is_student(i["email"])] if i[0]] + +def projectByTeacher(self, email): + query = "SELECT pcode FROM Project WHERE teacherEmail = %s" + codes = queryAll(query, (email, )) + return [project(code) for code in codes] + +def updateProject(self, pcode, title, abstract, reportPdf): + # print(reportPdf) + reportPdf = base64.b64decode(reportPdf) if reportPdf != None else "" + # print(reportPdf) + query = "UPDATE Project SET title = %s, abstract = %s, reportPdf = %s WHERE pcode = %s" + execute(query, (title, abstract, reportPdf, pcode)) + return project(pcode) + +def updateStudent(self, email, pfp, about): + pfp = base64.b64decode(pfp) if pfp != None else "" # convert base64 to bytes object if needed. + query = "UPDATE NUSHStudent SET pfp = %s, about = %s WHERE email = %s" + execute(query, (pfp, about, email)) + return get_nush_student(email) + +def _processJourn(self, journal): + query = "SELECT instId FROM PublishedBy WHERE issn = %s" + instIds = [i["instId"] for i in queryAll(query, (journal["issn"], )) if i] + institutes = remove_nulls([get_institution(instId) for instId in instIds]) + + publications = queryAll("SELECT pubTitle title, doi, url FROM Publication where journISSN = %s", (journal["issn"], )) + + return { + **journal, + "institutes": institutes, + "publications": publications + } + +def journals(self): + query = "SELECT issn, name FROM Journal" + return [_processJourn(it) for it in queryAll(query)] + +# ================================== AGGREGATION FUNCTIONALITY ================================= +def projectStats(self, email): + query = "SELECT year, COUNT(pcode) count FROM Works_On NATURAL JOIN Project WHERE studentEmail = %s GROUP BY year ORDER BY year" + stats = list(queryAll(query, (email, ))) + + if len(stats) == 0: return stats + minYear = min([i["year"] for i in stats]) + maxYear = max([i["year"] for i in stats]) + + for year in range(minYear, maxYear+1): + if any([i["year"] == year for i in stats]): continue; + stats.append({ "year": year, "count": 0 }) + + return sorted(stats, key=lambda i: i["year"]) + +def submissionStats(self, email): + query = "SELECT year, COUNT(pcode) count FROM Submits WHERE studentEmail = %s GROUP BY year ORDER BY year" + stats = list(queryAll(query, (email, ))) + if len(stats) == 0: return stats + + minYear = min([i["year"] for i in stats]) + maxYear = max([i["year"] for i in stats]) + + for year in range(minYear, maxYear+1): + if any([i["year"] == year for i in stats]): continue; + stats.append({ "year": year, "count": 0 }) + + return sorted(stats, key=lambda i: i["year"]) + +def awardStats(self, email): + query = "SELECT year, COUNT(accId) count FROM Accomplishment NATURAL INNER JOIN Submits WHERE studentEmail = %s AND isAward = true GROUP BY year ORDER BY year" + stats = list(queryAll(query, (email, ))) + if len(stats) == 0: return stats + + minYear = min([i["year"] for i in stats]) + maxYear = max([i["year"] for i in stats]) + + for year in range(minYear, maxYear+1): + if any([i["year"] == year for i in stats]): continue; + stats.append({ "year": year, "count": 0 }) + + return sorted(stats, key=lambda i: i["year"]) + +def projectAwardStats(self, email): + query = "SELECT pcode, count, title, year FROM (SELECT pcode, COUNT(accId) count FROM Accomplishment NATURAL INNER JOIN Submits WHERE studentEmail = %s AND isAward = true GROUP BY pcode ORDER BY pcode) agg NATURAL INNER JOIN Project p ORDER BY year, pcode" + stats = list(queryAll(query, (email, ))) + return stats + + + + + diff --git a/server/database_old.py b/server/database_old.py index eb35115..3508874 100644 --- a/server/database_old.py +++ b/server/database_old.py @@ -1,645 +1,640 @@ -from flask_mysqldb import MySQL -import MySQLdb.cursors -import base64 -from util import convertB64toBytes, removeNulls -import random -import itertools +# from flask_mysqldb import MySQL +# import MySQLdb.cursors +# import base64 +# from util import convertB64toBytes, remove_nulls +# import random +# import itertools -class Database: - def __init__(self, app): - app.config['MYSQL_HOST'] = 'database' - app.config['MYSQL_USER'] = 'root' - app.config['MYSQL_PASSWORD'] = 'admin' - app.config['MYSQL_DB'] = 'arxiv' - self.app = app - self.mysql = MySQL(app) +# class Database: +# def __init__(self, app): +# app.config['MYSQL_HOST'] = 'database' +# app.config['MYSQL_USER'] = 'root' +# app.config['MYSQL_PASSWORD'] = 'admin' +# app.config['MYSQL_DB'] = 'arxiv' +# self.app = app +# self.mysql = MySQL(app) - @property - def connection(self): - return self.mysql.connection +# @property +# def connection(self): +# return self.mysql.connection - @property - def cursor(self): - return self.mysql.connection.cursor(MySQLdb.cursors.DictCursor) - - def execute(self, query, args=None, commit=True): - cur = self.cursor - cur.execute(query, args) - if(commit): self.connection.commit() +# @property +# def cursor(self): +# return self.mysql.connection.cursor(MySQLdb.cursors.DictCursor) + +# def execute(self, query, args=None, commit=True): +# cur = self.cursor +# cur.execute(query, args) +# if(commit): self.connection.commit() - def executemany(self, query, args=None, commit=True): - cur = self.cursor - cur.executemany(query, args) - if(commit): self.connection.commit() - - def queryAll(self, query, args=None): - cur = self.cursor - cur.execute(query, args) - return cur.fetchall() - - def queryOne(self, query, args=None): - cur = self.cursor - cur.execute(query, args) - return cur.fetchone() +# def executemany(self, query, args=None, commit=True): +# cur = self.cursor +# cur.executemany(query, args) +# if(commit): self.connection.commit() + +# def queryAll(self, query, args=None): +# cur = self.cursor +# cur.execute(query, args) +# return cur.fetchall() + +# def queryOne(self, query, args=None): +# cur = self.cursor +# cur.execute(query, args) +# return cur.fetchone() - def close(self): - self.connection.close() +# def close(self): +# self.connection.close() - @property - def pfp(self): - with open("assets/default.png", "rb") as f: - pfp = f.read() - return pfp +# @property +# def pfp(self): +# with open("assets/default.png", "rb") as f: +# pfp = f.read() +# return pfp - # ==================================== EXISTS FUNCTIONALITY ==================================== +# # ==================================== EXISTS FUNCTIONALITY ==================================== - def isInstitute(self, email): - return len(self.queryAll("SELECT instId FROM Institution WHERE email = %s", (email,))) > 0 +# def isInstitute(self, email): +# return len(self.queryAll("SELECT instId FROM Institution WHERE email = %s", (email,))) > 0 - def isStudent(self, email): - return len(self.queryAll("SELECT email FROM Student WHERE email = %s", (email, ))) > 0 +# def isStudent(self, email): +# return len(self.queryAll("SELECT email FROM Student WHERE email = %s", (email, ))) > 0 - def isMentor(self, email): - return len(self.queryAll("SELECT email FROM ResearchMentor WHERE email = %s", (email, ))) > 0 +# def isMentor(self, email): +# return len(self.queryAll("SELECT email FROM ResearchMentor WHERE email = %s", (email, ))) > 0 - def isNUSHTeacher(self, email): - return len(self.queryAll("SELECT email FROM NUSHTeacher WHERE email = %s", (email, ))) > 0 +# def isNUSHTeacher(self, email): +# return len(self.queryAll("SELECT email FROM NUSHTeacher WHERE email = %s", (email, ))) > 0 - def isNUSHStudent(self, email): - return len(self.queryAll("SELECT email FROM NUSHStudent WHERE email = %s", (email, ))) > 0 +# def isNUSHStudent(self, email): +# return len(self.queryAll("SELECT email FROM NUSHStudent WHERE email = %s", (email, ))) > 0 - # ================================ AUTHENTICATION FUNCTIONALITY ================================ +# # ================================ AUTHENTICATION FUNCTIONALITY ================================ - def studentLogin(self, email, pwd): - query = "SELECT email FROM NUSHStudent WHERE email = %s and pwd = %s" - return bool(self.queryOne(query, (email, pwd))) +# def studentLogin(self, email, pwd): +# query = "SELECT email FROM NUSHStudent WHERE email = %s and pwd = %s" +# return bool(self.queryOne(query, (email, pwd))) - def teacherLogin(self, email, pwd): - query = "SELECT email FROM NUSHTeacher WHERE email = %s and pwd = %s" - return bool(self.queryOne(query, (email, pwd))) +# def teacherLogin(self, email, pwd): +# query = "SELECT email FROM NUSHTeacher WHERE email = %s and pwd = %s" +# return bool(self.queryOne(query, (email, pwd))) - def login(self, email, password): - isStudent = self.isNUSHStudent(email) - isStudentAuth = self.studentLogin(email, password) - isTeacher = self.isNUSHTeacher(email) - isTeacherAuth = self.teacherLogin(email, password) +# def login(self, email, password): +# isStudent = self.isNUSHStudent(email) +# isStudentAuth = self.studentLogin(email, password) +# isTeacher = self.isNUSHTeacher(email) +# isTeacherAuth = self.teacherLogin(email, password) - if isStudent and isStudentAuth: - return { - "result": True, "user": self.NUSHStudent(email), - "message": "Logged In Successfully!" - } - if isStudent and not isStudentAuth: - return { - "result": False, "user": None, - "message": "Incorrect Password Provided!" - } - if isTeacher and isTeacherAuth: - return { - "result": True, "user": self.NUSHTeacher(email), - "message": "Logged In Successfully!" - } - if isTeacher and not isTeacherAuth: - return { - "result": False, "user": None, - "message": "Incorrect Password Provided!" - } - return { - 'result': False, "user": None, - "message": "Account does not exist!" - } +# if isStudent and isStudentAuth: +# return { +# "result": True, "user": self.NUSHStudent(email), +# "message": "Logged In Successfully!" +# } +# if isStudent and not isStudentAuth: +# return { +# "result": False, "user": None, +# "message": "Incorrect Password Provided!" +# } +# if isTeacher and isTeacherAuth: +# return { +# "result": True, "user": self.NUSHTeacher(email), +# "message": "Logged In Successfully!" +# } +# if isTeacher and not isTeacherAuth: +# return { +# "result": False, "user": None, +# "message": "Incorrect Password Provided!" +# } +# return { +# 'result': False, "user": None, +# "message": "Account does not exist!" +# } - def registerStudent( - self, email, password, name, gradYear - ): - if not(email.endswith("@nushigh.edu.sg") and email[0] == 'h' and email[1:8].isnumeric()): - return { - "result": False, "user": None, - "message": "Please give a valid email of form `hXXXXXXX@nushigh.edu.sg`." - } - existing = self.isNUSHStudent(email) - if existing: - if(self.studentLogin(email, password)): - return { - "result": True, "user": self.NUSHStudent(email), - "message": "Account already exists, successfully logged in with details provided." - } - return { - "result": False, "user": self.login(email, password), - "message": "Account already exists!" - } - try: - self.execute("INSERT INTO Student(email, name) VALUES (%s, %s)", (email, name), commit=False) - self.execute("INSERT INTO NUSHStudent(email, pwd, pfp, gradYear, nush_sid) VALUES (%s, %s, %s, %s, %s)", ( - email, password, self.pfp, gradYear, email[:8] - )) - return { - "result": True, "user": self.NUSHStudent(email), - "message": "Registered Successfully!" - } - except Exception as e: - return { - "result": False, "user": None, - "message": str(e) - } +# def registerStudent( +# self, email, password, name, gradYear +# ): +# if not(email.endswith("@nushigh.edu.sg") and email[0] == 'h' and email[1:8].isnumeric()): +# return { +# "result": False, "user": None, +# "message": "Please give a valid email of form `hXXXXXXX@nushigh.edu.sg`." +# } +# existing = self.isNUSHStudent(email) +# if existing: +# if(self.studentLogin(email, password)): +# return { +# "result": True, "user": self.NUSHStudent(email), +# "message": "Account already exists, successfully logged in with details provided." +# } +# return { +# "result": False, "user": self.login(email, password), +# "message": "Account already exists!" +# } +# try: +# self.execute("INSERT INTO Student(email, name) VALUES (%s, %s)", (email, name), commit=False) +# self.execute("INSERT INTO NUSHStudent(email, pwd, pfp, gradYear, nush_sid) VALUES (%s, %s, %s, %s, %s)", ( +# email, password, self.pfp, gradYear, email[:8] +# )) +# return { +# "result": True, "user": self.NUSHStudent(email), +# "message": "Registered Successfully!" +# } +# except Exception as e: +# return { +# "result": False, "user": None, +# "message": str(e) +# } - def registerTeacher( - self, email, password, name, deptId - ): - if not(email.endswith("@nushigh.edu.sg")): - return { - "result": False, "user": None, - "message": "Please give a valid email ending with `@nushigh.edu.sg`." - } - existing = self.isNUSHTeacher(email) - if existing: - if(self.teacherLogin(email, password)): - return { - "result": True, "user": self.NUSHStudent(email), - "message": "Account already exists, successfully logged in with details provided." - } - return { - "result": False, "user": self.login(email, password), - "message": "Account already exists!" - } - try: - self.execute("INSERT INTO NUSHTeacher(email, pwd, name, pfp, isAdmin, isMentor, deptId) VALUES (%s, %s, %s, %s, %s, %s, %s)", ( - email, password, name, self.pfp, False, False, deptId - )) - return { - "result": True, "user": self.NUSHTeacher(email), "message": "Registered Successfully!" - } - except Exception as e: - return {"result": False, "error": str(e)} - - def changePassword(self, email, oldPw, newPw): - oldPwd = self.queryOne("SELECT pwd FROM ((SELECT email, pwd FROM NUSHStudent) UNION (SELECT email, pwd FROM NUSHTeacher)) everyone WHERE email = %s", (email, )).get("pwd", "") - if(oldPw != oldPwd): - return {"response": "Current Password is not correct!"} - if(self.isStudent(email)): - self.execute("UPDATE NUSHStudent SET pwd = %s WHERE email = %s", (newPw, email)) - else: - self.execute("UPDATE NUSHTeacher SET pwd = %s WHERE email = %s", (newPw, email)) - return {"response": "Success!"} +# def registerTeacher( +# self, email, password, name, deptId +# ): +# if not(email.endswith("@nushigh.edu.sg")): +# return { +# "result": False, "user": None, +# "message": "Please give a valid email ending with `@nushigh.edu.sg`." +# } +# existing = self.isNUSHTeacher(email) +# if existing: +# if(self.teacherLogin(email, password)): +# return { +# "result": True, "user": self.NUSHStudent(email), +# "message": "Account already exists, successfully logged in with details provided." +# } +# return { +# "result": False, "user": self.login(email, password), +# "message": "Account already exists!" +# } +# try: +# self.execute("INSERT INTO NUSHTeacher(email, pwd, name, pfp, isAdmin, isMentor, deptId) VALUES (%s, %s, %s, %s, %s, %s, %s)", ( +# email, password, name, self.pfp, False, False, deptId +# )) +# return { +# "result": True, "user": self.NUSHTeacher(email), "message": "Registered Successfully!" +# } +# except Exception as e: +# return {"result": False, "error": str(e)} + +# def changePassword(self, email, oldPw, newPw): +# oldPwd = self.queryOne("SELECT pwd FROM ((SELECT email, pwd FROM NUSHStudent) UNION (SELECT email, pwd FROM NUSHTeacher)) everyone WHERE email = %s", (email, )).get("pwd", "") +# if(oldPw != oldPwd): +# return {"response": "Current Password is not correct!"} +# if(self.isStudent(email)): +# self.execute("UPDATE NUSHStudent SET pwd = %s WHERE email = %s", (newPw, email)) +# else: +# self.execute("UPDATE NUSHTeacher SET pwd = %s WHERE email = %s", (newPw, email)) +# return {"response": "Success!"} - # ==================================== GETTER FUNCTIONALITY ==================================== - - def institute(self, instId): - return self.queryOne("SELECT * FROM Institution WHERE instId = %s", (instId, )) - - def NUSHTeacher(self, email): - teacher = self.queryOne("SELECT email, name, pfp, isAdmin, deptId FROM NUSHTeacher WHERE email = %s", (email, )) - if(teacher): teacher["pfp"] = base64.b64encode(teacher.get("pfp", b'')).decode("utf-8") if teacher.get("pfp", b'') != None else "" - return teacher - - def ext_teacher(self, email): - query = "SELECT email, name, schId FROM ExternalTeacher WHERE email = %s" - return self.queryOne(query, (email, )) - - def teacher(self, email): - if(self.isNUSHTeacher(email)): return self.NUSHTeacher(email) - else: return self.ext_teacher(email) - - def NUSHStudent(self, email): - query = "SELECT email, name, about, gradYear, nush_sid, pfp FROM NUSHStudent NATURAL INNER JOIN Student WHERE email = %s" - student = self.queryOne(query, (email, )) - if(student): student["pfp"] = base64.b64encode(student.get("pfp", b'')).decode("utf-8") if student.get("pfp", b'') != None else "" - return student - - def ext_student(self, email): - query = "SELECT email, name, emergencyEmail FROM ExternalStudent NATURAL INNER JOIN Student WHERE email = %s" - ext_student = self.queryOne(query, (email, )) - if(ext_student): - ext_teacher = self.ext_teacher(ext_student.get("emergencyEmail", "")) - # we want the external teacher email and name + the institution - return { - **ext_student, - "teacherName": ext_teacher.get("name", ""), - "schId": ext_teacher.get("schId", "") - } - return ext_student - - def student(self, email): - return self.NUSHStudent(email) if self.isNUSHStudent(email) else self.ext_student(email) +# # ==================================== GETTER FUNCTIONALITY ==================================== + +# def institute(self, instId): +# return self.queryOne("SELECT * FROM Institution WHERE instId = %s", (instId, )) + +# def NUSHTeacher(self, email): +# teacher = self.queryOne("SELECT email, name, pfp, isAdmin, deptId FROM NUSHTeacher WHERE email = %s", (email, )) +# if(teacher): teacher["pfp"] = base64.b64encode(teacher.get("pfp", b'')).decode("utf-8") if teacher.get("pfp", b'') != None else "" +# return teacher + +# def ext_teacher(self, email): +# query = "SELECT email, name, schId FROM ExternalTeacher WHERE email = %s" +# return self.queryOne(query, (email, )) + +# def teacher(self, email): +# if(self.isNUSHTeacher(email)): return self.NUSHTeacher(email) +# else: return self.ext_teacher(email) + +# def NUSHStudent(self, email): +# query = "SELECT email, name, about, gradYear, nush_sid, pfp FROM NUSHStudent NATURAL INNER JOIN Student WHERE email = %s" +# student = self.queryOne(query, (email, )) +# if(student): student["pfp"] = base64.b64encode(student.get("pfp", b'')).decode("utf-8") if student.get("pfp", b'') != None else "" +# return student + +# def ext_student(self, email): +# query = "SELECT email, name, emergencyEmail FROM ExternalStudent NATURAL INNER JOIN Student WHERE email = %s" +# ext_student = self.queryOne(query, (email, )) +# if(ext_student): +# ext_teacher = self.ext_teacher(ext_student.get("emergencyEmail", "")) +# # we want the external teacher email and name + the institution +# return { +# **ext_student, +# "teacherName": ext_teacher.get("name", ""), +# "schId": ext_teacher.get("schId", "") +# } +# return ext_student + +# def student(self, email): +# return self.NUSHStudent(email) if self.isNUSHStudent(email) else self.ext_student(email) - def mentor(self, email): - query = "SELECT email, name FROM ResearchMentor where email = %s" - mentor = self.queryOne(query, (email,)) - query = "SELECT * FROM Works_At NATURAL INNER JOIN Institution WHERE mentorEmail = %s" - jobs = self.queryAll(query, (email, )) - return { **mentor, "jobs": jobs } - - def event(self, eventId, year): - query = "SELECT * FROM ResearchEvent WHERE eventId=%s AND year=%s" - event = self.queryOne(query, (eventId, year)) - event["awardTypes"] = [i["awardType"] for i in self.queryAll("SELECT awardType FROM AwardTypes WHERE eventId=%s AND year=%s", (eventId, year))] if(event["isCompetition"]) else [] - instIds = self.queryAll("SELECT instId FROM Organises WHERE eventId = %s and year = %s", (eventId, year)) - event["organisers"] = [self.institute(instId["instId"]) for instId in instIds] - event["submissions"] = self.submissions(eventId, year) - return event +# def mentor(self, email): +# query = "SELECT email, name FROM ResearchMentor where email = %s" +# mentor = self.queryOne(query, (email,)) +# query = "SELECT * FROM Works_At NATURAL INNER JOIN Institution WHERE mentorEmail = %s" +# jobs = self.queryAll(query, (email, )) +# return { **mentor, "jobs": jobs } + +# def event(self, eventId, year): +# query = "SELECT * FROM ResearchEvent WHERE eventId=%s AND year=%s" +# event = self.queryOne(query, (eventId, year)) +# event["awardTypes"] = [i["awardType"] for i in self.queryAll("SELECT awardType FROM AwardTypes WHERE eventId=%s AND year=%s", (eventId, year))] if(event["isCompetition"]) else [] +# instIds = self.queryAll("SELECT instId FROM Organises WHERE eventId = %s and year = %s", (eventId, year)) +# event["organisers"] = [self.institute(instId["instId"]) for instId in instIds] +# event["submissions"] = self.submissions(eventId, year) +# return event - def project(self, pcode): - # print(pcode) - project = self.queryOne("SELECT * FROM Project WHERE pcode = %s", (pcode, )) - if not project: return None - # print(project) - project["members"] = self.projectMembers(pcode) - project["teacher"] = self.NUSHTeacher(project["teacherEmail"]) - project["reportPdf"] = base64.b64encode(project.get("reportPdf", b'')).decode("utf-8") if project.get("reportPdf", b'') != None else "" - project["mentors"] = self.mentorsByProject(pcode) - del project["teacherEmail"] - return project - - def submission(self, eventId, year, code): - event = self.queryOne("SELECT name, about, isCompetition, isConference, start_date, end_date FROM ResearchEvent WHERE eventId = %s AND year = %s", (eventId, year, )) - submission = self.queryOne("SELECT * FROM Submission where eventId=%s AND year=%s AND code=%s", (eventId, year, code)) # returns None if no match found. - if not(submission): return submission - pcodes = self.queryAll("SELECT distinct pcode FROM Submits where eventId=%s AND year=%s AND code=%s", (eventId, year, code)) - submission["projects"] = removeNulls([self.project(pcode["pcode"]) for pcode in pcodes if pcode]) - authors = self.queryAll("SELECT distinct studentEmail FROM Submits where eventId=%s AND year=%s AND code=%s", (eventId, year, code)) - submission["members"] = removeNulls([self.student(email["studentEmail"]) for email in authors if email]) - submission["accs"] = self.accBySubmission(eventId, year, code) - return {**event, **submission} - - def strongSubmissions(self, email): - query = "SELECT distinct eventId, year, code FROM Submits WHERE studentEmail = %s" - codes = removeNulls(self.queryAll(query, (email, ))) - return removeNulls([self.submission(**kw) for kw in codes]) +# def project(self, pcode): +# # print(pcode) +# project = self.queryOne("SELECT * FROM Project WHERE pcode = %s", (pcode, )) +# if not project: return None +# # print(project) +# project["members"] = self.projectMembers(pcode) +# project["teacher"] = self.NUSHTeacher(project["teacherEmail"]) +# project["reportPdf"] = base64.b64encode(project.get("reportPdf", b'')).decode("utf-8") if project.get("reportPdf", b'') != None else "" +# project["mentors"] = self.mentorsByProject(pcode) +# del project["teacherEmail"] +# return project + +# def submission(self, eventId, year, code): +# event = self.queryOne("SELECT name, about, isCompetition, isConference, start_date, end_date FROM ResearchEvent WHERE eventId = %s AND year = %s", (eventId, year, )) +# submission = self.queryOne("SELECT * FROM Submission where eventId=%s AND year=%s AND code=%s", (eventId, year, code)) # returns None if no match found. +# if not(submission): return submission +# pcodes = self.queryAll("SELECT distinct pcode FROM Submits where eventId=%s AND year=%s AND code=%s", (eventId, year, code)) +# submission["projects"] = remove_nulls([self.project(pcode["pcode"]) for pcode in pcodes if pcode]) +# authors = self.queryAll("SELECT distinct studentEmail FROM Submits where eventId=%s AND year=%s AND code=%s", (eventId, year, code)) +# submission["members"] = remove_nulls([self.student(email["studentEmail"]) for email in authors if email]) +# submission["accs"] = self.accBySubmission(eventId, year, code) +# return {**event, **submission} + +# def strongSubmissions(self, email): +# query = "SELECT distinct eventId, year, code FROM Submits WHERE studentEmail = %s" +# codes = remove_nulls(self.queryAll(query, (email, ))) +# return remove_nulls([self.submission(**kw) for kw in codes]) - # ==================================== CREATE FUNCTIONALITY ==================================== +# # ==================================== CREATE FUNCTIONALITY ==================================== - def createExternalStudent(self, email, name, teacherEmail, teacherName, instId): - if self.NUSHStudent(email): # Student is already in - return +# def createExternalStudent(self, email, name, teacherEmail, teacherName, instId): +# if self.NUSHStudent(email): # Student is already in +# return - if not self.ext_teacher(teacherEmail): # Teacher is not in - self.execute("INSERT INTO ExternalTeacher (email, name, schId) VALUES (%s,%s, %s)", (teacherEmail, teacherName, instId)) +# if not self.ext_teacher(teacherEmail): # Teacher is not in +# self.execute("INSERT INTO ExternalTeacher (email, name, schId) VALUES (%s,%s, %s)", (teacherEmail, teacherName, instId)) - self.execute("INSERT INTO Student (email, name) VALUES (%s, %s)", (email, name)) - self.execute("INSERT INTO ExternalStudent (email, emergencyEmail) VALUES (%s, %s)", (email, teacherEmail)) - - def createSubmission(self, eventId, year, code, subTitle, subAbstract, pcodes, authorEmails): - # print(eventId, year, code) - query = "INSERT INTO Submission(eventId, year, code, subTitle, subAbstract) VALUES (%s, %s, %s, %s, %s)" - self.execute(query, (eventId, year, code, subTitle, subAbstract), commit=False) - # print(pcodes) - # print(authorEmails) - query = "INSERT INTO Submits(eventId, year, code, studentEmail, pcode) VALUES (%s, %s, %s, %s, %s)" - self.executemany(query, [ - (eventId, year, code, email, pcode) for (email, pcode) in itertools.product(authorEmails, pcodes) - ]) - return self.submission(eventId, year, code) - - def createResearchEvent( - self, eventId, year, name, start_date, end_date, - format, about, isCompetition, isConference, - organisers, awardTypes, confDoi - ): - query = "INSERT INTO ResearchEvent(eventId, year, name, start_date, end_date, format, about, isCompetition, isConference, confDoi) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" - self.execute(query, ( - eventId, year, name, start_date, end_date, - format, about, isCompetition, isConference, confDoi - ), commit=False) - self.executemany("INSERT INTO AwardTypes(eventId, year, awardType) VALUES (%s, %s, %s)", [ - (eventId, year, awardType) for awardType in awardTypes - ], commit=False) - self.executemany("INSERT INTO Organises(eventId, year, instId) VALUES (%s, %s, %s)", [ - (eventId, year, instId) for instId in organisers - ]) - return self.event(eventId, year) - - def createProject( - self, pcode, year, deptId, title, abstract, teacherEmail, authorEmails - ): - query = "INSERT INTO Project(pcode, year, deptId, title, abstract, teacherEmail) VALUES (%s, %s, %s, %s, %s, %s)" - self.execute(query, ( - pcode, year, deptId, title, abstract, teacherEmail - ), commit=False) - self.executemany("INSERT INTO Works_On(studentEmail, pcode) VALUES (%s, %s)", [ - (authorEmail, pcode) for authorEmail in authorEmails - ]) - return self.project(pcode) +# self.execute("INSERT INTO Student (email, name) VALUES (%s, %s)", (email, name)) +# self.execute("INSERT INTO ExternalStudent (email, emergencyEmail) VALUES (%s, %s)", (email, teacherEmail)) + +# def createSubmission(self, eventId, year, code, subTitle, subAbstract, pcodes, authorEmails): +# # print(eventId, year, code) +# query = "INSERT INTO Submission(eventId, year, code, subTitle, subAbstract) VALUES (%s, %s, %s, %s, %s)" +# self.execute(query, (eventId, year, code, subTitle, subAbstract), commit=False) +# # print(pcodes) +# # print(authorEmails) +# query = "INSERT INTO Submits(eventId, year, code, studentEmail, pcode) VALUES (%s, %s, %s, %s, %s)" +# self.executemany(query, [ +# (eventId, year, code, email, pcode) for (email, pcode) in itertools.product(authorEmails, pcodes) +# ]) +# return self.submission(eventId, year, code) + +# def createResearchEvent( +# self, eventId, year, name, start_date, end_date, +# format, about, isCompetition, isConference, +# organisers, awardTypes, confDoi +# ): +# query = "INSERT INTO ResearchEvent(eventId, year, name, start_date, end_date, format, about, isCompetition, isConference, confDoi) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" +# self.execute(query, ( +# eventId, year, name, start_date, end_date, +# format, about, isCompetition, isConference, confDoi +# ), commit=False) +# self.executemany("INSERT INTO AwardTypes(eventId, year, awardType) VALUES (%s, %s, %s)", [ +# (eventId, year, awardType) for awardType in awardTypes +# ], commit=False) +# self.executemany("INSERT INTO Organises(eventId, year, instId) VALUES (%s, %s, %s)", [ +# (eventId, year, instId) for instId in organisers +# ]) +# return self.event(eventId, year) + +# def createProject( +# self, pcode, year, deptId, title, abstract, teacherEmail, authorEmails +# ): +# query = "INSERT INTO Project(pcode, year, deptId, title, abstract, teacherEmail) VALUES (%s, %s, %s, %s, %s, %s)" +# self.execute(query, ( +# pcode, year, deptId, title, abstract, teacherEmail +# ), commit=False) +# self.executemany("INSERT INTO Works_On(studentEmail, pcode) VALUES (%s, %s)", [ +# (authorEmail, pcode) for authorEmail in authorEmails +# ]) +# return self.project(pcode) - # ==================================== UPDATE FUNCTIONALITY ==================================== - - def addStudentsToProject(self, emails, pcode): - emails = [email for email in emails if not self.queryOne("SELECT studentEmail FROM Works_On WHERE studentEmail = %s AND pcode = %s", (email, pcode))] - self.executemany("INSERT INTO Works_On (studentEmail, pcode) VALUES (%s, %s)", [(email, pcode) for email in emails]) - - def addStudentsToSubmission(self, emails, eventId, year, code): - pcodes = [i["pcode"] for i in removeNulls(self.queryAll("SELECT distinct pcode FROM Submits WHERE eventId = %s AND year = %s AND code = %s", (eventId, year, code)))] - print(pcodes) - emails = [email for email in emails if not self.queryOne("SELECT distinct studentEmail FROM Submits WHERE studentEmail = %s AND eventId = %s AND year = %s AND code = %s", (email, eventId, year, code))] - self.executemany("INSERT INTO Submits (studentEmail, pcode, eventId, year, code) VALUES (%s, %s, %s, %s, %s)", [ - (email, pcode, eventId, year, code) for email, pcode in itertools.product(emails, pcodes) - ]) - - def updateSubmission(self, eventId, year, code, subTitle, subAbstract): - print(eventId, year, code) - query = "UPDATE Submission SET subTitle = %s, subAbstract = %s WHERE eventId = %s AND year = %s AND code = %s" - self.execute(query, (subTitle, subAbstract, eventId, year, code)) - res = self.submission(eventId, year, code) - print(res) - print(repr(res)) - return res - - def updateResearchEvent( - self, eventId, year, name, start_date, end_date, - format, about, isCompetition, isConference, - organisers, awardTypes, confDoi - ): - query = "UPDATE ResearchEvent SET name = %s, start_date = %s, end_date = %s, format = %s, about = %s, isCompetition = %s, isConference = %s, confDoi = %s WHERE eventId = %s AND year = %s" - self.execute(query, ( - name, start_date, end_date, format, about, - isCompetition, isConference, confDoi, eventId, year - ), commit=False) - self.execute("DELETE FROM AwardTypes WHERE eventId = %s AND year = %s", (eventId, year), commit=False) - self.executemany("INSERT INTO AwardTypes(eventId, year, awardType) VALUES (%s, %s, %s)", [ - (eventId, year, awardType) for awardType in awardTypes - ], commit=False) - self.execute("DELETE FROM Organises WHERE eventId = %s AND year = %s", (eventId, year), commit=False) - self.executemany("INSERT INTO Organises(eventId, year, instId) VALUES (%s, %s, %s)", [ - (eventId, year, instId) for instId in organisers - ]) - return self.event(eventId, year) +# # ==================================== UPDATE FUNCTIONALITY ==================================== + +# def addStudentsToProject(self, emails, pcode): +# emails = [email for email in emails if not self.queryOne("SELECT studentEmail FROM Works_On WHERE studentEmail = %s AND pcode = %s", (email, pcode))] +# self.executemany("INSERT INTO Works_On (studentEmail, pcode) VALUES (%s, %s)", [(email, pcode) for email in emails]) + +# def addStudentsToSubmission(self, emails, eventId, year, code): +# pcodes = [i["pcode"] for i in remove_nulls(self.queryAll("SELECT distinct pcode FROM Submits WHERE eventId = %s AND year = %s AND code = %s", (eventId, year, code)))] +# print(pcodes) +# emails = [email for email in emails if not self.queryOne("SELECT distinct studentEmail FROM Submits WHERE studentEmail = %s AND eventId = %s AND year = %s AND code = %s", (email, eventId, year, code))] +# self.executemany("INSERT INTO Submits (studentEmail, pcode, eventId, year, code) VALUES (%s, %s, %s, %s, %s)", [ +# (email, pcode, eventId, year, code) for email, pcode in itertools.product(emails, pcodes) +# ]) + +# def updateSubmission(self, eventId, year, code, subTitle, subAbstract): +# print(eventId, year, code) +# query = "UPDATE Submission SET subTitle = %s, subAbstract = %s WHERE eventId = %s AND year = %s AND code = %s" +# self.execute(query, (subTitle, subAbstract, eventId, year, code)) +# res = self.submission(eventId, year, code) +# print(res) +# print(repr(res)) +# return res + +# def updateResearchEvent( +# self, eventId, year, name, start_date, end_date, +# format, about, isCompetition, isConference, +# organisers, awardTypes, confDoi +# ): +# query = "UPDATE ResearchEvent SET name = %s, start_date = %s, end_date = %s, format = %s, about = %s, isCompetition = %s, isConference = %s, confDoi = %s WHERE eventId = %s AND year = %s" +# self.execute(query, ( +# name, start_date, end_date, format, about, +# isCompetition, isConference, confDoi, eventId, year +# ), commit=False) +# self.execute("DELETE FROM AwardTypes WHERE eventId = %s AND year = %s", (eventId, year), commit=False) +# self.executemany("INSERT INTO AwardTypes(eventId, year, awardType) VALUES (%s, %s, %s)", [ +# (eventId, year, awardType) for awardType in awardTypes +# ], commit=False) +# self.execute("DELETE FROM Organises WHERE eventId = %s AND year = %s", (eventId, year), commit=False) +# self.executemany("INSERT INTO Organises(eventId, year, instId) VALUES (%s, %s, %s)", [ +# (eventId, year, instId) for instId in organisers +# ]) +# return self.event(eventId, year) - # ==================================== DELETE FUNCTIONALITY ==================================== +# # ==================================== DELETE FUNCTIONALITY ==================================== - def removeStudentFromProject(self, email, pcode): - query = "DELETE FROM Works_On WHERE studentEmail = %s AND pcode = %s" - self.execute(query, (email, pcode, )) - return self.project(pcode) +# def removeStudentFromProject(self, email, pcode): +# query = "DELETE FROM Works_On WHERE studentEmail = %s AND pcode = %s" +# self.execute(query, (email, pcode, )) +# return self.project(pcode) - def removeStudentFromSubmission(self, email, eventId, year, code): - query = "DELETE FROM Submits WHERE studentEmail = %s AND eventId = %s AND year = %s AND code = %s" - self.execute(query, (email, eventId, year, code, )) - return self.submission(eventId, year, code) +# def removeStudentFromSubmission(self, email, eventId, year, code): +# query = "DELETE FROM Submits WHERE studentEmail = %s AND eventId = %s AND year = %s AND code = %s" +# self.execute(query, (email, eventId, year, code, )) +# return self.submission(eventId, year, code) - def deleteProject(self, pcode): - query = "DELETE FROM Project WHERE pcode = %s" - try: - self.execute(query, (pcode,)) - return {"result": True, "message": "Project Deleted Successfully!"} - except Exception as e: - return {"result": False, "message": str(e)} +# def deleteProject(self, pcode): +# query = "DELETE FROM Project WHERE pcode = %s" +# try: +# self.execute(query, (pcode,)) +# return {"result": True, "message": "Project Deleted Successfully!"} +# except Exception as e: +# return {"result": False, "message": str(e)} - def deleteSubmission(self, eventId, year, code): - query = "DELETE FROM Submission WHERE eventId = %s AND year = %s AND code = %s" - try: - self.execute(query, (eventId, year, code)) - return {"result": True, "message": "Submission Deleted Successfully!"} - except Exception as e: - return {"result": False, "message": str(e)} +# def deleteSubmission(self, eventId, year, code): +# query = "DELETE FROM Submission WHERE eventId = %s AND year = %s AND code = %s" +# try: +# self.execute(query, (eventId, year, code)) +# return {"result": True, "message": "Submission Deleted Successfully!"} +# except Exception as e: +# return {"result": False, "message": str(e)} - # ==================================== SEARCH FUNCTIONALITY ==================================== - - def searchSchools(self): - return self.queryAll("SELECT instId, name FROM Institution WHERE isSchool = TRUE") - - def searchOrganisers(self): - return self.queryAll("SELECT instId, name FROM Institution WHERE isOrganiser = TRUE") - - def searchAllStudents(self): - query = "SELECT email, name FROM ExternalStudent NATURAL INNER JOIN Student" - external_students = [{**i, 'pfp': ''} for i in self.queryAll(query)] - query = "SELECT email, name, pfp FROM NUSHStudent NATURAL INNER JOIN Student" - students = self.queryAll(query) - for student in students: - if(student): student["pfp"] = base64.b64encode(student.get("pfp", b'')).decode("utf-8") if student.get("pfp", b'') != None else "" - return list(students) + list(external_students) - - def searchAllTeachers(self): - query = "SELECT email, name, pfp FROM NUSHTeacher" - students = self.queryAll(query) - for student in students: - if(student): student["pfp"] = base64.b64encode(student.get("pfp", b'')).decode("utf-8") if student.get("pfp", b'') != None else "" - return students - - def events(self): - query = "SELECT eventId, year, name, about, isConference, isCompetition, start_date, end_date FROM ResearchEvent" - return self.queryAll(query) - - def best_students(self, email): - query = "SELECT studentEmail FROM Works_On NATURAL INNER JOIN Project WHERE teacherEmail = %s GROUP BY teacherEmail, studentEmail ORDER BY COUNT(studentEmail) DESC LIMIT 5" - studentEmails = self.queryAll(query, (email, )) - return [self.student(email["studentEmail"]) for email in studentEmails] - - def teacherProjects(self, email): - query = "SELECT pcode FROM Project WHERE teacherEmail = %s" - pcodes = self.queryAll(query, (email, )) - return [self.project(pcode["pcode"]) for pcode in pcodes] - - def extTeacherStudents(self, email): - query = "SELECT email FROM ExternalStudent WHERE emergencyEmail = %s LIMIT 5" - emails = self.queryAll(query, (email, )) - return [self.ext_student(email["email"]) for email in emails] +# # ==================================== SEARCH FUNCTIONALITY ==================================== + +# def searchSchools(self): +# return self.queryAll("SELECT instId, name FROM Institution WHERE isSchool = TRUE") + +# def searchOrganisers(self): +# return self.queryAll("SELECT instId, name FROM Institution WHERE isOrganiser = TRUE") + +# def searchAllStudents(self): +# query = "SELECT email, name FROM ExternalStudent NATURAL INNER JOIN Student" +# external_students = [{**i, 'pfp': ''} for i in self.queryAll(query)] +# query = "SELECT email, name, pfp FROM NUSHStudent NATURAL INNER JOIN Student" +# students = self.queryAll(query) +# for student in students: +# if(student): student["pfp"] = base64.b64encode(student.get("pfp", b'')).decode("utf-8") if student.get("pfp", b'') != None else "" +# return list(students) + list(external_students) + +# def searchAllTeachers(self): +# query = "SELECT email, name, pfp FROM NUSHTeacher" +# students = self.queryAll(query) +# for student in students: +# if(student): student["pfp"] = base64.b64encode(student.get("pfp", b'')).decode("utf-8") if student.get("pfp", b'') != None else "" +# return students + +# def events(self): +# query = "SELECT eventId, year, name, about, isConference, isCompetition, start_date, end_date FROM ResearchEvent" +# return self.queryAll(query) + +# def best_students(self, email): +# query = "SELECT studentEmail FROM Works_On NATURAL INNER JOIN Project WHERE teacherEmail = %s GROUP BY teacherEmail, studentEmail ORDER BY COUNT(studentEmail) DESC LIMIT 5" +# studentEmails = self.queryAll(query, (email, )) +# return [self.student(email["studentEmail"]) for email in studentEmails] + +# def teacherProjects(self, email): +# query = "SELECT pcode FROM Project WHERE teacherEmail = %s" +# pcodes = self.queryAll(query, (email, )) +# return [self.project(pcode["pcode"]) for pcode in pcodes] + +# def extTeacherStudents(self, email): +# query = "SELECT email FROM ExternalStudent WHERE emergencyEmail = %s LIMIT 5" +# emails = self.queryAll(query, (email, )) +# return [self.ext_student(email["email"]) for email in emails] - def _processAcc(self, result): - if result["isAward"]: - return { - "accId": result.get("accId", ""), - "name": result.get("name", ""), - "prize": result.get("prize", "") - } - else: - return self.queryOne("SELECT accId, pubTitle, doi FROM Publication WHERE accId = %s", (result.get("accId", ""), )) - - def accBySubmission(self, eventId, year, code): - # print("you chose", eventId, year, code) # , pubTitle, doi - query = "SELECT accId, isAward, name, prize FROM Accomplishment WHERE eventId = %s AND year = %s AND code = %s" - results = self.queryAll(query, (eventId, year, code, )) - return removeNulls([self._processAcc(result) for result in results]) - - def submissionsByProject(self, pcode): - query = "SELECT * FROM Submits WHERE pcode = %s" - submission_query_pairs = self.queryAll(query, (pcode, )) - query = "SELECT distinct eventId, year, code, subTitle, subAbstract FROM Submits NATURAL JOIN Submission WHERE pcode = %s" - submissions = self.queryAll(query, (pcode, )) - return [ - { - **submission, - "members": [ - self.student(i.get("studentEmail", "")) - for i in submission_query_pairs - if i.get("eventId", "") == submission.get("eventId", "") - and i.get("year", 0) == submission.get("year", 0) - and i.get("code", "") == submission.get("code", "") - ], - "accs": self.accBySubmission(submission.get("eventId", ""), submission.get("year", 0), submission.get("code", "")) - } - for submission in submissions - ] - - def submissionsByUser(self, email): - query = "SELECT * FROM Submits WHERE studentEmail = %s" - submission_query_pairs = self.queryAll(query, (email, )) - query = "SELECT distinct eventId, year, code, subTitle, subAbstract FROM Submits NATURAL JOIN Submission WHERE studentEmail = %s" - submissions = self.queryAll(query, (email, )) - return [ - { - **submission, - "projects": [ - i.get("pcode", "") - for i in submission_query_pairs - if i.get("eventId", "") == submission.get("eventId", "") - and i.get("year", 0) == submission.get("year", 0) - and i.get("code", "") == submission.get("code", "") - ], - # "accs": self.accBySubmission(submission.get("eventId", ""), submission.get("year", 0), submission.get("code", "")) - } - for submission in submissions - ] +# def _processAcc(self, result): +# if result["isAward"]: +# return { +# "accId": result.get("accId", ""), +# "name": result.get("name", ""), +# "prize": result.get("prize", "") +# } +# else: +# return self.queryOne("SELECT accId, pubTitle, doi FROM Publication WHERE accId = %s", (result.get("accId", ""), )) + +# def accBySubmission(self, eventId, year, code): +# # print("you chose", eventId, year, code) # , pubTitle, doi +# query = "SELECT accId, isAward, name, prize FROM Accomplishment WHERE eventId = %s AND year = %s AND code = %s" +# results = self.queryAll(query, (eventId, year, code, )) +# return remove_nulls([self._processAcc(result) for result in results]) + +# def submissionsByProject(self, pcode): +# query = "SELECT * FROM Submits WHERE pcode = %s" +# submission_query_pairs = self.queryAll(query, (pcode, )) +# query = "SELECT distinct eventId, year, code, subTitle, subAbstract FROM Submits NATURAL JOIN Submission WHERE pcode = %s" +# submissions = self.queryAll(query, (pcode, )) +# return [ +# { +# **submission, +# "members": [ +# self.student(i.get("studentEmail", "")) +# for i in submission_query_pairs +# if i.get("eventId", "") == submission.get("eventId", "") +# and i.get("year", 0) == submission.get("year", 0) +# and i.get("code", "") == submission.get("code", "") +# ], +# "accs": self.accBySubmission(submission.get("eventId", ""), submission.get("year", 0), submission.get("code", "")) +# } +# for submission in submissions +# ] + +# def submissionsByUser(self, email): +# query = "SELECT * FROM Submits WHERE studentEmail = %s" +# submission_query_pairs = self.queryAll(query, (email, )) +# query = "SELECT distinct eventId, year, code, subTitle, subAbstract FROM Submits NATURAL JOIN Submission WHERE studentEmail = %s" +# submissions = self.queryAll(query, (email, )) +# return [ +# { +# **submission, +# "projects": [ +# i.get("pcode", "") +# for i in submission_query_pairs +# if i.get("eventId", "") == submission.get("eventId", "") +# and i.get("year", 0) == submission.get("year", 0) +# and i.get("code", "") == submission.get("code", "") +# ], +# # "accs": self.accBySubmission(submission.get("eventId", ""), submission.get("year", 0), submission.get("code", "")) +# } +# for submission in submissions +# ] - def mentorsByProject(self, pcode): - query = "SELECT email FROM ResearchMentor INNER JOIN Mentors ON ResearchMentor.email = Mentors.mentorEmail WHERE pcode = %s" - emails = self.queryAll(query, (pcode, )) - return [self.mentor(email["email"]) for email in emails] - - - def projectsByMentor(self, email): - query = "SELECT pcode FROM ResearchMentor INNER JOIN Mentors ON ResearchMentor.email = Mentors.mentorEmail WHERE email = %s" - pcodes = self.queryAll(query, (email, )) - return [self.project(pcode["pcode"]) for pcode in pcodes] - - def mentorStudents(self, email): - query = "SELECT studentEmail FROM Works_On NATURAL INNER JOIN Project NATURAL INNER JOIN Mentors WHERE mentorEmail = %s GROUP BY mentorEmail, studentEmail ORDER BY COUNT(studentEmail) DESC LIMIT 5" - emails = self.queryAll(query, (email, )) - return [self.student(email["studentEmail"]) for email in emails] - - def _processSub(self, eventId, year, sub): - if not sub: return sub - query = "SELECT distinct pcode FROM Submits WHERE eventId = %s and year = %s and code = %s" - pcode = self.queryOne(query, (eventId, year, sub["code"])) - pcode = pcode if pcode else dict(pcode="") - students = removeNulls([self.student(email["studentEmail"]) for email in self.queryAll("SELECT distinct studentEmail FROM Submits WHERE eventId = %s and year = %s and code = %s", (eventId, year, sub["code"]))]) - return {**sub, **pcode, "members": students} - - def submissions(self, eventId, year): - query = "SELECT distinct code, subTitle title FROM Submission WHERE eventId = %s AND year = %s" - submissions = self.queryAll(query, (eventId, year, )) - return [self._processSub(eventId, year, submission) for submission in submissions] - - def otherProjects(self, email): - query = "SELECT pcode FROM Project p WHERE %s <> ALL (SELECT studentEmail FROM Works_On wo where wo.pcode = p.pcode)" - pcodes = [i["pcode"] for i in self.queryAll(query, (email, ))] - random.shuffle(pcodes) - return removeNulls([self.project(pcode) for pcode in pcodes if pcode]) - - def otherEvents(self, email): - query = "SELECT eventId, year FROM ResearchEvent re WHERE %s <> ALL (SELECT studentEmail FROM Submits s WHERE s.eventId = re.eventId AND s.year = re.year)" - ids = self.queryAll(query, (email, )) - return removeNulls([self.event(**id) for id in ids]) - - def projectMembers(self, pcode): - query = "SELECT studentEmail email FROM Works_On WHERE pcode = %s" - return [self.NUSHStudent(i["email"]) if self.isNUSHStudent(i["email"]) else self.ext_student(i["email"]) for i in self.queryAll(query, (pcode,))] - - def studentProjects(self, email): - pcodes = self.queryAll("SELECT pcode FROM Works_On WHERE studentEmail = %s", (email, )) - return removeNulls([self.project(pcode["pcode"]) for pcode in pcodes]) - - def coauthors(self, email): - query = "SELECT other.studentEmail email, COUNT(self.pcode) num FROM Works_On self, Works_On other WHERE self.pcode = other.pcode AND self.studentEmail = %s AND other.studentEmail <> self.studentEmail GROUP BY other.studentEmail ORDER BY COUNT(self.pcode) DESC LIMIT 5" - return [{**(i[0]), "count": i[1]} for i in [(self.NUSHStudent(i["email"]), i["num"]) for i in self.queryAll(query, (email,)) if self.isStudent(i["email"])] if i[0]] - - def projectByTeacher(self, email): - query = "SELECT pcode FROM Project WHERE teacherEmail = %s" - codes = self.queryAll(query, (email, )) - return [self.project(code) for code in codes] - - def updateProject(self, pcode, title, abstract, reportPdf): - # print(reportPdf) - reportPdf = convertB64toBytes(reportPdf) if reportPdf != None else "" - # print(reportPdf) - query = "UPDATE Project SET title = %s, abstract = %s, reportPdf = %s WHERE pcode = %s" - self.execute(query, (title, abstract, reportPdf, pcode)) - return self.project(pcode) - - def updateStudent(self, email, pfp, about): - pfp = convertB64toBytes(pfp) if pfp != None else "" # convert base64 to bytes object if needed. - query = "UPDATE NUSHStudent SET pfp = %s, about = %s WHERE email = %s" - self.execute(query, (pfp, about, email)) - return self.NUSHStudent(email) - - def _processJourn(self, journal): - query = "SELECT instId FROM PublishedBy WHERE issn = %s" - instIds = [i["instId"] for i in self.queryAll(query, (journal["issn"], )) if i] - institutes = removeNulls([self.institute(instId) for instId in instIds]) +# def mentorsByProject(self, pcode): +# query = "SELECT email FROM ResearchMentor INNER JOIN Mentors ON ResearchMentor.email = Mentors.mentorEmail WHERE pcode = %s" +# emails = self.queryAll(query, (pcode, )) +# return [self.mentor(email["email"]) for email in emails] + + +# def projectsByMentor(self, email): +# query = "SELECT pcode FROM ResearchMentor INNER JOIN Mentors ON ResearchMentor.email = Mentors.mentorEmail WHERE email = %s" +# pcodes = self.queryAll(query, (email, )) +# return [self.project(pcode["pcode"]) for pcode in pcodes] + +# def mentorStudents(self, email): +# query = "SELECT studentEmail FROM Works_On NATURAL INNER JOIN Project NATURAL INNER JOIN Mentors WHERE mentorEmail = %s GROUP BY mentorEmail, studentEmail ORDER BY COUNT(studentEmail) DESC LIMIT 5" +# emails = self.queryAll(query, (email, )) +# return [self.student(email["studentEmail"]) for email in emails] + +# def _processSub(self, eventId, year, sub): +# if not sub: return sub +# query = "SELECT distinct pcode FROM Submits WHERE eventId = %s and year = %s and code = %s" +# pcode = self.queryOne(query, (eventId, year, sub["code"])) +# pcode = pcode if pcode else dict(pcode="") +# students = remove_nulls([self.student(email["studentEmail"]) for email in self.queryAll("SELECT distinct studentEmail FROM Submits WHERE eventId = %s and year = %s and code = %s", (eventId, year, sub["code"]))]) +# return {**sub, **pcode, "members": students} + +# def submissions(self, eventId, year): +# query = "SELECT distinct code, subTitle title FROM Submission WHERE eventId = %s AND year = %s" +# submissions = self.queryAll(query, (eventId, year, )) +# return [self._processSub(eventId, year, submission) for submission in submissions] + +# def otherProjects(self, email): +# query = "SELECT pcode FROM Project p WHERE %s <> ALL (SELECT studentEmail FROM Works_On wo where wo.pcode = p.pcode)" +# pcodes = [i["pcode"] for i in self.queryAll(query, (email, ))] +# random.shuffle(pcodes) +# return remove_nulls([self.project(pcode) for pcode in pcodes if pcode]) + +# def otherEvents(self, email): +# query = "SELECT eventId, year FROM ResearchEvent re WHERE %s <> ALL (SELECT studentEmail FROM Submits s WHERE s.eventId = re.eventId AND s.year = re.year)" +# ids = self.queryAll(query, (email, )) +# return remove_nulls([self.event(**id) for id in ids]) + +# def projectMembers(self, pcode): +# query = "SELECT studentEmail email FROM Works_On WHERE pcode = %s" +# return [self.NUSHStudent(i["email"]) if self.isNUSHStudent(i["email"]) else self.ext_student(i["email"]) for i in self.queryAll(query, (pcode,))] + +# def studentProjects(self, email): +# pcodes = self.queryAll("SELECT pcode FROM Works_On WHERE studentEmail = %s", (email, )) +# return remove_nulls([self.project(pcode["pcode"]) for pcode in pcodes]) + +# def coauthors(self, email): +# query = "SELECT other.studentEmail email, COUNT(self.pcode) num FROM Works_On self, Works_On other WHERE self.pcode = other.pcode AND self.studentEmail = %s AND other.studentEmail <> self.studentEmail GROUP BY other.studentEmail ORDER BY COUNT(self.pcode) DESC LIMIT 5" +# return [{**(i[0]), "count": i[1]} for i in [(self.NUSHStudent(i["email"]), i["num"]) for i in self.queryAll(query, (email,)) if self.isStudent(i["email"])] if i[0]] + +# def projectByTeacher(self, email): +# query = "SELECT pcode FROM Project WHERE teacherEmail = %s" +# codes = self.queryAll(query, (email, )) +# return [self.project(code) for code in codes] + +# def updateProject(self, pcode, title, abstract, reportPdf): +# # print(reportPdf) +# reportPdf = convertB64toBytes(reportPdf) if reportPdf != None else "" +# # print(reportPdf) +# query = "UPDATE Project SET title = %s, abstract = %s, reportPdf = %s WHERE pcode = %s" +# self.execute(query, (title, abstract, reportPdf, pcode)) +# return self.project(pcode) + +# def updateStudent(self, email, pfp, about): +# pfp = convertB64toBytes(pfp) if pfp != None else "" # convert base64 to bytes object if needed. +# query = "UPDATE NUSHStudent SET pfp = %s, about = %s WHERE email = %s" +# self.execute(query, (pfp, about, email)) +# return self.NUSHStudent(email) + +# def _processJourn(self, journal): +# query = "SELECT instId FROM PublishedBy WHERE issn = %s" +# instIds = [i["instId"] for i in self.queryAll(query, (journal["issn"], )) if i] +# institutes = remove_nulls([self.institute(instId) for instId in instIds]) - publications = self.queryAll("SELECT pubTitle title, doi, url FROM Publication where journISSN = %s", (journal["issn"], )) +# publications = self.queryAll("SELECT pubTitle title, doi, url FROM Publication where journISSN = %s", (journal["issn"], )) - return { - **journal, - "institutes": institutes, - "publications": publications - } - - def journals(self): - query = "SELECT issn, name FROM Journal" - return [self._processJourn(it) for it in self.queryAll(query)] - - # ================================== AGGREGATION FUNCTIONALITY ================================= - def projectStats(self, email): - query = "SELECT year, COUNT(pcode) count FROM Works_On NATURAL JOIN Project WHERE studentEmail = %s GROUP BY year ORDER BY year" - stats = list(self.queryAll(query, (email, ))) +# return { +# **journal, +# "institutes": institutes, +# "publications": publications +# } + +# def journals(self): +# query = "SELECT issn, name FROM Journal" +# return [self._processJourn(it) for it in self.queryAll(query)] + +# # ================================== AGGREGATION FUNCTIONALITY ================================= +# def projectStats(self, email): +# query = "SELECT year, COUNT(pcode) count FROM Works_On NATURAL JOIN Project WHERE studentEmail = %s GROUP BY year ORDER BY year" +# stats = list(self.queryAll(query, (email, ))) - if len(stats) == 0: return stats - minYear = min([i["year"] for i in stats]) - maxYear = max([i["year"] for i in stats]) +# if len(stats) == 0: return stats +# minYear = min([i["year"] for i in stats]) +# maxYear = max([i["year"] for i in stats]) - for year in range(minYear, maxYear+1): - if any([i["year"] == year for i in stats]): continue; - stats.append({ "year": year, "count": 0 }) +# for year in range(minYear, maxYear+1): +# if any([i["year"] == year for i in stats]): continue; +# stats.append({ "year": year, "count": 0 }) - return sorted(stats, key=lambda i: i["year"]) +# return sorted(stats, key=lambda i: i["year"]) - def submissionStats(self, email): - query = "SELECT year, COUNT(pcode) count FROM Submits WHERE studentEmail = %s GROUP BY year ORDER BY year" - stats = list(self.queryAll(query, (email, ))) - if len(stats) == 0: return stats +# def submissionStats(self, email): +# query = "SELECT year, COUNT(pcode) count FROM Submits WHERE studentEmail = %s GROUP BY year ORDER BY year" +# stats = list(self.queryAll(query, (email, ))) +# if len(stats) == 0: return stats - minYear = min([i["year"] for i in stats]) - maxYear = max([i["year"] for i in stats]) +# minYear = min([i["year"] for i in stats]) +# maxYear = max([i["year"] for i in stats]) - for year in range(minYear, maxYear+1): - if any([i["year"] == year for i in stats]): continue; - stats.append({ "year": year, "count": 0 }) +# for year in range(minYear, maxYear+1): +# if any([i["year"] == year for i in stats]): continue; +# stats.append({ "year": year, "count": 0 }) - return sorted(stats, key=lambda i: i["year"]) +# return sorted(stats, key=lambda i: i["year"]) - def awardStats(self, email): - query = "SELECT year, COUNT(accId) count FROM Accomplishment NATURAL INNER JOIN Submits WHERE studentEmail = %s AND isAward = true GROUP BY year ORDER BY year" - stats = list(self.queryAll(query, (email, ))) - if len(stats) == 0: return stats +# def awardStats(self, email): +# query = "SELECT year, COUNT(accId) count FROM Accomplishment NATURAL INNER JOIN Submits WHERE studentEmail = %s AND isAward = true GROUP BY year ORDER BY year" +# stats = list(self.queryAll(query, (email, ))) +# if len(stats) == 0: return stats - minYear = min([i["year"] for i in stats]) - maxYear = max([i["year"] for i in stats]) +# minYear = min([i["year"] for i in stats]) +# maxYear = max([i["year"] for i in stats]) - for year in range(minYear, maxYear+1): - if any([i["year"] == year for i in stats]): continue; - stats.append({ "year": year, "count": 0 }) +# for year in range(minYear, maxYear+1): +# if any([i["year"] == year for i in stats]): continue; +# stats.append({ "year": year, "count": 0 }) - return sorted(stats, key=lambda i: i["year"]) +# return sorted(stats, key=lambda i: i["year"]) - def projectAwardStats(self, email): - query = "SELECT pcode, count, title, year FROM (SELECT pcode, COUNT(accId) count FROM Accomplishment NATURAL INNER JOIN Submits WHERE studentEmail = %s AND isAward = true GROUP BY pcode ORDER BY pcode) agg NATURAL INNER JOIN Project p ORDER BY year, pcode" - stats = list(self.queryAll(query, (email, ))) - return stats - - - - - +# def projectAwardStats(self, email): +# query = "SELECT pcode, count, title, year FROM (SELECT pcode, COUNT(accId) count FROM Accomplishment NATURAL INNER JOIN Submits WHERE studentEmail = %s AND isAward = true GROUP BY pcode ORDER BY pcode) agg NATURAL INNER JOIN Project p ORDER BY year, pcode" +# stats = list(self.queryAll(query, (email, ))) +# return stats diff --git a/server/models.py b/server/models.py new file mode 100644 index 0000000..e72ab48 --- /dev/null +++ b/server/models.py @@ -0,0 +1,662 @@ +from typing import Optional +from sqlalchemy import ForeignKey, MetaData, UniqueConstraint, create_engine, Index +from sqlalchemy.sql.expression import false +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, sessionmaker +from sqlalchemy.dialects.postgresql import BIGINT, VARCHAR, BOOLEAN, DATE, INTEGER, BYTEA +from datetime import date + +engine = create_engine('postgresql+asyncpg://postgres:admin@database/arxiv') +metadata_obj = MetaData(schema="arxiv") + +class Base(DeclarativeBase): + metadata = metadata_obj + +""" +Table "arxiv.researchevent" + Column | Type | Collation | Nullable | Default +---------------+-------------------------+-----------+----------+--------------------------------------------------- + numeventid | bigint | | not null | nextval('researchevent_numeventid_seq'::regclass) + eventid | character varying(15) | | not null | + year | integer | | not null | + name | character varying(100) | | not null | + about | character varying(5000) | | | + start_date | date | | not null | + end_date | date | | not null | + format | character varying(10) | | | + iscompetition | boolean | | not null | false + isconference | boolean | | not null | false + confdoi | character varying(200) | | | +Indexes: + "idx_16464_primary" PRIMARY KEY, btree (numeventid) + "idx_16464_eventid_2" UNIQUE, btree (eventid, year) +Referenced by: + TABLE "awardtypes" CONSTRAINT "awardtypes_ibfk_1" FOREIGN KEY (numeventid) REFERENCES researchevent(numeventid) ON UPDATE CASCADE ON DELETE CASCADE + TABLE "organises" CONSTRAINT "organises_ibfk_3" FOREIGN KEY (numeventid) REFERENCES researchevent(numeventid) ON UPDATE CASCADE ON DELETE CASCADE + TABLE "submission" CONSTRAINT "submission_ibfk_1" FOREIGN KEY (numeventid) REFERENCES researchevent(numeventid) ON UPDATE CASCADE ON DELETE CASCADE +""" +class ResearchEvent(Base): + __tablename__ = 'researchevent' + + num_event_id: Mapped[int] = mapped_column("numeventid", BIGINT, primary_key=True) + event_id: Mapped[str] = mapped_column("eventid", VARCHAR(15)) + year: Mapped[int] = mapped_column("year", INTEGER) + name: Mapped[str] = mapped_column("name", VARCHAR(100)) + about: Mapped[Optional[str]] = mapped_column("about", VARCHAR(5000)) + start_date: Mapped[date] = mapped_column("start_date", DATE) + end_date: Mapped[date] = mapped_column("end_date", DATE) + format: Mapped[Optional[str]] = mapped_column("format", VARCHAR(10)) + is_competition: Mapped[bool] = mapped_column("iscompetition", BOOLEAN, server_default=false(), default=False) + is_conference: Mapped[bool] = mapped_column("isconference", BOOLEAN, server_default=false(), default=False) + conf_doi: Mapped[Optional[str]] = mapped_column("confdoi", VARCHAR(200)) + + submissions: Mapped[list["Submission"]] = relationship(back_populates="event", cascade="all, delete-orphan", passive_deletes=True) + award_types: Mapped[list["AwardTypes"]] = relationship(back_populates="event", cascade="all, delete-orphan", passive_deletes=True) + organisers: Mapped[list["Organises"]] = relationship(back_populates="event", cascade="all, delete-orphan", passive_deletes=True) + + __table_args__ = (UniqueConstraint('eventid', 'year', name='idx_16464_eventid_2'),) + +""" +Table "arxiv.submission" + Column | Type | Collation | Nullable | Default +-------------+-------------------------+-----------+----------+------------------------------------------- + subid | bigint | | not null | nextval('submission_subid_seq'::regclass) + numeventid | bigint | | not null | + code | character varying(20) | | not null | + subtitle | character varying(200) | | not null | + subabstract | character varying(2000) | | not null | +Indexes: + "idx_16479_primary" PRIMARY KEY, btree (subid) + "idx_16479_numeventid" UNIQUE, btree (numeventid, code) +Foreign-key constraints: + "submission_ibfk_1" FOREIGN KEY (numeventid) REFERENCES researchevent(numeventid) ON UPDATE CASCADE ON DELETE CASCADE +Referenced by: + TABLE "accomplishment" CONSTRAINT "accomplishment_ibfk_1" FOREIGN KEY (subid) REFERENCES submission(subid) ON UPDATE CASCADE ON DELETE SET NULL + TABLE "submits" CONSTRAINT "submits_ibfk_3" FOREIGN KEY (subid) REFERENCES submission(subid) ON UPDATE CASCADE ON DELETE CASCADE +""" +class Submission(Base): + __tablename__ = 'submission' + + sub_id: Mapped[int] = mapped_column("subid", BIGINT, primary_key=True) + num_event_id: Mapped[int] = mapped_column("numeventid", ForeignKey("researchevent.numeventid", name="submission_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) + code: Mapped[str] = mapped_column("code", VARCHAR(20)) + sub_title: Mapped[str] = mapped_column("subtitle", VARCHAR(200)) + sub_abstract: Mapped[str] = mapped_column("subabstract", VARCHAR(2000)) + + event: Mapped[ResearchEvent] = relationship("ResearchEvent", back_populates="submissions") + + accomplishments: Mapped[list["Accomplishment"]] = relationship("Accomplishment", back_populates="submission") + submits: Mapped[list["Submits"]] = relationship("Submits", back_populates="submission", cascade="all, delete-orphan", passive_deletes=True) + + __table_args__ = (UniqueConstraint('numeventid', 'code', name='idx_16479_numeventid'),) + +""" +Table "arxiv.accomplishment" + Column | Type | Collation | Nullable | Default +---------+------------------------+-----------+----------+--------- + accid | integer | | not null | + isaward | boolean | | not null | false + name | character varying(100) | | | + prize | character varying(100) | | | + subid | bigint | | | +Indexes: + "idx_16386_primary" PRIMARY KEY, btree (accid) + "idx_16386_subid" btree (subid) +Foreign-key constraints: + "accomplishment_ibfk_1" FOREIGN KEY (subid) REFERENCES submission(subid) ON UPDATE CASCADE ON DELETE SET NULL +Referenced by: + TABLE "publication" CONSTRAINT "publication_ibfk_1" FOREIGN KEY (accid) REFERENCES accomplishment(accid) ON UPDATE CASCADE ON DELETE CASCADE +""" +class Accomplishment(Base): + __tablename__ = 'accomplishment' + + acc_id: Mapped[int] = mapped_column("accid", INTEGER, primary_key=True) + is_award: Mapped[bool] = mapped_column("isaward", BOOLEAN, server_default=false(), default=False) + name: Mapped[Optional[str]] = mapped_column("name", VARCHAR(100)) + prize: Mapped[Optional[str]] = mapped_column("prize", VARCHAR(100)) + sub_id: Mapped[Optional[int]] = mapped_column("subid", ForeignKey("submission.subid", name="accomplishment_ibfk_1", onupdate="CASCADE", ondelete="SET NULL")) + + submission: Mapped[Submission] = relationship("Submission", back_populates="accomplishments") + publication: Mapped["Publication"] = relationship("Publication", back_populates="accomplishment", cascade="all, delete-orphan", passive_deletes=True) + + __table_args__ = (Index('idx_16386_subid', 'subid'),) + +""" +Table "arxiv.awardtypes" + Column | Type | Collation | Nullable | Default +------------+------------------------+-----------+----------+---------------------------------------- + id | bigint | | not null | nextval('awardtypes_id_seq'::regclass) + numeventid | bigint | | not null | + awardtype | character varying(100) | | not null | +Indexes: + "idx_16391_primary" PRIMARY KEY, btree (id) + "idx_16391_numeventid" UNIQUE, btree (numeventid, awardtype) +Foreign-key constraints: + "awardtypes_ibfk_1" FOREIGN KEY (numeventid) REFERENCES researchevent(numeventid) ON UPDATE CASCADE ON DELETE CASCADE +""" +class AwardTypes(Base): + __tablename__ = 'awardtypes' + + id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) + num_event_id: Mapped[int] = mapped_column("numeventid", ForeignKey("researchevent.numeventid", name="awardtypes_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) + award_type: Mapped[str] = mapped_column("awardtype", VARCHAR(100)) + + event: Mapped[ResearchEvent] = relationship("ResearchEvent", back_populates="award_types") + + __table_args__ = (UniqueConstraint('numeventid', 'awardtype', name='idx_16391_numeventid'),) + +""" +Table "arxiv.department" + Column | Type | Collation | Nullable | Default +--------+-----------------------+-----------+----------+----------------------- + deptid | character(2) | | not null | + name | character varying(50) | | not null | ''::character varying +Indexes: + "idx_16395_primary" PRIMARY KEY, btree (deptid) +Referenced by: + TABLE "nushteacher" CONSTRAINT "nushteacher_ibfk_1" FOREIGN KEY (deptid) REFERENCES department(deptid) ON UPDATE CASCADE ON DELETE SET NULL + TABLE "project" CONSTRAINT "project_ibfk_1" FOREIGN KEY (deptid) REFERENCES department(deptid) ON UPDATE CASCADE ON DELETE SET NULL +""" +class Department(Base): + __tablename__ = 'department' + + dept_id: Mapped[str] = mapped_column("deptid", VARCHAR(2), primary_key=True) + name: Mapped[str] = mapped_column("name", VARCHAR(50), server_default="", default="") + + teachers: Mapped[list["NUSHTeacher"]] = relationship("NUSHTeacher", back_populates="department") + projects: Mapped[list["Project"]] = relationship("Project", back_populates="department") + +""" +Table "arxiv.student" + Column | Type | Collation | Nullable | Default +--------+------------------------+-----------+----------+--------- + email | character varying(255) | | not null | + name | character varying(100) | | | +Indexes: + "idx_16475_primary" PRIMARY KEY, btree (email) +Referenced by: + TABLE "externalstudent" CONSTRAINT "externalstudent_ibfk_1" FOREIGN KEY (email) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE + TABLE "nushstudent" CONSTRAINT "nushstudent_ibfk_1" FOREIGN KEY (email) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE + TABLE "submits" CONSTRAINT "submits_ibfk_1" FOREIGN KEY (studentemail) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE + TABLE "works_on" CONSTRAINT "works_on_ibfk_2" FOREIGN KEY (studentemail) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE +""" +class Student(Base): + __tablename__ = 'student' + + email: Mapped[str] = mapped_column("email", VARCHAR(255), primary_key=True) + name: Mapped[Optional[str]] = mapped_column("name", VARCHAR(100)) + + external_student: Mapped["ExternalStudent"] = relationship("ExternalStudent", back_populates="student", cascade="all, delete-orphan", passive_deletes=True) + nush_student: Mapped["NUSHStudent"] = relationship("NUSHStudent", back_populates="student", cascade="all, delete-orphan", passive_deletes=True) + submits: Mapped[list["Submits"]] = relationship("Submits", back_populates="student", cascade="all, delete-orphan", passive_deletes=True) + projects: Mapped[list["WorksOn"]] = relationship("WorksOn", back_populates="student", cascade="all, delete-orphan", passive_deletes=True) + +""" +Table "arxiv.institution" + Column | Type | Collation | Nullable | Default +-------------+------------------------+-----------+----------+----------------------- + instid | character varying(10) | | not null | + name | character varying(100) | | not null | ''::character varying + address | character varying(150) | | not null | ''::character varying + isschool | boolean | | not null | false + isinstitute | boolean | | not null | false + isorganiser | boolean | | not null | false + ispublisher | boolean | | not null | false +Indexes: + "idx_16407_primary" PRIMARY KEY, btree (instid) +Referenced by: + TABLE "externalteacher" CONSTRAINT "externalteacher_ibfk_1" FOREIGN KEY (schid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE SET NULL + TABLE "organises" CONSTRAINT "organises_ibfk_2" FOREIGN KEY (instid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE CASCADE + TABLE "publishedby" CONSTRAINT "publishedby_ibfk_2" FOREIGN KEY (instid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE CASCADE + TABLE "works_at" CONSTRAINT "works_at_ibfk_2" FOREIGN KEY (instid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE CASCADE +""" +class Institution(Base): + __tablename__ = 'institution' + + inst_id: Mapped[str] = mapped_column("instid", VARCHAR(10), primary_key=True) + name: Mapped[str] = mapped_column("name", VARCHAR(100), server_default="", default="") + address: Mapped[str] = mapped_column("address", VARCHAR(150), server_default="", default="") + is_school: Mapped[bool] = mapped_column("isschool", BOOLEAN, server_default=false(), default=False) + is_institute: Mapped[bool] = mapped_column("isinstitute", BOOLEAN, server_default=false(), default=False) + is_organiser: Mapped[bool] = mapped_column("isorganiser", BOOLEAN, server_default=false(), default=False) + is_publisher: Mapped[bool] = mapped_column("ispublisher", BOOLEAN, server_default=false(), default=False) + + teachers: Mapped[list["ExternalTeacher"]] = relationship("ExternalTeacher", back_populates="institution") + events: Mapped[list["Organises"]] = relationship("Organises", back_populates="institution", cascade="all, delete-orphan", passive_deletes=True) + publishes: Mapped[list["PublishedBy"]] = relationship("PublishedBy", back_populates="institution", cascade="all, delete-orphan", passive_deletes=True) + members: Mapped[list["WorksAt"]] = relationship("WorksAt", back_populates="institution", cascade="all, delete-orphan", passive_deletes=True) + +""" +Table "arxiv.externalteacher" + Column | Type | Collation | Nullable | Default +--------+------------------------+-----------+----------+--------- + email | character varying(255) | | not null | + name | character varying(100) | | | + schid | character varying(10) | | | +Indexes: + "idx_16404_primary" PRIMARY KEY, btree (email) + "idx_16404_schid" btree (schid) +Foreign-key constraints: + "externalteacher_ibfk_1" FOREIGN KEY (schid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE SET NULL +Referenced by: + TABLE "externalstudent" CONSTRAINT "externalstudent_ibfk_2" FOREIGN KEY (emergencyemail) REFERENCES externalteacher(email) ON UPDATE CASCADE ON DELETE SET NULL +""" +class ExternalTeacher(Base): + __tablename__ = 'externalteacher' + + email: Mapped[str] = mapped_column("email", VARCHAR(255), primary_key=True) + name: Mapped[Optional[str]] = mapped_column("name", VARCHAR(100)) + sch_id: Mapped[Optional[str]] = mapped_column("schid", ForeignKey("institution.instid", name="externalteacher_ibfk_1", onupdate="CASCADE", ondelete="SET NULL")) + + institution: Mapped[Institution] = relationship("Institution", back_populates="teachers") + students: Mapped[list["ExternalStudent"]] = relationship("ExternalStudent", back_populates="teacher") + + __table_args__ = (Index('idx_16404_schid', 'schid'),) + +""" +Table "arxiv.externalstudent" + Column | Type | Collation | Nullable | Default +----------------+------------------------+-----------+----------+--------- + email | character varying(255) | | not null | + emergencyemail | character varying(255) | | | +Indexes: + "idx_16399_primary" PRIMARY KEY, btree (email) + "idx_16399_emergencyemail" btree (emergencyemail) +Foreign-key constraints: + "externalstudent_ibfk_1" FOREIGN KEY (email) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE + "externalstudent_ibfk_2" FOREIGN KEY (emergencyemail) REFERENCES externalteacher(email) ON UPDATE CASCADE ON DELETE SET NULL +""" +class ExternalStudent(Base): + __tablename__ = 'externalstudent' + + email: Mapped[str] = mapped_column("email", ForeignKey("student.email", name="externalstudent_ibfk_1", onupdate="CASCADE", ondelete="CASCADE"), primary_key=True) + emergency_email: Mapped[Optional[str]] = mapped_column("emergencyemail", ForeignKey("externalteacher.email", name="externalstudent_ibfk_2", onupdate="CASCADE", ondelete="SET NULL")) + + student: Mapped[Student] = relationship("Student", back_populates="external_student") + teacher: Mapped[ExternalTeacher] = relationship("ExternalTeacher", back_populates="students") + + __table_args__ = (Index('idx_16399_emergencyemail', 'emergencyemail'),) + +""" +Table "arxiv.journal" + Column | Type | Collation | Nullable | Default +--------+------------------------+-----------+----------+--------- + issn | integer | | not null | + name | character varying(100) | | not null | +Indexes: + "idx_16416_primary" PRIMARY KEY, btree (issn) +Referenced by: + TABLE "publication" CONSTRAINT "publication_ibfk_2" FOREIGN KEY (journissn) REFERENCES journal(issn) ON UPDATE CASCADE ON DELETE CASCADE + TABLE "publishedby" CONSTRAINT "publishedby_ibfk_1" FOREIGN KEY (issn) REFERENCES journal(issn) ON UPDATE CASCADE ON DELETE CASCADE +""" +class Journal(Base): + __tablename__ = 'journal' + + issn: Mapped[int] = mapped_column("issn", INTEGER, autoincrement=False, primary_key=True) + name: Mapped[str] = mapped_column("name", VARCHAR(100)) + + publications: Mapped[list["Publication"]] = relationship("Publication", back_populates="journal", cascade="all, delete-orphan", passive_deletes=True) + publishers: Mapped[list["PublishedBy"]] = relationship("PublishedBy", back_populates="journal", cascade="all, delete-orphan", passive_deletes=True) + +""" +Table "arxiv.researchmentor" + Column | Type | Collation | Nullable | Default +--------+------------------------+-----------+----------+--------- + email | character varying(255) | | not null | + name | character varying(100) | | | +Indexes: + "idx_16472_primary" PRIMARY KEY, btree (email) +Referenced by: + TABLE "mentors" CONSTRAINT "mentors_ibfk_2" FOREIGN KEY (mentoremail) REFERENCES researchmentor(email) ON UPDATE CASCADE ON DELETE CASCADE + TABLE "works_at" CONSTRAINT "works_at_ibfk_1" FOREIGN KEY (mentoremail) REFERENCES researchmentor(email) ON UPDATE CASCADE ON DELETE CASCADE +""" +class ResearchMentor(Base): + __tablename__ = 'researchmentor' + + email: Mapped[str] = mapped_column("email", VARCHAR(255), primary_key=True) + name: Mapped[Optional[str]] = mapped_column("name", VARCHAR(100)) + + projects: Mapped[list["Mentors"]] = relationship("Mentors", back_populates="mentor", cascade="all, delete-orphan", passive_deletes=True) + workplaces: Mapped[list["WorksAt"]] = relationship("WorksAt", back_populates="mentor", cascade="all, delete-orphan", passive_deletes=True) + +""" +Table "arxiv.nushteacher" + Column | Type | Collation | Nullable | Default +----------+------------------------+-----------+----------+----------------------- + email | character varying(255) | | not null | + pwd | character varying(20) | | | + name | character varying(100) | | not null | ''::character varying + pfp | bytea | | | + isadmin | boolean | | not null | false + ismentor | boolean | | not null | false + deptid | character(2) | | | +Indexes: + "idx_16429_primary" PRIMARY KEY, btree (email) + "idx_16429_deptid" btree (deptid) +Foreign-key constraints: + "nushteacher_ibfk_1" FOREIGN KEY (deptid) REFERENCES department(deptid) ON UPDATE CASCADE ON DELETE SET NULL +Referenced by: + TABLE "project" CONSTRAINT "project_ibfk_2" FOREIGN KEY (teacheremail) REFERENCES nushteacher(email) ON UPDATE CASCADE ON DELETE SET NULL +""" +class NUSHTeacher(Base): + __tablename__ = 'nushteacher' + + email: Mapped[str] = mapped_column("email", VARCHAR(255), primary_key=True) + pwd: Mapped[Optional[str]] = mapped_column("pwd", VARCHAR(20)) + name: Mapped[str] = mapped_column("name", VARCHAR(100), server_default="", default="") + pfp_bytes: Mapped[Optional[bytes]] = mapped_column("pfp", BYTEA) + is_admin: Mapped[bool] = mapped_column("isadmin", BOOLEAN, server_default=false(), default=False) + is_mentor: Mapped[bool] = mapped_column("ismentor", BOOLEAN, server_default=false(), default=False) + dept_id: Mapped[Optional[str]] = mapped_column("deptid", ForeignKey("department.deptid", name="nushteacher_ibfk_1", onupdate="CASCADE", ondelete="SET NULL")) + + department: Mapped[Department] = relationship("Department", back_populates="teachers") + projects: Mapped[list["Project"]] = relationship("Project", back_populates="teacher") + + __table_args__ = (Index('idx_16429_deptid', 'deptid'),) + +""" +Table "arxiv.project" + Column | Type | Collation | Nullable | Default +--------------+-------------------------+-----------+----------+--------- + pcode | character varying(20) | | not null | + title | character varying(200) | | not null | + abstract | character varying(2000) | | | + reportpdf | bytea | | | + year | integer | | | + deptid | character(2) | | | + teacheremail | character varying(255) | | | +Indexes: + "idx_16442_primary" PRIMARY KEY, btree (pcode) + "idx_16442_deptid" btree (deptid) + "idx_16442_teacheremail" btree (teacheremail) +Foreign-key constraints: + "project_ibfk_1" FOREIGN KEY (deptid) REFERENCES department(deptid) ON UPDATE CASCADE ON DELETE SET NULL + "project_ibfk_2" FOREIGN KEY (teacheremail) REFERENCES nushteacher(email) ON UPDATE CASCADE ON DELETE SET NULL +Referenced by: + TABLE "mentors" CONSTRAINT "mentors_ibfk_1" FOREIGN KEY (pcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE + TABLE "projectcontinuation" CONSTRAINT "projectcontinuation_ibfk_1" FOREIGN KEY (prevpcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE + TABLE "projectcontinuation" CONSTRAINT "projectcontinuation_ibfk_2" FOREIGN KEY (nextpcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE + TABLE "submits" CONSTRAINT "submits_ibfk_2" FOREIGN KEY (pcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE + TABLE "works_on" CONSTRAINT "works_on_ibfk_1" FOREIGN KEY (pcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE +""" +class Project(Base): + __tablename__ = 'project' + + p_code: Mapped[str] = mapped_column("pcode", VARCHAR(20), primary_key=True) + title: Mapped[str] = mapped_column("title", VARCHAR(200)) + abstract: Mapped[Optional[str]] = mapped_column("abstract", VARCHAR(2000)) + report_pdf: Mapped[Optional[bytes]] = mapped_column("reportpdf", BYTEA) + year: Mapped[Optional[int]] = mapped_column("year", INTEGER) + dept_id: Mapped[Optional[str]] = mapped_column("deptid", ForeignKey("department.deptid", name="project_ibfk_1", onupdate="CASCADE", ondelete="SET NULL")) + teacher_email: Mapped[Optional[str]] = mapped_column("teacheremail", ForeignKey("nushteacher.email", name="project_ibfk_2", onupdate="CASCADE", ondelete="SET NULL")) + + department: Mapped[Department] = relationship("Department", back_populates="projects") + teacher: Mapped[NUSHTeacher] = relationship("NUSHTeacher", back_populates="projects") + + mentors: Mapped[list["Mentors"]] = relationship("Mentors", back_populates="project", cascade="all, delete-orphan", passive_deletes=True) + continuations: Mapped[list["ProjectContinuation"]] = relationship("ProjectContinuation", foreign_keys="[ProjectContinuation.prev_p_code]", back_populates="prev_project", cascade="all, delete-orphan", passive_deletes=True) + prev_projects: Mapped[list["ProjectContinuation"]] = relationship("ProjectContinuation", foreign_keys="[ProjectContinuation.next_p_code]", back_populates="next_project", cascade="all, delete-orphan", passive_deletes=True) + submits: Mapped[list["Submits"]] = relationship("Submits", back_populates="project", cascade="all, delete-orphan", passive_deletes=True) + students: Mapped[list["WorksOn"]] = relationship("WorksOn", back_populates="project", cascade="all, delete-orphan", passive_deletes=True) + + __table_args__ = (Index('idx_16442_deptid', 'deptid'), Index('idx_16442_teacheremail', 'teacheremail'),) + +""" +Table "arxiv.mentors" + Column | Type | Collation | Nullable | Default +-------------+------------------------+-----------+----------+------------------------------------- + id | bigint | | not null | nextval('mentors_id_seq'::regclass) + mentoremail | character varying(255) | | not null | + pcode | character varying(20) | | not null | +Indexes: + "idx_16420_primary" PRIMARY KEY, btree (id) + "idx_16420_mentoremail" btree (mentoremail) + "idx_16420_pcode_2" UNIQUE, btree (pcode, mentoremail) +Foreign-key constraints: + "mentors_ibfk_1" FOREIGN KEY (pcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE + "mentors_ibfk_2" FOREIGN KEY (mentoremail) REFERENCES researchmentor(email) ON UPDATE CASCADE ON DELETE CASCADE +""" +class Mentors(Base): + __tablename__ = 'mentors' + + id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) + mentor_email: Mapped[str] = mapped_column("mentoremail", ForeignKey("researchmentor.email", name="mentors_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) + p_code: Mapped[str] = mapped_column("pcode", ForeignKey("project.pcode", name="mentors_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) + + project: Mapped[Project] = relationship("Project", back_populates="mentors") + mentor: Mapped[ResearchMentor] = relationship("ResearchMentor", back_populates="projects") + + __table_args__ = (UniqueConstraint('pcode', 'mentoremail', name='idx_16420_pcode_2'), Index('idx_16420_mentoremail', 'mentoremail'),) + +""" +Table "arxiv.nushstudent" + Column | Type | Collation | Nullable | Default +----------+-------------------------+-----------+----------+--------- + email | character varying(255) | | not null | + pwd | character varying(20) | | | + pfp | bytea | | | + about | character varying(1000) | | | + gradyear | integer | | | + nush_sid | character varying(8) | | | +Indexes: + "idx_16424_primary" PRIMARY KEY, btree (email) +Foreign-key constraints: + "nushstudent_ibfk_1" FOREIGN KEY (email) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE +""" +class NUSHStudent(Base): + __tablename__ = 'nushstudent' + + email: Mapped[str] = mapped_column("email", ForeignKey("student.email", name="nushstudent_ibfk_1", onupdate="CASCADE", ondelete="CASCADE"), primary_key=True) + pwd: Mapped[Optional[str]] = mapped_column("pwd", VARCHAR(20)) + pfp_bytes: Mapped[Optional[bytes]] = mapped_column("pfp", BYTEA) + about: Mapped[Optional[str]] = mapped_column("about", VARCHAR(1000)) + grad_year: Mapped[Optional[int]] = mapped_column("gradyear", INTEGER) + nush_sid: Mapped[Optional[str]] = mapped_column("nush_sid", VARCHAR(8)) + + student: Mapped[Student] = relationship("Student", back_populates="nush_student") + +""" +Table "arxiv.organises" + Column | Type | Collation | Nullable | Default +------------+-----------------------+-----------+----------+--------------------------------------- + id | bigint | | not null | nextval('organises_id_seq'::regclass) + numeventid | bigint | | not null | + instid | character varying(10) | | not null | +Indexes: + "idx_16438_primary" PRIMARY KEY, btree (id) + "idx_16438_instid" btree (instid) + "idx_16438_numeventid" UNIQUE, btree (numeventid, instid) +Foreign-key constraints: + "organises_ibfk_2" FOREIGN KEY (instid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE CASCADE + "organises_ibfk_3" FOREIGN KEY (numeventid) REFERENCES researchevent(numeventid) ON UPDATE CASCADE ON DELETE CASCADE +""" +class Organises(Base): + __tablename__ = 'organises' + + id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) + num_event_id: Mapped[int] = mapped_column("numeventid", ForeignKey("researchevent.numeventid", name="organises_ibfk_3", onupdate="CASCADE", ondelete="CASCADE")) + inst_id: Mapped[str] = mapped_column("instid", ForeignKey("institution.instid", name="organises_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) + + event: Mapped[ResearchEvent] = relationship("ResearchEvent", back_populates="organisers") + institution: Mapped[Institution] = relationship("Institution", back_populates="events") + + __table_args__ = (UniqueConstraint('numeventid', 'instid', name='idx_16438_numeventid'), Index('idx_16438_instid', 'instid'),) + +""" +Table "arxiv.projectcontinuation" + Column | Type | Collation | Nullable | Default +-----------+-----------------------+-----------+----------+------------------------------------------------- + id | bigint | | not null | nextval('projectcontinuation_id_seq'::regclass) + prevpcode | character varying(20) | | not null | + nextpcode | character varying(20) | | not null | +Indexes: + "idx_16448_primary" PRIMARY KEY, btree (id) + "idx_16448_nextpcode" btree (nextpcode) + "idx_16448_prevpcode_2" UNIQUE, btree (prevpcode, nextpcode) +Foreign-key constraints: + "projectcontinuation_ibfk_1" FOREIGN KEY (prevpcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE + "projectcontinuation_ibfk_2" FOREIGN KEY (nextpcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE +""" +class ProjectContinuation(Base): + __tablename__ = 'projectcontinuation' + + id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) + prev_p_code: Mapped[str] = mapped_column("prevpcode", ForeignKey("project.pcode", name="projectcontinuation_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) + next_p_code: Mapped[str] = mapped_column("nextpcode", ForeignKey("project.pcode", name="projectcontinuation_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) + + prev_project: Mapped[Project] = relationship("Project", foreign_keys=[prev_p_code], back_populates="continuations") + next_project: Mapped[Project] = relationship("Project", foreign_keys=[next_p_code], back_populates="prev_projects") + + __table_args__ = (UniqueConstraint('prevpcode', 'nextpcode', name='idx_16448_prevpcode_2'), Index('idx_16448_nextpcode', 'nextpcode'),) + +""" +Table "arxiv.publication" + Column | Type | Collation | Nullable | Default +-----------+------------------------+-----------+----------+--------- + accid | integer | | not null | + pubtitle | character varying(200) | | not null | + doi | character varying(200) | | | + isjournal | boolean | | not null | false + url | character varying(300) | | | + journissn | integer | | | +Indexes: + "idx_16452_primary" PRIMARY KEY, btree (accid) + "idx_16452_journissn" btree (journissn) +Foreign-key constraints: + "publication_ibfk_1" FOREIGN KEY (accid) REFERENCES accomplishment(accid) ON UPDATE CASCADE ON DELETE CASCADE + "publication_ibfk_2" FOREIGN KEY (journissn) REFERENCES journal(issn) ON UPDATE CASCADE ON DELETE CASCADE +""" +class Publication(Base): + __tablename__ = 'publication' + + acc_id: Mapped[int] = mapped_column("accid", ForeignKey("accomplishment.accid", name="publication_ibfk_1", onupdate="CASCADE", ondelete="CASCADE"), primary_key=True) + pub_title: Mapped[str] = mapped_column("pubtitle", VARCHAR(200)) + doi: Mapped[Optional[str]] = mapped_column("doi", VARCHAR(200)) + is_journal: Mapped[bool] = mapped_column("isjournal", BOOLEAN, server_default=false(), default=False) + url: Mapped[Optional[str]] = mapped_column("url", VARCHAR(300)) + journ_issn: Mapped[Optional[int]] = mapped_column("journissn", ForeignKey("journal.issn", name="publication_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) + + accomplishment: Mapped[Accomplishment] = relationship("Accomplishment", back_populates="publication") + journal: Mapped[Journal] = relationship("Journal", back_populates="publications") + + __table_args__ = (Index('idx_16452_journissn', 'journissn'),) + +""" +Table "arxiv.publishedby" + Column | Type | Collation | Nullable | Default +--------+-----------------------+-----------+----------+----------------------------------------- + id | bigint | | not null | nextval('publishedby_id_seq'::regclass) + issn | integer | | not null | + instid | character varying(10) | | not null | +Indexes: + "idx_16459_primary" PRIMARY KEY, btree (id) + "idx_16459_instid" btree (instid) + "idx_16459_issn_2" UNIQUE, btree (issn, instid) +Foreign-key constraints: + "publishedby_ibfk_1" FOREIGN KEY (issn) REFERENCES journal(issn) ON UPDATE CASCADE ON DELETE CASCADE + "publishedby_ibfk_2" FOREIGN KEY (instid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE CASCADE +""" +class PublishedBy(Base): + __tablename__ = 'publishedby' + + id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) + issn: Mapped[int] = mapped_column("issn", ForeignKey("journal.issn", name="publishedby_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) + inst_id: Mapped[str] = mapped_column("instid", ForeignKey("institution.instid", name="publishedby_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) + + journal: Mapped[Journal] = relationship("Journal", back_populates="publishers") + institution: Mapped[Institution] = relationship("Institution", back_populates="publishes") + + __table_args__ = (UniqueConstraint('issn', 'instid', name='idx_16459_issn_2'), Index('idx_16459_instid', 'instid'),) + +""" +Table "arxiv.submits" + Column | Type | Collation | Nullable | Default +--------------+------------------------+-----------+----------+------------------------------------- + id | bigint | | not null | nextval('submits_id_seq'::regclass) + studentemail | character varying(255) | | not null | + pcode | character varying(20) | | not null | + subid | bigint | | not null | +Indexes: + "idx_16486_primary" PRIMARY KEY, btree (id) + "idx_16486_pcode" btree (pcode) + "idx_16486_studentemail_2" UNIQUE, btree (studentemail, pcode, subid) + "idx_16486_subid" btree (subid) +Foreign-key constraints: + "submits_ibfk_1" FOREIGN KEY (studentemail) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE + "submits_ibfk_2" FOREIGN KEY (pcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE + "submits_ibfk_3" FOREIGN KEY (subid) REFERENCES submission(subid) ON UPDATE CASCADE ON DELETE CASCADE +""" +class Submits(Base): + __tablename__ = 'submits' + + id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) + student_email: Mapped[str] = mapped_column("studentemail", ForeignKey("student.email", name="submits_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) + p_code: Mapped[str] = mapped_column("pcode", ForeignKey("project.pcode", name="submits_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) + sub_id: Mapped[int] = mapped_column("subid", ForeignKey("submission.subid", name="submits_ibfk_3", onupdate="CASCADE", ondelete="CASCADE")) + + student: Mapped[Student] = relationship("Student", back_populates="submits") + project: Mapped[Project] = relationship("Project", back_populates="submits") + submission: Mapped[Submission] = relationship("Submission", back_populates="submits") + + __table_args__ = (UniqueConstraint('studentemail', 'pcode', 'subid', name='idx_16486_studentemail_2'), Index('idx_16486_pcode', 'pcode'), Index('idx_16486_subid', 'subid'),) + +""" +Table "arxiv.works_at" + Column | Type | Collation | Nullable | Default +-------------+------------------------+-----------+----------+-------------------------------------- + id | bigint | | not null | nextval('works_at_id_seq'::regclass) + mentoremail | character varying(255) | | not null | + instid | character varying(10) | | not null | + dept | character varying(100) | | | + role | character varying(100) | | | + officeaddr | character varying(100) | | | +Indexes: + "idx_16491_primary" PRIMARY KEY, btree (id) + "idx_16491_instid" btree (instid) + "idx_16491_mentoremail" UNIQUE, btree (mentoremail, instid) +Foreign-key constraints: + "works_at_ibfk_1" FOREIGN KEY (mentoremail) REFERENCES researchmentor(email) ON UPDATE CASCADE ON DELETE CASCADE + "works_at_ibfk_2" FOREIGN KEY (instid) REFERENCES institution(instid) ON UPDATE CASCADE ON DELETE CASCADE +""" +class WorksAt(Base): + __tablename__ = 'works_at' + + id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) + mentor_email: Mapped[str] = mapped_column("mentoremail", ForeignKey("researchmentor.email", name="works_at_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) + inst_id: Mapped[str] = mapped_column("instid", ForeignKey("institution.instid", name="works_at_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) + dept: Mapped[Optional[str]] = mapped_column("dept", VARCHAR(100)) + role: Mapped[Optional[str]] = mapped_column("role", VARCHAR(100)) + office_addr: Mapped[Optional[str]] = mapped_column("officeaddr", VARCHAR(100)) + + mentor: Mapped[ResearchMentor] = relationship("ResearchMentor", back_populates="workplaces") + institution: Mapped[Institution] = relationship("Institution", back_populates="members") + + __table_args__ = (UniqueConstraint('mentoremail', 'instid', name='idx_16491_mentoremail'), Index('idx_16491_instid', 'instid'),) + +""" +Table "arxiv.works_on" + Column | Type | Collation | Nullable | Default +--------------+------------------------+-----------+----------+-------------------------------------- + id | bigint | | not null | nextval('works_on_id_seq'::regclass) + studentemail | character varying(255) | | not null | + pcode | character varying(20) | | not null | +Indexes: + "idx_16498_primary" PRIMARY KEY, btree (id) + "idx_16498_pcode" btree (pcode) + "idx_16498_studentemail" UNIQUE, btree (studentemail, pcode) +Foreign-key constraints: + "works_on_ibfk_1" FOREIGN KEY (pcode) REFERENCES project(pcode) ON UPDATE CASCADE ON DELETE CASCADE + "works_on_ibfk_2" FOREIGN KEY (studentemail) REFERENCES student(email) ON UPDATE CASCADE ON DELETE CASCADE +""" +class WorksOn(Base): + __tablename__ = 'works_on' + + id: Mapped[int] = mapped_column("id", BIGINT, primary_key=True) + student_email: Mapped[str] = mapped_column("studentemail", ForeignKey("student.email", name="works_on_ibfk_2", onupdate="CASCADE", ondelete="CASCADE")) + p_code: Mapped[str] = mapped_column("pcode", ForeignKey("project.pcode", name="works_on_ibfk_1", onupdate="CASCADE", ondelete="CASCADE")) + + project: Mapped[Project] = relationship("Project", back_populates="students") + student: Mapped[Student] = relationship("Student", back_populates="projects") + + __table_args__ = (UniqueConstraint('studentemail', 'pcode', name='idx_16498_studentemail'), Index('idx_16498_pcode', 'pcode'),) + +SessionLocal = sessionmaker(bind=engine, autocommit=False, autoflush=False) \ No newline at end of file diff --git a/server/schemas.py b/server/schemas.py new file mode 100644 index 0000000..74e0bd6 --- /dev/null +++ b/server/schemas.py @@ -0,0 +1,77 @@ +from typing import Optional +from pydantic import BaseModel, ConfigDict + +class NUSHStudent(BaseModel): + model_config = ConfigDict(from_attributes=True) + + email: str + pwd: Optional[str] + pfp: Optional[str] = "" + about: Optional[str] + grad_year: Optional[int] + nush_sid: Optional[str] + +class NUSHTeacher(BaseModel): + model_config = ConfigDict(from_attributes=True) + + email: str + pwd: Optional[str] + name: str + pfp: Optional[str] = "" + is_admin: bool + is_mentor: bool + dept_id: Optional[str] + +class ExternalStudent(BaseModel): + email: str + name: Optional[str] + emergency_email: Optional[str] + teacher_name: Optional[str] + sch_id: Optional[str] + +class WorksAt(BaseModel): + model_config = ConfigDict(from_attributes=True) + + id: int + mentor_email: str + inst_id: str + dept: Optional[str] + role: Optional[str] + office_addr: Optional[str] + +class ResearchMentor(BaseModel): + email: str + name: Optional[str] + + jobs: list[WorksAt] + +class LoginResult(BaseModel): + result: bool + user: Optional[NUSHTeacher | NUSHStudent] = None + message: str + +class RegisterStudentResult(BaseModel): + result: bool + user: Optional[NUSHStudent] = None + message: Optional[str] = None + error: Optional[str] = None + +class RegisterTeacherResult(BaseModel): + result: bool + user: Optional[NUSHTeacher] = None + message: Optional[str] = None + error: Optional[str] = None + +class ChangePasswordResult(BaseModel): + response: str + +class Institution(BaseModel): + model_config = ConfigDict(from_attributes=True) + + inst_id: str + name: str + address: str + is_school: bool + is_institute: bool + is_organiser: bool + is_publisher: bool diff --git a/server/util.py b/server/util.py index 4cd75e1..5e31c71 100644 --- a/server/util.py +++ b/server/util.py @@ -1,13 +1,6 @@ -from io import BytesIO -import base64 +from typing import TypeVar -def convertB64toBytes(b64): - f = BytesIO() - f.write(base64.b64decode(b64)) - f.seek(0) - bytes = f.read() - f.close() - return bytes +T = TypeVar('T') -def removeNulls(arr): +def remove_nulls(arr: list[T]) -> list[T]: return [i for i in arr if i] \ No newline at end of file