Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes and improvements from user testing #28

Merged
merged 19 commits into from
Jul 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions backend/ezConnect/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def __repr__(self):
class PersonalStudyPlan(db.Model):
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
date_updated = Column(DateTime, nullable=False, default=datetime.utcnow)
title = Column(String(150), default="Blank study plan")
title = Column(String(150), default="My study plan")
creator_id = Column(
UUID(as_uuid=True),
db.ForeignKey('users.azure_ad_oid'),
Expand Down Expand Up @@ -186,7 +186,7 @@ def get_semester_list_in_order(self):
class PublishedStudyPlan(db.Model):
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
date_updated = Column(DateTime, nullable=False, default=datetime.utcnow)
title = Column(String(150), nullable=False, default="Blank study plan")
title = Column(String(150), nullable=False, default="My study plan")
description = Column(Text, nullable=False, default="")
num_of_likes = Column(
Integer,
Expand All @@ -199,7 +199,11 @@ class PublishedStudyPlan(db.Model):
db.ForeignKey('users.azure_ad_oid'),
nullable=False
)
semesters = db.relationship('StudyPlanSemester', backref='published_study_plan')
semesters = db.relationship(
'StudyPlanSemester',
backref='published_study_plan',
order_by='StudyPlanSemester.semester_number'
)
personal_study_plan_id = Column(
UUID(as_uuid=True),
db.ForeignKey('personal_study_plan.id'),
Expand Down
4 changes: 1 addition & 3 deletions backend/ezConnect/study_plan/studyplan.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,7 @@ def delete_study_plan(study_plan_id):

if personal_study_plan:
if personal_study_plan.published_version is not None:
published_study_plan = personal_study_plan.published_version
db.session.delete(published_study_plan)
db.session.commit()
delete_study_plan(personal_study_plan.published_version.id)
db.session.delete(personal_study_plan)
db.session.commit()

Expand Down
10 changes: 9 additions & 1 deletion backend/ezConnect/study_plan/validation/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@


def tokenise_prerequisite_rule(rule_string: str) -> list[str]:
rule = rule_string.split('THEN')[1][1:]
if 'THEN' in rule_string:
rule = rule_string.split('THEN')[1][1:]
else:
rule = rule_string
# print(rule)
regex_pattern = re.compile(r'((COURSES( \([1-9]\))?)|([A-Z]+[0-9]+[A-Z]*)(?=(\:[A-F])?)|\(|\)|OR|AND)')
# for m in re.finditer(regex_pattern, rule):
# print('%02d-%02d: %s' % (m.start(), m.end(), m.group(0)))
# print(regex_pattern.findall(rule))
tokens = [m[0] for m in regex_pattern.findall(rule) if m]

# Pre req rule have no opening and closing parenthesis
if tokens[0] != '(' and tokens[-1] != ')':
tokens = ['('] + tokens + [')']

print(tokens)
return tokens

Expand Down
1 change: 1 addition & 0 deletions backend/ezConnect/swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ components:
type: string
format: uuid
example: 87654321-1234-1234-1234-1234abcdef00
nullable: true
semester_number:
type: integer
example: 3
Expand Down
28 changes: 28 additions & 0 deletions backend/pre_data/generate_course_json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import csv
import json

def csv_to_dict_of_dicts(file_path):
result = {}
with open(file_path, newline='') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
course_code = row['course_code']
course_name = row['course_name']
number_of_units = row['number_of_units']
is_offered_in_sem1 = row['is_offered_in_sem1']
is_offered_in_sem2 = row['is_offered_in_sem2']
result[course_code] = {
'course_name': course_name,
'number_of_units': number_of_units,
'is_offered_in_sem1': is_offered_in_sem1,
'is_offered_in_sem2': is_offered_in_sem2
}
return result

file_path = 'courses.csv'
data_dict = csv_to_dict_of_dicts(file_path)

with open('courseDictionary.json', 'w') as json_file:
json.dump(data_dict, json_file)

print("done!")
121 changes: 118 additions & 3 deletions backend/pre_data/init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ CREATE TABLE alembic_version (
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
);

-- Running upgrade -> 22be9cc508e8

CREATE TABLE course (
course_code VARCHAR(12) NOT NULL,
course_name VARCHAR(100),
Expand Down Expand Up @@ -134,8 +132,125 @@ CREATE TABLE semester_course (

INSERT INTO alembic_version (version_num) VALUES ('22be9cc508e8') RETURNING alembic_version.version_num;

CREATE TABLE personal_study_plan (
id UUID NOT NULL,
date_updated TIMESTAMP WITHOUT TIME ZONE NOT NULL,
title VARCHAR(150),
creator_id UUID NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY(creator_id) REFERENCES users (azure_ad_oid)
);

CREATE TABLE published_study_plan (
id UUID NOT NULL,
date_updated TIMESTAMP WITHOUT TIME ZONE NOT NULL,
title VARCHAR(150) NOT NULL,
description TEXT NOT NULL,
num_of_likes INTEGER NOT NULL,
creator_id UUID NOT NULL,
personal_study_plan_id UUID NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY(creator_id) REFERENCES users (azure_ad_oid),
FOREIGN KEY(personal_study_plan_id) REFERENCES personal_study_plan (id)
);

CREATE TABLE favorited_study_plan (
user_id UUID NOT NULL,
published_study_plan_id UUID NOT NULL,
FOREIGN KEY(published_study_plan_id) REFERENCES published_study_plan (id),
FOREIGN KEY(user_id) REFERENCES users (azure_ad_oid)
);

CREATE TABLE liked_study_plan (
user_id UUID NOT NULL,
published_study_plan_id UUID NOT NULL,
FOREIGN KEY(published_study_plan_id) REFERENCES published_study_plan (id),
FOREIGN KEY(user_id) REFERENCES users (azure_ad_oid)
);

ALTER TABLE study_plan_semester ADD COLUMN personal_study_plan_id UUID;

ALTER TABLE study_plan_semester ADD COLUMN published_study_plan_id UUID;

ALTER TABLE study_plan_semester DROP CONSTRAINT semesters_in_study_plan_unique;

ALTER TABLE study_plan_semester ADD CONSTRAINT semesters_in_published_study_plan_unique UNIQUE (published_study_plan_id, semester_number);

ALTER TABLE study_plan_semester DROP CONSTRAINT study_plan_semester_study_plan_id_fkey;

ALTER TABLE study_plan_semester ADD CONSTRAINT published_study_plan_semester FOREIGN KEY(published_study_plan_id) REFERENCES published_study_plan (id);

ALTER TABLE study_plan_semester ADD CONSTRAINT personal_study_plan_semester FOREIGN KEY(personal_study_plan_id) REFERENCES personal_study_plan (id);

ALTER TABLE study_plan_semester DROP COLUMN study_plan_id;

DROP TABLE study_plan;

UPDATE alembic_version SET version_num='0f60b0932ff1' WHERE alembic_version.version_num = '22be9cc508e8';

CREATE TABLE viewed_study_plan (
user_id UUID NOT NULL,
published_study_plan_id UUID NOT NULL,
date_viewed TIMESTAMP WITHOUT TIME ZONE NOT NULL,
FOREIGN KEY(published_study_plan_id) REFERENCES published_study_plan (id),
FOREIGN KEY(user_id) REFERENCES users (azure_ad_oid)
);

ALTER TABLE favorited_study_plan ADD COLUMN date_favourited TIMESTAMP WITHOUT TIME ZONE NOT NULL;

ALTER TABLE favorited_study_plan ADD CONSTRAINT unique_user_favourited_study_plan UNIQUE (user_id, published_study_plan_id);

ALTER TABLE liked_study_plan ADD COLUMN date_liked TIMESTAMP WITHOUT TIME ZONE NOT NULL;

ALTER TABLE liked_study_plan ADD CONSTRAINT unique_user_liked_study_plan UNIQUE (user_id, published_study_plan_id);

UPDATE alembic_version SET version_num='5d9bb93bb669' WHERE alembic_version.version_num = '0f60b0932ff1';

CREATE TABLE academic_plan (
id UUID NOT NULL,
published_study_plan_id UUID NOT NULL,
first_degree_id UUID NOT NULL,
second_degree_id UUID,
second_major VARCHAR(150),
PRIMARY KEY (id),
FOREIGN KEY(first_degree_id) REFERENCES degree (id),
FOREIGN KEY(published_study_plan_id) REFERENCES published_study_plan (id),
FOREIGN KEY(second_degree_id) REFERENCES degree (id)
);

CREATE TABLE minor_academic_plan (
minor_id UUID,
academic_plan_id UUID,
FOREIGN KEY(academic_plan_id) REFERENCES academic_plan (id),
FOREIGN KEY(minor_id) REFERENCES programme (id)
);

CREATE TABLE special_programmes_academic_plan (
special_programme_id UUID,
academic_plan_id UUID,
FOREIGN KEY(academic_plan_id) REFERENCES academic_plan (id),
FOREIGN KEY(special_programme_id) REFERENCES programme (id)
);

UPDATE alembic_version SET version_num='9d4370465dbd' WHERE alembic_version.version_num = '5d9bb93bb669';

ALTER TABLE prerequisites ADD COLUMN prerequisite_str TEXT;

ALTER TABLE prerequisites ALTER COLUMN course_code TYPE VARCHAR(12);

ALTER TABLE prerequisites DROP CONSTRAINT prerequisites_prerequisite_code_fkey;

ALTER TABLE prerequisites DROP COLUMN prerequisite_code;

UPDATE alembic_version SET version_num='f0c3451c1967' WHERE alembic_version.version_num = '9d4370465dbd';

ALTER TABLE prerequisites ALTER COLUMN course_code SET NOT NULL;

UPDATE alembic_version SET version_num='e534acc545c3' WHERE alembic_version.version_num = 'f0c3451c1967';

COMMIT;

COPY programme FROM '/pre_data/programmes.csv' DELIMITER ',' CSV HEADER;
COPY degree FROM '/pre_data/degrees.csv' DELIMITER ',' CSV HEADER;
COPY course FROM '/pre_data/courses.csv' DELIMITER ',' CSV HEADER;
COPY course FROM '/pre_data/courses.csv' DELIMITER ',' CSV HEADER;
COPY prerequisites FROM '/pre_data/prerequisites.csv' DELIMITER ',' CSV HEADER;
4 changes: 2 additions & 2 deletions backend/pre_data/test_token
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
User1:
12345678-1234-1234-1234-1234abcdef00
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZHAiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vNWJhNWVmNWUtMzEwOS00ZTc3LTg1YmQtY2ZlYjBkMzQ3ZTgyL3YyLjAiLCJuYW1lIjoidGVzdCB1c2VyIDEiLCJvaWQiOiIxMjM0NTY3OC0xMjM0LTEyMzQtMTIzNC0xMjM0YWJjZGVmMDAiLCJzdWIiOiIxMjM0NTY3OC0xMjM0LTEyMzQtMTIzNC0xMjM0YWJjZGVmMDAiLCJlbWFpbHMiOlsidGVzdGVtYWlsQHJ1aWJpbi5tZSJdLCJ0ZnAiOiJCMkNfMV9lemNvbm5lY3RkZXZfc3VzaSIsIm5vbmNlIjoiMWUxYTE3NGItMWYxMS00OTA1LTgyYzItNTBjOWZhNGFiZTllIiwic2NwIjoiQXBwLlVzZSIsImF6cCI6IjMxZTFmY2RkLTQ2MGItNDUwOS1hZjhiLTY0ZmRiZDY4NDQwYSIsInZlciI6IjEuMCIsImlhdCI6MTY4NzE2MTg1OSwiYXVkIjoiMzFlMWZjZGQtNDYwYi00NTA5LWFmOGItNjRmZGJkNjg0NDBhIiwiZXhwIjoxNjg5OTk1NDU5LCJpc3MiOiJodHRwczovL2V6Y29ubmVjdHRlc3RpbmcuYjJjbG9naW4uY29tL2UwMzA1ZTNmLTJiOGEtNDQxNS1hMWU4LTBmYjQ3Y2U4NzBhNy92Mi4wLyIsIm5iZiI6MTY4NzE2MTg1OX0.mb-G-EZGDXM4Tal_nHVbUz4iHyiF2z4r70RJ9P2kVgg
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZHAiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vNWJhNWVmNWUtMzEwOS00ZTc3LTg1YmQtY2ZlYjBkMzQ3ZTgyL3YyLjAiLCJuYW1lIjoidGVzdCB1c2VyIDEiLCJvaWQiOiIxMjM0NTY3OC0xMjM0LTEyMzQtMTIzNC0xMjM0YWJjZGVmMDAiLCJzdWIiOiIxMjM0NTY3OC0xMjM0LTEyMzQtMTIzNC0xMjM0YWJjZGVmMDAiLCJlbWFpbHMiOlsidGVzdGVtYWlsQHJ1aWJpbi5tZSJdLCJ0ZnAiOiJCMkNfMV9lemNvbm5lY3RkZXZfc3VzaSIsIm5vbmNlIjoiMWUxYTE3NGItMWYxMS00OTA1LTgyYzItNTBjOWZhNGFiZTllIiwic2NwIjoiQXBwLlVzZSIsImF6cCI6IjMxZTFmY2RkLTQ2MGItNDUwOS1hZjhiLTY0ZmRiZDY4NDQwYSIsInZlciI6IjEuMCIsImlhdCI6MTY5MDAxNTgxMywiYXVkIjoiMzFlMWZjZGQtNDYwYi00NTA5LWFmOGItNjRmZGJkNjg0NDBhIiwiZXhwIjoxNjkyNjA4MDQ0LCJpc3MiOiJodHRwczovL2V6Y29ubmVjdHRlc3RpbmcuYjJjbG9naW4uY29tL2UwMzA1ZTNmLTJiOGEtNDQxNS1hMWU4LTBmYjQ3Y2U4NzBhNy92Mi4wLyIsIm5iZiI6MTY4NzE2MTg1OX0.E2-hyJQWKumnzFBFnayMdLvHaMrWmUZP6Xc6rgBgx8k
User2:
aaaaaaaa-1234-1234-1234-1234abcdef00
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZHAiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vNWJhNWVmNWUtMzEwOS00ZTc3LTg1YmQtY2ZlYjBkMzQ3ZTgyL3YyLjAiLCJuYW1lIjoiVGVzdCB1c2VyIDIiLCJvaWQiOiJhYWFhYWFhYS0xMjM0LTEyMzQtMTIzNC0xMjM0YWJjZGVmMDAiLCJzdWIiOiJhYWFhYWFhYS0xMjM0LTEyMzQtMTIzNC0xMjM0YWJjZGVmMDAiLCJlbWFpbHMiOlsidGVzdGVtYWlsQHJ1aWJpbi5tZSJdLCJ0ZnAiOiJCMkNfMV9lemNvbm5lY3RkZXZfc3VzaSIsIm5vbmNlIjoiMWUxYTE3NGItMWYxMS00OTA1LTgyYzItNTBjOWZhNGFiZTllIiwic2NwIjoiQXBwLlVzZSIsImF6cCI6IjMxZTFmY2RkLTQ2MGItNDUwOS1hZjhiLTY0ZmRiZDY4NDQwYSIsInZlciI6IjEuMCIsImlhdCI6MTY4NzE2MTg1OSwiYXVkIjoiMzFlMWZjZGQtNDYwYi00NTA5LWFmOGItNjRmZGJkNjg0NDBhIiwiZXhwIjoxNjg5OTk1NDU5LCJpc3MiOiJodHRwczovL2V6Y29ubmVjdHRlc3RpbmcuYjJjbG9naW4uY29tL2UwMzA1ZTNmLTJiOGEtNDQxNS1hMWU4LTBmYjQ3Y2U4NzBhNy92Mi4wLyIsIm5iZiI6MTY4NzE2MTg1OX0.sI8ZpuIumzWuWVI1v-WZ_QJXAC1PZXm1XcVhOnvs2IE
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZHAiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vNWJhNWVmNWUtMzEwOS00ZTc3LTg1YmQtY2ZlYjBkMzQ3ZTgyL3YyLjAiLCJuYW1lIjoidGVzdCB1c2VyIDIiLCJvaWQiOiJhYWFhYWFhYS0xMjM0LTEyMzQtMTIzNC0xMjM0YWJjZGVmMDAiLCJzdWIiOiJhYWFhYWFhYS0xMjM0LTEyMzQtMTIzNC0xMjM0YWJjZGVmMDAiLCJlbWFpbHMiOlsidGVzdGVtYWlsMkBydWliaW4ubWUiXSwidGZwIjoiQjJDXzFfZXpjb25uZWN0ZGV2X3N1c2kiLCJub25jZSI6IjFlMWExNzRiLTFmMTEtNDkwNS04MmMyLTUwYzlmYTRhYmU5ZSIsInNjcCI6IkFwcC5Vc2UiLCJhenAiOiIzMWUxZmNkZC00NjBiLTQ1MDktYWY4Yi02NGZkYmQ2ODQ0MGEiLCJ2ZXIiOiIxLjAiLCJpYXQiOjE2OTAwMTU4MTMsImF1ZCI6IjMxZTFmY2RkLTQ2MGItNDUwOS1hZjhiLTY0ZmRiZDY4NDQwYSIsImV4cCI6MTY5MjYwODA0NCwiaXNzIjoiaHR0cHM6Ly9lemNvbm5lY3R0ZXN0aW5nLmIyY2xvZ2luLmNvbS9lMDMwNWUzZi0yYjhhLTQ0MTUtYTFlOC0wZmI0N2NlODcwYTcvdjIuMC8iLCJuYmYiOjE2ODcxNjE4NTl9.mDEVNNYRUcmku4s5ZtOTvu0QYW7x8qk08DthP3UMoZ4
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ services:
- "443:443"
- "80:80"
cloudflared:
image: cloudflare/cloudflared
image: cloudflare/cloudflared:latest
restart: unless-stopped
hostname: cloudflared
entrypoint: "/usr/local/bin/cloudflared tunnel --url http://caddy-proxy --no-autoupdate run --token ${CLOUDFLARED_SECRET}"
Expand Down
3 changes: 3 additions & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*
/test-results/
/playwright-report/
/playwright/.cache/
11 changes: 6 additions & 5 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// import { useEffect, useState } from "react";
import { MsalProvider } from '@azure/msal-react';
import { Route, Routes } from "react-router-dom";
import { useState } from 'react';
import LoginPage from "./Pages/LoginPage";
import AboutUs from "./Pages/AboutUs";
import Homepage from "./Pages/Homepage";
Expand All @@ -17,19 +17,20 @@ import UpdateMentorRequest from './Pages/Mentoring/UpdateMentorRequest';
import RequestMentor from './Pages/Mentoring/RequestMentor';
import RequestMentee from './Pages/Mentoring/RequestMentee';
import AcceptMatch from './Pages/Mentoring/AcceptMatch';
import FavouritedStudyPlanPage from './Pages/StudyPlan/PersonalTabs/FavouritedStudyPlanPage';
import NotFound from './Pages/404';

const Pages = () => {
const [showLoginModal, setLoginModal] = useState(false);
return (
<>
<header>
<Navigation/>
<Navigation showLoginModal={showLoginModal} setLoginModal={setLoginModal}/>
</header>
<body>
<Routes>
<Route
path="/"
element={<AboutUs />}
element={<AboutUs showLoginModal={showLoginModal} setLoginModal={setLoginModal}/>}
/>
<Route
path="/homepage"
Expand All @@ -50,7 +51,7 @@ const Pages = () => {
<Route path="/mentoring/matches/accept" element={<AcceptMatch/>} />
<Route path="/studyplan" element={<StudyPlanMainPage />} />
<Route path="/studyplan/editor/:studyPlanId" element={<StudyPlanEditor />} />
<Route path="/studyplan/favourites" element={<FavouritedStudyPlanPage />} />
<Route path="*" element={<NotFound />} />
</Routes>
</body>
<footer>
Expand Down
Binary file added frontend/src/Components/AccessDenied.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 0 additions & 31 deletions frontend/src/Components/LoginModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,37 +28,6 @@ function LoginModal({setLoginModal, showLoginModal}) {


return (
// <div>
// <div className="fixed z-10 inset-0 overflow-y-auto">
// <div className="flex items-center justify-center min-h-screen px-4">
// <div className="fixed inset-0 transition-opacity">
// <div className="absolute inset-0 bg-gray-500 opacity-75"></div>
// </div>
// <div className="bg-white rounded-lg overflow-hidden shadow-xl transform transition-all sm:max-w-lg sm:w-full">
// <div className="p-4">
// <h2 className="text-xl mb-4">Login / Create an account</h2>
// <p className="text-sm mb-4">
// Press the button below to be redirected for login using school Microsoft account.
// </p>
// <button
// onClick={handleLoginRedirect}
// className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
// >
// Login
// </button>
// <button
// onClick={closeModal}
// className="bg-gray-500 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded ml-2"
// >
// <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-4 h-4">
// <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
// </svg>
// </button>
// </div>
// </div>
// </div>
// </div>
// </div>
<Dialog onClose={closeModal} open={showLoginModal}>
<span>
<DialogTitle>Sign in / Create account</DialogTitle>
Expand Down
Loading
Loading