Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
acbdad5
initial commit
Mar 19, 2025
b015ef7
resolve merge conflicts
Mar 19, 2025
447c1f9
add migration file
Mar 19, 2025
d5c5854
Added friends storing
JoshD94 Mar 23, 2025
ce5b415
updates
Mar 28, 2025
a9849a4
typo
sophiestrausberg Mar 28, 2025
fad12b4
add comment
sophiestrausberg Mar 28, 2025
3856881
Merge pull request #203 from cuappdev/sophie/capacity-reminders
sophiestrausberg Mar 28, 2025
5d401d0
Update requirements.txt
sophiestrausberg Mar 28, 2025
a6aa4c4
Merge pull request #204 from cuappdev/Update-firebase-admin,-google-a…
sophiestrausberg Mar 29, 2025
5b855d0
Merge branch 'friends' of https://github.com/cuappdev/uplift-backend …
JoshD94 Mar 29, 2025
e0c6f8f
Solved merge conflicts
JoshD94 Mar 29, 2025
347205e
Changed back run migrations to be false
JoshD94 Mar 29, 2025
dd10ac1
initial commit
Apr 12, 2025
56975a0
Merge pull request #206 from cuappdev/capacity-reminders
sophiestrausberg Apr 15, 2025
e938396
Finally added friends
JoshD94 Apr 16, 2025
9148130
Removed random migration file
JoshD94 Apr 16, 2025
a8d4bf0
Removed space
JoshD94 Apr 16, 2025
df17198
Added space
JoshD94 Apr 16, 2025
159a0d2
Removed tabs
JoshD94 Apr 16, 2025
70389bf
Merge pull request #198 from cuappdev/friends
JoshD94 Apr 16, 2025
275d5d5
Added merging migration
JoshD94 Apr 16, 2025
9b1c12d
Merge pull request #207 from cuappdev/friends
JoshD94 Apr 16, 2025
dda3884
Removed duplicate file and fixed merge migration
JoshD94 Apr 16, 2025
c6558e9
Merge pull request #208 from cuappdev/friends
JoshD94 Apr 16, 2025
7240065
Fixed special hours bug (9am-9am)
thesinglecaskdev Apr 23, 2025
a2ee9ec
Added unchecked get/get all queries
JoshD94 Apr 23, 2025
81eb8d8
Exclude fcm token from schema
JoshD94 Apr 23, 2025
19ebfdb
Merge pull request #209 from cuappdev/spechour-bug
JoshD94 Apr 24, 2025
65d1af8
Merge pull request #210 from cuappdev/capacityreminder-query
JoshD94 Apr 28, 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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ build/
Archive
scripts
*.sqlite3
service-account-key.json
service-account-key.json
docker-compose.yml
19 changes: 17 additions & 2 deletions app_factory.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import logging
from datetime import timedelta, timezone
from flask_jwt_extended import JWTManager
from src.utils.constants import SERVICE_ACCOUNT_PATH, JWT_SECRET_KEY
from datetime import datetime
from flask import Flask, render_template
from graphene import Schema
from graphql.utils import schema_printer
from src.utils.constants import JWT_SECRET_KEY
from src.database import db_session, init_db
from src.database import Base as db
from src.database import db_url, db_user, db_password, db_name, db_host, db_port
Expand All @@ -14,6 +14,20 @@
from flasgger import Swagger
from flask_graphql import GraphQLView
from src.models.token_blacklist import TokenBlocklist
import firebase_admin
from firebase_admin import credentials

def initialize_firebase():
if not firebase_admin._apps:
if SERVICE_ACCOUNT_PATH:
cred = credentials.Certificate(SERVICE_ACCOUNT_PATH)
firebase_app = firebase_admin.initialize_app(cred)
else:
raise ValueError("GOOGLE_SERVICE_ACCOUNT_PATH environment variable not set.")
else:
firebase_app = firebase_admin.get_app()
logging.info("Firebase app created...")
return firebase_app


