Merge pull request #1 from UofCBaja/monoRepoPrep

Mono repo finish
This commit is contained in:
darkicewolf50 2024-12-21 22:55:35 -07:00 committed by GitHub
commit ac862bc213
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 975 additions and 2 deletions

4
.dockerignore Normal file
View File

@ -0,0 +1,4 @@
.git
__pycache__
*.pyc
.env

70
.github/workflows/Actions.yaml vendored Normal file
View File

@ -0,0 +1,70 @@
# name of the workflow.
# this is optional.
name: Interview Cloud Actions
# events that will trigger this workflow.
# here, we only have "pull_request", so the workflow will run
# whenever we create a pull request.
# other examples: [push] and [pull_request, push]
on:
pull_request:
push:
branches:
- master
# each workflow must have at least one job.
# jobs run in parallel by default (we can change that).
# each job groups together a series of steps to accomplish a purpose.
jobs:
# name of the job
ruffLint:
# the platform or OS that the workflow will run on.
runs-on: ubuntu-latest
# series of steps to finish the job.
steps:
# name of the step.
# steps run sequentially.
# this is optionale
- name: checkout
# each step can either have "uses" or "run".
# "uses" run an action written somewhere other than this workflow .
# usually from the community.
# this action checks out the repo code to the runner (instance)
# running the action
uses: actions/checkout@v3
# another step.
# this step runs a bash (Ubuntu's default shell) command
- name: install ruff
run: pip install ruff
- name: Lint
run: ruff check ./*/*.py --ignore E402
Dockerhub:
runs-on: ubuntu-latest
needs: ruffLint # will only run if linter is successful
if: ${{ github.ref == 'refs/heads/master' || github.event.pull_request.merged == true }} # Runs if it's a push to 'main' or a merged PR to 'main'
steps:
- name: checkout
uses: actions/checkout@v3
- name: Login to Dockerhub # log into docker hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }} # Using secret for Docker username
password: ${{ secrets.DOCKER_PASSWORD }} # Using secret for Docker password
id: docker-login
- name: build container image # build the container
run: docker compose build --no-cache
id: docker-build
- name: Upload to Dockerhub
run: docker push darkicewolf50/uofcbajacloud:latest
if: ${{ steps.docker-login.outcome == 'success' && steps.docker-build.outcome == 'success' }}

21
Dockerfile Normal file
View File

@ -0,0 +1,21 @@
# Use an official Python runtime as a parent image
FROM python:3.10-slim
# Set the working directory inside the container
WORKDIR /BajaCloudBackend
# Copy the current directory contents into the container at /app
COPY ./InterviewBooking /BajaCloudBackend/InterviewBooking
# Copy the main file to the working directory
COPY main.py /BajaCloudBackend
# Install any necessary dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Expose port 8000 for the container to listen on
EXPOSE 8000
# Command to run the Python server when the container starts
#CMD ["fastapi", "run" "main.py"]
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--reload"]

141
InterviewBooking/NoSheet.py Normal file
View File

@ -0,0 +1,141 @@
import openpyxl
import yaml
import datetime
from openpyxl.styles import Font, Border, Side, PatternFill
from openpyxl.formatting.rule import FormulaRule
def NoSheet(file_path):
"""
Creates the Template for more data to be added
``REQUIRES``: ``None`` Ensure no other sheets are present, will overwrite them
``PROMISES``: ``XLSX File`` give the template for recuitment for the year
``Develop in part by``: Brock
``Contact``: darkicewolf50@gmail.com
"""
yamlraw = """
Recruitment Responses:
- Frist Name (What we should call them): Steve
- Last Name: the Bug
- Ucalgary Email: steve.the.bug@ucalgary.ca
- What Subsystem/SubTeam are you interested in?: |
Chassis
Ergonomics
Suspension
Steering
Powertrain
Final Drive
Any Mechanical
Business - Content Creation
Business - Business Relations
Software
- Major: General (1st Year)
- Academic Year: 1st
- Why are you interested in joining UCalgary BAJA?: Example Interest
- Where did you hear about us?: Testing
- Are you available for team meetings/work days? Saturdays 10 am - 4 pm: "No" #add condiftional formatting for no to make whole line red
Interview TimeTable:
- Date: 2024-09-16
- Meeting Duration: 30 min
- Start Time Slot: 10:00:00 AM
- Slot: 1
- Interviewee Name (What to call them): Steve
- Interviewee Email: steve.the.bug@ucalgary.ca
- Category (if not general): Test
- Interviewer(s) Name(s): Example
- Status: Dropdown (Options in datahelp) #default is Unknown
Data Helper And Info:
- Status Dropdown:
- Unknown
- Done
- No Show
- Cancelled/Moved
- First time Startup: Move docker volume pointer to new drive and start up container
- Weird Date: Add more space and it will change from ### to a date
- How to Add Dropdown: Go into data, click data validation, select list then select the area you want to get values from in the formula spot
"""
# uses the base above "yaml file" to create the base template
yamlsheet = yaml.safe_load(yamlraw)
year_donation = int(str(datetime.datetime.now().year)[2:]) + 1 # gets the last two digits of the current year then adds 1 for the current season
file_name = file_path
# border style
border = Border( # defualt behaviour is thin
left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin')
)
# create workbook in memory
work_book = openpyxl.Workbook()
# remove default sheet
default_sheet = work_book.active
work_book.remove(default_sheet)
# decomposes the yaml file at the top and convertss it into a standard template
# does one sheet at a time
for sheet_name, title_list in yamlsheet.items():
# add 1 standard sheet, by the outermost name
sheet = work_book.create_sheet(sheet_name)
# gets header titles for each sheet, from the inner list
titles = [list(title.keys())[0] for title in title_list]
# makes the header titles to bold, have a border and have text
for col_num, title in enumerate(titles, start=1):
cell = sheet.cell(row=1, column=col_num)
cell.value = title
cell.font = Font(bold=True)
cell.border = border
# example data to show on what it will look like or to copy formatting down
example_data = [list(data.values())[0] for data in title_list]
for col_num, data in enumerate(example_data, start=1):
# for special case Data Helper where there a list in a dictionary
if isinstance(data, list):
row_num = 2
for item in data:
cell = sheet.cell(row=row_num, column=col_num)
cell.value = item
row_num += 1
# adds data to the cells
else:
cell = sheet.cell(row=2, column=col_num)
# changes the Dropdown data in status to unknown instead of the other option, only there for prep for a dropdown
if data == "Dropdown (Options in datahelp)":
cell.value = "Unknown"
elif isinstance(data, datetime.date):
cell.value = data
# Convert the example date '2024-09-16' to a datetime object
# Set the number format to 'YYYY-MM-DD'
cell.number_format = 'yyyy-mmm-d'
else:
cell.value = data
if sheet.title == "Recruitment Responses":
sheet.conditional_formatting.add("A2:I2", FormulaRule(formula=['=$I2="No"'], fill=PatternFill(start_color="FF0000", end_color="FF0000", fill_type="solid")))
# save to storage
work_book.save(file_name)
print(f"Created {file_name} for {year_donation}")
if __name__ == "__main__":
year_donation = int(str(datetime.datetime.now().year)[2:]) + 1 # gets the last two digits of the current year then adds 1 for the current season
# name based off the 2025 naming system
# Define the path to the Excel file and the lock file
file_name = f"./Interviews/OR{year_donation}-L-Interview Data.xlsx"
NoSheet(file_name)

View File

@ -0,0 +1,90 @@
import pandas as pd
import json
from filelock import FileLock, Timeout
import time
import datetime
"""
TODO change to use new tempate
TODO change names to be more clear
"""
def ReadDatabase(file_path):
"""
Reads the database for which slots are available
``REQUIRES``: ``File_Path`` where the file is
``PROMISES``: ``JSON`` Interview Available Slots
``Developed in part by``: Ahmad, Brock
``Contact``: ahmad.ahmad1@ucalgary.ca, darkicewolf50@gmail.com
"""
# Define the path to the Excel file and the lock file
excel_file_path = file_path
lock_file_path = file_path + ".lock"
# Retry parameters
max_retries = 60 # Maximum number of retries if the file is locked
retry_interval = 0.5 # Wait time (in seconds) between retries
retries = 0
while retries < max_retries:
try:
# Attempt to acquire a shared read (non-blocking) access
with FileLock(lock_file_path, timeout=0): # Non-blocking, checks if the lock exists
# Load the Excel file into a pandas DataFrame
df = pd.read_excel(excel_file_path, sheet_name="Interview TimeTable")
# Initialize the dictionary to store the structured data
interview_data = {}
# Group the DataFrame by Date, Start Time, and Slot for organization
for _, row in df.iterrows():
date = str(row['Date']).split(" ")[0]
start_time = str(row['Start Time Slot'])
slot = int(row['Slot']) if not pd.isna(row['Slot']) else 0
# Returns the number of interviewees in the slot; returns 0 if empty
interviewee_amount = len(str(row['Interviewee Name (What to call them)']).split()) if str(row['Interviewee Name (What to call them)']) != "nan" else 0
# Check if the slot is available for an interviewee to attend
available_slots = interviewee_amount != slot
if available_slots:
# Initialize nested structure if not present
if date not in interview_data:
interview_data[date] = {}
# Add the start time and duration if not present
if start_time not in interview_data[date]:
interview_data[date][start_time] = {
'Meeting Duration': row['Meeting Duration'],
}
return interview_data # Successfully read the database
except Timeout:
# File is locked; wait and retry
retries += 1
print(f"File is locked, retrying ({retries}/{max_retries})...")
time.sleep(retry_interval)
# If max retries are exceeded, raise an error
raise RuntimeError("Unable to access the database after multiple attempts due to a file lock.")
# Example usage of the ReadDatabase function
if __name__ == "__main__":
import datetime
year_donation = int(str(datetime.datetime.now().year)[2:]) + 1 # gets the last two digits of the current year then adds 1 for the current season
# name based off the 2025 naming system
# Define the path to the Excel file and the lock file
file_name = f"./Interviews/OR{year_donation}-L-Interview Data.xlsx"
try:
data = ReadDatabase(file_name)
print(json.dumps(data, indent=4))
except RuntimeError as e:
print(e)

156
InterviewBooking/WriteDB.py Normal file
View File

@ -0,0 +1,156 @@
import pandas as pd
import json
from openpyxl import load_workbook
from .send_email import send_email
from filelock import FileLock
"""
TODO update names to be more clear
TODO try to remove pandas
"""
def ReadDatabase(file_path, lock_path):
"""
Reads the Database to retrieve available interview slots
``REQUIRES``: ``File_Path`` ``Lock_Path`` where the file and lock are located
``PROMISES``: JSON (Available interview slots)
``Developed by``: Ahmad, Brock
``Contact``: ahmad.ahmad1@ucalgary.ca, darkicewolf50@gmail.com
"""
# Use a file-based lock for thread-safe and process-safe access
with FileLock(lock_path):
# Load the Excel file into a pandas DataFrame with specific columns
df = pd.read_excel(file_path, usecols=['Date', 'Start Time Slot', 'Slot', 'Interviewee Name (What to call them)', 'Interviewee Email', 'Meeting Duration'], sheet_name="Interview TimeTable")
# Initialize the dictionary to store structured data for available slots
interview_data = {}
# Process each row in the DataFrame to structure data by date and time
for _, row in df.iterrows():
# Convert Date and Start Time to string format for easier comparison
date = str(row['Date']).split(" ")[0] # Format date to YYYY-MM-DD
start_time = str(row['Start Time Slot'])
# Calculate the slot capacity and current number of interviewees
slot_capacity = int(row['Slot']) if not pd.isna(row['Slot']) else 0
interviewee_names = [name.strip() for name in str(row['Interviewee Name (What to call them)']).split(',') if name.strip()]
interviewee_count = len(interviewee_names) if interviewee_names != ["nan"] else 0
# Check if there are available slots for more interviewees
if interviewee_count < slot_capacity:
# Organize data by date and time, keeping track of available slots and meeting duration
if date not in interview_data:
interview_data[date] = {}
interview_data[date][start_time] = {
'Meeting Duration': row['Meeting Duration'],
'Available Slots': slot_capacity - interviewee_count
}
return interview_data
def AppendAppointment(file_path, date, start_time, interviewee_name, interviewee_email):
"""
Appends a new appointment with the interviewee's name and email if the slot is available.
``REQUIRES``: ``File_Path`` ``str`` date, ``str`` start_time, ``str`` interviewee_name, ``str`` interviewee_email
``PROMISES``: ``None`` Updates the Excel file with the new interviewee's name and email if there is an available slot. Returns Bool.
``Developed by``: Ahmad, Brock
``Contact``: ahmad.ahmad1@ucalgary.ca, darkicewolf50@gmail.com
"""
lock_path = file_path + ".lock"
available_slots = ReadDatabase(file_path, lock_path)
# Check if the requested slot is available in the `available_slots` structure
if date in available_slots and start_time in available_slots[date]:
with FileLock(lock_path): # Ensure process-safe access to the file
# Load workbook and select "Interview TimeTable" for updating appointments
workbook = load_workbook(file_path)
sheet = workbook["Interview TimeTable"]
df = pd.read_excel(file_path, sheet_name="Interview TimeTable")
# Find and update the row that matches the provided date and start time
for index, row in df.iterrows():
row_date = str(row['Date']).split(" ")[0]
row_start_time = str(row['Start Time Slot'])
if row_date == date and row_start_time == start_time:
# Current entries for names and emails, and append new data with comma and space
current_names = str(row['Interviewee Name (What to call them)']).strip()
current_emails = str(row['Interviewee Email']).strip()
updated_names = f"{current_names}, {interviewee_name}" if current_names != "nan" else interviewee_name
updated_emails = f"{current_emails}, {interviewee_email}" if current_emails != "nan" else interviewee_email
# Update the cells with new names and emails
name_cell = sheet.cell(row=index + 2, column=df.columns.get_loc('Interviewee Name (What to call them)') + 1)
email_cell = sheet.cell(row=index + 2, column=df.columns.get_loc('Interviewee Email') + 1)
name_cell.value = updated_names
email_cell.value = updated_emails
status_cell = sheet.cell(row=index + 2, column=df.columns.get_loc('Status') + 1)
status_cell.value = "Unknown"
workbook.save(file_path)
send_email(interviewee_email, interviewee_name, date, start_time)
return True
# If no slots available, return that the slot is unavailable
return False
def run_tests():
"""
Executes test cases to verify appointment scheduling and slot availability.
``REQUIRES``: None
``PROMISES``: Prints test outcomes to validate successful booking or slot unavailability.
"""
import datetime
year_donation = int(str(datetime.datetime.now().year)[2:]) + 1 # gets the last two digits of the current year then adds 1 for the current season
# name based off the 2025 naming system
# Define the path to the Excel file and the lock file
file_name = f"./Interviews/OR{year_donation}-L-Interview Data.xlsx"
lock = file_name + ".lock"
print("Available Slots:")
available_slots = ReadDatabase(file_path=file_name, lock_path=lock)
print(json.dumps(available_slots, indent=4))
# Test Case 1: Append to an available slot on 2024-09-16 at 10:30:00
date_1 = "9/16/2024"
start_time_1 = "10:30:00"
interviewee_name_1 = "Alice Johnson"
interviewee_email_1 = "ahmadmuhammadofficial@gmail.com"
print(f"\nTest Case 1: Trying to book {date_1} at {start_time_1} for {interviewee_name_1} ({interviewee_email_1})")
AppendAppointment(file_name, date_1, start_time_1, interviewee_name_1, interviewee_email_1)
# Test Case 2: Append to an available slot on 2024-09-17 at 13:30:00
date_2 = "9/17/2024"
start_time_2 = "13:30:00"
interviewee_name_2 = "Bob Smith"
interviewee_email_2 = "bob.smith@example.com"
print(f"\nTest Case 2: Trying to book {date_2} at {start_time_2} for {interviewee_name_2} ({interviewee_email_2})")
AppendAppointment(file_name, date_2, start_time_2, interviewee_name_2, interviewee_email_2)
# Test Case 3: Attempting to book at 10:30:00 on 2024-09-16 for a different interviewee
date_3 = "9/16/2024"
start_time_3 = "10:30:00"
interviewee_name_3 = "Charlie Brown"
interviewee_email_3 = "charlie.brown@example.com"
print(f"\nTest Case 3: Trying to book {date_3} at {start_time_3} for {interviewee_name_3} ({interviewee_email_3})")
AppendAppointment(file_name, date_3, start_time_3, interviewee_name_3, interviewee_email_3)
# Run tests
if __name__ == "__main__":
run_tests()

View File

@ -0,0 +1,55 @@
from .ReadDB import ReadDatabase
def getSchedulePackager(file_name):
"""
Packages up the response for a http response
``REQUIRES``: ``File_Path`` where the file is
``PROMISES``: ``JSON`` http response ready
``Develop in part by``: Brock T
``Contact``: darkicewolf50@gmail.ocm
"""
return {
"interviewDates": ReadDatabase(file_path=file_name)
}
from .WriteDB import AppendAppointment
from email_validator import validate_email, EmailNotValidError
def SelectAppointment (file_name, appointmentJson):
"""
Packages up a response for a http request
``REQUIRES``: ``File_Path`` ``JSON`` where the file is, json has the data of interviewee name, date, starttime and interviewee email
``PROMISES``: ``JSON`` Returns if the booking was a success
``Developed in part by``: Brock
``Contact``: darkicewolf50@gmail.com
"""
try:
validEmail = validate_email(appointmentJson["intervieweeEmail"], check_deliverability=True)
if validEmail:
status = AppendAppointment(file_path=file_name, date=appointmentJson["date"], start_time=appointmentJson["startTime"], interviewee_name=appointmentJson["intervieweeName"], interviewee_email=appointmentJson["intervieweeEmail"])
if status:
resBody = {"Success": True, "validEmail": "true"}
else:
resBody = {"Success": False, "validEmail": "true"}
# resBody["message"] = appointmentJson for testing
return resBody
except EmailNotValidError as e:
print(e)
return {"Success": False, "validEmail": "false"}

View File

@ -0,0 +1,94 @@
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from datetime import datetime, timedelta
import pytz # For timezone handling
"""
TODO add
"""
def send_email(interviewee_email="darkicewolf50@gmail.com", interviewee_name="brock", date="2024-1-10", start_time="10:00:00", location ="ENC25"):
"""
Sends an email notification to the interviewee and to the uofcbaja account
``REQUIRES``: ``str`` interviewee_email, ``str`` interviewee_name, ``str`` date, ``str`` start_time
``PROMISES``: ``EMAIL`` Sends an email to interviewee and static email on successful appointment booking.
``Developed by``: Ahmad
``Contact``: ahmad.ahmad1@ucalgary.ca
"""
# Define static email for notifications and Gmail credentials
static_email = "uofcbaja@gmail.com"
gmail_user = "uofcbaja.noreply@gmail.com"
gmail_apppassword = "pver lpnt upjd zvld"
# Define Mountain Standard Time
mst = pytz.timezone("America/Edmonton") # MST with Daylight Savings considered
# Parse the input date and time, localize to MST
start_datetime = mst.localize(datetime.strptime(f"{date} {start_time}", "%Y-%m-%d %H:%M:%S"))
end_datetime = start_datetime + timedelta(minutes=30)
# Format date and time for the calendar URLs
start_time_google = start_datetime.strftime("%Y%m%dT%H%M%S") # Google Calendar (Local time without Z)
end_time_google = end_datetime.strftime("%Y%m%dT%H%M%S") # Google Calendar (Local time without Z)
outlook_start = start_datetime.isoformat() # Outlook Calendar (ISO local time)
outlook_end = end_datetime.isoformat() # Outlook Calendar (ISO local time)
# Create message object
msg = MIMEMultipart()
msg['From'] = gmail_user
msg['To'] = f"{interviewee_email}, {static_email}"
msg['Subject'] = "Interview Appointment Confirmation"
# Message body
body = f'''
<html lang="en-US">
<head>
<title>Interview Invitation</title>
</head>
<body>
<p>Dear {interviewee_name},</p>
<p>Your interview has been scheduled on {date} at {start_time} MST.</p>
<p> Your interview location is at {location} or will be emailed to you. </p>
<p>Please ensure to be available at the designated time.</p>
<a
href="https://calendar.google.com/calendar/render?action=TEMPLATE&text=UCalgary+Baja+Interview+with+{interviewee_name}&dates={start_time_google}/{end_time_google}&details=Interview+with+UCalgary+Baja+Team&location={location}"
target="_blank"
>
<button type="button" class="AddtoCal">Add to Google Calendar</button>
</a>
<a
href="https://outlook.live.com/calendar/0/deeplink/compose?subject=UCalgary+Baja+Interview+with+{interviewee_name}&body=Interview+with+UCalgary+Baja+Team&location={location}&startdt={outlook_start}&enddt={outlook_end}"
target="_blank"
>
<button type="button" class="AddtoCal">Add to Outlook Calendar</button>
</a>
<p>Best regards,</p>
<p>UCalgary Baja Interview Team</p>
<img
src="https://res.cloudinary.com/dpgrgsh7g/image/upload/v1733003224/UCalgaryBAJA_Logo-2024_mpmljh.png"
alt="UCalgary Baja Team"
height="120svh"
/>
</body>
</html>
'''
msg.attach(MIMEText(body, 'html'))
try:
# Setup the server and send the email
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(gmail_user, gmail_apppassword)
server.sendmail(gmail_user, [interviewee_email, static_email], msg.as_string())
server.quit()
# print(f"Email sent successfully to {interviewee_email} and {static_email}.")
except Exception as e:
print(f"Failed to send email: {e}")
if __name__ == "__main__":
send_email()

View File

@ -0,0 +1,44 @@
import pandas as pd
import yaml
# Load the YAML file
with open("./interview_database.yaml", 'r') as file:
interview_data = yaml.safe_load(file)
# Access the nested structure within 'Data'
flattened_data = []
for date, date_info in interview_data['Data'].items():
meeting_duration = date_info.get('Meeting Duration')
for start_time_info in date_info.get('Meeting Start Times', []):
for start_time, meeting_info in start_time_info.items():
interviewer_name = meeting_info['Interviewer'][0].get('Name')
interviewer_email = meeting_info['Interviewer'][1].get('Email')
interviewee_name = meeting_info['Interviewee'][0].get('Name')
interviewee_email = meeting_info['Interviewee'][1].get('Email')
category = meeting_info.get('Category')
status = meeting_info.get('Status')
slot = meeting_info.get('Slot')
# Add flattened row to list
flattened_data.append({
'Date': date,
'Meeting Duration': meeting_duration,
'Start Time': start_time,
'Interviewer Name': interviewer_name,
'Interviewer Email': interviewer_email,
'Interviewee Name': interviewee_name,
'Interviewee Email': interviewee_email,
'Category': category,
'Status': status,
'Slot': slot
})
# Convert to DataFrame if flattened data is not empty
if flattened_data:
df = pd.DataFrame(flattened_data)
# Write the DataFrame to an Excel file
df.to_excel("interview_database.xlsx", index=False)
print("Data has been written to interview_database.xlsx")
else:
print("No data found to write.")

View File

@ -0,0 +1,11 @@
from WriteDB import AppendAppointment
def TestBookAppointment():
date_1 = "2024-09-16"
start_time_1 = "10:30:00"
interviewee_name_1 = "Alice Johnson"
interviewee_email_1 = "ahmadmuhammadofficial@gmail.com"
print(f"\nTest Case 1: Trying to book {date_1} at {start_time_1} for {interviewee_name_1} ({interviewee_email_1})")
AppendAppointment(date_1, start_time_1, interviewee_name_1, interviewee_email_1)
TestBookAppointment()

View File

@ -0,0 +1,64 @@
Data:
September 16:
Meeting Duration: 30 min
Meeting Start Times:
- 10:00 AM:
Interviewer:
- Name: John
- Email: john@example.com
Interviewee:
- Name: Jane
- Email: jane@example.com
Category: PowerDrive
Status: Done
Slot: 2
- 10:30 AM:
Interviewer:
- Name: Jay
- Email: jay@example.com
Interviewee:
- Name: Zoz
- Email: Zoz@example.com
Category: PowerTrain
Status: Pending
Slot: 3
- 11:00 AM:
Interviewer:
- Name: Ali
- Email: Ali@example.com
Interviewee:
- Name: Bob
- Email: Bob@example.com
Category: Software
Status: Rescheduled
Slot: 1
- 11:30 AM:
Interviewer:
- Name:
- Email:
Interviewee:
- Name:
- Email:
Category:
Status:
Slot: 1
- 12:00 PM:
Interviewer:
- Name: Ali, John
- Email: Ali@example.com, Jhon@example.com
Interviewee:
- Name: Bob
- Email: Bob@example.com
Category: Software
Status: Cancelled
Slot: 1
- 12:30 PM:
Interviewer:
- Name: Ali
- Email: Ali@example.com
Interviewee:
- Name: Bob, Jish
- Email: Bob@example.com, jish@example.com
Category: Software
Status: Cancelled
Slot: 2

Binary file not shown.

View File

@ -0,0 +1,17 @@
import requests
import json
if __name__ == "__main__":
getres = requests.get("http://bajacloud.ddnsking.com:43443/getAppointments")
print(getres)
print(json.dumps(json.loads(getres.text), indent=4))
# example of a request
# postdata = {
# "intervieweeName": "Brock",
# "date": "2024-09-16",
# "startTime": "11:00:00",
# "intervieweeEmail": "darkicewolf50@gmail.com"
# }
# res = requests.post("http://bajacloud.ddnsking.com:43443/SelectInterview", json.dumps(postdata))
# print(res)
# print(res.text)

25
Other Items/testhttp.py Normal file
View File

@ -0,0 +1,25 @@
import json
import requests
import timeit
def BenchMarkServer():
rawRes = requests.get("http://localhost:8080/getAppointments")
res = json.loads(rawRes.text)
print(json.dumps(res, indent=1))
def BenchMarkDjango():
rawRes = requests.get("http://127.0.0.1:8000/getAppointments")
res = json.loads(rawRes.text)
print(json.dumps(res, indent=1))
if __name__ == "__main__":
test = 1
if test:
djangoTime = timeit.timeit(stmt=BenchMarkDjango, number=1000)
# pythonTime = timeit.timeit(stmt=BenchMarkServer, number=10)
print(f"FastAPI: {djangoTime}\nPython: ")
# reqbody = {
# "body": {"message": "hello"}
# }
# rawRes = requests.post("http://localhost:8000/SelectInterview", reqbody)

29
Other Items/web1.html Normal file
View File

@ -0,0 +1,29 @@
<html lang="en-US">
<head>
<title>Interview Invitation</title>
</head>
<body>
<p>Dear {interviewee_name},</p>
<p>Your interview has been scheduled on {date} at {start_time}</p>
<p>Please ensure to be available at the designated time.</p>
<a
href="https://calendar.google.com/calendar/render?action=TEMPLATE&text=Interview+with+{interviewee_name}&dates=20241130T100000Z/20241130T110000Z&details=Interview+with+UCalgary+Baja+Team&location=ENC37"
target="_blank"
>
<button type="button" class="AddtoCal">Add to Google Calendar</button>
</a>
<a
href="https://outlook.live.com/calendar/0/deeplink/compose?subject=Interview+with+{interviewee_name}&body=Interview+with+UCalgary+Baja+Team&location=ENC37&startdt=2024-11-30T10:00:00&enddt=2024-11-30T11:00:00"
target="_blank"
>
<button type="button" class="AddtoCal">Add to Outlook Calendar</button>
</a>
<p>Best regards,</p>
<p>UCalgary Baja Interview Team</p>
<img
src="https://res.cloudinary.com/dpgrgsh7g/image/upload/v1733003224/UCalgaryBAJA_Logo-2024_mpmljh.png"
alt="UCalgary Baja Team"
height="120svh"
/>
</body>
</html>

5
README.MD Normal file
View File

@ -0,0 +1,5 @@
# Deprecaited Moved to Central Repo
Found [Here](https://github.com/UofCBaja/BajaCloud)
Reason in "Baja Data 2024 - 2025/W - Software/Brock's Learning.docx"

View File

@ -1,2 +1,5 @@
# BajaCloud # Deprecaited Moved to Central Repo
The Docker Project that runs on the Baja Nas
Found [Here](https://github.com/UofCBaja/BajaCloud)
Reason in "Baja Data 2024 - 2025/W - Software/Brock's Learning.docx"

BIN
bajacloud.tar.gz Normal file

Binary file not shown.

11
docker-compose.yaml Normal file
View File

@ -0,0 +1,11 @@
services:
bajacloud:
container_name: uofcbajacloud
image: darkicewolf50/uofcbajacloud:latest
ports:
- 43443:8000
volumes:
- ./L - Logistics/Interviews:/Interviews
# networks:
# - testnet
build: . # do not include in delpoyment version

128
main.py Normal file
View File

@ -0,0 +1,128 @@
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from .InterviewBooking.NoSheet import NoSheet
import datetime
import os
year_donation = int(str(datetime.datetime.now().year)[2:]) + 1 # gets the last two digits of the current year then adds 1 for the current season
# name based off the 2025 naming system
# Define the path to the Excel file and the lock file
file_name = f"/Interviews/OR{year_donation}-L-Interview Data.xlsx"
if not os.path.isfile(file_name):
os.makedirs(os.path.dirname(file_name), exist_ok=True)
NoSheet(file_name)
app = FastAPI()
@app.get("/")
def get_root():
"""
This does nothing, allows for pings to check for life
``REQUIRES``: ```None`` Nothing
``PROMISES``: ``JSON`` returns a short message in the body
``Develop in part by``: Brock
``Contact``: darkicewolf50@gmail.com
"""
res = {"message": "Hello I am alive, this does nothing"}
# Return the response with the custom header
return JSONResponse(
headers={
"isBase64Encoded": "false", # Header Modification
},
content={
"body": res # Ensure res is a dict or do json.dumps to enusre it is stringified
},
# status_code=200 commented out just to show how to change it if you wanted
)
from .InterviewBooking.interviewPackagers import getSchedulePackager
@app.get("/getAppointments")
async def getAppointments():
"""
checks for all available slots in the database
``REQUIRES``: ``None`` Nothing
``PROMISES``: ``JSON`` returns all of the avaialbe slots by date then time
``Develop in part by``: Brock
``Contact``: darkicewolf50@gmail.com
"""
res = getSchedulePackager(file_name)
return JSONResponse(
headers={
"isBase64Encoded": "false", # Header Modification
},
content={
"body": res # Ensure res is a dict or do json.dumps to enusre it is stringified
},
# status_code=200 commented out just to show how to change it if you wanted
)
from .InterviewBooking.interviewPackagers import SelectAppointment
class Appointment(BaseModel):
"""
The formatted
``REQUIRES``: Correct Format
``PROMISES``: Formatted class, needs to be converted into dict os that it can be used in another file
``Develop in part by``: Brock
``Contact``: darkicewolf50@gmail.com
"""
intervieweeName: str
date: str
startTime: str
intervieweeEmail: str
@app.post("/SelectInterview")
async def postSelectInterview(rawRequest: Appointment):
"""
Books an interview, first checks if the slot is valid
``REQUIRES``: ``Appointment`` A specifically formatted request
``PROMISES``: ``JSON`` returns if the booking was successful or not
``Develop in part by``: Brock
``Contact``: darkicewolf50@gmail.com
"""
requestDict = {key: str(value) for key, value in rawRequest.dict().items()}
res = SelectAppointment(file_name, requestDict)
return JSONResponse(
headers={
"isBase64Encoded": "false", # Header Modification
},
content={
"body": res # Ensure res is a dict or do json.dumps to enusre it is stringified
},
# status_code=200 commented out just to show how to change it if you wanted
)

5
requirements.txt Normal file
View File

@ -0,0 +1,5 @@
fastapi[standard]
pandas
openpyxl
PyYAML
filelock