Skip to content

Commit

Permalink
Merge pull request #783 from Lunatic-Labs/SKIL-202
Browse files Browse the repository at this point in the history
Merge Skil 202 with MySQL changes into master
  • Loading branch information
sah0017 authored Nov 22, 2024
2 parents 212a056 + 8a8c9f6 commit 1a1a1c4
Show file tree
Hide file tree
Showing 11 changed files with 147 additions and 77 deletions.
4 changes: 4 additions & 0 deletions BackEndFlask/.env
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ DEMO_ADMIN_PASSWORD=demo_admin
DEMO_TA_INSTRUCTOR_PASSWORD=demo_ta
DEMO_STUDENT_PASSWORD=demo_student
SECRET_KEY=Thisissupposedtobesecret!
MYSQL_HOST=localhost
MYSQL_USER=skillbuilder
MYSQL_PASSWORD=WasPogil1#
MYSQL_DATABASE=account
22 changes: 15 additions & 7 deletions BackEndFlask/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
from models.tests import testing
from dotenv import load_dotenv
from flask import Flask
from flask_cors import CORS
import subprocess
load_dotenv()
import sys
import os
import subprocess
import re
import redis

Expand Down Expand Up @@ -78,13 +80,19 @@ def setup_cron_jobs():

# Initialize JWT
jwt = JWTManager(app)
account_db_path = os.getcwd() + os.path.join(os.path.sep, "core") + os.path.join(os.path.sep, "account.db")

MYSQL_HOST=os.getenv('MYSQL_HOST')

MYSQL_USER=os.getenv('MYSQL_USER')

MYSQL_PASSWORD=os.getenv('MYSQL_PASSWORD')

MYSQL_DATABASE=os.getenv('MYSQL_DATABASE')

db_uri = (f"mysql+pymysql://{MYSQL_USER}:{MYSQL_PASSWORD}@{MYSQL_HOST}/{MYSQL_DATABASE}")

# Database configuration
account_db_path = os.path.join(os.getcwd(), "core", "account.db")
if os.path.exists(account_db_path):
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///./account.db'
else:
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///../instance/account.db'
app.config['SQLALCHEMY_DATABASE_URI'] = db_uri

db = SQLAlchemy(app)
ma = Marshmallow(app)
Expand Down
40 changes: 20 additions & 20 deletions BackEndFlask/dbcreate.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,21 @@
except Exception as e:
print(f"[dbcreate] an error ({e}) occured with db.create_all()")
print("[dbcreate] exiting...")
os.abort()
raise e
print("[dbcreate] successfully created new db")
time.sleep(sleep_time)
if (get_roles().__len__() == 0):
print("[dbcreate] attempting to load existing roles...")
time.sleep(sleep_time)
load_existing_roles()
print("[dbcreate] successfully loaded existing roles")
time.sleep(sleep_time)
if(get_users().__len__()==0):
print("[dbcreate] attempting to load SuperAdminUser...")
time.sleep(sleep_time)
load_SuperAdminUser()
print("[dbcreate] successfully loaded SuperAdminUser")
time.sleep(sleep_time)
if(get_rubrics().__len__()==0):
print("[dbcreate] attempting to load existing rubrics...")
time.sleep(sleep_time)
Expand All @@ -61,18 +73,6 @@
time.sleep(sleep_time)
load_existing_suggestions()
print("[dbcreate] successfully loaded existing suggestions")
if(get_roles().__len__()==0):
print("[dbcreate] attempting to load existing roles...")
time.sleep(sleep_time)
load_existing_roles()
print("[dbcreate] successfully loaded existing roles")
time.sleep(sleep_time)
if(get_users().__len__()==0):
print("[dbcreate] attempting to load SuperAdminUser...")
time.sleep(sleep_time)
load_SuperAdminUser()
print("[dbcreate] successfully loaded SuperAdminUser")
time.sleep(sleep_time)
if len(sys.argv) == 2 and sys.argv[1]=="demo":
if(get_users().__len__()==1):
print("[dbcreate] attempting to load demo Admin...")
Expand Down Expand Up @@ -130,17 +130,17 @@
load_demo_admin_assessment_task()
print("[dbcreate] successfully loaded demo AssessmentTask")
time.sleep(sleep_time)
if(get_feedback().__len__()==0):
print("[dbcreate] attempting to load demo Feedback...")
time.sleep(sleep_time)
load_demo_feedback()
print("[dbcreate] successfully loaded demo Feedback")
time.sleep(sleep_time)
if (get_completed_assessments().__len__() == 0):
print("[dbcreate] attempting to load demo completed assessments...")
time.sleep(sleep_time)
load_demo_completed_assessment()
print("[dbcreate] successfully loaded demo completed assessments")
time.sleep(sleep_time)
if(get_feedback().__len__()==0):
print("[dbcreate] attempting to load demo Feedback...")
time.sleep(sleep_time)
load_demo_feedback()
print("[dbcreate] successfully loaded demo Feedback")
time.sleep(sleep_time)

