Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
597e3e5
include members
pulaskii Sep 12, 2025
f58a6e1
create and populate documentation directory
pulaskii Sep 15, 2025
e1cca29
Merge pull request #1 from pulaskii/documentation
pulaskii Sep 15, 2025
2776e28
Update README.md
np568 Oct 5, 2025
1bf8aa5
Create requirements.txt
pulaskii Oct 5, 2025
a4c5f39
Update README.md
np568 Oct 5, 2025
cc21b50
Merge pull request #2 from pulaskii/documentation
pulaskii Oct 5, 2025
be0aaa6
Add files via upload
np568 Oct 5, 2025
27606ce
Create requirementsSpecificationRawPDF.pdf
pulaskii Oct 8, 2025
6813062
Merge pull request #3 from pulaskii/documentation
pulaskii Oct 8, 2025
d4c328b
Create planning.txt
pulaskii Oct 24, 2025
0ac6080
Create test.txt
pulaskii Oct 24, 2025
68f91b0
Merge pull request #4 from pulaskii/test-branch
pulaskii Oct 24, 2025
a64bd3d
Delete test.txt
pulaskii Oct 24, 2025
ad1db97
Merge pull request #5 from pulaskii/test-branch
pulaskii Oct 24, 2025
d224232
Update planning.txt
pulaskii Oct 24, 2025
ee6ce66
Update planning.txt
chavda-a Oct 24, 2025
64c8000
Created basic backend layout and html signup page for patient
np568 Oct 24, 2025
156ddc3
Merge branch 'main' of https://github.com/pulaskii/AssignmentRepo355
np568 Oct 24, 2025
4420a09
Added email validation for sign up page
GreyGhost03 Oct 29, 2025
14a9428
Comfirm password now appears!
GreyGhost03 Oct 29, 2025
1f12512
regexp works properly for phone number validation
GreyGhost03 Oct 29, 2025
202088b
add sql code
pulaskii Oct 29, 2025
806ffb2
Removed the clutter of separate patient and provider sign up and logi…
np568 Oct 29, 2025
140af9a
Hashed the password
GreyGhost03 Oct 29, 2025
f5814d4
Merge branch 'main' of https://github.com/pulaskii/AssignmentRepo355
GreyGhost03 Oct 29, 2025
ccb2588
start creating sql python files
pulaskii Oct 29, 2025
37dd5c7
Incomplete implementation of the login form
np568 Oct 29, 2025
97dc322
Merge remote-tracking branch 'origin/main'
np568 Oct 29, 2025
a1fbd19
The login page has been added
GreyGhost03 Oct 29, 2025
cf205f2
ye
GreyGhost03 Oct 29, 2025
69c8150
begin mysql and mysql-connector implementation
pulaskii Oct 29, 2025
9d8de49
Merge pull request #6 from pulaskii/sql
pulaskii Oct 29, 2025
8211750
connect and add data to sql database
pulaskii Oct 30, 2025
065cb6a
Merge branch 'main' into sql
pulaskii Oct 30, 2025
38dedfd
Merge pull request #7 from pulaskii/sql
pulaskii Oct 30, 2025
a127fd0
integrate hashed password into sql methods
pulaskii Oct 30, 2025
9376ec9
Update main.py
pulaskii Oct 30, 2025
06fc0c3
Merge pull request #8 from pulaskii/sql
pulaskii Oct 30, 2025
f325a88
Made a small change to the main.py file to properly call the addNewUs…
GreyGhost03 Oct 30, 2025
d0135ad
Implemented a simple checkbox on the signup page, currently has no fu…
np568 Oct 30, 2025
5ae9e40
Merge remote-tracking branch 'origin/main'
np568 Oct 30, 2025
f6deed2
patient_or_provider variable added to signup route and passed to crea…
GreyGhost03 Oct 30, 2025
051fc72
patient_or_provider will be equal to either "option_patient" or "opti…
GreyGhost03 Oct 30, 2025
5c9bfee
Created back buttons for the signup and log in pages that returns to …
np568 Oct 31, 2025
0500a05
Added h2 elements to the signup and log in pages to create visual app…
np568 Oct 31, 2025
eabc26c
Made the patient and provider text within the radio field bold to dra…
np568 Oct 31, 2025
f6d9e94
Merge pull request #9 from pulaskii/main
pulaskii Oct 31, 2025
47eb35b
changed patient or doctor to patient or provider
pulaskii Oct 31, 2025
113d6c5
Merge pull request #10 from pulaskii/sql
pulaskii Oct 31, 2025
265d939
fix patient or provider strings
pulaskii Oct 31, 2025
38f1701
Merge pull request #11 from pulaskii/sql
pulaskii Oct 31, 2025
a82840e
change some sql code
pulaskii Oct 31, 2025
898b281
Merge pull request #12 from pulaskii/sql
pulaskii Oct 31, 2025
b987232
more sql
pulaskii Oct 31, 2025
bff1729
Merge pull request #13 from pulaskii/sql
pulaskii Oct 31, 2025
f0936ae
patient_or_provider will now store either "Patient" or "Provider" ins…
GreyGhost03 Oct 31, 2025
e373a40
patient_or_provider will be either Patient or Provider now rather tha…
GreyGhost03 Oct 31, 2025
8b7d708
make numbers in order
pulaskii Oct 31, 2025
f381dcd
Merge pull request #14 from pulaskii/sql
pulaskii Oct 31, 2025
4d963bf
Created an env file and gitignore file to hide sensitive information,…
np568 Oct 31, 2025
81bb48b
Merge remote-tracking branch 'origin/main'
np568 Oct 31, 2025
06954c9
Removed unused libraries
np568 Oct 31, 2025
dc584e6
Create patient_hompage.html
bkarp10 Oct 31, 2025
5644769
Added spacing between the login and sign up anchor elements on the ho…
np568 Oct 31, 2025
05d69ee
Merge remote-tracking branch 'origin/main'
np568 Oct 31, 2025
cd35c4c
fix patient homepage
bkarp10 Oct 31, 2025
4626217
debugging sqlconnector
pulaskii Nov 1, 2025
a978ce6
rename
pulaskii Nov 1, 2025
97d784a
Revert "debugging sqlconnector"
pulaskii Nov 1, 2025
38f0871
fix
pulaskii Nov 1, 2025
55d962b
Merge branch 'main' into sql
pulaskii Nov 1, 2025
285421f
Merge pull request #17 from pulaskii/sql
pulaskii Nov 1, 2025
2dcee3e
rename app.py
pulaskii Nov 1, 2025
6f54500
table stuff
pulaskii Nov 1, 2025
d4d1edd
add documentation files
pulaskii Nov 1, 2025
52cdfb8
rename
pulaskii Nov 1, 2025
b6c3a09
Merge branch 'main' into sql
pulaskii Nov 1, 2025
941cd8a
Merge pull request #19 from pulaskii/sql
pulaskii Nov 1, 2025
f01ed76
Rename 2025-10-31 21-02-41.mkv to demoForSprint1.mkv
pulaskii Nov 1, 2025
ec7651e
Started testing the PDF editor
GreyGhost03 Nov 15, 2025
84ecf0f
Built strucutre for the edit record page with a text editor.
GreyGhost03 Nov 15, 2025
9e1dc96
Did more work on the edit_record_page, just need to add the back buton
GreyGhost03 Nov 15, 2025
a1e7b99
Created a rough layout for the provider portal and added a temporary …
np568 Nov 15, 2025
1c43f1f
Merge remote-tracking branch 'origin/main'
np568 Nov 15, 2025
6f37504
Added back button to edit record page and fixed its functionality
GreyGhost03 Nov 15, 2025
99c7ff3
Created a rough layout for the provider portal and added a temporary …
np568 Nov 15, 2025
7eaed73
Merge remote-tracking branch 'origin/main'
np568 Nov 15, 2025
4103696
Hooked up everything together
GreyGhost03 Nov 15, 2025
e7898ac
add more sql methods
pulaskii Nov 17, 2025
6bbfb7d
Integrated fetchData and saveData in the edit_record_page, there is a…
GreyGhost03 Nov 17, 2025
9687bd8
Fixed back button navigation on provider homepage and added buttons f…
GreyGhost03 Nov 17, 2025
431943e
change some names and add some sql stuff
pulaskii Nov 17, 2025
ef2e24d
sql stuff
pulaskii Nov 17, 2025
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
Binary file modified .DS_Store
Binary file not shown.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#Hides CSRF key
.env
6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/profiles_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 18 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
My groupmembers are:
- XXXX
- XXXX
- XXXX
- XXXX
Team Penguin Members:
- Jo Vinson
- Andrew Dickerson
- Ben Karp
- Arth Chavda
- Nasmir Pasic
- Owen Cosner


