Exemple #1
0
class Message(db.Model):
    """An individual message ("warble")."""

    __tablename__ = 'messages'

    id = db.Column(
        db.Integer,
        primary_key=True,
    )

    text = db.Column(
        db.String(140),
        nullable=False,
    )

    timestamp = db.Column(
        db.DateTime,
        nullable=False,
        default=datetime.utcnow(),
    )

    user_id = db.Column(
        db.Integer,
        db.ForeignKey('users.id', ondelete='CASCADE'),
        nullable=False,
    )

    user = db.relationship('User')

    def __repr__(self):
        return f"<Message #{self.id}: u_id={self.user_id}>"
Exemple #2
0
class Delivery(db.Model):
    """A single delivery"""
    __tablename__ = "deliveries"
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    driver_id = db.Column(db.Integer, db.ForeignKey(
        'users.id', ondelete='CASCADE'))
    driver = db.relationship('User',
                             backref='deliveries')
    orders = db.relationship('Order',
                             backref='delivery')

    @classmethod
    def save_delivery(cls, delivery, driver_id, api_id):
        date = delivery['date']
        store = delivery['store']
        orders = delivery['orders']
        old_deliveries = set()

        delivery = Delivery(driver_id=driver_id)
        db.session.add(delivery)
        db.session.commit()
        ######
        # A little wasteful, good optimization possibility, I think
        for order in orders:
            # maybe change this to a hash of the phone and address
            customer_id = Customer.make_id_from_phone(order['phone'])
            customer = Customer.create_or_get(
                id=customer_id)
            # name = order['name'].split(' ')[0]

            db_order = Order.get(order['num'], date, store, api_id)
            if db_order:
                old_deliveries.add(db_order.del_id)
                db_order.del_id = delivery.id
                db_order.driver_id = driver_id
                db_order.cust_id = customer_id
            else:
                db_order = Order(
                    num=order['num'],
                    date=date,
                    store=store,
                    api_id=api_id,
                    del_id=delivery.id,
                    cust_id=customer_id,
                    driver_id=driver_id)
            db.session.add(db_order)
        db.session.commit()

        Delivery.dispose_of_empty_dels(old_deliveries)
        return delivery

    @classmethod
    def dispose_of_empty_dels(cls, del_ids):
        for del_id in del_ids:
            d = cls.query.get(del_id)
            if len(d.orders) == 0:
                db.session.delete(d)
        db.session.commit()
Exemple #3
0
class Like(db.Model):
    """Mapping user likes to warbles."""

    __tablename__ = 'likes'

    id = db.Column(db.Integer, primary_key=True)

    user_id = db.Column(db.Integer,
                        db.ForeignKey('users.id', ondelete='cascade'))

    message_id = db.Column(db.Integer,
                           db.ForeignKey('messages.id', ondelete='cascade'),
                           unique=True)
Exemple #4
0
class Note(db.Model):
    """A single note"""
    __tablename__ = "notes"
    cust_id = db.Column(db.String(32),
                        db.ForeignKey('customers.id', ondelete='CASCADE'),
                        primary_key=True)
    driver_id = db.Column(db.Integer,
                          db.ForeignKey('users.id', ondelete='CASCADE'),
                          primary_key=True)
    note = db.Column(db.Text, nullable=False)

    driver = db.relationship('User', backref='notes')

    customer = db.relationship('Customer', backref='notes')

    def serialize(self):
        return {
            "cust_id": self.cust_id,
            "driver_id": self.driver_id,
            "note": self.note
        }

    @classmethod
    def get(cls, cust_id, driver_id):
        return cls.query.get((cust_id, driver_id))

    @classmethod
    def delete(cls, cust_id, driver_id):
        note = cls.get(cust_id=cust_id, driver_id=driver_id)
        if note:
            db.session.delete(note)
            db.session.commit()
            return True
        else:
            return False

    @classmethod
    def create_or_update_note(cls, cust_id, driver_id, new_note):
        try:
            note = cls.get(cust_id=cust_id, driver_id=driver_id)
            if note:
                note.note = new_note
            else:
                note = cls(cust_id=cust_id, driver_id=driver_id, note=new_note)

            db.session.add(note)
            db.session.commit()
            return note
        except:
            db.session.rollback()
            return False