# Set up logging at module level
Expand All @@ -32,6 +46,7 @@ def create_app(run_migrations=False):
Configured Flask application
"""
logger.info("Initializing application")
initialize_firebase()

# Create and configure Flask app
app = Flask(__name__)
Expand All @@ -56,7 +71,7 @@ def create_app(run_migrations=False):
schema = Schema(query=Query, mutation=Mutation)
swagger = Swagger(app)

app.config["JWT_SECRET_KEY"] = JWT_SECRET_KEY
app.config['JWT_SECRET_KEY'] = JWT_SECRET_KEY
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(hours=1)
app.config["JWT_REFRESH_TOKEN_EXPIRES"] = timedelta(days=30)

Expand Down
24 changes: 24 additions & 0 deletions migrations/versions/3c406131c004_merge_branches.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""merge branches

Revision ID: 3c406131c004
Revises: 7a3c14648e56
Create Date: 2025-03-29 00:36:22.980924

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '3c406131c004'
down_revision = '7a3c14648e56'
branch_labels = None
depends_on = None


def upgrade():
pass


def downgrade():
pass
68 changes: 68 additions & 0 deletions migrations/versions/7a3c14648e56_add_capacity_reminder_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""add capacity reminder model

Revision ID: 7a3c14648e56
Revises: add99ce06ff5
Create Date: 2025-03-19 17:32:02.592027

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql


# revision identifiers, used by Alembic.
revision = '7a3c14648e56'
down_revision = 'add99ce06ff5'
branch_labels = None
depends_on = None

capacity_reminder_gym_enum = postgresql.ENUM(
'TEAGLEUP', 'TEAGLEDOWN', 'HELENNEWMAN', 'TONIMORRISON', 'NOYES',
name='capacityremindergym', create_type=False
)

day_of_week_enum = postgresql.ENUM(
'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday',
name='dayofweekenum', create_type=False
)

def upgrade():
op.execute("""
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'capacity_reminder') THEN
CREATE TABLE capacity_reminder (
id SERIAL PRIMARY KEY,
fcm_token VARCHAR NOT NULL,
gyms capacityremindergym[] NOT NULL,
capacity_threshold INTEGER NOT NULL,
days_of_week dayofweekenum[] NOT NULL,
is_active BOOLEAN DEFAULT TRUE NOT NULL
);
END IF;
END $$;
""")


def downgrade():
op.execute("""
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'capacity_reminder') THEN
DROP TABLE capacity_reminder;
END IF;
END $$;
""")

op.execute("""
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM pg_type WHERE typname = 'capacityremindergym')
AND NOT EXISTS (
SELECT 1 FROM pg_attribute
WHERE atttypid = (SELECT oid FROM pg_type WHERE typname = 'capacityremindergym')
) THEN
DROP TYPE capacityremindergym CASCADE;
END IF;
END $$ LANGUAGE plpgsql;
""")
36 changes: 36 additions & 0 deletions migrations/versions/add_friends_table_migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Add friends table

Revision ID: add_friends_table
Revises: 3c406131c004
Create Date: 2025-03-29 00:55:00.000000

"""
from alembic import op
import sqlalchemy as sa
from datetime import datetime


# revision identifiers, used by Alembic.
revision = 'add_friends_table'
down_revision = '3c406131c004'
branch_labels = None
depends_on = None


