class Like(db.Model): __tablename__ = 'Like' liker_id = db.Column( db.Integer, db.ForeignKey( 'Customer.id', ondelete="CASCADE" ), primary_key=True ) liker = relationship( 'Customer', back_populates='likes' ) restaurant_id = db.Column( db.Integer, db.ForeignKey( 'Restaurant.id', ondelete="CASCADE" ), primary_key=True ) restaurant = relationship( 'Restaurant', back_populates='likes' ) timestamp = db.Column(db.DateTime, default=datetime.datetime.utcnow) def __init__(self, *args, **kw): super(Like, self).__init__(*args, **kw)
class RestaurantRating(db.Model): MIN_VALUE = 0 MAX_VALUE = 10 __tablename__ = 'RestaurantRating' REVIEW_MAX_LENGTH = 200 customer_id = db.Column(db.Integer, db.ForeignKey('Customer.id'), primary_key=True) customer = relationship('Customer', back_populates='ratings') restaurant_id = db.Column(db.Integer, db.ForeignKey('Restaurant.id'), primary_key=True) restaurant = relationship('Restaurant', back_populates='ratings') value = db.Column(db.SmallInteger, nullable=False) review = db.Column(db.String(length=REVIEW_MAX_LENGTH, ), nullable=True) timestamp = db.Column(db.DateTime, default=datetime.datetime.utcnow) def __init__(self, customer_id, restaurant_id, value: int, review=None): self.customer_id = customer_id self.restaurant_id = restaurant_id self.value = value self.review = review @staticmethod def check_value(value: int): if value < RestaurantRating.MIN_VALUE or value > RestaurantRating.MAX_VALUE: raise ValueError('Invalid value for rating!') @staticmethod def check_review(review: str): if len(review) > RestaurantRating.REVIEW_MAX_LENGTH: raise ValueError( 'Review\'s length must not be greater than MAX_SIZE') def set_value(self, value): RestaurantRating.check_value(value) self.value = value def set_review(self, review): RestaurantRating.check_review(review) self.review = review def get_how_long_ago(self): return timeago.format(datetime.datetime.now(), self.timestamp)
class Authority(User): __tablename__ = 'Authority' id = db.Column(db.Integer, db.ForeignKey('User.id', ondelete="CASCADE"), primary_key=True) name = db.Column(db.Unicode(128)) city = db.Column(db.Unicode(128)) address = db.Column(db.Unicode(128)) phone = db.Column(db.Unicode(128)) __mapper_args__ = { 'polymorphic_identity': 'authority', } def __init__(self, *args, **kw): super(Authority, self).__init__(*args, **kw) self._authenticated = False
class Table(db.Model): __tablename__ = 'Table' MIN_TABLE_CAPACITY = 1 MAX_TABLE_CAPACITY = 15 id = db.Column(db.Integer, primary_key=True, autoincrement=True) restaurant_id = db.Column(db.Integer, db.ForeignKey('Restaurant.id', ondelete="CASCADE")) restaurant = relationship('Restaurant', back_populates="tables") capacity = db.Column(db.Integer) def __init__(self, capacity, restaurant): self.capacity = capacity self.restaurant = restaurant def set_capacity(self, capacity): if capacity < self.MIN_TABLE_CAPACITY or capacity > self.MAX_TABLE_CAPACITY: raise ValueError('You can\'t set a negative value, zero or greater than ' + str(self.MAX_TABLE_CAPACITY)) self.capacity = capacity def set_restaurant(self, restaurant): self.restaurant = restaurant
class Operator(User): __tablename__ = 'Operator' id = db.Column(db.Integer, db.ForeignKey('User.id', ondelete='CASCADE'), primary_key=True) __mapper_args__ = { 'polymorphic_identity': 'operator', } def __init__(self, *args, **kw): super(Operator, self).__init__(*args, **kw) self._authenticated = False def new_notifications(self): return 0
class Operator(User): __tablename__ = 'Operator' id = db.Column(db.Integer, db.ForeignKey('User.id', ondelete='CASCADE'), primary_key=True) restaurant = relationship('Restaurant', uselist=False, back_populates="owner") __mapper_args__ = { 'polymorphic_identity': 'operator', } def __init__(self, *args, **kw): super(Operator, self).__init__(*args, **kw) self._authenticated = False def set_restaurant(self, restaurant): self.restaurant = restaurant def new_notifications(self): return 0
class User(UserMixin, db.Model): __tablename__ = 'User' id = db.Column(db.Integer, primary_key=True, autoincrement=True) email = db.Column(db.Unicode(128), nullable=False, unique=True) password = db.Column(db.Unicode(128)) is_active = db.Column(db.Boolean, default=True) is_admin = db.Column(db.Boolean, default=False) authenticated = db.Column(db.Boolean, default=True) is_anonymous = False type = db.Column(db.Unicode(128)) __mapper_args__ = {'polymorphic_identity': 'user', 'polymorphic_on': type} def __init__(self, *args, **kw): super(User, self).__init__(*args, **kw) self.authenticated = False def set_password(self, password): self.password = generate_password_hash(password) def set_email(self, email): self.email = email def is_authenticated(self): return self.authenticated def authenticate(self, password): checked = check_password_hash(self.password, password) self.authenticated = checked return self.authenticated def is_lha(self): return self.type == 'authority' def is_rest_operator(self): return self.type == 'operator' def is_customer(self): return self.type == 'customer'
class Reservation(db.Model): __tablename__ = 'Reservation' MAX_TIME_RESERVATION = 3 id = db.Column(db.Integer, primary_key=True, autoincrement=True) user_id = db.Column(db.Integer, db.ForeignKey('User.id', ondelete="CASCADE")) user = relationship('User', foreign_keys='Reservation.user_id') table_id = db.Column(db.Integer, db.ForeignKey('Table.id', ondelete="CASCADE")) table = relationship('Table') restaurant_id = db.Column(db.Integer, db.ForeignKey('Restaurant.id')) restaurant = relationship("Restaurant", back_populates="reservations") timestamp = db.Column(db.DateTime, default=datetime.utcnow) people_number = db.Column(db.Integer) start_time = db.Column(db.DateTime) end_time = db.Column(db.DateTime) is_confirmed = db.Column(db.Boolean, default=False) def __init__(self, user, table, restaurant, people_number, start_time): self.user = user self.table = table self.restaurant = restaurant self.people_number = people_number self.start_time = start_time self.set_end_time_by_avg_stay(restaurant.avg_stay) @staticmethod def check_time(start_time, end_time): actual_time = datetime.utcnow() if start_time >= end_time: raise ValueError('The start time cannot be greater than end_time') def set_end_time_by_avg_stay(self, avg_stay): if avg_stay is None or avg_stay == 0: self.end_time = self.start_time + timedelta( hours=self.MAX_TIME_RESERVATION) else: avg_stay = self.restaurant.avg_stay h_avg_stay = avg_stay // 60 m_avg_stay = avg_stay - (h_avg_stay * 60) self.end_time = self.start_time + timedelta(hours=h_avg_stay, minutes=m_avg_stay) def set_user(self, user): self.user = user def set_table(self, table): self.table = table def set_restaurant(self, restaurant): self.restaurant = restaurant def set_people_number(self, people_number): self.people_number = people_number def set_start_time(self, start_time): self.start_time = start_time self.set_end_time(start_time + timedelta(hours=self.MAX_TIME_RESERVATION)) def set_end_time(self, end_time): Reservation.check_time(self.start_time, end_time) self.end_time = end_time def set_is_confirmed(self): self.is_confirmed = True
class Restaurant(db.Model): __tablename__ = 'Restaurant' MAX_STRING_LENGTH = 100 # taken from Google Maps bounds MAX_LAT = 90 MIN_LAT = -90 MAX_LON = 180 MIN_LON = -180 MAX_PHONE_LEN = 25 id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(length=MAX_STRING_LENGTH)) address = db.Column(db.String(length=MAX_STRING_LENGTH)) city = db.Column(db.String(length=MAX_STRING_LENGTH)) lat = db.Column(db.Float) lon = db.Column(db.Float) phone = db.Column(db.String(length=MAX_PHONE_LEN)) menu_type = db.Column(db.String(length=MAX_STRING_LENGTH)) measures = db.Column(db.Unicode(), default="") is_open = db.Column(db.Boolean, default=False) owner_id = db.Column( db.Integer, db.ForeignKey('Operator.id'), ) avg_stay = db.Column(db.Integer, ) owner = relationship('Operator', back_populates='restaurant') reservations = relationship("Reservation", back_populates="restaurant") tables = relationship("Table", back_populates="restaurant") availabilities = relationship("RestaurantAvailability", back_populates="restaurant") ratings = relationship('RestaurantRating', back_populates='restaurant') likes = relationship('Like', back_populates='restaurant') def __init__(self, name, address, city, lat, lon, phone, menu_type): Restaurant.check_phone_number(phone) self.name = name self.address = address self.city = city self.lat = lat self.lon = lon self.phone = phone self.menu_type = menu_type self.avg_stay = 0 # this can be set to False by LHA self.is_open = True @staticmethod def check_phone_number(phone): if len(phone) > Restaurant.MAX_PHONE_LEN or len(phone) <= 0: raise ValueError("Invalid phone number") @staticmethod def check_string_attribute(string_attribute): if len(string_attribute) > Restaurant.MAX_STRING_LENGTH or len( string_attribute) <= 0: raise ValueError("Invalid attribute length") def set_name(self, name): Restaurant.check_string_attribute(name) self.name = name def set_address(self, address): Restaurant.check_string_attribute(address) self.address = address location = geolocator.geocode(address + " " + self.city) lat = 0 lon = 0 if location is not None: lat = location.latitude lon = location.longitude self.set_lat(lat) self.set_lon(lon) def set_city(self, city): Restaurant.check_string_attribute(city) self.city = city location = geolocator.geocode(self.address + " " + city) lat = 0 lon = 0 if location is not None: lat = location.latitude lon = location.longitude self.set_lat(lat) self.set_lon(lon) def set_lat(self, lat): if self.MIN_LAT <= lat <= self.MAX_LAT: self.lat = lat else: raise ValueError("Invalid latitude value") def set_lon(self, lon): if self.MIN_LON <= lon <= self.MAX_LON: self.lon = lon else: raise ValueError("Invalid longitude value") def set_phone(self, phone): Restaurant.check_phone_number(phone) self.phone = phone def set_menu_type(self, menu_type): Restaurant.check_string_attribute(menu_type) self.menu_type = menu_type def set_measures(self, measure): self.measures = measure def set_is_open(self, is_open): self.is_open = is_open def likes_count(self): return len(self.likes) def set_avg_stay(self, avg_stay): self.avg_stay = avg_stay def is_open_date(self, when=datetime.datetime.now()): for av in self.availabilities: if av.day == av.week_days[when.weekday()]: if av.start_time < when.time() < av.end_time: return True and self.is_open return False
class Reservation(db.Model): __tablename__ = 'Reservation' MAX_TIME_RESERVATION = 3 id = db.Column(db.Integer, primary_key=True, autoincrement=True) user_id = db.Column(db.Integer) table_id = db.Column(db.Integer) restaurant_id = db.Column(db.Integer) timestamp = db.Column(db.DateTime, default=datetime.utcnow) people_number = db.Column(db.Integer) start_time = db.Column(db.DateTime) end_time = db.Column(db.DateTime) is_confirmed = db.Column(db.Boolean, default=False) def serialize(self): def r(v): if type(v) == datetime: return v.__str__() else: return v return dict([(k, r(v)) for k, v in self.__dict__.items() if k[0] != '_']) def __init__(self, user_id, table_id, restaurant_id, people_number, start_time): self.user_id = user_id self.table_id = table_id self.restaurant_id = restaurant_id self.people_number = people_number self.start_time = start_time self.end_time = self.start_time + timedelta( hours=self.MAX_TIME_RESERVATION) # self.set_end_time_by_avg_stay(restaurant_id.avg_stay) @staticmethod def check_time(start_time, end_time): actual_time = datetime.utcnow() if start_time >= end_time: raise ValueError('The start time cannot be greater than end_time') """ def set_end_time_by_avg_stay(self, avg_stay): if avg_stay is None or avg_stay == 0: self.end_time = self.start_time + timedelta(hours=self.MAX_TIME_RESERVATION) else: avg_stay = self.restaurant_id.avg_stay h_avg_stay = avg_stay//60 m_avg_stay = avg_stay - (h_avg_stay*60) self.end_time = self.start_time + timedelta(hours=h_avg_stay, minutes=m_avg_stay) """ def set_user_id(self, user_id): self.user_id = user_id def set_table_id(self, table_id): self.table_id = table_id def set_restaurant_id(self, restaurant_id): self.restaurant_id = restaurant_id def set_people_number(self, people_number): self.people_number = people_number def set_start_time(self, start_time): self.start_time = start_time self.set_end_time(start_time + timedelta(hours=self.MAX_TIME_RESERVATION)) def set_end_time(self, end_time): Reservation.check_time(self.start_time, end_time) self.end_time = end_time def set_is_confirmed(self): self.is_confirmed = True
class Customer(User): SOCIAL_CODE_LENGTH = 16 __tablename__ = 'Customer' MAX_PHONE_LEN = 25 id = db.Column(db.Integer, db.ForeignKey('User.id', ondelete="CASCADE"), primary_key=True) firstname = db.Column(db.Unicode(128)) lastname = db.Column(db.Unicode(128)) birthdate = db.Column(db.Date) social_number = db.Column(db.Unicode(SOCIAL_CODE_LENGTH), default="") health_status = db.Column(db.Boolean, default=False) phone = db.Column(db.String(length=MAX_PHONE_LEN)) likes = relationship('Like', back_populates='liker') ratings = relationship('RestaurantRating', back_populates='customer') last_notification_read_time = db.Column(db.DateTime, default=datetime.utcnow) __mapper_args__ = { 'polymorphic_identity': 'customer', } def __init__(self, *args, **kw): super(Customer, self).__init__(*args, **kw) self._authenticated = False @staticmethod def check_phone_number(phone): if len(phone) > Customer.MAX_PHONE_LEN or len(phone) <= 0: raise ValueError("Invalid phone number") def set_phone(self, phone): Customer.check_phone_number(phone) self.phone = phone def set_firstname(self, name): self.firstname = name def set_lastname(self, name): self.lastname = name def set_birthday(self, birthday): self.birthdate = birthday def set_health_status(self, status): self.health_status = status @staticmethod def check_social_number(social_number): if len(social_number) != Customer.SOCIAL_CODE_LENGTH: raise ValueError("Invalid Social Number length") def set_social_number(self, social_number): Customer.check_social_number(social_number) self.social_number = social_number def set_last_notification_read_time(self, read_time): self.last_notification_read_time = read_time def new_notifications(self): return 0
class User(db.Model): __tablename__ = 'User' SERIALIZE_LIST = ['id', 'email', 'is_active', 'authenticated', 'is_anonymous', 'type'] id = db.Column(db.Integer, primary_key=True, autoincrement=True) email = db.Column(db.Unicode(128), nullable=False, unique=True) password = db.Column(db.Unicode(128)) is_active = db.Column(db.Boolean, default=True) is_admin = db.Column(db.Boolean, default=False) authenticated = db.Column(db.Boolean, default=True) is_anonymous = False type = db.Column(db.Unicode(128)) __mapper_args__ = { 'polymorphic_identity': 'user', 'polymorphic_on': type } def __init__(self, *args, **kw): super(User, self).__init__(*args, **kw) self.authenticated = False def set_password(self, password): self.password = generate_password_hash(password) def set_email(self, email): self.email = email def is_authenticated(self): return self.authenticated def authenticate(self, password): checked = check_password_hash(self.password, password) self.authenticated = checked return self.authenticated def is_lha(self): return self.type == 'authority' def is_rest_operator(self): return self.type == 'operator' def is_customer(self): return self.type == 'customer' # def encode_auth_token(self, user_id): # """ # Generates the Auth Token # :return: string # """ # try: # payload = { # "iss": JWT_ISSUER, # "iat": datetime.datetime.utcnow(), # "exp": datetime.datetime.utcnow() + datetime.timedelta(seconds=JWT_LIFETIME_SECONDS), # "sub": str(user_id), # } # return jwt.encode( # payload, # JWT_SECRET, # algorithm=JWT_ALGORITHM # ) # except Exception as e: # return e # # @staticmethod # def decode_auth_token(auth_token): # """ # Decodes the auth token # :param auth_token: # :return: integer|string # """ # try: # return jwt.decode(auth_token, JWT_SECRET, algorithms=[JWT_ALGORITHM]) # except jwt.ExpiredSignatureError: # return 'Signature expired. Please log in again.' # except jwt.InvalidTokenError: # return 'Invalid token. Please log in again.' def serialize(self): return dict([(k, self.__getattribute__(k)) for k in self.SERIALIZE_LIST])
class Customer(User): __tablename__ = 'Customer' MAX_PHONE_LEN = 25 SOCIAL_CODE_LENGTH = 16 LIST = [ 'firstname', 'lastname', 'birthdate', 'social_number', 'health_status', 'phone' ] id = db.Column(db.Integer, db.ForeignKey('User.id', ondelete="CASCADE"), primary_key=True) firstname = db.Column(db.Unicode(128)) lastname = db.Column(db.Unicode(128)) birthdate = db.Column(db.Date) social_number = db.Column(db.Unicode(SOCIAL_CODE_LENGTH), default="") health_status = db.Column(db.Boolean, default=False) health_status_change_datetime = db.Column(db.DateTime, default=datetime.utcnow) phone = db.Column(db.String(length=MAX_PHONE_LEN)) last_notification_read_time = db.Column(db.DateTime, default=datetime.utcnow) __mapper_args__ = { 'polymorphic_identity': 'customer', } def __init__(self, *args, **kw): super(Customer, self).__init__(*args, **kw) self._authenticated = False @staticmethod def check_phone_number(phone): if len(phone) > Customer.MAX_PHONE_LEN or len(phone) <= 0: raise ValueError("Invalid phone number") def set_phone(self, phone): Customer.check_phone_number(phone) self.phone = phone def set_firstname(self, name): self.firstname = name def set_lastname(self, name): self.lastname = name def set_birthday(self, birthday): self.birthdate = birthday def set_health_status(self, status): self.health_status = status if self.health_status: self.health_status_change_datetime = datetime.utcnow() @staticmethod def check_social_number(social_number): if len(social_number) != Customer.SOCIAL_CODE_LENGTH: raise ValueError("Invalid Social Number length") def set_social_number(self, social_number): Customer.check_social_number(social_number) self.social_number = social_number def set_last_notification_read_time(self, read_time): self.last_notification_read_time = read_time def serialize(self): p_ser = dict([(k, self.__getattribute__(k)) for k in self.SERIALIZE_LIST]) c_ser = dict([(k, self.__getattribute__(k)) for k in self.LIST]) return dict(c_ser, **p_ser)