------------------ Fill in some information about your project under this ------------------
------------------ Project Summary ------------------

A medical records sharing platform, supporting both emergency sharing and recipient specified sharing.

The program has a web front end, with different portals for doctors and patients. Patients are able to fill in and create medical fields or upload a pdf, which then fills in for a sql table on a database. Patients are also able to search for and share documents with doctors that have public accounts on the site, and patients have the ability to create emergency keys, in the form of qr codes, to enable doctors to access their records without sharing access.

The web app contains an AI tool which helps provide a quick summary of a patient’s medical history for doctors who need quick access to specific information.

Doctors have the ability to edit records which are shared with them, and can access new records using an emergency key.

Both types of accounts can set their privacy status to public or private, to enable or disable new accounts from sharing/accessing documents with them. Accounts are created using an email, which is sent a verification email, and can be deleted.
Binary file added Requirements Specifications.pdf
Binary file not shown.
Binary file added Sprint 1/Flask Backend/.DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions Sprint 1/Flask Backend/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CONFIG_KEY="W<0:2e?Qr9)cA{:3|~T*5%ZxS"
1 change: 1 addition & 0 deletions Sprint 1/Flask Backend/AssignmentRepo355
Submodule AssignmentRepo355 added at d4c328
154 changes: 154 additions & 0 deletions Sprint 1/Flask Backend/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
from flask import Flask, render_template, request, redirect, url_for, jsonify
from flask_bcrypt import Bcrypt
from wtforms import StringField, PasswordField, SubmitField, RadioField, validators
from flask_wtf import FlaskForm, CSRFProtect
from wtforms.validators import EqualTo, InputRequired
import jinja2
import mysql
import pyModules.sqlpy.connectToDB as connectToDB
import pyModules.sqlpy.createAccountRow as createAccountRow
import pyModules.sqlpy.fetchData as fetchData
import pyModules.sqlpy.saveData as saveData
import os
from dotenv import load_dotenv