Exemple #5
0
class Follow(db.Model):
    """Connection of a follower <-> followed_user."""

    __tablename__ = 'follows'

    user_being_followed_id = db.Column(
        db.Integer,
        db.ForeignKey('users.id', ondelete="cascade"),
        primary_key=True,
    )

    user_following_id = db.Column(
        db.Integer,
        db.ForeignKey('users.id', ondelete="cascade"),
        primary_key=True,
    )
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)

    def __init__(self, username):
        self.username = username

    def __repr__(self):
        return "<User %r>" % self.username

    def json(self):
        return {"username": self.username}


# if __name__ == "__main__":
#     db.create_all()
#     db.session.commit()
Exemple #7
0
class Customer(db.Model):
    """A single customer"""
    __tablename__ = "customers"
    id = db.Column(db.String(32), primary_key=True)
    name = db.Column(db.Text)
    phone = db.Column(db.Text)
    address = db.Column(db.Text)

    def serialize(self):
        return {
            "id": self.id,
            "name": self.name,
            "phone": self.phone,
            "address": self.address,
            "notes": [n.serialize() for n in self.notes]
        }

    def has_note_from(self, user_id):
        for note in self.notes:
            if note.driver_id == user_id:
                return True
        return False

    @classmethod
    def make_id_from_phone(cls, phone):
        return hashlib.md5(phone.encode()).hexdigest()

    @classmethod
    def create_or_get(cls, id, name=None, address=None, phone=None):
        customer = cls.query.get(id)
        if customer:
            # update customer
            if name:
                customer.name = name
            if address:
                customer.address = address
            if phone:
                customer.phone = phone
        else:
            customer = cls(id=id, name=name, address=address, phone=phone)
        db.session.add(customer)
        db.session.commit()
        return customer
Exemple #8
0
class WeekCode(db.Model):
    """represets one week of data(so we don't write the same week twice)"""
    __tablename__ = "week_codes"
    code = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey(
        'users.id', ondelete='CASCADE'), primary_key=True)

    @classmethod
    def add(cls, code, user_id):
        """add a code to the db"""
        db_entry = cls(code=code, user_id=user_id)
        db.session.add(db_entry)
        try:
            db.session.commit()
            return True
        except:
            return False

    @classmethod
    def get_codes_for_user(cls, user_id, limit = 8):
        """gets the codes for a specified user. defaults to limiting to 3"""
        week_codes = cls.query.filter_by(user_id=user_id).order_by(
            cls.code.desc()).limit(limit).all()
        return [w.code for w in week_codes]
