Skip to content

Commit

Permalink
Merge pull request #148 from cuappdev/master
Browse files Browse the repository at this point in the history
Merge to prod
  • Loading branch information
vinnie4k authored Apr 15, 2024
2 parents 459a2cb + 3c1a9aa commit 716e93c
Show file tree
Hide file tree
Showing 13 changed files with 651 additions and 19 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,22 @@ on:
jobs:
build:
runs-on: ubuntu-latest

services:
postgres:
image: postgres:latest
env:
POSTGRES_DB: uplift
POSTGRES_PASSWORD: password
POSTGRES_USER: local
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v1
- uses: actions/setup-python@v1
Expand All @@ -22,8 +38,17 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install libxml2-dev libxslt-dev
sudo apt-get install --yes --no-install-recommends postgresql-client
pip install --force-reinstall pip==20.0.2
pip install --force-reinstall setuptools==44.0.0
pip freeze
pip install -r requirements.txt
python -m unittest src.tests.test_scraper
env:
DB_HOST: localhost
DB_NAME: uplift
DB_PORT: 5432
DB_PASSWORD: password
DB_USERNAME: local
FLASK_ENV: dev
GOOGLE_SERVICE_ACCOUNT_PATH: service-account-key.json
18 changes: 16 additions & 2 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@
from graphene import Schema
from graphql.utils import schema_printer
from src.database import db_session, init_db
from src.schema import Query
from src.schema import Query, Mutation
from src.scrapers.capacities_scraper import fetch_capacities
from src.scrapers.reg_hours_scraper import fetch_reg_building, fetch_reg_facility
from src.scrapers.scraper_helpers import clean_past_hours
from src.scrapers.sp_hours_scraper import fetch_sp_facility
from src.scrapers.equipment_scraper import scrape_equipment
from src.scrapers.class_scraper import fetch_classes
from src.utils.utils import create_gym_table
from src.models.openhours import OpenHours


app = Flask(__name__)
app.debug = True
schema = Schema(query=Query)
schema = Schema(query=Query, mutation=Mutation)

# Scheduler
scheduler = APScheduler()
Expand Down Expand Up @@ -45,6 +47,9 @@ def shutdown_session(exception=None):
def scrape_hours():
logging.info("Scraping hours from sheets...")

# Clear hours
db_session.query(OpenHours).delete()

fetch_reg_facility()
fetch_reg_building()
fetch_sp_facility()
Expand All @@ -59,9 +64,18 @@ def scrape_capacities():
fetch_capacities()


# Scrape classes every hour
@scheduler.task("interval", id="scrape_classes", seconds=3600)
def scrape_classes():
logging.info("Scraping classes from group-fitness-classes...")

fetch_classes(3)


# Create database and fill it with data
init_db()
create_gym_table()
scrape_classes()
scrape_hours()
scrape_capacities()
scrape_equipment()
Expand Down
70 changes: 68 additions & 2 deletions schema.graphql
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
schema {
query: Query
mutation: Mutation
}

enum AccessibilityType {
WHEELCHAIR
}

type Activity {
id: ID!
facilityId: Int!
gymId: Int!
hasMembership: Boolean!
name: String!
needsReserve: Boolean!
pricing: [Price]
}

