Пример #1
0
class Fraternity(SurrogatePK, Model):
    """A fraternity."""

    __tablename__ = 'fraternities'
    title = Column(db.String(80), nullable=False)
    capacity = Column(db.Integer(), nullable=False)
    users = relationship('User')
    parties = relationship('Party', cascade='delete', single_parent=True)
    can_have_parties = Column(db.Boolean(), default=True, nullable=False)
    school_id = reference_col('schools', nullable=False)
    school = relationship('School')

    def __repr__(self):
        """Represent instance as a unique string."""
        return '<Fraternity({title})>'.format(title=self.title)

    @validates('title')
    def validate_title(self, key, title):
        """Validate the title of the fraternity."""
        if not all([x.lower() in greek_letters for x in title.split()]):
            raise InvalidAPIUsage(payload={
                'error':
                locales.Error.INVALID_FRAT_NAME_TEMPLATE.format(title)
            })
        return title
Пример #2
0
class Party(SurrogatePK, Model):
    """A party for a fraternity."""

    __tablename__ = 'parties'
    name = Column(db.String(80), nullable=False)
    date = Column(db.Date(), nullable=False)
    started = Column(db.Boolean(), nullable=False, default=False)
    ended = Column(db.Boolean(), nullable=False, default=False)
    creator_id = reference_col('users', nullable=False)
    creator = relationship('User')
    fraternity_id = reference_col('fraternities', nullable=False)
    fraternity = relationship('Fraternity')
    guests = relationship('Guest', cascade='delete', single_parent=True)

    def __repr__(self):
        """Represent instance as a unique string."""
        return '<Party({name})>'.format(name=self.name)

    @validates('fraternity', 'creator')
    def validate_fraternity(self, key, field):
        """Ensures that the creator is part of the fraternity"""
        if key is 'creator' and self.fraternity is not None:
            if field.fraternity != self.fraternity:
                raise InvalidAPIUsage(
                    payload={'error': locales.Error.PARTY_CREATOR_MISALIGNED},
                    status_code=403)
        elif key is 'fraternity' and self.creator is not None:
            if self.creator.fraternity != field:
                raise InvalidAPIUsage(
                    payload={'error': locales.Error.PARTY_CREATOR_MISALIGNED},
                    status_code=403)
        return field

    def is_on_guest_list(self, guest_name):
        """Validates whether or not the guest is on the party list."""
        return guest_name.lower() in [
            guest.name.lower() for guest in self.guests
        ]

    @property
    def male_guests(self):
        """Get the male guests"""
        return [guest for guest in self.guests if guest.is_male]

    @property
    def female_guests(self):
        """Get the female guests"""
        return [guest for guest in self.guests if not guest.is_male]

    def start(self):
        """Let's get it started"""
        self.started = True
        self.save()

    def end(self):
        """Ok, that's enough PARTY'S OVER."""
        assert self.started, locales.Error.PARTY_END_BEFORE_START
        self.ended = True
        self.save()
Пример #3
0
class Guest(SurrogatePK, Model):
    """A guest for a party"""

    __tablename__ = 'guests'

    name = Column(db.String(80), nullable=False)
    host_id = reference_col('users', nullable=False)
    host = relationship('User')
    party_id = reference_col('parties', nullable=False)
    party = relationship('Party')
    is_at_party = Column(db.Boolean(), default=False, nullable=False)
    is_male = Column(db.Boolean(), nullable=False)
    entered_party_at = Column(db.DateTime)
    left_party_at = Column(db.DateTime)
    __table_args__ = (db.UniqueConstraint('name',
                                          'party_id',
                                          name='_name_party_uc'), )

    def __repr__(self):
        """Represent instance as a unique string."""
        return '<Guest({name} at {party})>'.format(name=self.name,
                                                   party=self.party.name)

    @validates('name')
    def validate_name(self, key, field):
        """Ensures that the guest is not already added to the party list"""
        if len(field) < 3:
            raise InvalidAPIUsage(
                payload={'error': locales.Error.GUEST_NAME_SHORT},
                status_code=422)
        return field.lower()

    @property
    def json_dict(self):
        """Returns the guest as a JSON serializable python dict."""
        return {
            'name': titlecase(self.name),
            'host': self.host.full_name,
            'is_male': self.is_male,
            'is_at_party': self.is_at_party,
            'id': self.id,
            'left_at': self.left_party_at,
            'entered_at': self.entered_party_at
        }

    def leave_party(self):
        """The logic for a guest leaving the party."""
        self.is_at_party = False
        if self.left_party_at is None:
            self.left_party_at = dt.utcnow()
        self.save()

    def enter_party(self):
        """The logic for a guest entering a party."""
        self.is_at_party = True
        if self.entered_party_at is None:
            self.entered_party_at = dt.utcnow()
        self.save()
Пример #4
0
class School(SurrogatePK, Model):
    """A school for an implementation of this software."""

    __tablename__ = 'schools'
    title = Column(db.String(120), unique=True, nullable=False)
    short_title = Column(db.String(10))
    fraternities = relationship('Fraternity',
                                cascade='delete',
                                single_parent=True)

    def __repr__(self):
        """Represent instance as a unique string."""
        return '<School({title})>'.format(title=self.title)

    @property
    def abbreviation(self):
        return self.short_title

    @property
    def frats(self):
        return self.fraternities
Пример #5
0
class Role(SurrogatePK, Model):
    """A role for a user."""

    __tablename__ = 'roles'
    title = Column(db.String(80), unique=True, nullable=False)
    users = relationship('User')

    def __init__(self, title, **kwargs):
        """Create instance."""
        db.Model.__init__(self, title=title, **kwargs)

    def __repr__(self):
        """Represent instance as a unique string."""
        return '<Role({title})>'.format(title=self.title)

    @validates('title')
    def validate_title(self, key, title):
        """Validate the title of the role."""
        assert title in ['ifc_admin', 'chapter_admin', 'normal'], \
            locales.Error.INVALID_ROLE
        return title