Exemple #9
0
class User(db.Model):
    """User in the system."""

    __tablename__ = 'users'

    id = db.Column(
        db.Integer,
        primary_key=True,
    )

    email = db.Column(
        db.Text,
        nullable=False,
        unique=True,
    )

    username = db.Column(
        db.Text,
        nullable=False,
        unique=True,
    )

    image_url = db.Column(
        db.Text,
        default="/static/images/default-pic.png",
    )

    header_image_url = db.Column(db.Text,
                                 default="/static/images/warbler-hero.jpg")

    bio = db.Column(db.Text, )

    location = db.Column(db.Text, )

    password = db.Column(
        db.Text,
        nullable=False,
    )

    messages = db.relationship('Message')

    followers = db.relationship(
        "User",
        secondary="follows",
        primaryjoin=(Follow.user_being_followed_id == id),
        secondaryjoin=(Follow.user_following_id == id))

    following = db.relationship(
        "User",
        secondary="follows",
        primaryjoin=(Follow.user_following_id == id),
        secondaryjoin=(Follow.user_being_followed_id == id))

    likes = db.relationship('Message', secondary="likes")

    def __repr__(self):
        return f"<User #{self.id}: {self.username}, {self.email}>"

    def is_followed_by(self, other_user):
        """Is this user followed by `other_user`?"""

        found_user_list = [
            user for user in self.followers if user == other_user
        ]
        return len(found_user_list) == 1

    def is_following(self, other_user):
        """Is this user following `other_use`?"""

        found_user_list = [
            user for user in self.following if user == other_user
        ]
        return len(found_user_list) == 1

    def update_from_serial(self, d):
        username = d.get('username')

        email = d.get('email')

        image_url = d.get('image_url')
        if image_url == '':
            image_url = User.image_url.default.arg

        header_image_url = d.get('header_image_url')
        if header_image_url == '':
            header_image_url = User.header_image_url.default.arg

        bio = d.get('bio')
        location = d.get('location')

        if username:
            self.username = username
        if email:
            self.email = email
        if image_url:
            self.image_url = image_url
        if header_image_url:
            self.header_image_url = header_image_url
        if bio:
            self.bio = bio
        if location:
            self.location = location

    @classmethod
    def signup(cls, username, email, password, image_url):
        """Sign up user.

        Hashes password and adds user to system.
        """

        hashed_pwd = bcrypt.generate_password_hash(password).decode('UTF-8')

        user = User(
            username=username,
            email=email,
            password=hashed_pwd,
            image_url=image_url,
        )

        db.session.add(user)
        return user

    @classmethod
    def authenticate(cls, username, password):
        """Find user with `username` and `password`.

        This is a class method (call it on the class, not an individual user.)
        It searches for a user whose password hash matches this password
        and, if it finds such a user, returns that user object.

        If can't find matching user (or if password is wrong), returns False.
        """

        user = cls.query.filter_by(username=username).first()

        if user:
            is_auth = bcrypt.check_password_hash(user.password, password)
            if is_auth:
                return user

        return False
Exemple #10
0
class Order(db.Model):
    """A single order"""
    __tablename__ = "orders"
    id = db.Column(db.Integer, primary_key=True)
    
    num = db.Column(db.Integer)
    date = db.Column(db.Date)
    store = db.Column(db.Text)
    api_id = db.Column(db.Text)
    
    tip = db.Column(db.Float, server_default='0')
    del_id = db.Column(db.Integer, db.ForeignKey(
        'deliveries.id', ondelete='CASCADE'))
    cust_id = db.Column(db.String(32), db.ForeignKey(
        'customers.id', ondelete='SET NULL'))
    driver_id = db.Column(db.Integer, db.ForeignKey(
        'users.id', ondelete='CASCADE'))
    driver = db.relationship('User',
                             backref='orders')
    customer = db.relationship('Customer',
                               backref='orders')

    def serialize(self):
        return {"id": self.id,
                "num": self.num,
                "tip": self.tip,
                "date": self.date,
                "del_id": self.del_id,
                "cust_id": self.cust_id,
                "driver_id": self.driver_id,
                "store": self.store,
                "api_id": self.api_id
                }

    def update_db(self):
        db.session.add(self)
        db.session.commit()

    @classmethod
    def get(cls, num, date, store, api_id):
        return cls.query.filter_by(num=num, date=date, store=store, api_id=api_id).first()

    @classmethod
    def get_orders_for_day(cls, driver_id, date=date_class.today()):
        """ Returns 
        {num, tip, date, del_id, cust_id, driver_id, customer:{id, name, phone, address}
        """
        result = db.session.query(
            Order, Customer).join(
                Customer, Customer.id == Order.cust_id).filter(
                    Order.driver_id == driver_id,
                    Order.date == date).all()
        return Order.compile_orders_and_customers(result)

    @classmethod
    def get_orders_for(cls, driver_id):
        """ Returns 
        213, 04-19-21, 8425-881-7843
        """
        result = db.session.query(
            Order, Customer).join(
                Customer, Customer.id == Order.cust_id).filter(
                    Order.driver_id == driver_id).order_by(Order.date.desc(), Order.num.desc()).all()
        orders = Order.compile_orders_and_customers(result)
        orders_list = {}

        for order in orders:
            orders_for_date = orders_list.get(order['date'], [])
            orders_for_date.append(order)
            orders_list[order['date']] = orders_for_date
        return orders_list

    @classmethod
    def make_id_from_date_and_num(cls, date, num):
        return f'{date}|{num}'

    @ classmethod
    def compile_orders_and_customers(cls, order_array):
        return [{**order.serialize(), "customer": {**customer.serialize()}} for (order, customer) in order_array]