app = Flask(__name__)
load_dotenv()
app.config["SECRET_KEY"] = os.getenv("CONFIG_KEY")
csrf = CSRFProtect(app)
bcrypt = Bcrypt(app)

@app.route("/")
def home():
return render_template("home.html")

@app.route("/signup_page", methods = ['GET', 'POST'])
def signup():
patient_or_provider = None
first_name = None
last_name = None
phone_number = None
user_email = None
password = None

sign_up_form = SignUp()
if request.method == "POST":
if sign_up_form.validate_on_submit():
patient_or_provider = sign_up_form.patient_or_provider.data
first_name = sign_up_form.first_name.data
last_name = sign_up_form.last_name.data
phone_number = sign_up_form.phone_number.data
user_email = sign_up_form.user_email.data
password = sign_up_form.password.data
hashed_password = bcrypt.generate_password_hash(sign_up_form.password.data).decode('utf-8')
password = hashed_password


createAccountRow.addNewUser(first_name,
last_name,
user_email,
phone_number,
password,
patient_or_provider,
connectToDB.connectDatabase()
)

return render_template("signup_page.html", patient_or_provider = patient_or_provider, first_name = first_name, last_name = last_name,
user_email = user_email, phone_number = phone_number, password = password,
form = sign_up_form)

@app.route("/login_page", methods = ['GET', 'POST'])
def login():
email_login = None
password_login = None

login_form = LogIn()
if request.method == "POST":
if login_form.validate_on_submit():
email_login = login_form.email_login.data
password_login = login_form.password_login.data