print("[dbcreate] exiting...")
print("[dbcreate] exiting...")
63 changes: 28 additions & 35 deletions BackEndFlask/models/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,44 +16,44 @@
Team(team_id, team_name, course_id, observer_id, date_created, active_until)
TeamUser(team_user_id, team_id, user_id)
AssessmentTask(assessment_task_id, assessment_task_name, course_id, rubric_id, role_id, due_date, time_zone, show_suggestions, show_ratings, unit_of_assessment, comment, number_of_teams)
Completed_Assessment(completed_assessment_id, assessment_task_id, by_role, team_id, user_id, initial_time, last_update, rating_observable_characteristics_suggestions_data)
Checkin(checkin_id, assessment_task_id, team_number, user_id, time)
CompletedAssessment(completed_assessment_id, assessment_task_id, by_role, team_id, user_id, initial_time, last_update, rating_observable_characteristics_suggestions_data)
Feedback(feedback_id, user_id, completed_assessment_id, feedback_time, lag_time)
Blacklist(id, token)
"""

class Role(db.Model):
__tablename__ = "Role"
__table_args__ = {'sqlite_autoincrement': True}
role_id = db.Column(db.Integer, primary_key=True)
role_name = db.Column(db.String(100), nullable=False)
role_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
role_name = db.Column(db.Text, nullable=False)

class User(db.Model):
__tablename__ = "User"
__table_args__ = {'sqlite_autoincrement': True}
user_id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(30), nullable=False)
last_name = db.Column(db.String(30), nullable=False)
email = db.Column(db.String(255), unique=True, nullable=False)
password = db.Column(db.String(80), nullable=False)
user_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
first_name = db.Column(db.Text, nullable=False)
last_name = db.Column(db.Text, nullable=False)
email = db.Column(db.String(254), unique=True, nullable=False)
password = db.Column(db.Text, nullable=False)
lms_id = db.Column(db.Integer, nullable=True)
consent = db.Column(db.Boolean, nullable=True)
owner_id = db.Column(db.Integer, ForeignKey(user_id), nullable=True)
has_set_password = db.Column(db.Boolean, nullable=False)
reset_code = db.Column(db.String(6), nullable=True)
reset_code = db.Column(db.Text, nullable=True)
is_admin = db.Column(db.Boolean, nullable=False)

class Rubric(db.Model):
__tablename__ = "Rubric"
__table_args__ = {'sqlite_autoincrement': True}
rubric_id = db.Column(db.Integer, primary_key=True)
rubric_name = db.Column(db.String(100))
rubric_description = db.Column(db.String(100), nullable=True)
rubric_description = db.Column(db.Text, nullable=True)
owner = db.Column(db.Integer, ForeignKey(User.user_id), nullable=True)

class Category(db.Model):
__tablename__ = "Category"
__table_args__ = {'sqlite_autoincrement': True}
category_id = db.Column(db.Integer, primary_key=True)
category_name = db.Column(db.String(30), nullable=False)
category_name = db.Column(db.Text, nullable=False)
description = db.Column(db.String(255), nullable=False)
rating_json = db.Column(db.JSON, nullable=False)

Expand All @@ -80,12 +80,11 @@ class SuggestionsForImprovement(db.Model):

class Course(db.Model):
__tablename__ = "Course"
__table_args__ = {'sqlite_autoincrement': True}
course_id = db.Column(db.Integer, primary_key=True)
course_number = db.Column(db.String(10), nullable=False)
course_name = db.Column(db.String(50), nullable=False)
course_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
course_number = db.Column(db.Text, nullable=False)
course_name = db.Column(db.Text, nullable=False)
year = db.Column(db.Integer, nullable=False)
term = db.Column(db.String(50), nullable=False)
term = db.Column(db.Text, nullable=False)
active = db.Column(db.Boolean, nullable=False)
admin_id = db.Column(db.Integer, ForeignKey(User.user_id, ondelete='RESTRICT'), nullable=False)
use_tas = db.Column(db.Boolean, nullable=False)
Expand All @@ -102,44 +101,40 @@ class UserCourse(db.Model):

class Team(db.Model): # keeps track of default teams for a fixed team scenario
__tablename__ = "Team"
__table_args__ = {'sqlite_autoincrement': True}
team_id = db.Column(db.Integer, primary_key=True)
team_name = db.Column(db.String(25), nullable=False)
team_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
team_name = db.Column(db.Text, nullable=False)
course_id = db.Column(db.Integer, ForeignKey(Course.course_id), nullable=False)
observer_id = db.Column(db.Integer, ForeignKey(User.user_id, ondelete='RESTRICT'), nullable=False)
date_created = db.Column(db.Date, nullable=False)
active_until = db.Column(db.Date, nullable=True)

class TeamUser(db.Model):
__tablename__ = "TeamUser"
__table_args__ = {'sqlite_autoincrement': True}
team_user_id = db.Column(db.Integer, primary_key=True)
team_user_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
team_id = db.Column(db.Integer, ForeignKey(Team.team_id), nullable=False)
user_id = db.Column(db.Integer, ForeignKey(User.user_id), nullable=False)

class AssessmentTask(db.Model):
__tablename__ = "AssessmentTask"
__table_args__ = {'sqlite_autoincrement' : True}
assessment_task_id = db.Column(db.Integer, primary_key=True)
assessment_task_name = db.Column(db.String(100))
assessment_task_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
assessment_task_name = db.Column(db.Text)
course_id = db.Column(db.Integer, ForeignKey(Course.course_id))
rubric_id = db.Column(db.Integer, ForeignKey(Rubric.rubric_id)) # how to handle updates and deletes
role_id = db.Column(db.Integer, ForeignKey(Role.role_id))
due_date = db.Column(db.DateTime, nullable=False)
time_zone = db.Column(db.String(3), nullable=False)
time_zone = db.Column(db.Text, nullable=False)
show_suggestions = db.Column(db.Boolean, nullable=False)
show_ratings = db.Column(db.Boolean, nullable=False)
unit_of_assessment = db.Column(db.Boolean, nullable=False) # true if team, false if individuals
comment = db.Column(db.String(3000), nullable=True)
create_team_password = db.Column(db.String(25), nullable=True)
comment = db.Column(db.Text, nullable=True)
create_team_password = db.Column(db.Text, nullable=True)
number_of_teams = db.Column(db.Integer, nullable=True)
max_team_size = db.Column(db.Integer, nullable=True)
notification_sent = db.Column(DateTime(timezone=True), nullable=True)

class Checkin(db.Model): # keeps students checking to take a specific AT
__tablename__ = "Checkin"
__table_args__ = {'sqlite_autoincrement': True}
checkin_id = db.Column(db.Integer, primary_key=True)
checkin_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
assessment_task_id = db.Column(db.Integer, ForeignKey(AssessmentTask.assessment_task_id), nullable=False)
# not a foreign key because in the scenario without fixed teams, there will not be default team entries
# to reference. if they are default teams, team_number will equal the team_id of the corresponding team
Expand All @@ -149,8 +144,7 @@ class Checkin(db.Model): # keeps students checking to take a specific AT

class CompletedAssessment(db.Model):
__tablename__ = "CompletedAssessment"
__table_args__ = {'sqlite_autoincrement': True}
completed_assessment_id = db.Column(db.Integer, primary_key=True)
completed_assessment_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
assessment_task_id = db.Column(db.Integer, ForeignKey(AssessmentTask.assessment_task_id))
completed_by = db.Column(db.Integer, ForeignKey(User.user_id), nullable=False)
team_id = db.Column(db.Integer, ForeignKey(Team.team_id), nullable=True)
Expand All @@ -162,8 +156,7 @@ class CompletedAssessment(db.Model):

class Feedback(db.Model):
__tablename__ = "Feedback"
__table_args__ = {'sqlite_autoincrement': True}
feedback_id = db.Column(db.Integer, primary_key=True)
feedback_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
user_id = db.Column(db.Integer, ForeignKey(User.user_id), nullable=False)
completed_assessment_id = db.Column(db.Integer, ForeignKey(CompletedAssessment.completed_assessment_id), nullable=False)
feedback_time = db.Column(DateTime(timezone=True), nullable=True) # time the student viewed their feedback
2 changes: 1 addition & 1 deletion BackEndFlask/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def load_SuperAdminUser():
"password": str(os.environ.get('SUPER_ADMIN_PASSWORD')),
"lms_id": 0,
"consent": None,
"owner_id": 0,
"owner_id": None,
"role_id": None
})

Expand Down
3 changes: 2 additions & 1 deletion BackEndFlask/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ Werkzeug >= 2.0.2
redis >= 4.5.5
python-dotenv >= 1.0.0
yagmail >= 0.15.293
openpyxl >= 3.1.2
openpyxl >= 3.1.2
cryptography >= 43.0.1
8 changes: 0 additions & 8 deletions BackEndFlask/run.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
from core import app
# this variable is expected by the wsgi server
# application = app

if __name__ == '__main__':
#The app.run(debug = True) line is needed if we are working on our local machine
# app.run(debug=True)

#the app.run(host="0.0.0.0") line is currently commented out and if and only when we are seting up an EC2 instance
app.run(host="0.0.0.0")

# token: MFFt4RjpXNMh1c_T1AQj
2 changes: 2 additions & 0 deletions BackEndFlask/setupEnv.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ def cmd(command, parent_function):

err(f"Error running command: {command} in function: {parent_function}")

err(f"Exception: {e}")

err(f"Return code: {e.returncode}")

err(f"Output: {e.output}")
Expand Down
5 changes: 1 addition & 4 deletions Dockerfile.backend
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,8 @@ RUN pip install --no-cache-dir --upgrade pip \
# Copy the rest of the backend code
COPY BackEndFlask/ /app/

# Initialize the Backend environment
RUN python setupEnv.py -d

# Expose the Backend port
EXPOSE 5000

# Start the Flask server
CMD ["python", "setupEnv.py", "-s"]
CMD ["python", "setupEnv.py", "-ds"]
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ for analysis.

- Python 3.12 and up.

- MySQL-Server.

- Homebrew 4.2.18 and up.

- Redis 7.2.4 and up.
Expand All @@ -117,6 +119,49 @@ NOTE:
- WINDOWS DEVELOPERS ARE NO LONGER SUPPORTED.


## Setting up the MySQL Environment: ##

- Run the following command to install MySQL-Server
on Linux:

sudo apt install mysql-server

- Run the following command to install MySQL-Server
on MacOS:

brew install mysql

- Run the following command to start MySQL-Server
on MacOS:

brew services start mysql

- Run the following command to start MySQL-Server
in a new terminal:

sudo mysql -u root

- Next use these commands to create an account
named skillbuilder and set the password to
"WasPogil1#"

CREATE DATABASE account;
CREATE USER 'skillbuilder'@'localhost' IDENTIFIED BY 'WasPogil1#';
GRANT ALL PRIVILEGES ON *.* TO 'skillbuilder'@'localhost';
FLUSH PRIVILEGES;
exit;

NOTE:

- The password should be changed for deployment.

- Once this is done, you can use: `setupEnv.py` as normal
to create the database. If for any reason you want to
access the database directly, run the following command:

mysql -u skillbuilder -p

and then type the password.

## Installing requirements ##

Expand Down
Loading

0 comments on commit 1a1a1c4

Please sign in to comment.