Пример #6
0
class User(UserMixin, SurrogatePK, Model):
    """A user of the app."""

    __tablename__ = 'users'
    email = Column(db.String(100), unique=True, nullable=False)
    #: The hashed password
    password = Column(db.String(128), nullable=True)
    first_name = Column(db.String(30), nullable=True)
    last_name = Column(db.String(30), nullable=True)
    active = Column(db.Boolean(), default=False)
    is_admin = Column(db.Boolean(), default=False)
    role_id = reference_col('roles', nullable=False)
    role = relationship('Role')

    fraternity_id = reference_col('fraternities', nullable=False)
    fraternity = relationship('Fraternity')

    capacity_id = reference_col('capacities', nullable=True)
    party_capacity = relationship('Capacity')

    parties = relationship('Party', cascade='delete', single_parent=True)

    def __init__(self, email, password=None, **kwargs):
        """Create instance."""
        pre = Preuser.query.filter(Preuser.email == email).first()
        if pre is None:
            raise Forbidden()

        role = self.resolve_role_from_preuser(pre)
        if role is None and 'role_id' in kwargs:
            role = Role.find_by_id(kwargs['role_id'])

        fraternity = self.resolve_frat_from_preuser(pre)
        if fraternity is None and 'fraternity_id' in kwargs:
            fraternity = Fraternity.find_by_id(kwargs['fraternity_id'])

        # create the user
        db.Model.__init__(self,
                          email=email,
                          role=role,
                          fraternity=fraternity,
                          first_name=pre.first_name,
                          last_name=pre.last_name)
        if password:
            self.set_password(password)
        else:
            self.password = None
        self.active = True

    def set_password(self, password):
        """Set password."""
        self.password = bcrypt.generate_password_hash(password)

    def check_password(self, value):
        """Check password."""
        return bcrypt.check_password_hash(self.password, value)

    def resolve_role_from_preuser(self, pre):
        """Figures out what the role is from the preregistered-user model."""
        if pre.ifc_admin:
            return Role.query.filter(Role.title == 'ifc_admin').first()
        elif pre.chapter_admin:
            return Role.query.filter(Role.title == 'chapter_admin').first()
        else:
            return Role.query.filter(Role.title == 'normal').first()

    def resolve_frat_from_preuser(self, pre):
        """Finds the fraternity from the preregistered-user model."""
        return Fraternity.query.filter_by(title=pre.fraternity_name)\
            .join(Fraternity.school).filter_by(title=pre.school_title).first()

    @property
    def full_name(self):
        """Full user name."""
        return '{0} {1}'.format(self.first_name, self.last_name)

    @property
    def username(self):
        """Username derived from email."""
        return self.email.split('@')[0]

    @property
    def is_site_admin(self):
        """True if the user is a site admin."""
        return self.role.title == 'ifc_admin'

    @property
    def is_chapter_admin(self):
        """True if the user is a chapter admin."""
        return self.role.title == 'chapter_admin'

    @property
    def school_name(self):
        """Gets the shortened school name if there is one, otherwise returns
        the full name."""
        if self.fraternity.school.short_title is not None:
            return self.fraternity.school.short_title
        else:
            return self.fraternity.school.title

    def can_delete_party_by_id(self, party_id):
        """True if the user can delete the given party."""
        party = Party.find_or_404(party_id)
        flask.g.party = party
        return self.can_delete_party(party)

    def can_delete_party(self, party):
        """True if the user can delete the given party."""
        return self.is_site_admin or (self.is_chapter_admin
                                      and self.fraternity == party.fraternity)

    @property
    def can_create_party(self):
        """True if the user can create a party."""
        return self.is_site_admin or self.is_chapter_admin

    def can_view_party_by_id(self, party_id, guest_id=None):
        """True if the user can view the given party."""
        party = Party.find_or_404(party_id)
        if guest_id is not None:
            guest = Guest.find_or_404(guest_id)
            flask.g.guest = guest
        flask.g.party = party
        return self.can_view_party(party)

    def can_manage_brother_by_id(self, brother_id):
        """True if the user can manage the brother."""
        brother = User.find_or_404(brother_id)
        flask.g.brother = brother
        return self

    def can_manage_brother(self, brother):
        """True if the user can manage the brother."""
        return self.fraternity_id == brother.fraternity_id and \
            (self.is_admin or self.is_chapter_admin or self.is_site_admin)

    @property
    def can_manage_fraternity(self):
        """True if the user is an admin of any kind."""
        return self.is_admin or self.is_site_admin or self.is_chapter_admin

    def can_view_party(self, party):
        """True if the user can view the guest list of a party"""
        return self.is_site_admin or party.fraternity == self.fraternity

    def can_edit_guest_by_id(self, guest_id, party_id=None):
        """True if the user can edit the guest."""
        guest = Guest.find_or_404(guest_id)
        if party_id is not None:
            party = Party.find_or_404(party_id)
            flask.g.party = party
        flask.g.guest = guest
        return self.can_edit_guest(guest)

    def can_edit_guest(self, guest):
        """True if the user can edit the guest."""
        return guest.host == self

    def __repr__(self):
        """Represent instance as a unique string."""
        return '<User({email})>'.format(email=self.email)

    @property
    def json_dict(self):
        """Represent the instance as a dict that can be converted to JSON."""
        return {
            'username': self.username,
            'first_name': self.first_name,
            'last_name': self.last_name,
            'full_name': self.full_name,
            'id': self.id
        }