#TODO: We need to validate the email and password against the database here
#If validated and the user is a doctor, redirect to doctor page
#If validated and the user is a patient, redirect to patient page
#Jo work your magic

return redirect(url_for("provider"))

return render_template("login_page.html", email_login = email_login, password_login = password_login,
form = login_form)

@app.route("/edit_record_page")
def edit_record_page():
return render_template("edit_record_page.html")

# Get patient data for edit_record_page
@app.route("/api/get_patient")
def api_get_patient():
email = request.args.get("email")

db = connectToDB.connectDatabase()
result = fetchData.fetchUserData(email, db)

if isinstance(result, map):
return jsonify(result)

return jsonify({"error": "Could not fetch user"}), 400

# Save updated patient data from edit_record_page
@app.route("/api/update_record", methods=["POST"])
def api_update_record():
data = request.get_json()
updated_fields = data.get("updated_fields")
email = data.get("email")

db = connectToDB.connectDatabase()

for column, value in updated_fields.items():
saveData.saveUserData(email,
dbConnection=db,
columnToSet=column,
valueToSet=value)

return jsonify({"message": "Record saved"})

@app.route('/provider_portal')
def provider():
return render_template('provider_homepage.html')

class SignUp(FlaskForm):
patient_or_provider = RadioField("Are you a patient or a provider?", choices=[('Patient', 'Patient'), ('Provider', 'Provider')], validators=[InputRequired()])

first_name = StringField("Enter your first name", validators = [validators.DataRequired(message = "First name is required")], render_kw = {'placeholder': "John"})

last_name = StringField("Enter your last name", validators = [validators.DataRequired(message = "Last name is required")], render_kw = {'placeholder': "Doe"})

phone_number = StringField("Phone number", validators = [validators.DataRequired(message = "Phone number is required"),
validators.Length(min = 10, message = "Must be at least 10 characters"),
validators.Regexp(r'^\(\d{3}\)\s?\d{3}-\d{4}$',
message="Invalid phone number format. Use (123) 456-7890")
], render_kw = {'placeholder': "(000) 000-0000"})
user_email = StringField("Email", validators = [validators.DataRequired(), validators.Email("Must be a valid email")], render_kw = {'placeholder': "example@email.com"})

password = PasswordField("Create a unique password.", validators = [validators.DataRequired(message = "Please enter a password"),
validators.Length(min = 8, max = 20, message = "Please enter a password between 8 and 20 characters"),
validators.Regexp(r'^(?=.*[A-Z])(?=.*[!@#$%^+=-])(?=.{8,20}$)[^{}[\]<|*&"()]*$', message = "Please enter a valid password. Valid special characters are @, #, !, $, -, or _"),
EqualTo('confirm_password', message="Passwords must match")],
render_kw = {'placeholder': "8-20 characters long, one capital letter, one special character"})

confirm_password = PasswordField("Confirm your password", validators = [validators.DataRequired(message="Please confirm your password")
], render_kw={'placeholder': "Re-enter your password"})

submit_button = SubmitField("Submit")

class LogIn(FlaskForm):
email_login = StringField("Email", validators=[validators.DataRequired(message="Please enter your email"),validators.Email("Must be a valid email")],
render_kw={'placeholder': "Enter your email"})
password_login = PasswordField("Password.", validators = [validators.DataRequired(message = "Please enter your password"),
validators.Length(min = 8, max = 20, message = "Must be between 8 and 20 characters"),
validators.Regexp(r'^(?=.*[A-Z])(?=.*[!@#$%^+=-])(?=.{8,20}$)[^{}[\]<|*&"()]*$', message = "Invalid format.")], render_kw={'placeholder': "Enter your password"})

submit_button = SubmitField("Submit")

if __name__ == "__main__":
app.run(debug = True)
1 change: 1 addition & 0 deletions Sprint 1/Flask Backend/pyModules/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__all__ = ["sqlpy"]
Binary file not shown.
1 change: 1 addition & 0 deletions Sprint 1/Flask Backend/pyModules/sqlpy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__all__ = ["connectToDB" "createAccountRow"]
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
25 changes: 25 additions & 0 deletions Sprint 1/Flask Backend/pyModules/sqlpy/connectToDB.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from mysql import connector


