From 4165927d1f233f568e444d0ec6a5c429aa50860d Mon Sep 17 00:00:00 2001 From: SquiddyPoos Date: Fri, 1 Dec 2023 04:14:30 +0800 Subject: [PATCH] update schema --- server/{app.py => app_old.py} | 2 +- server/database.py | 1301 +++++++++++++++++---------------- server/database_old.py | 645 ++++++++++++++++ server/schema.py | 625 ---------------- server/tables.txt | 13 + 5 files changed, 1317 insertions(+), 1269 deletions(-) rename server/{app.py => app_old.py} (99%) create mode 100644 server/database_old.py delete mode 100644 server/schema.py create mode 100644 server/tables.txt diff --git a/server/app.py b/server/app_old.py similarity index 99% rename from server/app.py rename to server/app_old.py index cb41840..3b75985 100644 --- a/server/app.py +++ b/server/app_old.py @@ -1,6 +1,6 @@ from flask import Flask, request, jsonify from flask_cors import CORS -from database import Database +from server.database_old import Database app = Flask(__name__) #app = Flask(__name__) diff --git a/server/database.py b/server/database.py index eb35115..c3debb0 100644 --- a/server/database.py +++ b/server/database.py @@ -1,645 +1,660 @@ -from flask_mysqldb import MySQL -import MySQLdb.cursors -import base64 -from util import convertB64toBytes, removeNulls -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) - - @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() - - 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() - - @property - def pfp(self): - with open("assets/default.png", "rb") as f: - pfp = f.read() - return pfp - - - - - # ==================================== EXISTS FUNCTIONALITY ==================================== - - 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 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 isNUSHStudent(self, email): - return len(self.queryAll("SELECT email FROM NUSHStudent WHERE email = %s", (email, ))) > 0 - - - - # ================================ 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 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) - - 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 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) - - 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]) - - - - # ==================================== CREATE FUNCTIONALITY ==================================== - - 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)) - - 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) - - # ==================================== 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 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 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)} +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") - - # ==================================== 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 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]) - - 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, ))) - - 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(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]) - - 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(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]) - - 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(self.queryAll(query, (email, ))) - return stats - - - - - +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 diff --git a/server/database_old.py b/server/database_old.py new file mode 100644 index 0000000..eb35115 --- /dev/null +++ b/server/database_old.py @@ -0,0 +1,645 @@ +from flask_mysqldb import MySQL +import MySQLdb.cursors +import base64 +from util import convertB64toBytes, removeNulls +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) + + @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() + + 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() + + @property + def pfp(self): + with open("assets/default.png", "rb") as f: + pfp = f.read() + return pfp + + + + + # ==================================== EXISTS FUNCTIONALITY ==================================== + + 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 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 isNUSHStudent(self, email): + return len(self.queryAll("SELECT email FROM NUSHStudent WHERE email = %s", (email, ))) > 0 + + + + # ================================ 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 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) + + 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 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) + + 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]) + + + + # ==================================== CREATE FUNCTIONALITY ==================================== + + 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)) + + 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) + + # ==================================== 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 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 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] + + 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 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]) + + 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, ))) + + 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(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]) + + 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(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]) + + 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(self.queryAll(query, (email, ))) + return stats + + + + + diff --git a/server/schema.py b/server/schema.py deleted file mode 100644 index 95f93cf..0000000 --- a/server/schema.py +++ /dev/null @@ -1,625 +0,0 @@ -# generated from pwiz, manually checked -# comments are generated from \dt - -from peewee import * - -database = PostgresqlDatabase('arxiv', **{'host': 'database', 'user': 'postgres', 'password': 'admin'}) - -class BaseModel(Model): - class Meta: - database = database - -""" -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(BaseModel): - about = CharField(max_length=5000, null=True) - conf_DOI = CharField(column_name='confdoi', max_length=200, null=True) - end_date = DateField() - event_id = CharField(column_name='eventid', max_length=15) - event_format = CharField(column_name='format', null=True, max_length=10) - is_competition = BooleanField(column_name="iscompetition", default=False) - is_conference = BooleanField(column_name="isconference", default=False) - name = CharField(max_length=100) - num_event_id = BigAutoField(column_name='numeventid') - start_date = DateField() - year = IntegerField() - - class Meta: - table_name = 'researchevent' - indexes = ( - (('eventid', 'year'), True), - ) - schema = 'arxiv' - - -""" -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(BaseModel): - code = CharField(max_length=20) - num_event_id = ForeignKeyField(column_name='numeventid', field='numeventid', model=ResearchEvent) - sub_abstract = CharField(column_name='subabstract', max_length=2000) - sub_id = BigAutoField(column_name='subid') - sub_title = CharField(column_name='subtitle', max_length=200) - - class Meta: - table_name = 'submission' - indexes = ( - (('numeventid', 'code'), True), - ) - schema = 'arxiv' - -""" -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(BaseModel): - acc_id = AutoField(column_name='accid') - is_award = BooleanField(column_name='isaward', default=False) - name = CharField(max_length=100, null=True) - prize = CharField(max_length=100, null=True) - sub_id = ForeignKeyField(column_name='subid', field='subid', model=Submission, null=True) - - class Meta: - table_name = 'accomplishment' - schema = 'arxiv' - -""" -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(BaseModel): - award_type = CharField(max_length=100, column_name='awardtype') - id = BigAutoField() - num_event_id = ForeignKeyField(column_name='numeventid', field='numeventid', model=ResearchEvent) - - class Meta: - table_name = 'awardtypes' - indexes = ( - (('numeventid', 'awardtype'), True), - ) - schema = 'arxiv' - -""" -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(BaseModel): - dept_id = FixedCharField(max_length=2, column_name='deptid', primary_key=True) - name = CharField(max_length=50, default='') - - class Meta: - table_name = 'department' - schema = 'arxiv' - -""" -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(BaseModel): - email = CharField(max_length=255, primary_key=True) - name = CharField(max_length=100, null=True) - - class Meta: - table_name = 'student' - schema = 'arxiv' - -""" -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(BaseModel): - address = CharField(max_length=150, default='') - inst_id = CharField(max_length=10, primary_key=True, column_name='instid') - is_institute = BooleanField(default=False, column_name='isinstitute') - is_organiser = BooleanField(default=False, column_name='isorganiser') - is_publisher = BooleanField(default=False, column_name='ispublisher') - is_school = BooleanField(default=False, column_name='isschool') - name = CharField(max_length=100, default='') - - class Meta: - table_name = 'institution' - schema = 'arxiv' - -""" -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(BaseModel): - email = CharField(max_length=255, primary_key=True) - name = CharField(max_length=100, null=True) - sch_id = ForeignKeyField(column_name='schid', field='instid', model=Institution, null=True) - - class Meta: - table_name = 'externalteacher' - schema = 'arxiv' - -""" -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(BaseModel): - email = ForeignKeyField(column_name='email', field='email', model=Student, primary_key=True) - emergency_email = ForeignKeyField(column_name='emergencyemail', field='email', model=ExternalTeacher, null=True) - - class Meta: - table_name = 'externalstudent' - schema = 'arxiv' - -""" -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(BaseModel): - issn = IntegerField(primary_key=True) - name = CharField(max_length=100) - - class Meta: - table_name = 'journal' - schema = 'arxiv' - -""" -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(BaseModel): - email = CharField(max_length=255, primary_key=True) - name = CharField(max_length=100, null=True) - - class Meta: - table_name = 'researchmentor' - schema = 'arxiv' - -""" -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(BaseModel): - dept_id = ForeignKeyField(column_name='deptid', field='deptid', model=Department, null=True) - email = CharField(max_length=255, primary_key=True) - is_admin = BooleanField(column_name="isadmin", default=False) - is_mentor = BooleanField(column_name="ismentor", default=False) - name = CharField(max_length=100, default='') - pfp = BlobField(null=True) - pwd = CharField(max_length=20, null=True) - - class Meta: - table_name = 'nushteacher' - schema = 'arxiv' - -""" -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(BaseModel): - abstract = CharField(max_length=2000, null=True) - dept_id = ForeignKeyField(column_name='deptid', field='deptid', model=Department, null=True) - project_code = CharField(column_name='pcode', primary_key=True, max_length=20) - report_pdf = BlobField(null=True, column_name='reportpdf') - teacher_email = ForeignKeyField(column_name='teacheremail', field='email', model=NUSHTeacher, null=True) - title = CharField(max_length=200) - year = IntegerField(null=True) - - class Meta: - table_name = 'project' - schema = 'arxiv' - -""" -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(BaseModel): - id = BigAutoField() - mentor_email = ForeignKeyField(column_name='mentoremail', field='email', model=ResearchMentor) - project_code = ForeignKeyField(column_name='pcode', field='pcode', model=Project) - - class Meta: - table_name = 'mentors' - indexes = ( - (('pcode', 'mentoremail'), True), - ) - schema = 'arxiv' - -""" -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(BaseModel): - about = CharField(max_length=255, null=True) - email = ForeignKeyField(column_name='email', field='email', model=Student, primary_key=True) - grad_year = IntegerField(column_name='gradyear', null=True) - nush_student_id = CharField(column_name='nush_sid', max_length=8, null=True) - pfp = BlobField(null=True) - pwd = CharField(max_length=20, null=True) - - class Meta: - table_name = 'nushstudent' - schema = 'arxiv' - -""" -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(BaseModel): - id = BigAutoField() - inst_id = ForeignKeyField(column_name='instid', field='instid', model=Institution) - num_event_id = ForeignKeyField(column_name='numeventid', field='numeventid', model=ResearchEvent) - - class Meta: - table_name = 'organises' - indexes = ( - (('numeventid', 'instid'), True), - ) - schema = 'arxiv' - -""" -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(BaseModel): - id = BigAutoField() - next_project_code = ForeignKeyField(column_name='nextpcode', field='pcode', model=Project) - prev_project_code = ForeignKeyField(backref='project_prev_code_set', column_name='prevpcode', field='pcode', model=Project) - - class Meta: - table_name = 'projectcontinuation' - indexes = ( - (('prevpcode', 'nextpcode'), True), - ) - schema = 'arxiv' - -""" -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(BaseModel): - acc_id = ForeignKeyField(column_name='accid', field='accid', model=Accomplishment, primary_key=True) - doi = CharField(max_length=200, null=True) - is_journal = BooleanField(column_name="isjournal", default=False) - journal_issn = ForeignKeyField(column_name='journissn', field='issn', model=Journal, null=True) - title = CharField(max_length=200, column_name='pubtitle') - url = CharField(max_length=300, null=True) - - class Meta: - table_name = 'publication' - schema = 'arxiv' - -""" -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(BaseModel): - id = BigAutoField() - inst_id = ForeignKeyField(column_name='instid', field='instid', model=Institution) - issn = ForeignKeyField(column_name='issn', field='issn', model=Journal) - - class Meta: - table_name = 'publishedby' - indexes = ( - (('issn', 'instid'), True), - ) - schema = 'arxiv' - -""" -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(BaseModel): - id = BigAutoField() - project_code = ForeignKeyField(column_name='pcode', field='pcode', model=Project) - student_email = ForeignKeyField(column_name='studentemail', field='email', model=Student) - sub_id = ForeignKeyField(column_name='subid', field='subid', model=Submission) - - class Meta: - table_name = 'submits' - indexes = ( - (('studentemail', 'pcode', 'subid'), True), - ) - schema = 'arxiv' - -""" -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(BaseModel): - dept = CharField(max_length=100, null=True) - id = BigAutoField() - inst_id = ForeignKeyField(column_name='instid', field='instid', model=Institution) - mentor_email = ForeignKeyField(column_name='mentoremail', field='email', model=ResearchMentor) - office_addr = CharField(column_name='officeaddr', max_length=100, null=True) - role = CharField(max_length=100, null=True) - - class Meta: - table_name = 'works_at' - indexes = ( - (('mentoremail', 'instid'), True), - ) - schema = 'arxiv' - -""" -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(BaseModel): - id = BigAutoField() - project_code = ForeignKeyField(column_name='pcode', field='pcode', model=Project) - student_email = ForeignKeyField(column_name='studentemail', field='email', model=Student) - - class Meta: - table_name = 'works_on' - indexes = ( - (('studentemail', 'pcode'), True), - ) - schema = 'arxiv' - diff --git a/server/tables.txt b/server/tables.txt new file mode 100644 index 0000000..299c308 --- /dev/null +++ b/server/tables.txt @@ -0,0 +1,13 @@ +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