def upgrade():
# Create friends table
op.create_table('friends',
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('friend_id', sa.Integer(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=True, server_default=sa.text('CURRENT_TIMESTAMP')),
sa.Column('is_accepted', sa.Boolean(), nullable=True, server_default=sa.text('false')),
sa.Column('accepted_at', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['friend_id'], ['users.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('user_id', 'friend_id')
)


def downgrade():
# Drop friends table
op.drop_table('friends')
5 changes: 3 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Flask-Script==2.0.5
Flask-SQLAlchemy==2.3.1
Flask-RESTful==0.3.10
flasgger==0.9.7.1
google-auth==1.12.0
google-auth==2.14.1
graphene==2.1.3
graphene-sqlalchemy==2.3.0
graphql-core==2.1
Expand Down Expand Up @@ -79,4 +79,5 @@ wcwidth==0.2.6
Werkzeug==2.2.2
zipp==3.15.0
sentry-sdk==2.13.0
flask_jwt_extended==4.7.1
flask_jwt_extended==4.7.1
firebase-admin==6.4.0
59 changes: 59 additions & 0 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,23 @@ type Capacity {
updated: Int!
}

type CapacityReminder {
id: ID!
fcmToken: String!
gyms: [CapacityReminderGym]!
capacityThreshold: Int!
daysOfWeek: [DayOfWeekEnum]!
isActive: Boolean
}

enum CapacityReminderGym {
TEAGLEUP
TEAGLEDOWN
HELENNEWMAN
TONIMORRISON
NOYES
}

type Class {
id: ID!
name: String!
Expand Down Expand Up @@ -71,6 +88,16 @@ type CreateReport {

scalar DateTime

enum DayOfWeekEnum {
MONDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY
SATURDAY
SUNDAY
}

enum DayOfWeekGraphQLEnum {
MONDAY
TUESDAY
Expand Down Expand Up @@ -109,6 +136,21 @@ enum FacilityType {
COURT
}

type Friendship {
id: ID!
userId: Int!
friendId: Int!
createdAt: DateTime
isAccepted: Boolean
acceptedAt: DateTime
user: User
friend: User
}

type GetPendingFriendRequests {
pendingRequests: [Friendship]
}

type Giveaway {
id: ID!
name: String!
Expand Down Expand Up @@ -184,6 +226,13 @@ type Mutation {
refreshAccessToken: RefreshAccessToken
createReport(createdAt: DateTime!, description: String!, gymId: Int!, issue: String!): CreateReport
deleteUser(userId: Int!): User
createCapacityReminder(capacityPercent: Int!, daysOfWeek: [String]!, fcmToken: String!, gyms: [String]!): CapacityReminder
editCapacityReminder(capacityPercent: Int!, daysOfWeek: [String]!, gyms: [String]!, reminderId: Int!): CapacityReminder
deleteCapacityReminder(reminderId: Int!): CapacityReminder
addFriend(friendId: Int!, userId: Int!): Friendship
acceptFriendRequest(friendshipId: Int!): Friendship
removeFriend(friendId: Int!, userId: Int!): RemoveFriend
getPendingFriendRequests(userId: Int!): GetPendingFriendRequests
}

type OpenHours {
Expand Down Expand Up @@ -215,6 +264,7 @@ enum PriceType {
type Query {
getAllGyms: [Gym]
getUserByNetId(netId: String): [User]
getUsersFriends(id: Int): [User]
getUsersByGiveawayId(id: Int): [User]
getWeeklyWorkoutDays(id: Int): [String]
getWorkoutsById(id: Int): [Workout]
Expand All @@ -223,12 +273,17 @@ type Query {
getWorkoutGoals(id: Int!): [String]
getUserStreak(id: Int!): JSONString
getHourlyAverageCapacitiesByFacilityId(facilityId: Int): [HourlyAverageCapacity]
getUserFriends(userId: Int!): [User]
}

type RefreshAccessToken {
newAccessToken: String
}

type RemoveFriend {
success: Boolean
}

type Report {
id: ID!
createdAt: DateTime!
Expand Down Expand Up @@ -256,6 +311,10 @@ type User {
workoutGoal: [DayOfWeekGraphQLEnum]
encodedImage: String
giveaways: [Giveaway]
friendRequestsSent: [Friendship]
friendRequestsReceived: [Friendship]
friendships: [Friendship]
friends: [User]
}

type Workout {
Expand Down
27 changes: 27 additions & 0 deletions src/models/capacity_reminder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from sqlalchemy import Column, Integer, ForeignKey, ARRAY, Boolean, Table, String
from sqlalchemy.orm import relationship
from sqlalchemy import Enum as SQLAEnum
from src.models.enums import DayOfWeekEnum, CapacityReminderGym
from src.database import Base

class CapacityReminder(Base):
"""
A capacity reminder for an Uplift user.
Attributes:
- `id` The ID of the capacity reminder.
- `fcm_token` FCM token used to send notifications to the user's device.
- `user_id` The ID of the user who owns this reminder.
- `gyms` The list of gyms the user wants to monitor for capacity.
- `capacity_threshold` Notify user when gym capacity dips below this percentage.
- `days_of_week` The days of the week when the reminder is active.
- `is_active` Whether the reminder is currently active (default is True).
"""

__tablename__ = "capacity_reminder"

id = Column(Integer, primary_key=True)
fcm_token = Column(String, nullable=False)
gyms = Column(ARRAY(SQLAEnum(CapacityReminderGym)), nullable=False)
capacity_threshold = Column(Integer, nullable=False)
days_of_week = Column(ARRAY(SQLAEnum(DayOfWeekEnum)), nullable=False)
is_active = Column(Boolean, default=True)
16 changes: 15 additions & 1 deletion src/models/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,18 @@ class DayOfWeekGraphQLEnum(GrapheneEnum):
THURSDAY = "THURSDAY"
FRIDAY = "FRIDAY"
SATURDAY = "SATURDAY"
SUNDAY = "SUNDAY"
SUNDAY = "SUNDAY"

class CapacityReminderGym(enum.Enum):
TEAGLEUP = "TEAGLEUP"
TEAGLEDOWN = "TEAGLEDOWN"
HELENNEWMAN = "HELENNEWMAN"
TONIMORRISON = "TONIMORRISON"
NOYES = "NOYES"

class CapacityReminderGymGraphQLEnum(GrapheneEnum):
TEAGLEUP = "TEAGLEUP"
TEAGLEDOWN = "TEAGLEDOWN"
HELENNEWMAN = "HELENNEWMAN"
TONIMORRISON = "TONIMORRISON"
NOYES = "NOYES"
Loading
Loading