diff --git a/Dockerfile b/Dockerfile index 301f637..7eb4f10 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,4 +5,7 @@ WORKDIR /usr/src/app COPY . . +ENV MAX_CONCURRENT_PIP=4 + +RUN pip install --upgrade pip RUN pip install -r requirements.txt diff --git a/T b/T new file mode 100644 index 0000000..e69de29 diff --git a/app.py b/app.py index 68d9798..34dda11 100644 --- a/app.py +++ b/app.py @@ -5,6 +5,8 @@ from src.database import db_session, init_db from src.schema import Query from src.constants import create_gym_table +from src.scrapers.scraper import scrape_classes +from src.scrapers.gym_scraper import scrape_times from src.scrapers.scraper import scrape_classes, scrape_pool_hours @@ -30,6 +32,7 @@ def shutdown_session(exception=None): # Create database and fill it with constants init_db() create_gym_table() +scrape_times() scrape_classes(3) scrape_pool_hours() diff --git a/manager.py b/manager.py index f5815e6..4c58245 100644 --- a/manager.py +++ b/manager.py @@ -1,10 +1,10 @@ import os from flask_script import Manager from flask_migrate import Migrate, MigrateCommand -from app import app, db +from app import app#, db # Build manager -migrate = Migrate(app, db) +#migrate = Migrate(app, db) manager = Manager(app) manager.add_command("db", MigrateCommand) diff --git a/schema.graphql b/schema.graphql index 3747d29..a925801 100644 --- a/schema.graphql +++ b/schema.graphql @@ -25,8 +25,8 @@ type ClassInstance { instructor: String! isCanceled: Boolean! isVirtual: Boolean! - startTime: DateTime! - endTime: DateTime! + startTime: DateTime + endTime: DateTime class_: Class gym: Gym } @@ -64,8 +64,8 @@ type OpenHours { id: ID! facilityId: Int! day: Int! - startTime: String! - endTime: String! + startTime: String + endTime: String } type Query { diff --git a/src/constants.json b/src/constants.json index ecc0439..fdec27f 100644 --- a/src/constants.json +++ b/src/constants.json @@ -63,12 +63,12 @@ "image_url": "gyms/teagle.jpg", "facilities": [ { - "name": "Teagle Up", + "name": "Teagle Upstairs", "type": "fitness", "hours": [] }, { - "name": "Teagle Down", + "name": "Teagle Downstairs", "type": "fitness", "hours": [] }, @@ -80,4 +80,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/src/constants.py b/src/constants.py index 8d6a846..a5fdbb7 100644 --- a/src/constants.py +++ b/src/constants.py @@ -49,6 +49,4 @@ def create_gym_table(): db_session.merge(gym) for facility in facilities: db_session.merge(facility) - for hours in fitness_hours: - db_session.merge(hours) db_session.commit() diff --git a/src/models/activity.py b/src/models/activity.py new file mode 100644 index 0000000..a5e9df6 --- /dev/null +++ b/src/models/activity.py @@ -0,0 +1,33 @@ +from sqlalchemy import Column, Float, String, Integer, ForeignKey, Table +from sqlalchemy.orm import relationship +from src.database import Base + +def Activity(Base): + __tablename__ = 'activity' + + id = Column(Integer, primary_key = True) + name = Column(String, nullable=False) + activity_type = Column(Integer, ForeignKey('activitytype.id'), nullable=False) + facility_id = Column(Integer, ForeignKey('facility.id'), nullable=False) + prices = relationship('Price') + image_url = Column(String(), nullable=False) + + def __init__(self, **kwargs): + self.id = kwargs.get('id') + self.name = kwargs.get('name') + self.activity_type = kwargs.get('activity_type') + self.facility_id = kwargs.get('facility_id') + self.image_url = kwargs.get('image_url') + + +def ActivityType(Base): + __tablename__ = 'activitytype' + + id = Column(Integer, primary_key=True) + name = Column(String, nullable=False) + + def __init__(self, **kwargs): + self.id = kwargs.get('id') + self.name = kwargs.get('name') + + diff --git a/src/models/capacity.py b/src/models/capacity.py index 7810800..009275b 100644 --- a/src/models/capacity.py +++ b/src/models/capacity.py @@ -1,3 +1,4 @@ + from sqlalchemy import Column, ForeignKey, Integer, DateTime, Float from sqlalchemy.orm import backref, relationship from src.database import Base diff --git a/src/models/classes.py b/src/models/classes.py index 0ebc4f6..60e97be 100644 --- a/src/models/classes.py +++ b/src/models/classes.py @@ -43,8 +43,8 @@ class ClassInstance(Base): instructor = Column(String(), nullable=False) isCanceled = Column(Boolean(), nullable=False, default=False) isVirtual = Column(Boolean(), nullable=False, default=False) - start_time = Column(DateTime(), nullable=False) - end_time = Column(DateTime(), nullable=False) + start_time = Column(DateTime(), nullable=True) + end_time = Column(DateTime(), nullable=True) class_ = relationship("Class", back_populates="gyms") gym = relationship("Gym", back_populates="classes") diff --git a/src/models/facility.py b/src/models/facility.py index 5b15ca9..614dee8 100644 --- a/src/models/facility.py +++ b/src/models/facility.py @@ -1,11 +1,13 @@ +import sys +sys.path.append('..') import enum from sqlalchemy import Column, ForeignKey, String, Enum, Integer from sqlalchemy.orm import relationship from src.database import Base -from src.models.openhours import OpenHours from src.models.capacity import Capacity + class FacilityType(enum.Enum): fitness = 0 pool = 1 @@ -23,8 +25,6 @@ class Facility(Base): capacities = relationship("Capacity") # TODO: - Implement the following - # prices = relationship('Price', cascade='delete, all') - # amenities = relationship('Amenity', cascade='delete, all') # image_url = Column(String(1000), nullable=True) def __init__(self, **kwargs): @@ -36,47 +36,36 @@ def __init__(self, **kwargs): # TODO: - Implement the following # self.image_url = kwargs.get("image_url") - def serialize(self): - return { - "id": self.id, - "name": self.name, - "gym_id": self.gym_id, - "facility_type": self.facility_type, - "capacities": self.capacities, - } + # def serialize(self): + # return { + # "id": self.id, + # "name": self.name, + # "gym_id": self.gym_id, + # "facility_type": self.facility_type, + # "capacities": self.capacities, + # } # Left here as a reference for the above TODOs + """ -class Price(Base): - __tablename__ = "price" +class Amenity(Base): + __tablename__ = 'amenity' id = Column(Integer, primary_key=True) - name = Column(String(100), nullable=False) - cost = Column(Integer, nullable=False) - one_time = Column(Boolean, nullable=False) - image_url = Column(String(1000), nullable=True) + name = Column(String(), nullable=False) + image_url = Column(String(), nullable=True) activity_id = Column(Integer, ForeignKey('activity.id'), nullable=False) def __init__(self, **kwargs): self.name = kwargs.get("name") - self.cost = kwargs.get("cost") - self.one_time = kwargs.get("one_time") self.image_url = kwargs.get("image_url") self.activity_id = kwargs.get("activity_id") -class Amenity(Base): - __tablename__ = 'amenity' - - id = Column(Integer, primary_key=True) - name = Column(String(), nullable=False) - image_url = Column(String(), nullable=True) - activity_id = Column(Integer, ForeignKey('activity.id'), nullable=False) - def __init__(self, **kwargs): self.name = kwargs.get("name") self.image_url = kwargs.get("image_url") self.activity_id = kwargs.get("activity_id") -""" +""" \ No newline at end of file diff --git a/src/models/gym.py b/src/models/gym.py index 73c5527..4cb34a0 100644 --- a/src/models/gym.py +++ b/src/models/gym.py @@ -5,7 +5,7 @@ class Gym(Base): - __tablename__ = "gym" + __tablename__ = 'gym' id = Column(Integer, primary_key=True) name = Column(String(100), nullable=False) @@ -13,8 +13,8 @@ class Gym(Base): facilities = relationship("Facility") classes = relationship("ClassInstance", back_populates="gym") - # TODO: - Complete capacity table - # capacity = relationship('Capacity', cascade='delete, all') + # TODO: - complete amenities table and scraper + # # amenities = relationship('Amenity', cascade='delete, all') location = Column(String(1000), nullable=False) latitude = Column(Float, nullable=False) diff --git a/src/models/openhours.py b/src/models/openhours.py index a56e3f4..a76f2bd 100644 --- a/src/models/openhours.py +++ b/src/models/openhours.py @@ -1,5 +1,5 @@ import enum -from sqlalchemy import Column, ForeignKey, Integer, Float, Time, String, Table, Enum +from sqlalchemy import Column, ForeignKey, Integer, Float, String, Time, String, Table, Enum from sqlalchemy.orm import backref, relationship from src.database import Base @@ -15,8 +15,8 @@ class OpenHours(Base): id = Column(Integer, primary_key=True) facility_id = Column(Integer, ForeignKey("facility.id"), nullable=False) day = Column(Integer, nullable=False) # 0=Monday, 5=Weekend - start_time = Column(Time(), nullable=False) - end_time = Column(Time(), nullable=False) + start_time = Column(Time(), nullable=True) + end_time = Column(Time(), nullable=True) # TODO: - Handle restrictions and special hours restrictions = relationship("Restrictions", secondary=openhours_restrictions, back_populates="openhours") # special_hours = Column(Boolean, nullable=False) diff --git a/src/models/price.py b/src/models/price.py new file mode 100644 index 0000000..3f35a61 --- /dev/null +++ b/src/models/price.py @@ -0,0 +1,20 @@ +from database import Base +from sqlalchemy import Column, String, Integer, ForeignKey, Boolean +from sqlalchemy.orm import relationship + +class Price(Base): + __tablename__ = "price" + + id = Column(Integer, primary_key=True) + name = Column(String(), nullable=False) + cost = Column(Integer, nullable=False) + one_time = Column(Boolean, nullable=False) + activity_id = Column(Integer, ForeignKey('activity.id'), nullable=False) + + def __init__(self, **kwargs): + self.id = kwargs.get('id') + self.name = kwargs.get("name") + self.cost = kwargs.get("cost") + self.one_time = kwargs.get("one_time") + self.activity_id = kwargs.get('activity_id') + diff --git a/src/scrapers/__init__.py b/src/scrapers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/c2c_scraper.py b/src/scrapers/c2c_scraper.py similarity index 100% rename from c2c_scraper.py rename to src/scrapers/c2c_scraper.py diff --git a/src/scrapers/gym_scraper.py b/src/scrapers/gym_scraper.py index 39c0c10..9bdcb25 100644 --- a/src/scrapers/gym_scraper.py +++ b/src/scrapers/gym_scraper.py @@ -1,19 +1,16 @@ import sys sys.path.append('..') -from database import db_session +from src.database import db_session from bs4 import BeautifulSoup import requests -from models.facility import Facility, FacilityType -from models.openhours import OpenHours -from models.gym import Gym +from src.models.facility import Facility, FacilityType +from src.models.openhours import OpenHours +from src.models.gym import Gym +from datetime import datetime as dt -# BASE_URL = 'https://scl.cornell.edu/recreation' BASE_URL_CENTERS = 'https://scl.cornell.edu/recreation/cornell-fitness-centers' -NEWMAN = 'https://scl.cornell.edu/recreation/facility/helen-newman-fitness-center' -result = requests.get(BASE_URL_CENTERS).text - - -def create_openhours(times_set, name, start_day, end_day): + +def create_openhours(times_set, name, begin_day, end_day): for time in times_set: times = time.strip().split('-') times = [t.strip() for t in times] @@ -22,42 +19,56 @@ def create_openhours(times_set, name, start_day, end_day): if len(times) != 2: continue - am = times[0].lower().find('am') != -1 - stime_loc = times[0].lower().find('am') if am else times[0].lower().find('pm') - etime_loc = times[1].lower().find('am') if am else times[1].lower().find('pm') + am_st = times[0].lower().find('am') != -1 + am_e = times[1].lower().find('am') != -1 + stime_loc = times[0].lower().find('am') if am_st else times[0].lower().find('pm') + etime_loc = times[1].lower().find('am') if am_e else times[1].lower().find('pm') start = times[0][:stime_loc].strip() - start = start + 'am' if am else start + 'pm' + start = start + 'AM' if am_st else start + 'PM' end = times[1][:etime_loc].strip() - end = end + 'am' if am else end + 'pm' + end = end + 'AM' if am_e else end + 'PM' + - #get facility id for specific fitness center - gym = db_session.query(Gym).filter(Gym.name == name).first() - facility = db_session.query(Facility).filter(Facility.gym_id == gym.id).first() + facility = db_session.query(Facility).filter(Facility.name == name).first() #put an open hour for each day: 1 = Monday, 2 = Tuesday, etc. - for i in range(start_day, end_day): + for i in range(begin_day, end_day): + # if int(start[0]) < 10: + # start = '0' + start + # if int(end[0]) < 10: + # end = '0' + end + if ':' in start: + st_obj = dt.strptime(start, "%I:%M%p") + else: + st_obj = dt.strptime(start, "%I%p") + if ':' in end: + end_obj = dt.strptime(end, "%I:%M%p") + else: + end_obj = dt.strptime(end, "%I%p") try: - hour = db_session.query(OpenHours).filter(OpenHours.facility_id==facility.id, OpenHours.day == i, OpenHours.start_time == start, OpenHours.end_time == end).first() + hour = db_session.query(OpenHours).filter(OpenHours.facility_id==facility.id, OpenHours.day == i, OpenHours.start_time == st_obj.time(), OpenHours.end_time == end_obj.time()).first() assert hour is not None except AssertionError: - hour = OpenHours(facility_id=facility.id, day=i, start_time=start, end_time=end) + + hour = OpenHours(facility_id=facility.id, day=i, start_time=st_obj.time(), end_time=end_obj.time(), restrictions=[]) db_session.add(hour) db_session.commit() -days_to_nums = { - 'monday': 1, - 'tuesday': 2, - 'wednesday': 3, - 'thursday': 4, - 'friday': 5, - 'saturday': 6, - 'sunday': 7, -} - -#finding the days - (for break hours this is necessary) -def convert_days(data): +def get_days(data): + days_to_nums = { + 'monday': 0, + 'tuesday': 1, + 'wednesday': 2, + 'thursday': 3, + 'friday': 4, + 'saturday': 5, + 'sunday': 6, + } + + + #finding the days - (for break hours this is necessary) day_set = data[0].find_all('th')[1:] day_set = [days.text.strip().split('-') for days in day_set] @@ -71,32 +82,47 @@ def convert_days(data): for day in days: converted.append(days_to_nums[day.strip().lower()]) if len(converted == 1): - converted.append(converted[0]+1) + converted.append(converted[0]) + converted[-1] += 1 day_set[i] = converted - return day_set + +def create_times(day_set, data): + for row in data[1:]: + row_data = row.find_all('td') + name = row_data[0].text.strip() + row_data= row_data[1:] + + k = 0 + for i in range(len(row_data)): + colspan = 1 + if 'colspan' in row_data[i].attrs: + colspan = row_data[i].attrs['colspan'] + + begin_day = day_set[k][0] + for j in range(colspan): + end_day = day_set[k][1] + k += 1 + times = row_data[i].text.strip().split('/') -page = requests.get(BASE_URL_CENTERS).text -soup = BeautifulSoup(page, 'lxml') -table = soup.find('table', class_='colored striped') -data = table.find_all('tr') + create_openhours(times, name, begin_day, end_day) -day_set = convert_days(data) +def scrape_times(): + page = requests.get(BASE_URL_CENTERS).text + soup = BeautifulSoup(page, 'lxml') + table = soup.find('table', class_='colored striped') + data = table.find_all('tr') -for row in data[1:]: - row_eles = row.find_all('td') - name = row_eles[0].text.strip() + d_set = get_days(data) + create_times(d_set, data) - for element in row_eles: - if int(element.attr.colspan) > 1: - + - for i in range(1, len(day_set)+1): - times = row_eles[i].text.strip().split('/') - create_openhours(times, name, day_set[i-1][0], day_set[i-1][1]) + + diff --git a/src/scrapers/scraper.py b/src/scrapers/scraper.py index 947b515..097b2f5 100644 --- a/src/scrapers/scraper.py +++ b/src/scrapers/scraper.py @@ -86,16 +86,18 @@ def scrape_classes(num_pages): # special handling for time (cancelled) time_str = row_elems[3].string.replace("\n", "").strip() - if time_str != "" and "Canceled" not in time_str: + if time_str != "" and time_str != 'Canceled': class_instance.is_canceled = False time_strs = time_str.split(" - ") start_time_string = time_strs[0].strip() + # print(start_time_string) end_time_string = time_strs[1].strip() + # print(end_time_string) class_instance.start_time = datetime.strptime(f"{date_string} {start_time_string}", "%m/%d/%Y %I:%M%p") class_instance.end_time = datetime.strptime(f"{date_string} {end_time_string}", "%m/%d/%Y %I:%M%p") else: - class_instance.is_canceled = True + class_instance.isCanceled = True try: class_instance.instructor = row_elems[4].a.string diff --git a/src/uplift/database.py b/src/uplift/database.py new file mode 100644 index 0000000..ab905d4 --- /dev/null +++ b/src/uplift/database.py @@ -0,0 +1,234 @@ +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import scoped_session, sessionmaker +import datetime + +ASSET_BASE_URL = "https://raw.githubusercontent.com/cuappdev/assets/master/uplift/" + +engine = create_engine("sqlite:///database.sqlite3") +db_session = scoped_session( + sessionmaker(autocommit=False, autoflush=False, bind=engine) +) +Base = declarative_base() +Base.query = db_session.query_property() + +def init_db(): + """ + Initialize database for uplift. + """ + # import all modules that might define models so they will be registered properly + # on metadata - otherwise import them first before calling init_db() + Base.metadata.create_all(bind=engine) + def init_db(): + # import all modules that might define models so they will be registered properly + # on metadata - otherwise import them first before calling init_db() + from models.gym import Gym, GymTime + from models.daytime import DayTime + from models.activity import Activity, Amenity, ActivityPrice + from models.price import Price + from models.facility import Facility, FacilityTime, Equipment, FacilityPrice + + Base.metadata.drop_all(bind=engine) + Base.metadata.create_all(bind=engine) + + gym_1 = Gym(name='Helen Newman', description='Something', + location='North', image_url='something') + db_session.add(gym_1) + daytime_1 = DayTime(day=1, start_time=datetime.datetime.utcnow( + ), end_time=datetime.datetime.utcnow(), restrictions='None', special_hours=True) + db_session.add(daytime_1) + db_session.commit() + + gymtime_1 = GymTime(daytime_id=daytime_1.id, gym_id=gym_1.id) + db_session.add(gymtime_1) + db_session.commit() + + activity_1 = Activity( + name='Volleyball', details='It fun', image_url='None') + db_session.add(activity_1) + db_session.commit() + + # adding the gym Helen Newman to the activity Volleyball + activity_1.gyms.append(gym_1) + db_session.add(activity_1) + db_session.commit() + + price_1 = Price(name="price1", cost=20, one_time=False, image_url="none") + db_session.add(price_1) + db_session.commit() + + price_2 = Price(name="price2", cost=40, one_time=True, image_url="n/a") + db_session.add(price_2) + db_session.commit() + + price_3=Price(name="price3", cost=50, one_time=False, image_url="none") + price_4=Price(name="price4", cost=15, one_time=False, image_url="n/a") + db_session.add(price_3) + db_session.add(price_4) + db_session.commit() + + activityprice_1 = ActivityPrice(activity_id=activity_1.id, price_id=price_1.id) + activityprice_2=ActivityPrice(activity_id=activity_1.id, price_id=price_2.id) + db_session.add(activityprice_1) + db_session.add(activityprice_2) + db_session.commit() + + + amenity_1 = Amenity(name="locker", image_url="none", activity_id=activity_1.id) + db_session.add(amenity_1) + db_session.commit() + activity_1.amenities.append(amenity_1) + db_session.add(activity_1) + db_session.commit() + + facility_1 = Facility(name="basketball court", image_url="None") + db_session.add(facility_1) + db_session.commit() + + facility_2 = Facility(name="beach volleyball court", image_url="N/A") + db_session.add(facility_2) + db_session.commit() + + facilitytime_1 = FacilityTime(facility_id=facility_1.id, daytime_id=daytime_1.id) + db_session.add(facilitytime_1) + db_session.commit() + + facilityprice_1 = FacilityPrice(facility_id=facility_1.id, price_id=price_3.id) + facilityprice_2 = FacilityPrice(facility_id=facility_1.id, price_id=price_4.id) + db_session.add(facilityprice_1) + db_session.add(facilityprice_2) + db_session.commit() + + equipment_1 = Equipment(equipment_type="Exercise machine", name="Squat Rack 1", quantity=2, facility_id=facility_1.id, image_url="n/a") + db_session.add(equipment_1) + db_session.commit() + + equipment_2 = Equipment(equipment_type="Exercise thingy", name="Dumbbell", quantity=20, facility_id=facility_1.id, image_url="none") + db_session.add(equipment_2) + db_session.commit() + + gym_2 = Gym(name="Morrison", description="Nicer", + location="North", image_url="N/A") + db_session.add(gym_2) + daytime_2 = DayTime(day=2, start_time=datetime.datetime.utcnow( + ), end_time=datetime.datetime.utcnow(), restrictions="A few", special_hours=False) + db_session.add(daytime_2) + db_session.commit() + + facilitytime_2 = FacilityTime(facility_id=facility_2.id, daytime_id=daytime_2.id) + db_session.add(facilitytime_2) + db_session.commit() + + gymtime_2 = GymTime(daytime_id=daytime_2.id, gym_id=gym_2.id) + db_session.add(gymtime_2) + db_session.commit() + + activity_2 = Activity(name="Dancing", details="more fun", image_url="No") + db_session.add(activity_2) + db_session.commit() + + activity_2.gyms.append(gym_1) + activity_2.gyms.append(gym_2) + db_session.add(activity_2) + db_session.commit() + + + +""" +Initialize basic information for all five fitness centers +(Helen Newman...Teagle Down) with location, hours, images. +""" +def create_gym_table(): + # import all modules that might define models so they will be registered properly + # on metadata - otherwise import them first before calling init_db() + from models.gym import Gym, GymTime + from models.daytime import DayTime + from models.capacity import Capacity + + helen_newman = Gym( + id=1, + name='Helen Newman', + description='description', + location='123 Cradit Farm Road', + latitude=42.454342, + longitude=-76.473618, + image_url=ASSET_BASE_URL + 'gyms/helen-newman.jpg' + ) + + toni_morrison = Gym( + id=2, + name = 'Toni Morrison', + description='description', + location='18 Sisson Place', + latitude=0.00, + longitude=0.00, + image_url = ASSET_BASE_URL + 'gyms/toni-morrison-outside-min.jpeg' + ) + + noyes = Gym( + id=3, + name='Noyes', + description='description', + location='306 West Avenue', + latitude=0.0, + longitude=0.0, + image_url=ASSET_BASE_URL + 'gyms/noyes.jpg' + ) + + teagle_up = Gym( + id=4, + name='Teagle Up', + description='description', + location='512 Campus Road', + latitude=0.0, + longitude=0.0, + image_url=ASSET_BASE_URL + 'gyms/teagle.jpg' + ) + + teagle_down = Gym( + id=5, + name='Teagle Down', + description='description', + location='512 Campus Road', + latitude=0.0, + longitude=0.0, + image_url=ASSET_BASE_URL + 'gyms/teagle.jpg' + ) + + gyms = [ + helen_newman, + noyes, + # morrison, + teagle_up, + teagle_down + ] + + for gym in gyms: + db_session.merge(gym) + +def create_activities_table(): + from models.activity import Activity, Amenity + from models.daytime import DayTime + + basketball = Activity(name = "Basketball", + details="details", + image_url="None" + ) + + beach_volleyball = Activity( + name="Beach Volleyball", + details="details", + image_url="N/A" + ) + + activities = [ + basketball, + beach_volleyball + ] + + for act in activities: + db_session.merge(act) + + + + diff --git a/src/uplift/database.sqlite3 b/src/uplift/database.sqlite3 new file mode 100644 index 0000000..b9e8615 Binary files /dev/null and b/src/uplift/database.sqlite3 differ diff --git a/src/uplift/models/gym.py b/src/uplift/models/gym.py new file mode 100644 index 0000000..495ba08 --- /dev/null +++ b/src/uplift/models/gym.py @@ -0,0 +1,49 @@ +import datetime +from database import Base +from sqlalchemy import Column, DateTime, ForeignKey, Integer, Float, String, Boolean, func +from sqlalchemy.orm import backref, relationship +from models.facility import Facility +from models.activity import activities_to_gyms + +class Gym(Base): + __tablename__ = "gym" + + id = Column(Integer, primary_key=True) + name = Column(String(), nullable=False) + description = Column(String(), nullable=False) + activities = relationship( + 'Activity', secondary=activities_to_gyms, back_populates="gyms") + facilities = relationship('Facility', cascade='delete, all') + times = relationship('GymTime', cascade='delete, all') + capacity = relationship('Capacity', cascade='delete, all') + location = Column(String(), nullable=False) + latitude = Column(Integer, nullable=False) + longitude = Column(Float, nullable=False) + image_url = Column(String(), nullable=True) + + def __init__(self, **kwargs): + self.id = kwargs.get("id") + self.name = kwargs.get("name") + self.description = kwargs.get("description") + self.location = kwargs.get("location") + self.latitude = kwargs.get('latitude') + self.longitude = kwargs.get('longitude') + self.image_url = kwargs.get("image_url") + + +class GymTime(Base): + __tablename__ = 'gymtime' + + id = Column(Integer, primary_key=True) + daytime_id = Column(Integer, ForeignKey('daytime.id'), nullable=False) + gym_id = Column(Integer, ForeignKey('gym.id'), nullable=False) + + def __init__(self, **kwargs): + self.daytime_id = kwargs.get("daytime_id") + self.gym_id = kwargs.get("gym_id") + + def serialize(self): + return { + "daytime_id": self.daytime_id, + "gym_id": self.gym_id + } diff --git a/src/uplift/schema.py b/src/uplift/schema.py index 104631a..0a0cde6 100644 --- a/src/uplift/schema.py +++ b/src/uplift/schema.py @@ -1,213 +1,90 @@ -import datetime as dt -from socketserver import StreamRequestHandler -from xml.sax.handler import property_declaration_handler -from graphene import Field, ObjectType, String, List, Int, Boolean -from graphene.types.datetime import Date, Time -from models.gym import Gym as GymModel, GymTime as GymTimeModel -# from models.daytime import DayTime as DayTimeModel -from models.activity import Activity as ActivityModel, ActivityPrice as ActivityPriceModel -from models.capacity import Capacity as CapacityModel -from models.activity import Amenity as AmenityModel -from models.price import Price as PriceModel -from models.facility import Facility as FacilityModel, FacilityPrice as FacilityPriceModel, Equipment as EquipmentModel, FacilityTime as FacilityTimeModel import graphene -from graphene import relay -from graphene_sqlalchemy import SQLAlchemyConnectionField, SQLAlchemyObjectType -from sqlalchemy import desc +from graphene import ObjectType +from graphene_sqlalchemy import SQLAlchemyObjectType +from src.models.capacity import Capacity as CapacityModel +from src.models.facility import Facility as FacilityModel +from src.models.gym import Gym as GymModel +from src.models.openhours import OpenHours as OpenHoursModel +from src.models.classes import Class as ClassModel +from src.models.classes import ClassInstance as ClassInstanceModel + + +# MARK: - Gym class Gym(SQLAlchemyObjectType): class Meta: model = GymModel - times = graphene.List(lambda: DayTime, day=graphene.Int(), start_time=graphene.DateTime( - ), end_time=graphene.DateTime(), restrictions=graphene.String(), special_hours=graphene.Boolean()) - activities = graphene.List(lambda: Activity, name=graphene.String()) - capacities = graphene.List(lambda: Capacity, gym_id=graphene.Int()) - - @staticmethod - def resolve_times(self, info, day=None, start_time=None, end_time=None): - query = GymTime.get_query(info=info) - query = query.filter(GymTimeModel.gym_id == self.id) - query_daytime = DayTime.get_query(info=info) # could be wrong - if day: - query_daytime = query_daytime.filter(DayTimeModel.day == day) - if start_time: - query_daytime = query_daytime.filter(DayTimeModel.start_time == start_time) - if end_time: - query_daytime = query_daytime.filter(DayTimeModel.end_time == end_time) - - daytime_queries = [] - for row in query: - daytime = query_daytime.filter(DayTimeModel.id == row.daytime_id) - if daytime.first(): - daytime_queries.append(daytime[0]) - - return daytime_queries - - def resolve_activities(self, info, name=None): - query = Activity.get_query(info=info) - activity_queries = [] - for act in self.activities: - activity = query.filter(ActivityModel.id == act.id) - if activity.first() and (name == act.name or name == None): - activity_queries.append(activity[0]) - return activity_queries - - @staticmethod - def resolve_capacities(self, info, gym_id=None): - query = Capacity.get_query(info=info) \ - .filter(CapacityModel.gym_id == self.id) \ - .order_by(desc(CapacityModel.updated)) - - return [query.first()] - -class DayTime(SQLAlchemyObjectType): - class Meta: - model = DayTimeModel + facilities = graphene.List(lambda: Facility) -class GymTime(SQLAlchemyObjectType): - class Meta: - model = GymTimeModel + def resolve_facilities(self, info): + query = Facility.get_query(info=info).filter(FacilityModel.gym_id == self.id) + return query -class Activity(SQLAlchemyObjectType): - class Meta: - model = ActivityModel - gyms = graphene.List(lambda: Gym, name=graphene.String()) - prices = graphene.List(lambda: Price, cost=graphene.Int(), one_time=graphene.Boolean()) +# MARK: - Facility - def resolve_gyms(self, info, name=None): - query = Gym.get_query(info=info) - gym_queries = [] - for g in self.gyms: - gym = query.filter(GymModel.id == g.id) - if gym.first() and (name == g.name or name == None): - gym_queries.append(gym[0]) - return gym_queries +class Facility(SQLAlchemyObjectType): + class Meta: + model = FacilityModel - @staticmethod - def resolve_prices(self, info, name=None, cost=None): - query = ActivityPrice.get_query(info=info) - query = query.filter(ActivityPriceModel.activity_id == self.id) - query_price = Price.get_query(info=info) + open_hours = graphene.List(lambda: OpenHours, name=graphene.String()) + capacity = graphene.Field(lambda: Capacity) - if name: - query_price = query_price.filter(PriceModel.name == name) - if cost: - query_price = query_price.filter(PriceModel.cost == cost) + def resolve_open_hours(self, info): + query = OpenHours.get_query(info=info).filter(OpenHoursModel.facility_id == self.id) + return query - price_queries = [] - for row in query: - price = query_price.filter(PriceModel.id == row.price_id) + def resolve_capacity(self, info): + query = ( + Capacity.get_query(info=info) + .filter(CapacityModel.facility_id == self.id) + .order_by(CapacityModel.updated.desc()) + .first() + ) + return query - if price.first(): - price_queries.append(price[0]) - return price_queries +# MARK: - Classes -class Capacity(SQLAlchemyObjectType): +class Class(SQLAlchemyObjectType): class Meta: - model = CapacityModel + model = ClassModel -class Price(SQLAlchemyObjectType): +class ClassInstance(SQLAlchemyObjectType): class Meta: - model = PriceModel + model = ClassInstanceModel -class ActivityPrice(SQLAlchemyObjectType): - class Meta: - model = ActivityPriceModel +# MARK: - Open Hours -class Facility(SQLAlchemyObjectType): +class OpenHours(SQLAlchemyObjectType): class Meta: - model = FacilityModel - - @staticmethod - def resolve_times(self, info, day=None, start_time=None, end_time=None): - query = FacilityTime.get_query(info=info) - query = query.filter(FacilityTimeModel.facilty_id == self.id) - query_daytime = DayTime.get_query(info=info) + model = OpenHoursModel - if day: - query_datytime = query_daytime.filter(DayTimeModel.day == day) - if start_time: - query_daytime = query_daytime.filter(DayTimeModel.start_time == start_time) - if end_time: - query_daytime = query_daytime.filter(DayTimeModel.end_time == end_time) - daytime_queries = [] - for row in query: - daytime = query_daytime.filter(DayTimeModel.id == row.daytime_id) - if daytime.first(): - daytime_queries.append(daytime[0]) +# MARK: - Capacity - return daytime_queries - @staticmethod - def resolve_price(self, info, name=None, cost=None): - query = FacilityPrice.get_query(info=info) - query = query.filter(FacilityPriceModel.facility_id == self.id) - query_price = Price.get_query(info=info) - - if name: - query_price = query_price.filter(PriceModel.name == name) - if cost: - query_price = query_price.filter(PriceModel.cost == cost) - - price_queries = [] - for row in query: - price = query_price.filter(PriceModel.id == row.price_id) - - if price.first(): - price_queries.append(price[0]) - - return price_queries - -class FacilityTime(SQLAlchemyObjectType): +class Capacity(SQLAlchemyObjectType): class Meta: - model = FacilityTimeModel + model = CapacityModel -class FacilityPrice(SQLAlchemyObjectType): - class Meta: - model = FacilityPriceModel -class Equipment(SQLAlchemyObjectType): - class Meta: - model = EquipmentModel +# MARK: - Query -class Amenity(SQLAlchemyObjectType): - class Meta: - model = AmenityModel class Query(graphene.ObjectType): + gyms = graphene.List(Gym) - gyms = graphene.List(lambda: Gym, - id=graphene.Int(), - name=graphene.String(), - description=graphene.String(), - location=graphene.String(), - latitude=graphene.Float(), - longitude=graphene.Float(), - image_url=graphene.String()) - - def resolve_gyms(self, info, name=None): + def resolve_gyms(self, info): query = Gym.get_query(info) - if name: - query = query.filter(GymModel.name == name) return query.all() - activities = graphene.List(lambda: Activity, name=graphene.String( - ), details=graphene.String(), image_url=graphene.String()) - - def resolve_activities(self, info, name=None): - query = Activity.get_query(info) - if name: - query = query.filter(ActivityModel.name == name) - return query.all() -schema = graphene.Schema(query=Query) +schema = graphene.Schema(query=Query) \ No newline at end of file