def connectDatabase(user = "root",
password = "password",
host = "127.0.0.1",
database = "medicalrecords",
raiseOnWarnings = True
):

connectionConfig = {
'user': user,
'password': password,
'host': host,
'database': database,
'raise_on_warnings': raiseOnWarnings
}

dbConnection = connector.connect(**connectionConfig)

return dbConnection


def disconnectDatabase(connectionToClose):
connectionToClose.close()
62 changes: 62 additions & 0 deletions Sprint 1/Flask Backend/pyModules/sqlpy/createAccountRow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from mysql import connector
from mysql.connector import errorcode
import mysql


def addNewUser( firstName,
lastName,
userEmail,
phoneNumber,
password,
PatientOrProvider,
dbConnection
):

returnVal = 1

addUser = ("INSERT INTO users"
"(Email, FirstName, LastName, PasswordHash, Phone, PatientOrProvider)"
"VALUES ((%(EmailVal)s)," \
"(%(FirstNameVal)s)," \
"(%(LastNameVal)s)," \
"(%(PasswordVal)s)," \
"(%(PhoneVal)s)," \
"(%(PatientOrProviderVal)s))"
)





dataUser = {
'EmailVal': userEmail,
'FirstNameVal': firstName,
'LastNameVal': lastName,
'PasswordVal': password,
'PhoneVal': phoneNumber,
'PatientOrProviderVal': PatientOrProvider
}


cursor = dbConnection.cursor()

try:
cursor.execute(addUser, dataUser)
except mysql.connector.Error as err:
if err.errno == 1062:
returnVal = 2

try:
dbConnection.commit()
except mysql.connector.Error as err:
if err.errno == 1062:
returnVal = 3

cursor.close() # close cursor
dbConnection.close() # close connection

return returnVal


def addNewUserTest():
print("import successful! :)")
45 changes: 45 additions & 0 deletions Sprint 1/Flask Backend/pyModules/sqlpy/fetchAccessMap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from mysql import connector

def fetchAccessMap(userEmail,
dbConnection,
patientOrDoctor # "doctor" or "patient"
):

cursor = dbConnection.cursor()

if patientOrDoctor == "doctor":
query = ("SELECT u.FirstName, u.LastName, u.Email FROM users u"
"JOIN accessMap AM"
"ON AM.patient = u.Email"
"WHERE AM.doctor = %(EmailVal)s"
)
else:
query = ("SELECT u.FirstName, u.LastName, u.Email FROM users u"
"JOIN accessMap AM "
"ON AM.doctor = u.Email"
"WHERE AM.patient = %(EmailVal)s"
)


queryData = {
'emailVal': userEmail
} # user primary key

try:
cursor.execute(query, queryData) # execute the changes
except:
return 2 #errorval


returnList = []
for (FirstName, LastName, Email) in cursor:
# iterate through a set of tuples
# the tuples are the rows
returnList.append((FirstName, LastName, Email))


cursor.close() # close cursor
dbConnection.close() # close connection

return returnList #return the map

39 changes: 39 additions & 0 deletions Sprint 1/Flask Backend/pyModules/sqlpy/fetchData.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from mysql import connector

def fetchUserData(userEmail,
dbConnection
):

cursor = dbConnection.cursor()

query = ("SELECT FirstName, LastName, Age, Phone FROM users "
"WHERE Email EQUALS %(emailVal)s") # fetch user data

queryData = {
'emailVal': userEmail
} # user primary key

try:
cursor.execute(query, queryData) # execute the changes
except:
return 2 #errorval

returnMap = {}
for (FirstName, LastName, Age, Phone,) in cursor:
# iterate through a set of tuples
# the tuples are the rows, but we only fetched one
returnMap = {
'FirstNameVal': FirstName,
'LastNameVal': LastName,
'AgeVal': Age,
'PhoneVal': Phone
} # make a return map for the row




cursor.close() # close cursor
dbConnection.close() # close connection

return returnMap #return the map

Loading