type Amenity {
id: ID!
gymId: Int!
Expand Down Expand Up @@ -33,6 +44,18 @@ enum CourtType {
BADMINTON
}

type CreateGiveaway {
giveaway: Giveaway
}

type CreateUser {
user: User
}

type EnterGiveaway {
giveawayInstance: GiveawayInstance
}

type Equipment {
id: ID!
name: String!
Expand All @@ -57,9 +80,10 @@ type Facility {
facilityType: FacilityType!
gymId: Int!
name: String!
activities: [Activity]
capacity: Capacity
hours: [OpenHours]
equipment: [Equipment]
hours: [OpenHours]
}

enum FacilityType {
Expand All @@ -69,18 +93,38 @@ enum FacilityType {
COURT
}

type Giveaway {
id: ID!
name: String!
users: [User]
}

type GiveawayInstance {
id: ID!
userId: Int!
giveawayId: Int!
numEntries: Int!
}

type Gym {
id: ID!
address: String!
imageUrl: String
latitude: Float!
longitude: Float!
name: String!
activities: [Activity]
amenities: [Amenity]
facilities: [Facility]
hours: [OpenHours]
}

type Mutation {
createGiveaway(name: String!): CreateGiveaway
createUser(netId: String!): CreateUser
enterGiveaway(giveawayId: Int!, userNetId: String!): EnterGiveaway
}

type OpenHours {
id: ID!
courtType: CourtType
Expand All @@ -93,6 +137,28 @@ type OpenHours {
startTime: Int!
}

type Price {
id: ID!
activityId: Int!
name: String!
cost: Float!
rate: String
type: PriceType!
}

enum PriceType {
RATE
GEAR
}

type Query {
gyms: [Gym]
getAllGyms: [Gym]
getUsersByGiveawayId(id: Int): [User]
activities: [Activity]
}

type User {
id: ID!
netId: String!
giveaways: [Giveaway]
}
8 changes: 3 additions & 5 deletions src/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker

# engine = create_engine("sqlite:///database.sqlite3")

db_user = os.environ.get("DB_USERNAME")
db_password = os.environ.get("DB_PASSWORD")
db_name = os.environ.get("DB_NAME")
db_host = os.environ.get("DB_HOST")
db_port = os.environ.get("DB_PORT")

db_url = f"postgresql://{db_user}:{db_password}@{db_host}:{db_port}/{db_name}"
engine = create_engine(db_url) # Soley for temp dev testing
engine = create_engine(db_url)
db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))

Base = declarative_base()
Expand All @@ -23,8 +21,8 @@ def init_db():
"""
Initialize database for Uplift.
"""
# Clear all tables and then repopulate
logging.info("Initializing database")
Base.metadata.drop_all(bind=engine)

# Load initial data
Base.metadata.create_all(bind=engine)
db_session.commit()
99 changes: 99 additions & 0 deletions src/models/activity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import enum
from sqlalchemy import Column, Integer, String, ForeignKey, Boolean, Float, Enum
from sqlalchemy.orm import relationship
from src.database import Base


class PriceType(enum.Enum):
"""
An enumeration representing a price type.
"""

rate = 0
gear = 1


class Activity(Base):
"""
Activity provided by a recreation center.
Attributes:
- `id` The ID of this activity.
- `facility_id` The ID of the facility this activity belongs to.
- `gym_id` The ID of the gym this activity belongs to.
- `has_membership True if this activity is available with memberships.
- `name` The name of this activity.
- `needs_reserve` True if this activity requires group reservation.
- `pricing` (nullable) This activity's pricing.
"""

__tablename__ = "activity"

id = Column(Integer, primary_key=True)
facility_id = Column(Integer, ForeignKey("facility.id"), nullable=False)
gym_id = Column(Integer, ForeignKey("gym.id"), nullable=False)
has_membership = Column(Boolean, nullable=False)
name = Column(String, nullable=False)
needs_reserve = Column(Boolean, nullable=False)
pricing = relationship("Price", cascade="delete")

def __init__(self, **kwargs):
self.id = kwargs.get("id")
self.facility_id = kwargs.get("facility_id")
self.gym_id = kwargs.get("gym_id")
self.has_membership = kwargs.get("has_membership")
self.name = kwargs.get("name")
self.needs_reserve = kwargs.get("needs_reserve")

def serialize(self):
return {
"id": self.id,
"facility_id": self.facility_id,
"gear": self.gear,
"gym_id": self.gym_id,
"has_membership": self.has_membership,
"name": self.name,
"needs_reserve": self.needs_reserve,
"pricing": self.pricing,
}


class Price(Base):
"""
The price of a gear or pricing option.
Attributes:
- `id` The ID of this price.
- `activity_id` The ID of the activity this price belongs to.
- `name` The name associated with this price.
- `cost` The cost of this price.
- `rate` (nullable) The pricing rate of this price.
= `type` The type of this price.
"""

__tablename__ = "gear"

id = Column(Integer, primary_key=True)
activity_id = Column(Integer, ForeignKey("activity.id"), nullable=False)
name = Column(String, nullable=False)
cost = Column(Float, nullable=-False)
rate = Column(String)
type = Column(Enum(PriceType), nullable=False)

def __init__(self, **kwargs):
self.id = kwargs.get("id")
self.activity_id = kwargs.get("activity_id")
self.name = kwargs.get("name")
self.cost = kwargs.get("price")
self.rate = kwargs.get("rate")
self.type = kwargs.get("type")

def serialize(self):
return {
"id": self.id,
"activity_id": self.activity_id,
"name": self.name,
"cost": self.cost,
"rate": self.rate,
"type": self.type,
}
Loading

0 comments on commit 716e93c

Please sign in to comment.