Exemple #11
0
class Schedule(db.Model):
    """A single shift"""
    __tablename__ = "schedules"
    id = db.Column(
        db.Integer, autoincrement=True, primary_key=True)
    start = db.Column(db.DateTime, nullable=False)
    end = db.Column(db.DateTime, nullable=False)
    shift_type = db.Column(db.String(20))
    user_id = db.Column(db.Integer, db.ForeignKey(
        'users.id', ondelete='CASCADE'))

    def get_shift_length(self):
        """gets the length of the shift
        returns a datetime.timedelta object """
        return self.end-self.start


    def get_shift_hours(self):
        """gets the length of the shift in hours """
        
        delta = self.get_shift_length()
        # 60 seconds in a min, 60 mins in a hour
        return delta.total_seconds() / 60 / 60

    @classmethod
    def get_future_shifts(cls, user_id):
        """returns a list of shifts for user_id 
        that end on or after today"""
        #get a timestamp for the beginning of the day
        today = datetime.date.today()
        return cls.query.filter(
            Schedule.user_id == user_id,
            Schedule.end >= today
        ).order_by(Schedule.start).all()

    @classmethod
    def get_last(cls, user_id, delta=None):
        """returns a list of shifts for user_id that start on or before today
        optionally the delta param further limits the results to shits that end on or after 
        today - delta"""
        #get a timestamp at the end of the day
        today = datetime.datetime.today() + datetime.timedelta(hours=11, minutes=59)
        if delta:
            return cls.query.filter(
                Schedule.user_id == user_id,
                Schedule.start <= today,
                Schedule.end >= (datetime.date.today() - delta)

            ).all()
        else:
            return cls.query.filter(
                Schedule.user_id == user_id,
                Schedule.start <= today

            ).all()

    @classmethod
    def add_from_pag(cls, schedules, user_id):
        """adds a list of schedules from the pag api"""
        #weeks that are already in the DB
        used_codes = WeekCode.get_codes_for_user(user_id, limit=10)
        for week in schedules:
            
            code = week['pag_code']
            if int(code) not in used_codes:
                # for each week in schedules,
                # add the pag_code to WeekCode
                WeekCode.add(code, user_id)
                for shift in week['schedule']:
                    # for every shift, make a new schedule
                    db_shift = Schedule(
                        start=shift['start'],
                        end=shift['end'],
                        shift_type=shift['shift_type'],
                        user_id=user_id)
                    db.session.add(db_shift)
        db.session.commit()

    @classmethod
    def add_from_demo(cls, schedules, user_id):
        """adds a list of schedules from the demo api"""
        used_codes = WeekCode.get_codes_for_user(user_id, limit=10)
        for week in schedules:
            # for each week in schedules,
            # add the week_code to WeekCode
            code = week['week_code']
            if int(code) not in used_codes:
                WeekCode.add(code, user_id)
                for shift in week['schedule']:
                    # for every shift, make a new schedule
                    db_shift = Schedule(
                        start=shift['start'],
                        end=shift['end'],
                        shift_type=shift['shift_type'],
                        user_id=user_id)
                    db.session.add(db_shift)
        db.session.commit()
Exemple #12
0
class User(db.Model):
    """A single user"""
    __tablename__ = "users"
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    name = db.Column(db.Text)
    email = db.Column(db.Text, nullable=False)
    token = db.Column(db.Text, nullable=False, unique=True)
    token_expiration = db.Column(db.DateTime, nullable=True)
    accessor = db.Column(db.Text, nullable=True)
    accessor_expiration = db.Column(db.DateTime, nullable=True)
    api_id = db.Column(db.Text, nullable=False)
    shifts = db.relationship('Schedule',
                             backref='user')
    def make_jwt(self):
        #JWT payload looks like {ACCESSOR_SESSION_KEY: accessor, USER_SESSION_KEY: u.id}
        return jwt.encode({
            ACCESSOR_SESSION_KEY: self.accessor,
            USER_SESSION_KEY: self.id
        },
            SECRET_KEY,
            algorithm="HS256")
        
    def update_token(self, token, token_expiration):
        """updates a users token"""

        self.token = token
        self.token_expiration = token_expiration
        db.session.add(self)
        db.session.commit()


    def update_accessor(self):
        """updates a users accessor"""
        ACCESSOR_TIMEOUT_DAYS = 4
        
        accessor = User.create_unique_accessor()
        self.accessor = accessor

        expiration = make_date_time_from_now(days=ACCESSOR_TIMEOUT_DAYS)
        self.accessor_expiration = expiration

        db.session.add(self)
        db.session.commit()
        # unneccesary
        # #use bcrypt to hash the accessor
        # hashed = bcrypt.generate_password_hash(user.accessor)
        # # turn bytestring into normal (unicode utf8) string
        # hashed_utf8 = hashed.decode("utf8")

        return self.accessor

    @classmethod
    def get(cls, pk):
        """a shortcut for the cls.query.get() function"""
        return cls.query.get(pk)


    @classmethod
    def authenticate(cls, user_jwt):
        """gets a user by its accessor"""
        user_data = jwt.decode(user_jwt, SECRET_KEY, algorithms="HS256")

        accessor = user_data[ACCESSOR_SESSION_KEY]
        u_id = user_data[USER_SESSION_KEY]
        user = cls.get(u_id)
        if user:
            if user.accessor == accessor:
                return user
            else:
                return False
        else:
            return False

    @classmethod
    def get_by_accessor(cls, accessor):
        """gets a user by its accessor"""
        user = cls.query.filter_by(accessor=accessor).first()
        return user if user else False
    

    @classmethod
    def delete_by_email(cls, email):
        """A quick way of deleting a user by email"""
        cls.query.filter_by(email=email).delete()
        db.session.commit()

    @classmethod
    def create(cls, email, token, api_id, token_expiration=None,  name=None):
        user = User(email=email, token=token, token_expiration=token_expiration, name=email, api_id=api_id)
        if name:
            user.name = name
        db.session.add(user)
        db.session.commit()
        user.update_accessor()

        return user
    
    @classmethod
    def create_or_update(cls, email, token, api_id, token_expiration=None, name=None):
        """If a user with this email already exists, update the token (and name if given) 
        and return the id to the caller
            otherwise, create the user and return the id to the caller"""
        user = cls.query.filter_by(email=email).first()
        
        if user:
            # user already exists, just update token
            user.token = token
        else:
            user = User(email=email, token=token, name=email, api_id=api_id)

        if name:
            user.name = name
            
        if token_expiration:
            user.token_expiration = token_expiration

        db.session.add(user)
        db.session.commit()
        user.update_accessor()
        
        return user
    
    @classmethod
    def create_unique_accessor(cls):
        accessor = secrets.token_urlsafe()
        
        while cls.get_by_accessor(accessor):
            accessor = secrets.token_urlsafe()
            
        return accessor