class UserFavouriteSession(db.Model, Timestamp):
    __tablename__ = 'user_favourite_sessions'
    __table_args__ = (db.UniqueConstraint('session_id',
                                          'user_id',
                                          name='uq_session_user'), )

    id = db.Column(db.Integer, primary_key=True)
    session_id = db.Column(db.Integer,
                           db.ForeignKey('sessions.id', ondelete='CASCADE'))
    user_id = db.Column(db.Integer,
                        db.ForeignKey('users.id', ondelete='CASCADE'))
    session = db.relationship('Session', backref='favourites')
    user = db.relationship('User', backref='favourite_sessions')

    @property
    def safe_user(self):
        from app.api.helpers.permission_manager import require_current_user
        from app.models.user import User

        if not self.user_id:
            return None
        can_access = require_current_user() and (
            current_user.is_staff or current_user.id == self.user_id)
        if not self.user.is_profile_public and not can_access:
            name = self.user.anonymous_name
            return User(
                id=self.user.id,
                email='*****@*****.**',
                public_name=name,
            )
        return self.user
class Permission(db.Model):
    """Role-Service Permissions"""

    __tablename__ = 'permissions'
    __table_args__ = (db.UniqueConstraint('role_id',
                                          'service_id',
                                          name='role_service_uc'), )

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

    role_id = db.Column(db.Integer,
                        db.ForeignKey('roles.id', ondelete='CASCADE'))
    role = db.relationship('Role')

    service_id = db.Column(db.Integer,
                           db.ForeignKey('services.id', ondelete='CASCADE'))
    service = db.relationship('Service')

    can_create = db.Column(db.Boolean, nullable=False, default=True)
    can_read = db.Column(db.Boolean, nullable=False, default=True)
    can_update = db.Column(db.Boolean, nullable=False, default=True)
    can_delete = db.Column(db.Boolean, nullable=False, default=True)

    def __repr__(self):
        return f'<Perm {self.role!r} for {self.service!r}>'
Beispiel #3
0
class Feedback(SoftDeletionModel):
    """Feedback model class"""

    __tablename__ = 'feedback'
    __table_args__ = (db.UniqueConstraint('session_id',
                                          'user_id',
                                          name='session_user_uc'), )

    id = db.Column(db.Integer, primary_key=True)
    rating = db.Column(db.Float, nullable=False)
    comment = db.Column(db.String, nullable=True)
    user_id = db.Column(db.Integer,
                        db.ForeignKey('users.id', ondelete='CASCADE'))
    event_id = db.Column(db.Integer,
                         db.ForeignKey('events.id', ondelete='CASCADE'))
    session_id = db.Column(db.Integer,
                           db.ForeignKey('sessions.id', ondelete='CASCADE'))

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # TODO(Areeb): Test rating rounding on __init__
        rating = float(kwargs.get('rating'))
        self.rating = round(rating * 2, 0) / 2  # Rounds to nearest 0.5

    def __repr__(self):
        return '<Feedback %r>' % self.rating
class UsersEventsRoles(db.Model):
    __tablename__ = 'users_events_roles'
    __table_args__ = (
        db.UniqueConstraint(
            'user_id', 'event_id', 'role_id', name='uq_uer_user_event_role'
        ),
    )

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

    event_id = db.Column(
        db.Integer, db.ForeignKey('events.id', ondelete='CASCADE'), nullable=False
    )

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

    role_id = db.Column(
        db.Integer, db.ForeignKey('roles.id', ondelete='CASCADE'), nullable=False
    )
    role = db.relationship("Role")

    def __repr__(self):
        return f'<UER {self.user!r}:{self.event_id!r}:{self.role!r}>'
Beispiel #5
0
class TicketTag(SoftDeletionModel):
    """
    Tags to group tickets
    """
    __tablename__ = 'ticket_tag'
    __table_args__ = (db.UniqueConstraint('name',
                                          'event_id',
                                          name='unique_ticket_tag'), )

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

    event_id = db.Column(db.Integer,
                         db.ForeignKey('events.id', ondelete='CASCADE'))
    event = db.relationship('Event', backref='ticket_tags')

    def __init__(self, name=None, event_id=None, deleted_at=None):
        self.name = name
        self.event_id = event_id
        self.deleted_at = deleted_at

    def __repr__(self):
        return '<TicketTag %r>' % self.name

    def __str__(self):
        return self.__repr__()
Beispiel #6
0
class BookedTicket(db.Model):
    __tablename__ = 'booked_ticket'
    __table_args__ = (db.UniqueConstraint('user_id',
                                          'ticket_id',
                                          name='user_ticket_uc'), )

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id',
                                                  ondelete='CASCADE'))
    user = db.relationship('User', backref='booked_tickets')
    ticket_id = db.Column(db.Integer,
                          db.ForeignKey('ticket.id', ondelete='CASCADE'))
    ticket = db.relationship('Ticket', backref='booked_tickets')
    quantity = db.Column(db.Integer)

    def __init__(self, user, ticket, quantity):
        self.user = user
        self.ticket = ticket
        self.quantity = quantity

    def __repr__(self):
        return '<BookedTicket %r by %r' % (
            self.ticket,
            self.user,
        )

    def __str__(self):
        return unicode(self).encode('utf-8')

    def __unicode__(self):
        return self.ticket
class UsersGroupsRoles(db.Model):
    __tablename__ = 'users_groups_roles'
    __table_args__ = (
        db.UniqueConstraint(
            'user_id', 'group_id', 'role_id', name='uq_ugr_user_group_role'
        ),
        db.UniqueConstraint(
            'email', 'group_id', 'role_id', name='uq_ugr_email_group_role'
        ),
    )

    id = db.Column(db.Integer, primary_key=True)
    token = db.Column(db.String, default=generate_hash)
    email = db.Column(CIText, nullable=False)
    accepted = db.Column(
        db.Boolean, default=False, nullable=False, server_default='False'
    )

    group_id = db.Column(
        db.Integer, db.ForeignKey('groups.id', ondelete='CASCADE'), nullable=False
    )

    user_id = db.Column(
        db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), nullable=True
    )
    user = db.relationship("User")

    role_id = db.Column(
        db.Integer, db.ForeignKey('roles.id', ondelete='CASCADE'), nullable=False
    )
    role = db.relationship("Role")

    def __repr__(self):
        return f'<UGR {self.email!r}:{self.user!r}:{self.group!r}:{self.role!r}>'

    def send_invite(self):
        """
        Send mail to invitee
        """
        group = self.group
        role = self.role
        frontend_url = get_settings()['frontend_url']
        link = f"{frontend_url}/group-invites?token={self.token}"
        if group.user != current_user:
            raise ForbiddenError({'pointer': 'group'}, 'Owner access is required.')

        send_email_group_role_invite(self.email, role.name, group.name, link)
Beispiel #8
0
class Permission(db.Model):
    """Role-Service Permissions
    """
    __tablename__ = 'permissions'
    __table_args__ = (db.UniqueConstraint('role_id',
                                          'service_id',
                                          name='role_service_uc'), )

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

    role_id = db.Column(db.Integer,
                        db.ForeignKey('roles.id', ondelete='CASCADE'))
    role = db.relationship('Role')

    service_id = db.Column(db.Integer,
                           db.ForeignKey('services.id', ondelete='CASCADE'))
    service = db.relationship('Service')

    can_create = db.Column(db.Boolean, nullable=False)
    can_read = db.Column(db.Boolean, nullable=False)
    can_update = db.Column(db.Boolean, nullable=False)
    can_delete = db.Column(db.Boolean, nullable=False)

    def __init__(self,
                 role,
                 service,
                 can_create=True,
                 can_read=True,
                 can_update=True,
                 can_delete=True):
        self.role = role
        self.service = service
        self.can_create = can_create
        self.can_read = can_read
        self.can_update = can_update
        self.can_delete = can_delete

    def __repr__(self):
        return '<Perm %r for %r>' % (
            self.role,
            self.service,
        )

    def __str__(self):
        return unicode(self).encode('utf-8')

    def __unicode__(self):
        return 'Perm %r for %r' % (
            self.role,
            self.service,
        )
class UserFollowGroup(db.Model, Timestamp):
    __tablename__ = 'user_follow_groups'
    __table_args__ = (db.UniqueConstraint('group_id',
                                          'user_id',
                                          name='uq_group_user'), )

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer,
                        db.ForeignKey('users.id', ondelete='CASCADE'),
                        nullable=False)
    user = db.relationship('User', backref='followed_groups')
    group_id = db.Column(db.Integer,
                         db.ForeignKey('groups.id', ondelete='CASCADE'),
                         nullable=False)
    group = db.relationship("Group", backref='followers')
Beispiel #10
0
class Organisation(ModelMixin):
    """ Organisation table definition """

    _tablename_ = 'organisations'
    __table_args__ = (db.UniqueConstraint('name', name='organisation_unique_name'),)

    # fields of the Organisation table
    id = db.Column(UUID(as_uuid=True), primary_key=True, server_default=sa_text("uuid_generate_v4()"))
    name = db.Column(db.String(256), nullable=False)
    date_created = db.Column(db.DateTime, default=db.func.current_timestamp())
    admins = relationship('User', secondary='organisation_admins', backref='organisation_admin')
    members = relationship('User', secondary='organisation_members', backref='organisations')

    def __init__(self, name):
        """ initialize with name, member and namespace """
        self.name = name
class PlatformConfigModel(db.Model):
    __tablename__ = 'platform_config'
    __table_args__ = (db.UniqueConstraint('platform_id',
                                          'id_config',
                                          name='unq_config_platform'), {
                                              'schema': cfg_db_schema
                                          })
    id = db.Column(db.Integer, primary_key=True)
    platform_id = db.Column(db.Integer,
                            db.ForeignKey(cfg_db_schema + '.platform.id'),
                            nullable=False)
    id_config = db.Column(db.Integer, nullable=False)
    name = db.Column(db.String(128), unique=True, nullable=False)
    value = db.Column(db.String(256), nullable=False)

    def __repr__(self):
        return "<PlatformConfig %r val: %r>" % (self.name, self.value)
Beispiel #12
0
class Feedback(SoftDeletionModel):
    """Feedback model class"""

    __tablename__ = 'feedback'
    __table_args__ = (db.UniqueConstraint('session_id',
                                          'user_id',
                                          name='session_user_uc'), )

    id = db.Column(db.Integer, primary_key=True)
    rating = db.Column(db.Float, nullable=False)
    comment = db.Column(db.String, nullable=True)
    user_id = db.Column(db.Integer,
                        db.ForeignKey('users.id', ondelete='CASCADE'))
    event_id = db.Column(db.Integer,
                         db.ForeignKey('events.id', ondelete='CASCADE'))
    session_id = db.Column(db.Integer,
                           db.ForeignKey('sessions.id', ondelete='CASCADE'))

    def __init__(
        self,
        rating=None,
        comment=None,
        event_id=None,
        user_id=None,
        session_id=None,
        deleted_at=None,
    ):
        rating = float(rating)
        self.rating = round(rating * 2, 0) / 2  # Rounds to nearest 0.5

        self.comment = comment
        self.event_id = event_id
        self.user_id = user_id
        self.session_id = session_id
        self.deleted_at = deleted_at

    def __repr__(self):
        return '<Feedback %r>' % self.rating

    def __str__(self):
        return self.__repr__()

    @property
    def serialize(self):
        """Return object data in easily serializable format"""
        return {'id': self.id, 'rating': self.rating, 'comment': self.comment}
Beispiel #13
0
class UserTokenBlackListTime(db.Model):
    """user token blacklist time model class"""
    __tablename__ = 'user_token_blacklist_time'
    __table_args__ = (db.UniqueConstraint('user_id', name='user_blacklist_time_uc'),)

    id = db.Column(db.Integer, primary_key=True)
    created_at = db.Column(db.DateTime(timezone=True), default=sql_func.now(), nullable=False)
    blacklisted_at = db.Column(db.DateTime(timezone=True), default=sql_func.now(), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), nullable=False)
    user = db.relationship("User", backref="token_blacklist_times", foreign_keys=[user_id])

    def __init__(self, user_id=None, created_at=None, blacklisted_at=None):
        self.user_id = user_id
        self.created_at = created_at
        self.blacklisted_at = blacklisted_at

    def __str__(self):
        return '<TokenBlackListTime User %s blacklisted at %s>' % (self.user, self.blacklisted_at)
Beispiel #14
0
class UserTokenBlackListTime(db.Model):
    """user token blacklist time model class"""

    __tablename__ = 'user_token_blacklist_time'
    __table_args__ = (db.UniqueConstraint('user_id', name='user_blacklist_time_uc'),)

    id: int = db.Column(db.Integer, primary_key=True)
    created_at: datetime = db.Column(
        db.DateTime(timezone=True), default=sql_func.now(), nullable=False
    )
    blacklisted_at: datetime = db.Column(
        db.DateTime(timezone=True), default=sql_func.now(), nullable=False
    )
    user_id: int = db.Column(
        db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), nullable=False
    )
    user = db.relationship(
        "User", backref="token_blacklist_times", foreign_keys=[user_id]
    )
Beispiel #15
0
class Namespace(ModelMixin):
    """ Namespace table definition """

    _tablename_ = 'namespace'
    __table_args__ = (db.UniqueConstraint('name',
                                          name='namespace_unique_name'), )

    # fields of the Namespace table
    id = db.Column(UUID(as_uuid=True),
                   primary_key=True,
                   server_default=sa_text("uuid_generate_v4()"))
    name = db.Column(db.String(256), nullable=False)
    organisation_id = db.Column(
        "organisation_id", UUID(as_uuid=True),
        db.ForeignKey(Organisation.id, ondelete='CASCADE'))
    date_created = db.Column(db.DateTime, default=db.func.current_timestamp())

    def __init__(self, name, organisation_id):
        """ initialize with name and org_id """
        self.name = name
        self.organisation_id = organisation_id
Beispiel #16
0
class Speaker(SoftDeletionModel, Timestamp):
    """Speaker model class"""

    __tablename__ = 'speaker'
    __table_args__ = (
        db.UniqueConstraint(
            'event_id', 'email', 'deleted_at', name='uq_speaker_event_email'
        ),
        db.Index('speaker_event_idx', 'event_id'),
    )
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)
    photo_url = db.Column(db.String)
    thumbnail_image_url = db.Column(db.String)
    small_image_url = db.Column(db.String)
    icon_image_url = db.Column(db.String)
    short_biography = db.Column(db.Text)
    long_biography = db.Column(db.Text)
    speaking_experience = db.Column(db.Text)
    email = db.Column(CIText)
    mobile = db.Column(db.String)
    website = db.Column(db.String)
    twitter = db.Column(db.String)
    facebook = db.Column(db.String)
    github = db.Column(db.String)
    mastodon = db.Column(db.String)
    linkedin = db.Column(db.String)
    instagram = db.Column(db.String)
    organisation = db.Column(db.String)
    is_featured = db.Column(db.Boolean, default=False)
    is_email_overridden = db.Column(
        db.Boolean, default=False, nullable=False, server_default='False'
    )
    position = db.Column(db.String)
    country = db.Column(db.String)
    city = db.Column(db.String)
    address = db.Column(db.String)
    gender = db.Column(db.String)
    order = db.Column(db.Integer, default=0, nullable=False)
    heard_from = db.Column(db.String)
    sponsorship_required = db.Column(db.Text)
    complex_field_values = db.Column(db.JSON)
    event_id = db.Column(db.Integer, db.ForeignKey('events.id', ondelete='CASCADE'))
    user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='SET NULL'))

    @staticmethod
    def get_service_name():
        return 'speaker'

    def __repr__(self):
        return '<Speaker %r>' % self.name

    def __setattr__(self, name, value):
        if (
            name == 'short_biography'
            or name == 'long_biography'
            or name == 'speaking_experience'
            or name == 'sponsorship_required'
        ):
            super().__setattr__(name, clean_html(clean_up_string(value)))
        else:
            super().__setattr__(name, value)
class Event(db.Model):
    """Event object table"""
    __tablename__ = 'events'
    __versioned__ = {'exclude': ['schedule_published_on', 'created_at']}
    id = db.Column(db.Integer, primary_key=True)
    identifier = db.Column(db.String)
    name = db.Column(db.String, nullable=False)
    event_url = db.Column(db.String)
    email = db.Column(db.String)
    logo = db.Column(db.String)
    start_time = db.Column(db.DateTime, nullable=False)
    end_time = db.Column(db.DateTime, nullable=False)
    timezone = db.Column(db.String, nullable=False, default="UTC")
    latitude = db.Column(db.Float)
    longitude = db.Column(db.Float)
    location_name = db.Column(db.String)
    searchable_location_name = db.Column(db.String)
    description = db.Column(db.Text)
    background_url = db.Column(db.String)
    thumbnail = db.Column(db.String)
    large = db.Column(db.String)
    icon = db.Column(db.String)
    organizer_name = db.Column(db.String)
    show_map = db.Column(db.Integer)
    organizer_description = db.Column(db.String)
    has_session_speakers = db.Column(db.Boolean, default=False)
    track = db.relationship('Track', backref="event")
    microlocation = db.relationship('Microlocation', backref="event")
    session = db.relationship('Session', backref="event")
    speaker = db.relationship('Speaker', backref="event")
    sponsor = db.relationship('Sponsor', backref="event")
    users = db.relationship("EventsUsers", backref="event")
    roles = db.relationship("UsersEventsRoles", backref="event")
    role_invites = db.relationship('RoleInvite', back_populates='event')
    privacy = db.Column(db.String, default="public")
    state = db.Column(db.String, default="Draft")
    type = db.Column(db.String)
    topic = db.Column(db.String)
    sub_topic = db.Column(db.String)
    ticket_url = db.Column(db.String)
    db.UniqueConstraint('track.name')
    code_of_conduct = db.Column(db.String)
    schedule_published_on = db.Column(db.DateTime)
    ticket_include = db.Column(db.Boolean, default=False)
    deleted_at = db.Column(db.DateTime)
    payment_country = db.Column(db.String)
    payment_currency = db.Column(db.String)
    paypal_email = db.Column(db.String)
    tax_allow = db.Column(db.Boolean, default=False)
    pay_by_paypal = db.Column(db.Boolean, default=False)
    pay_by_stripe = db.Column(db.Boolean, default=False)
    pay_by_cheque = db.Column(db.Boolean, default=False)
    pay_by_bank = db.Column(db.Boolean, default=False)
    pay_onsite = db.Column(db.Boolean, default=False)
    cheque_details = db.Column(db.String)
    bank_details = db.Column(db.String)
    onsite_details = db.Column(db.String)
    created_at = db.Column(db.DateTime)

    discount_code_id = db.Column(db.Integer,
                                 db.ForeignKey('discount_codes.id',
                                               ondelete='SET NULL'),
                                 nullable=True,
                                 default=None)
    discount_code = db.relationship('DiscountCode',
                                    backref='events',
                                    foreign_keys=[discount_code_id])

    def __init__(self,
                 name=None,
                 logo=None,
                 start_time=None,
                 end_time=None,
                 timezone='UTC',
                 latitude=None,
                 longitude=None,
                 location_name=None,
                 email=None,
                 description=None,
                 event_url=None,
                 background_url=None,
                 thumbnail=None,
                 large=None,
                 icon=None,
                 organizer_name=None,
                 organizer_description=None,
                 state=None,
                 type=None,
                 privacy=None,
                 topic=None,
                 sub_topic=None,
                 ticket_url=None,
                 copyright=None,
                 code_of_conduct=None,
                 schedule_published_on=None,
                 has_session_speakers=False,
                 show_map=1,
                 searchable_location_name=None,
                 ticket_include=None,
                 deleted_at=None,
                 payment_country=None,
                 payment_currency=None,
                 paypal_email=None,
                 call_for_papers=None,
                 pay_by_paypal=None,
                 pay_by_stripe=None,
                 pay_by_cheque=None,
                 identifier=None,
                 pay_by_bank=None,
                 pay_onsite=None,
                 cheque_details=None,
                 bank_details=None,
                 discount_code_id=None,
                 onsite_details=None):

        self.name = name
        self.logo = logo
        self.email = email
        self.start_time = start_time
        self.end_time = end_time
        self.timezone = timezone
        self.latitude = latitude
        self.longitude = longitude
        self.location_name = location_name
        self.description = clean_up_string(description)
        self.event_url = event_url
        self.background_url = background_url
        self.thumbnail = thumbnail
        self.large = large
        self.icon = icon
        self.organizer_name = organizer_name
        self.organizer_description = clean_up_string(organizer_description)
        self.state = state
        self.show_map = show_map
        self.privacy = privacy
        self.type = type
        self.topic = topic
        self.copyright = copyright
        self.sub_topic = sub_topic
        self.ticket_url = ticket_url
        self.code_of_conduct = code_of_conduct
        self.schedule_published_on = schedule_published_on
        self.has_session_speakers = has_session_speakers
        self.searchable_location_name = searchable_location_name
        self.ticket_include = ticket_include
        self.deleted_at = deleted_at
        self.payment_country = payment_country
        self.payment_currency = payment_currency
        self.paypal_email = paypal_email
        self.call_for_papers = call_for_papers
        self.pay_by_paypal = pay_by_paypal
        self.pay_by_stripe = pay_by_stripe
        self.pay_by_cheque = pay_by_cheque
        self.pay_by_bank = pay_by_bank
        self.pay_onsite = pay_onsite
        self.identifier = get_new_event_identifier()
        self.cheque_details = cheque_details
        self.bank_details = bank_details
        self.onsite_details = onsite_details
        self.discount_code_id = discount_code_id
        self.created_at = datetime.utcnow()

    def __repr__(self):
        return '<Event %r>' % self.name

    def __str__(self):
        return unicode(self).encode('utf-8')

    def __unicode__(self):
        return self.name

    def __setattr__(self, name, value):
        if name == 'organizer_description' or name == 'description' or name == 'code_of_conduct':
            super(Event, self).__setattr__(name,
                                           clean_html(clean_up_string(value)))
        else:
            super(Event, self).__setattr__(name, value)

    def notification_settings(self, user_id):
        try:
            return EmailNotification.query.filter_by(
                user_id=(login.current_user.id if not user_id else int(user_id)
                         )).filter_by(event_id=self.id).first()
        except:
            return None

    def has_staff_access(self, user_id):
        """does user have role other than attendee"""
        access = False
        for _ in self.roles:
            if _.user_id == (login.current_user.id
                             if not user_id else int(user_id)):
                if _.role.name != ATTENDEE:
                    access = True
        return access

    def get_staff_roles(self):
        """returns only roles which are staff i.e. not attendee"""
        return [role for role in self.roles if role.role.name != ATTENDEE]

    @property
    def serialize(self):
        """Return object data in easily serializable format"""
        return {
            'id': self.id,
            'name': self.name,
            'logo': self.logo,
            'begin': DateFormatter().format_date(self.start_time),
            'end': DateFormatter().format_date(self.end_time),
            'timezone': self.timezone,
            'latitude': self.latitude,
            'longitude': self.longitude,
            'location_name': self.location_name,
            'email': self.email,
            'description': self.description,
            'event_url': self.event_url,
            'background_url': self.background_url,
            'thumbnail': self.thumbnail,
            'large': self.large,
            'icon': self.icon,
            'organizer_name': self.organizer_name,
            'organizer_description': self.organizer_description,
            'has_session_speakers': self.has_session_speakers,
            'privacy': self.privacy,
            'ticket_url': self.ticket_url,
            'code_of_conduct': self.code_of_conduct,
            'schedule_published_on': self.schedule_published_on
        }
Beispiel #18
0
class Ticket(db.Model):
    __tablename__ = 'ticket'
    __table_args__ = (db.UniqueConstraint('name',
                                          'event_id',
                                          name='name_event_uc'), )

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    description = db.Column(db.String)
    description_toggle = db.Column(db.Boolean)
    type = db.Column(db.String)
    quantity = db.Column(db.Integer)
    price = db.Column(db.Float)
    absorb_fees = db.Column(db.Boolean)

    sales_start = db.Column(db.DateTime)
    sales_end = db.Column(db.DateTime)
    hide = db.Column(db.Boolean)

    min_order = db.Column(db.Integer)
    max_order = db.Column(db.Integer)

    event_id = db.Column(db.Integer,
                         db.ForeignKey('events.id', ondelete='CASCADE'))
    event = db.relationship('Event', backref='tickets')

    tags = db.relationship('TicketTag',
                           secondary=ticket_tags_table,
                           backref='tickets')
    order_ticket = db.relationship('OrderTicket',
                                   backref="ticket",
                                   passive_deletes=True)

    def __init__(self,
                 name=None,
                 event=None,
                 type=None,
                 sales_start=None,
                 sales_end=None,
                 hide=False,
                 description=None,
                 description_toggle=True,
                 quantity=100,
                 price=0,
                 min_order=1,
                 max_order=10,
                 absorb_fees=False,
                 tags=None):

        if tags is None:
            tags = []
        self.name = name
        self.quantity = quantity
        self.type = type
        self.event = event
        self.description = description
        self.description_toggle = description_toggle
        self.price = price
        self.sales_start = sales_start
        self.sales_end = sales_end
        self.hide = hide
        self.min_order = min_order
        self.max_order = max_order
        self.tags = tags
        self.absorb_fees = absorb_fees

    def has_order_tickets(self):
        """Returns True if ticket has already placed orders.
        Else False.
        """
        from app.helpers.helpers import get_count
        orders = Order.id.in_(
            OrderTicket.query.with_entities(
                OrderTicket.order_id).filter_by(ticket_id=self.id).all())
        count = get_count(
            Order.query.filter(orders).filter(Order.status != 'deleted'))
        # Count is zero if no completed orders are present
        return bool(count > 0)

    def has_completed_order_tickets(self):
        """Returns True if ticket has already placed orders.
        Else False.
        """
        order_tickets = OrderTicket.query.filter_by(ticket_id=self.id)

        count = 0
        for order_ticket in order_tickets:
            order = Order.query.filter_by(id=order_ticket.order_id).first()
            if order.status == "completed" or order.status == "placed":
                count += 1

        return bool(count > 0)

    def tags_csv(self):
        """Return list of Tags in CSV.
        """
        tag_names = [tag.name for tag in self.tags]
        return ','.join(tag_names)

    def __repr__(self):
        return '<Ticket %r>' % self.name

    def __str__(self):
        return unicode(self).encode('utf-8')

    def __unicode__(self):
        return self.name

    @property
    def serialize(self):
        """Return object data in easily serializeable format"""
        data = {
            'id':
            self.id,
            'name':
            self.name,
            'quantity':
            self.quantity,
            'type':
            self.type,
            'description_visibility':
            self.description_toggle,
            'description':
            self.description,
            'price':
            self.price,
            'sales_start_date':
            self.sales_start.strftime('%m/%d/%Y') if self.sales_start else '',
            'sales_start_time':
            self.sales_start.strftime('%H:%M') if self.sales_start else '',
            'sales_end_date':
            self.sales_end.strftime('%m/%d/%Y') if self.sales_end else '',
            'sales_end_time':
            self.sales_end.strftime('%H:%M') if self.sales_end else '',
            'ticket_visibility':
            self.hide,
            'min_order':
            self.min_order,
            'max_order':
            self.max_order,
            'tags_string':
            '',
            'has_orders':
            self.has_order_tickets(),
            'has_completed_orders':
            self.has_completed_order_tickets(),
            'absorb_fees':
            self.absorb_fees
        }

        tags = []
        for tag in self.tags:
            tags.append(tag.name)

        data['tags'] = ",".join(tags)
        return data
Beispiel #19
0
class Ticket(SoftDeletionModel):
    __tablename__ = 'tickets'
    __table_args__ = (db.UniqueConstraint('name',
                                          'event_id',
                                          'deleted_at',
                                          name='name_event_deleted_at_uc'), )

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)
    description = db.Column(db.String)
    is_description_visible = db.Column(db.Boolean)
    type = db.Column(db.String, nullable=False)
    quantity = db.Column(db.Integer)
    position = db.Column(db.Integer)
    price = db.Column(db.Float)
    min_price = db.Column(db.Float, default=0, nullable=False)
    max_price = db.Column(db.Float)
    is_fee_absorbed = db.Column(db.Boolean)
    sales_starts_at = db.Column(db.DateTime(timezone=True), nullable=False)
    sales_ends_at = db.Column(db.DateTime(timezone=True), nullable=False)
    is_hidden = db.Column(db.Boolean)

    min_order = db.Column(db.Integer)
    max_order = db.Column(db.Integer)
    is_checkin_restricted = db.Column(db.Boolean)
    auto_checkin_enabled = db.Column(db.Boolean)
    event_id = db.Column(db.Integer,
                         db.ForeignKey('events.id', ondelete='CASCADE'))
    event = db.relationship('Event', backref='tickets_')

    tags = db.relationship('TicketTag',
                           secondary=ticket_tags_table,
                           backref='tickets')
    order_ticket = db.relationship('OrderTicket',
                                   backref="ticket",
                                   passive_deletes=True)

    access_codes = db.relationship('AccessCode',
                                   secondary=access_codes_tickets,
                                   backref='tickets')

    discount_codes = db.relationship('DiscountCode',
                                     secondary=discount_codes_tickets,
                                     backref="tickets")

    def __init__(self,
                 name=None,
                 event_id=None,
                 type=None,
                 sales_starts_at=None,
                 sales_ends_at=None,
                 is_hidden=False,
                 description=None,
                 is_description_visible=True,
                 is_checkin_restricted=True,
                 auto_checkin_enabled=False,
                 quantity=100,
                 position=1,
                 price=0,
                 min_order=1,
                 max_order=10,
                 min_price=0,
                 max_price=0,
                 is_fee_absorbed=False,
                 tags=[],
                 access_codes=[],
                 discount_codes=[]):

        self.name = name
        self.quantity = quantity
        self.position = position
        self.type = type
        self.event_id = event_id
        self.description = description
        self.is_description_visible = is_description_visible
        self.is_checkin_restricted = is_checkin_restricted
        self.auto_checkin_enabled = auto_checkin_enabled
        self.price = price
        self.min_price = min_price
        self.max_price = max_price
        self.sales_starts_at = sales_starts_at
        self.sales_ends_at = sales_ends_at
        self.is_hidden = is_hidden
        self.min_order = min_order
        self.max_order = max_order
        self.tags = tags
        self.is_fee_absorbed = is_fee_absorbed
        self.access_codes = access_codes
        self.discount_codes = discount_codes

    def has_order_tickets(self):
        """Returns True if ticket has already placed orders.
        Else False.
        """
        from app.api.helpers.db import get_count
        orders = Order.id.in_(
            OrderTicket.query.with_entities(
                OrderTicket.order_id).filter_by(ticket_id=self.id).all())
        count = get_count(
            Order.query.filter(orders).filter(Order.status != 'deleted'))
        # Count is zero if no completed orders are present
        return bool(count > 0)

    def has_completed_order_tickets(self):
        """Returns True if ticket has already placed orders.
        Else False.
        """
        order_tickets = OrderTicket.query.filter_by(ticket_id=self.id)

        count = 0
        for order_ticket in order_tickets:
            order = Order.query.filter_by(id=order_ticket.order_id).first()
            if order.status == "completed" or order.status == "placed":
                count += 1

        return bool(count > 0)

    def tags_csv(self):
        """Return list of Tags in CSV.
        """
        tag_names = [tag.name for tag in self.tags]
        return ','.join(tag_names)

    def __repr__(self):
        return '<Ticket %r>' % self.name

    def __str__(self):
        return self.__repr__()

    @property
    def serialize(self):
        """Return object data in easily serializable format"""
        data = {
            'id':
            self.id,
            'name':
            self.name,
            'quantity':
            self.quantity,
            'position':
            self.position,
            'type':
            self.type,
            'description_visibility':
            self.is_description_visible,
            'description':
            self.description,
            'price':
            self.price,
            'sales_start_date':
            self.sales_starts_at.strftime('%m/%d/%Y')
            if self.sales_starts_at else '',
            'sales_starts_at':
            self.sales_starts_at.strftime('%H:%M')
            if self.sales_starts_at else '',
            'sales_end_date':
            self.sales_ends_at.strftime('%m/%d/%Y')
            if self.sales_ends_at else '',
            'sales_ends_at':
            self.sales_ends_at.strftime('%H:%M') if self.sales_ends_at else '',
            'ticket_visibility':
            self.hide,
            'min_order':
            self.min_order,
            'max_order':
            self.max_order,
            'tags_string':
            '',
            'has_orders':
            self.has_order_tickets(),
            'has_completed_orders':
            self.has_completed_order_tickets(),
            'is_fee_absorbed':
            self.is_fee_absorbed
        }

        tags = []
        for tag in self.tags:
            tags.append(tag.name)

        data['tags'] = ",".join(tags)
        return data
Beispiel #20
0
class Event(SoftDeletionModel):
    """Event object table"""

    __tablename__ = 'events'
    __versioned__ = {'exclude': ['schedule_published_on', 'created_at']}
    id = db.Column(db.Integer, primary_key=True)
    identifier = db.Column(db.String, default=get_new_event_identifier)
    name = db.Column(db.String, nullable=False)
    external_event_url = db.Column(db.String)
    logo_url = db.Column(db.String)
    starts_at = db.Column(db.DateTime(timezone=True), nullable=False)
    ends_at = db.Column(db.DateTime(timezone=True), nullable=False)
    timezone = db.Column(db.String, nullable=False, default="UTC")
    online = db.Column(db.Boolean,
                       nullable=False,
                       default=False,
                       server_default='False')
    latitude = db.Column(db.Float)
    longitude = db.Column(db.Float)
    location_name = db.Column(db.String)
    searchable_location_name = db.Column(db.String)
    is_featured = db.Column(db.Boolean, default=False, nullable=False)
    is_promoted = db.Column(db.Boolean, default=False, nullable=False)
    description = db.Column(db.Text)
    original_image_url = db.Column(db.String)
    thumbnail_image_url = db.Column(db.String)
    large_image_url = db.Column(db.String)
    show_remaining_tickets = db.Column(db.Boolean,
                                       default=False,
                                       nullable=False)
    icon_image_url = db.Column(db.String)
    owner_name = db.Column(db.String)
    is_map_shown = db.Column(db.Boolean)
    has_owner_info = db.Column(db.Boolean)
    owner_description = db.Column(db.String)
    is_sessions_speakers_enabled = db.Column(db.Boolean, default=False)
    track = db.relationship('Track', backref="event")
    microlocation = db.relationship('Microlocation', backref="event")
    session = db.relationship('Session', backref="event")
    speaker = db.relationship('Speaker', backref="event")
    sponsor = db.relationship('Sponsor', backref="event")
    tickets = db.relationship('Ticket', backref="event_")
    tags = db.relationship('TicketTag', backref='events')
    roles = db.relationship("UsersEventsRoles", backref="event")
    role_invites = db.relationship('RoleInvite', back_populates='event')
    custom_form = db.relationship('CustomForms', backref="event")
    faqs = db.relationship('Faq', backref="event")
    feedbacks = db.relationship('Feedback', backref="event")
    attendees = db.relationship('TicketHolder', backref="event")
    privacy = db.Column(db.String, default="public")
    state = db.Column(db.String, default="Draft")
    event_type_id = db.Column(
        db.Integer, db.ForeignKey('event_types.id', ondelete='CASCADE'))
    event_topic_id = db.Column(
        db.Integer, db.ForeignKey('event_topics.id', ondelete='CASCADE'))
    event_sub_topic_id = db.Column(
        db.Integer, db.ForeignKey('event_sub_topics.id', ondelete='CASCADE'))
    ticket_url = db.Column(db.String)
    db.UniqueConstraint('track.name')
    code_of_conduct = db.Column(db.String)
    schedule_published_on = db.Column(db.DateTime(timezone=True))
    is_ticketing_enabled = db.Column(db.Boolean, default=False)
    is_donation_enabled = db.Column(db.Boolean, default=False)
    is_ticket_form_enabled = db.Column(db.Boolean,
                                       default=True,
                                       nullable=False)
    payment_country = db.Column(db.String)
    payment_currency = db.Column(db.String)
    paypal_email = db.Column(db.String)
    is_tax_enabled = db.Column(db.Boolean, default=False)
    is_billing_info_mandatory = db.Column(db.Boolean,
                                          default=False,
                                          nullable=False)
    can_pay_by_paypal = db.Column(db.Boolean, default=False, nullable=False)
    can_pay_by_stripe = db.Column(db.Boolean, default=False, nullable=False)
    can_pay_by_cheque = db.Column(db.Boolean, default=False, nullable=False)
    can_pay_by_bank = db.Column(db.Boolean, default=False, nullable=False)
    can_pay_onsite = db.Column(db.Boolean, default=False, nullable=False)
    can_pay_by_omise = db.Column(db.Boolean, default=False, nullable=False)
    can_pay_by_alipay = db.Column(db.Boolean, default=False, nullable=False)
    can_pay_by_paytm = db.Column(db.Boolean, default=False, nullable=False)
    cheque_details = db.Column(db.String)
    bank_details = db.Column(db.String)
    onsite_details = db.Column(db.String)
    created_at = db.Column(db.DateTime(timezone=True), default=func.now())
    pentabarf_url = db.Column(db.String)
    ical_url = db.Column(db.String)
    xcal_url = db.Column(db.String)
    is_sponsors_enabled = db.Column(db.Boolean, default=False)
    refund_policy = db.Column(db.String)
    is_stripe_linked = db.Column(db.Boolean, default=False)
    live_stream_url = db.Column(db.String)
    webinar_url = db.Column(db.String)
    discount_code_id = db.Column(
        db.Integer, db.ForeignKey('discount_codes.id', ondelete='CASCADE'))
    discount_code = db.relationship('DiscountCode',
                                    backref='events',
                                    foreign_keys=[discount_code_id])
    event_type = db.relationship('EventType',
                                 backref='event',
                                 foreign_keys=[event_type_id])
    event_topic = db.relationship('EventTopic',
                                  backref='event',
                                  foreign_keys=[event_topic_id])
    event_sub_topic = db.relationship('EventSubTopic',
                                      backref='event',
                                      foreign_keys=[event_sub_topic_id])
    owner = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "owner"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='owner_events',
        uselist=False,
    )
    organizers = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "organizer"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='organizer_events',
    )
    coorganizers = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "coorganizer"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='coorganizer_events',
    )
    track_organizers = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id,'
        ' Role.name == "track_organizer"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='track_organizer_events',
    )
    registrars = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "registrar"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='registrar_events',
    )
    moderators = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "moderator"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='moderator_events',
    )
    # staff
    users = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name != "attendee"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='events',
    )

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        original_image_url = kwargs.get('original_image_url')
        self.original_image_url = (self.set_default_event_image(
            kwargs.get('event_topic_id')) if original_image_url is None else
                                   original_image_url)
        # TODO(Areeb): Test for cleaning up of these on __init__
        self.description = clean_up_string(kwargs.get('description'))
        self.owner_description = clean_up_string(
            kwargs.get('owner_description'))
        self.code_of_conduct = clean_up_string(kwargs.get('code_of_conduct'))

    def __repr__(self):
        return '<Event %r>' % self.name

    def __setattr__(self, name, value):
        allow_link = name == 'description'
        if (name == 'owner_description' or name == 'description'
                or name == 'code_of_conduct'):
            super().__setattr__(
                name, clean_html(clean_up_string(value),
                                 allow_link=allow_link))
        else:
            super().__setattr__(name, value)

    @classmethod
    def set_default_event_image(cls, event_topic_id):
        if event_topic_id is None:
            return None
        event_topic = EventTopic.query.filter_by(id=event_topic_id).first()
        return event_topic.system_image_url

    @property
    def fee(self):
        """
        Returns the fee as a percentage from 0 to 100 for this event
        """
        return get_fee(self.payment_country, self.payment_currency)

    @property
    def maximum_fee(self):
        """
        Returns the maximum fee for this event
        """
        return get_maximum_fee(self.payment_country, self.payment_currency)

    def notification_settings(self, user_id):
        try:
            return (EmailNotification.query.filter_by(
                user_id=(login.current_user.id if not user_id else int(user_id)
                         )).filter_by(event_id=self.id).first())
        except:
            return None

    def get_average_rating(self):
        avg = (db.session.query(func.avg(
            Feedback.rating)).filter_by(event_id=self.id).scalar())
        if avg is not None:
            avg = round(avg, 2)
        return avg

    def is_payment_enabled(self):
        return (self.can_pay_by_paypal or self.can_pay_by_stripe
                or self.can_pay_by_omise or self.can_pay_by_alipay
                or self.can_pay_by_cheque or self.can_pay_by_bank
                or self.can_pay_onsite or self.can_pay_by_paytm)

    @property
    def average_rating(self):
        return self.get_average_rating()

    def get_organizer(self):
        """returns organizer of an event"""
        for role in self.roles:
            if role.role.name == ORGANIZER:
                return role.user
        return None

    def get_owner(self):
        """returns owner of an event"""
        for role in self.roles:
            if role.role.name == OWNER:
                return role.user
        return None

    def has_staff_access(self, user_id):
        """does user have role other than attendee"""
        for _ in self.roles:
            if _.user_id == (login.current_user.id
                             if not user_id else int(user_id)):
                if _.role.name != ATTENDEE:
                    return True
        return False

    def get_staff_roles(self):
        """returns only roles which are staff i.e. not attendee"""
        return [role for role in self.roles if role.role.name != ATTENDEE]

    def as_dict(self):
        return {c.name: getattr(self, c.name) for c in self.__table__.columns}

    @property
    def tickets_sold_object(self):
        obj = (db.session.query(Order.event_id).filter_by(
            event_id=self.id, status='completed').join(TicketHolder))
        return obj

    def calc_tickets_sold_count(self):
        """Calculate total number of tickets sold for the event"""
        return self.tickets_sold_object.count()

    def calc_tickets_sold_prev_month(self):
        """Calculate tickets sold in the previous month"""
        previous_month = datetime.now().month - 1
        return self.tickets_sold_object.filter_by(
            completed_at=previous_month).count()

    def calc_total_tickets_count(self):
        """Calculate total available tickets for all types of tickets"""
        total_available = (db.session.query(func.sum(
            Ticket.quantity)).filter_by(event_id=self.id).scalar())
        if total_available is None:
            total_available = 0
        return total_available

    def get_orders_query(self, start=None, end=None):
        query = Order.query.filter_by(event_id=self.id, status='completed')
        if start:
            query = query.filter(Order.completed_at > start)
        if end:
            query = query.filter(Order.completed_at < end)
        return query

    def calc_revenue(self, start=None, end=None):
        """Returns total revenues of all completed orders for the given event"""
        return (self.get_orders_query(start=start, end=end).with_entities(
            func.sum(Order.amount)).scalar() or 0)

    @property
    def tickets_available(self):
        return self.calc_total_tickets_count()

    @property
    def tickets_sold(self):
        return self.calc_tickets_sold_count()

    @property
    def revenue(self):
        return self.calc_revenue()

    @property
    def has_sessions(self):
        return Session.query.filter_by(event_id=self.id).count() > 0

    @property
    def has_speakers(self):
        return Speaker.query.filter_by(event_id=self.id).count() > 0

    @property
    def order_statistics(self):
        return Namespace(id=self.id)

    @property
    def general_statistics(self):
        return Namespace(id=self.id)
Beispiel #21
0
class Ticket(SoftDeletionModel):
    __tablename__ = 'tickets'
    __table_args__ = (db.UniqueConstraint('name',
                                          'event_id',
                                          'deleted_at',
                                          name='name_event_deleted_at_uc'), )

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)
    description = db.Column(db.String)
    is_description_visible = db.Column(db.Boolean)
    type = db.Column(db.String, nullable=False)
    quantity = db.Column(db.Integer, default=100)
    position = db.Column(db.Integer, default=1)
    price = db.Column(db.Float, default=0)
    min_price = db.Column(db.Float, default=0, nullable=False)
    max_price = db.Column(db.Float, default=0)
    is_fee_absorbed = db.Column(db.Boolean, default=False)
    sales_starts_at = db.Column(db.DateTime(timezone=True), nullable=False)
    sales_ends_at = db.Column(db.DateTime(timezone=True), nullable=False)
    is_hidden = db.Column(db.Boolean, default=False)

    min_order = db.Column(db.Integer, default=1)
    max_order = db.Column(db.Integer, default=10)
    is_checkin_restricted = db.Column(db.Boolean)
    auto_checkin_enabled = db.Column(db.Boolean, default=False)
    event_id = db.Column(db.Integer,
                         db.ForeignKey('events.id', ondelete='CASCADE'))
    event = db.relationship('Event', backref='tickets_')

    tags = db.relationship('TicketTag',
                           secondary=ticket_tags_table,
                           backref='tickets')
    order_ticket = db.relationship('OrderTicket',
                                   backref="ticket",
                                   passive_deletes=True)

    access_codes = db.relationship('AccessCode',
                                   secondary=access_codes_tickets,
                                   backref='tickets')

    discount_codes = db.relationship('DiscountCode',
                                     secondary=discount_codes_tickets,
                                     backref="tickets")

    def has_order_tickets(self):
        """Returns True if ticket has already placed orders.
        Else False.
        """
        from app.api.helpers.db import get_count

        orders = Order.id.in_(
            OrderTicket.query.with_entities(
                OrderTicket.order_id).filter_by(ticket_id=self.id).all())
        count = get_count(
            Order.query.filter(orders).filter(Order.status != 'deleted'))
        # Count is zero if no completed orders are present
        return bool(count > 0)

    def has_completed_order_tickets(self):
        """Returns True if ticket has already placed orders.
        Else False.
        """
        order_tickets = OrderTicket.query.filter_by(ticket_id=self.id)

        count = 0
        for order_ticket in order_tickets:
            order = Order.query.filter_by(id=order_ticket.order_id).first()
            if order.status == "completed" or order.status == "placed":
                count += 1

        return bool(count > 0)

    def tags_csv(self):
        """Return list of Tags in CSV."""
        tag_names = [tag.name for tag in self.tags]
        return ','.join(tag_names)

    @property
    def has_current_orders(self):
        return db.session.query(
            Order.query.join(TicketHolder).filter(
                TicketHolder.ticket_id == self.id,
                or_(Order.status == 'completed', Order.status == 'placed',
                    Order.status == 'pending',
                    Order.status == 'initializing')).exists()).scalar()

    @property
    def reserved_count(self):
        from app.api.attendees import get_sold_and_reserved_tickets_count

        return get_sold_and_reserved_tickets_count(self.id)

    @property
    def is_available(self):
        return self.reserved_count < self.quantity

    def raise_if_unavailable(self):
        if not self.is_available:
            raise ConflictError({'id': self.id},
                                f"Ticket {self.id} already sold out")

    def __repr__(self):
        return '<Ticket %r>' % self.name
Beispiel #22
0
class Event(SoftDeletionModel):
    """Event object table"""
    __tablename__ = 'events'
    __versioned__ = {'exclude': ['schedule_published_on', 'created_at']}
    id = db.Column(db.Integer, primary_key=True)
    identifier = db.Column(db.String)
    name = db.Column(db.String, nullable=False)
    external_event_url = db.Column(db.String)
    logo_url = db.Column(db.String)
    starts_at = db.Column(db.DateTime(timezone=True), nullable=False)
    ends_at = db.Column(db.DateTime(timezone=True), nullable=False)
    timezone = db.Column(db.String, nullable=False, default="UTC")
    is_event_online = db.Column(db.Boolean, default=False)
    latitude = db.Column(db.Float)
    longitude = db.Column(db.Float)
    location_name = db.Column(db.String)
    searchable_location_name = db.Column(db.String)
    is_featured = db.Column(db.Boolean, default=False, nullable=False)
    description = db.Column(db.Text)
    original_image_url = db.Column(db.String)
    thumbnail_image_url = db.Column(db.String)
    large_image_url = db.Column(db.String)
    show_remaining_tickets = db.Column(db.Boolean,
                                       default=False,
                                       nullable=False)
    icon_image_url = db.Column(db.String)
    owner_name = db.Column(db.String)
    is_map_shown = db.Column(db.Boolean)
    has_owner_info = db.Column(db.Boolean)
    owner_description = db.Column(db.String)
    is_sessions_speakers_enabled = db.Column(db.Boolean, default=False)
    track = db.relationship('Track', backref="event")
    microlocation = db.relationship('Microlocation', backref="event")
    session = db.relationship('Session', backref="event")
    speaker = db.relationship('Speaker', backref="event")
    sponsor = db.relationship('Sponsor', backref="event")
    tickets = db.relationship('Ticket', backref="event_")
    tags = db.relationship('TicketTag', backref='events')
    roles = db.relationship("UsersEventsRoles", backref="event")
    role_invites = db.relationship('RoleInvite', back_populates='event')
    custom_form = db.relationship('CustomForms', backref="event")
    faqs = db.relationship('Faq', backref="event")
    feedbacks = db.relationship('Feedback', backref="event")
    attendees = db.relationship('TicketHolder', backref="event")
    privacy = db.Column(db.String, default="public")
    state = db.Column(db.String, default="Draft")
    event_type_id = db.Column(
        db.Integer, db.ForeignKey('event_types.id', ondelete='CASCADE'))
    event_topic_id = db.Column(
        db.Integer, db.ForeignKey('event_topics.id', ondelete='CASCADE'))
    event_sub_topic_id = db.Column(
        db.Integer, db.ForeignKey('event_sub_topics.id', ondelete='CASCADE'))
    events_orga_id = db.Column(
        db.Integer, db.ForeignKey('events_orga.id', ondelete='CASCADE'))
    ticket_url = db.Column(db.String)
    db.UniqueConstraint('track.name')
    code_of_conduct = db.Column(db.String)
    schedule_published_on = db.Column(db.DateTime(timezone=True))
    is_ticketing_enabled = db.Column(db.Boolean, default=False)
    is_donation_enabled = db.Column(db.Boolean, default=False)
    is_ticket_form_enabled = db.Column(db.Boolean,
                                       default=True,
                                       nullable=False)
    payment_country = db.Column(db.String)
    payment_currency = db.Column(db.String)
    paypal_email = db.Column(db.String)
    is_tax_enabled = db.Column(db.Boolean, default=False)
    is_billing_info_mandatory = db.Column(db.Boolean, default=False)
    can_pay_by_paypal = db.Column(db.Boolean, default=False)
    can_pay_by_stripe = db.Column(db.Boolean, default=False)
    can_pay_by_cheque = db.Column(db.Boolean, default=False)
    can_pay_by_bank = db.Column(db.Boolean, default=False)
    can_pay_onsite = db.Column(db.Boolean, default=False)
    can_pay_by_omise = db.Column(db.Boolean, default=False)
    can_pay_by_alipay = db.Column(db.Boolean, default=False)
    cheque_details = db.Column(db.String)
    bank_details = db.Column(db.String)
    onsite_details = db.Column(db.String)
    created_at = db.Column(db.DateTime(timezone=True))
    pentabarf_url = db.Column(db.String)
    ical_url = db.Column(db.String)
    xcal_url = db.Column(db.String)
    is_sponsors_enabled = db.Column(db.Boolean, default=False)
    refund_policy = db.Column(
        db.String,
        default='All sales are final. No refunds shall be issued in any case.')
    is_stripe_linked = db.Column(db.Boolean, default=False)
    discount_code_id = db.Column(
        db.Integer, db.ForeignKey('discount_codes.id', ondelete='CASCADE'))
    discount_code = db.relationship('DiscountCode',
                                    backref='events',
                                    foreign_keys=[discount_code_id])
    event_type = db.relationship('EventType',
                                 backref='event',
                                 foreign_keys=[event_type_id])
    event_topic = db.relationship('EventTopic',
                                  backref='event',
                                  foreign_keys=[event_topic_id])
    event_sub_topic = db.relationship('EventSubTopic',
                                      backref='event',
                                      foreign_keys=[event_sub_topic_id])
    events_orga = db.relationship('EventOrgaModel',
                                  backref='event',
                                  foreign_keys=[events_orga_id])
    owner = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "owner"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='owner_events',
        uselist=False)
    organizers = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "organizer"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='organizer_events')
    coorganizers = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "coorganizer"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='coorganizer_events')
    track_organizers = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id,'
        ' Role.name == "track_organizer"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='track_organizer_events')
    registrars = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "registrar"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='registrar_events')
    moderators = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "moderator"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='moderator_events')
    # staff
    users = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name != "attendee"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='events')

    def __init__(
            self,
            name=None,
            logo_url=None,
            starts_at=None,
            ends_at=None,
            timezone='UTC',
            is_event_online=False,
            latitude=None,
            longitude=None,
            location_name=None,
            description=None,
            external_event_url=None,
            original_image_url=None,
            thumbnail_image_url=None,
            large_image_url=None,
            icon_image_url=None,
            owner_name=None,
            owner_description=None,
            state=None,
            event_type_id=None,
            privacy=None,
            event_topic_id=None,
            event_sub_topic_id=None,
            events_orga_id=None,
            ticket_url=None,
            copyright=None,
            code_of_conduct=None,
            schedule_published_on=None,
            is_sessions_speakers_enabled=False,
            show_remaining_tickets=False,
            is_ticket_form_enabled=True,
            is_donation_enabled=False,
            is_map_shown=False,
            has_owner_info=False,
            searchable_location_name=None,
            is_ticketing_enabled=None,
            deleted_at=None,
            payment_country=None,
            payment_currency=None,
            paypal_email=None,
            speakers_call=None,
            can_pay_by_paypal=None,
            can_pay_by_stripe=None,
            can_pay_by_cheque=None,
            can_pay_by_omise=None,
            can_pay_by_alipay=None,
            identifier=None,
            can_pay_by_bank=None,
            is_featured=False,
            can_pay_onsite=None,
            cheque_details=None,
            bank_details=None,
            pentabarf_url=None,
            ical_url=None,
            xcal_url=None,
            discount_code_id=None,
            onsite_details=None,
            is_tax_enabled=None,
            is_billing_info_mandatory=False,
            is_sponsors_enabled=None,
            stripe_authorization=None,
            tax=None,
            refund_policy='All sales are final. No refunds shall be issued in any case.',
            is_stripe_linked=False):

        self.name = name
        self.logo_url = logo_url
        self.starts_at = starts_at
        self.ends_at = ends_at
        self.timezone = timezone
        self.is_event_online = is_event_online
        self.latitude = latitude
        self.longitude = longitude
        self.location_name = location_name
        self.description = clean_up_string(description)
        self.external_event_url = external_event_url
        self.original_image_url = original_image_url
        self.original_image_url = self.set_default_event_image(event_topic_id) if original_image_url is None \
            else original_image_url
        self.thumbnail_image_url = thumbnail_image_url
        self.large_image_url = large_image_url
        self.icon_image_url = icon_image_url
        self.owner_name = owner_name
        self.owner_description = clean_up_string(owner_description)
        self.state = state
        self.is_map_shown = is_map_shown
        self.has_owner_info = has_owner_info
        self.privacy = privacy
        self.event_type_id = event_type_id
        self.event_topic_id = event_topic_id
        self.show_remaining_tickets = show_remaining_tickets
        self.copyright = copyright
        self.event_sub_topic_id = event_sub_topic_id
        self.events_orga_id = events_orga_id
        self.ticket_url = ticket_url
        self.code_of_conduct = code_of_conduct
        self.schedule_published_on = schedule_published_on
        self.is_sessions_speakers_enabled = is_sessions_speakers_enabled
        self.searchable_location_name = searchable_location_name
        self.is_ticketing_enabled = is_ticketing_enabled
        self.deleted_at = deleted_at
        self.payment_country = payment_country
        self.payment_currency = payment_currency
        self.paypal_email = paypal_email
        self.speakers_call = speakers_call
        self.can_pay_by_paypal = can_pay_by_paypal
        self.can_pay_by_stripe = can_pay_by_stripe
        self.can_pay_by_cheque = can_pay_by_cheque
        self.can_pay_by_bank = can_pay_by_bank
        self.can_pay_onsite = can_pay_onsite
        self.can_pay_by_omise = can_pay_by_omise
        self.can_pay_by_alipay = can_pay_by_alipay
        self.is_donation_enabled = is_donation_enabled
        self.is_featured = is_featured
        self.is_ticket_form_enabled = is_ticket_form_enabled
        self.identifier = get_new_event_identifier()
        self.cheque_details = cheque_details
        self.bank_details = bank_details
        self.pentabarf_url = pentabarf_url
        self.ical_url = ical_url
        self.xcal_url = xcal_url
        self.onsite_details = onsite_details
        self.discount_code_id = discount_code_id
        self.created_at = datetime.now(pytz.utc)
        self.is_tax_enabled = is_tax_enabled
        self.is_billing_info_mandatory = is_billing_info_mandatory
        self.is_sponsors_enabled = is_sponsors_enabled
        self.stripe_authorization = stripe_authorization
        self.tax = tax
        self.refund_policy = refund_policy
        self.is_stripe_linked = is_stripe_linked

    def __repr__(self):
        return '<Event %r>' % self.name

    def __str__(self):
        return self.__repr__()

    def __setattr__(self, name, value):
        if name == 'owner_description' or name == 'description' or name == 'code_of_conduct':
            super(Event, self).__setattr__(name,
                                           clean_html(clean_up_string(value)))
        else:
            super(Event, self).__setattr__(name, value)

    @classmethod
    def set_default_event_image(self, event_topic_id):
        if event_topic_id is None:
            return None
        else:
            event_topic = EventTopic.query.filter_by(id=event_topic_id).first()
            return event_topic.system_image_url

    @property
    def fee(self):
        """
        Returns the fee as a percentage from 0 to 100 for this event
        """
        return get_fee(self.payment_country, self.payment_currency)

    @property
    def maximum_fee(self):
        """
        Returns the maximum fee for this event
        """
        return get_maximum_fee(self.payment_country, self.payment_currency)

    def notification_settings(self, user_id):
        try:
            return EmailNotification.query.filter_by(
                user_id=(login.current_user.id if not user_id else int(user_id))). \
                filter_by(event_id=self.id).first()
        except:
            return None

    def get_average_rating(self):
        avg = db.session.query(func.avg(
            Feedback.rating)).filter_by(event_id=self.id).scalar()
        if avg is not None:
            avg = round(avg, 2)
        return avg

    def is_payment_enabled(self):
        return self.can_pay_by_paypal or self.can_pay_by_stripe or self.can_pay_by_omise or self.can_pay_by_alipay \
            or self.can_pay_by_cheque or self.can_pay_by_bank or self.can_pay_onsite

    @property
    def average_rating(self):
        return self.get_average_rating()

    def get_organizer(self):
        """returns organizer of an event"""
        for role in self.roles:
            if role.role.name == ORGANIZER:
                return role.user
        return None

    def get_owner(self):
        """returns owner of an event"""
        for role in self.roles:
            if role.role.name == OWNER:
                return role.user
        return None

    def has_staff_access(self, user_id):
        """does user have role other than attendee"""
        for _ in self.roles:
            if _.user_id == (login.current_user.id
                             if not user_id else int(user_id)):
                if _.role.name != ATTENDEE:
                    return True
        return False

    def get_staff_roles(self):
        """returns only roles which are staff i.e. not attendee"""
        return [role for role in self.roles if role.role.name != ATTENDEE]

    def as_dict(self):
        return {c.name: getattr(self, c.name) for c in self.__table__.columns}

    def calc_tickets_sold_count(self):
        """Calculate total number of tickets sold for the event"""
        return db.session.query(Order.event_id).filter_by(event_id=self.id, status='completed').join(TicketHolder)\
            .count()

    def calc_total_tickets_count(self):
        """Calculate total available tickets for all types of tickets"""
        total_available = db.session.query(func.sum(
            Ticket.quantity)).filter_by(event_id=self.id).scalar()
        if total_available is None:
            total_available = 0
        return total_available

    def calc_revenue(self):
        """Returns total revenues of all completed orders for the given event"""
        revenue = db.session.query(func.sum(Order.amount)).filter_by(
            event_id=self.id, status='completed').scalar()
        if revenue is None:
            revenue = 0
        return revenue

    def calc_monthly_revenue(self):
        """Returns revenue of current month. Invoice sent every 1st of the month for the previous month"""
        previous_month = datetime.datetime.now().month - 1
        monthly_revenue = db.session.query(func.sum(Order.amount)).filter(
            Order.event_id == self.id,
            Order.completed_at.month == previous_month,
            Order.status == 'completed').scalar()
        if monthly_revenue is None:
            monthly_revenue = 0
        return monthly_revenue

    @property
    def tickets_available(self):
        return self.calc_total_tickets_count()

    @property
    def tickets_sold(self):
        return self.calc_tickets_sold_count()

    @property
    def revenue(self):
        return self.calc_revenue()

    @property
    def has_sessions(self):
        return Session.query.filter_by(event_id=self.id).count() > 0

    @property
    def has_speakers(self):
        return Speaker.query.filter_by(event_id=self.id).count() > 0
Beispiel #23
0
class Event(SoftDeletionModel):
    """Event object table"""
    class State:
        PUBLISHED = 'published'
        DRAFT = 'draft'

    class Privacy:
        PUBLIC = 'public'
        PRIVATE = 'private'

    __tablename__ = 'events'
    __versioned__ = {'exclude': ['schedule_published_on', 'created_at']}
    id = db.Column(db.Integer, primary_key=True)
    identifier = db.Column(db.String,
                           default=get_new_event_identifier,
                           nullable=False,
                           unique=True)
    name = db.Column(db.String, nullable=False)
    external_event_url = db.Column(db.String)
    logo_url = db.Column(db.String)
    starts_at = db.Column(db.DateTime(timezone=True), nullable=False)
    ends_at = db.Column(db.DateTime(timezone=True), nullable=False)
    timezone = db.Column(db.String, nullable=False, default="UTC")
    online = db.Column(db.Boolean,
                       nullable=False,
                       default=False,
                       server_default='False')
    latitude = db.Column(db.Float)
    longitude = db.Column(db.Float)
    location_name = db.Column(db.String)
    searchable_location_name = db.Column(db.String)
    is_featured = db.Column(db.Boolean, default=False, nullable=False)
    is_promoted = db.Column(db.Boolean, default=False, nullable=False)
    is_demoted = db.Column(db.Boolean, default=False, nullable=False)
    is_chat_enabled = db.Column(db.Boolean, default=False, nullable=False)
    is_videoroom_enabled = db.Column(db.Boolean, default=False, nullable=False)
    is_document_enabled = db.Column(db.Boolean, default=False, nullable=False)
    document_links = db.Column(JSONB)
    chat_room_id = db.Column(db.String)
    description = db.Column(db.Text)
    after_order_message = db.Column(db.Text)
    original_image_url = db.Column(db.String)
    thumbnail_image_url = db.Column(db.String)
    large_image_url = db.Column(db.String)
    show_remaining_tickets = db.Column(db.Boolean,
                                       default=False,
                                       nullable=False)
    icon_image_url = db.Column(db.String)
    owner_name = db.Column(db.String)
    is_map_shown = db.Column(db.Boolean)
    is_oneclick_signup_enabled = db.Column(db.Boolean)
    has_owner_info = db.Column(db.Boolean)
    owner_description = db.Column(db.String)
    is_sessions_speakers_enabled = db.Column(db.Boolean, default=False)
    is_cfs_enabled = db.Column(db.Boolean,
                               default=False,
                               nullable=False,
                               server_default='False')
    track = db.relationship('Track', backref="event")
    microlocation = db.relationship('Microlocation', backref="event")
    session = db.relationship('Session', backref="event")
    speaker = db.relationship('Speaker', backref="event")
    sponsor = db.relationship('Sponsor', backref="event")
    exhibitors = db.relationship('Exhibitor', backref="event")
    tickets = db.relationship('Ticket', backref="event_")
    tags = db.relationship('TicketTag', backref='events')
    roles = db.relationship("UsersEventsRoles", backref="event")
    role_invites = db.relationship('RoleInvite', back_populates='event')
    custom_form = db.relationship('CustomForms', backref="event")
    faqs = db.relationship('Faq', backref="event")
    feedbacks = db.relationship('Feedback', backref="event")
    attendees = db.relationship('TicketHolder', backref="event")
    privacy = db.Column(db.String, default="public")
    state = db.Column(db.String, default="draft")
    event_type_id = db.Column(
        db.Integer, db.ForeignKey('event_types.id', ondelete='CASCADE'))
    event_topic_id = db.Column(
        db.Integer, db.ForeignKey('event_topics.id', ondelete='CASCADE'))
    event_sub_topic_id = db.Column(
        db.Integer, db.ForeignKey('event_sub_topics.id', ondelete='CASCADE'))
    group_id = db.Column(db.Integer,
                         db.ForeignKey('groups.id', ondelete='SET NULL'))
    is_announced = db.Column(db.Boolean,
                             default=False,
                             nullable=False,
                             server_default='False')
    ticket_url = db.Column(db.String)
    db.UniqueConstraint('track.name')
    code_of_conduct = db.Column(db.String)
    schedule_published_on = db.Column(db.DateTime(timezone=True))
    is_ticketing_enabled = db.Column(db.Boolean, default=False)
    is_donation_enabled = db.Column(db.Boolean, default=False)
    is_ticket_form_enabled = db.Column(db.Boolean,
                                       default=True,
                                       nullable=False)
    payment_country = db.Column(db.String)
    payment_currency = db.Column(db.String)
    paypal_email = db.Column(db.String)
    is_tax_enabled = db.Column(db.Boolean, default=False)
    is_billing_info_mandatory = db.Column(db.Boolean,
                                          default=False,
                                          nullable=False)
    can_pay_by_paypal = db.Column(db.Boolean,
                                  default=False,
                                  nullable=False,
                                  server_default='False')
    can_pay_by_stripe = db.Column(db.Boolean,
                                  default=False,
                                  nullable=False,
                                  server_default='False')
    can_pay_by_cheque = db.Column(db.Boolean,
                                  default=False,
                                  nullable=False,
                                  server_default='False')
    can_pay_by_bank = db.Column(db.Boolean,
                                default=False,
                                nullable=False,
                                server_default='False')
    can_pay_by_invoice = db.Column(db.Boolean,
                                   default=False,
                                   nullable=False,
                                   server_default='False')
    can_pay_onsite = db.Column(db.Boolean,
                               default=False,
                               nullable=False,
                               server_default='False')
    can_pay_by_omise = db.Column(db.Boolean,
                                 default=False,
                                 nullable=False,
                                 server_default='False')
    can_pay_by_alipay = db.Column(db.Boolean,
                                  default=False,
                                  nullable=False,
                                  server_default='False')
    can_pay_by_paytm = db.Column(db.Boolean,
                                 default=False,
                                 nullable=False,
                                 server_default='False')
    cheque_details = db.Column(db.String)
    bank_details = db.Column(db.String)
    onsite_details = db.Column(db.String)
    invoice_details = db.Column(db.String)
    created_at = db.Column(db.DateTime(timezone=True), default=func.now())
    pentabarf_url = db.Column(db.String)
    ical_url = db.Column(db.String)
    xcal_url = db.Column(db.String)
    is_sponsors_enabled = db.Column(db.Boolean, default=False)
    refund_policy = db.Column(db.String)
    is_stripe_linked = db.Column(db.Boolean, default=False)
    completed_order_sales = db.Column(db.Integer)
    placed_order_sales = db.Column(db.Integer)
    pending_order_sales = db.Column(db.Integer)
    completed_order_tickets = db.Column(db.Integer)
    placed_order_tickets = db.Column(db.Integer)
    pending_order_tickets = db.Column(db.Integer)
    discount_code_id = db.Column(
        db.Integer, db.ForeignKey('discount_codes.id', ondelete='CASCADE'))
    discount_code = db.relationship('DiscountCode',
                                    backref='events',
                                    foreign_keys=[discount_code_id])
    event_type = db.relationship('EventType',
                                 backref='event',
                                 foreign_keys=[event_type_id])
    event_topic = db.relationship('EventTopic',
                                  backref='event',
                                  foreign_keys=[event_topic_id])
    event_sub_topic = db.relationship('EventSubTopic',
                                      backref='event',
                                      foreign_keys=[event_sub_topic_id])
    group = db.relationship('Group', backref='events', foreign_keys=[group_id])
    owner = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "owner"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='owner_events',
        sync_backref=False,
        uselist=False,
    )
    organizers = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "organizer"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='organizer_events',
        sync_backref=False,
    )
    coorganizers = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "coorganizer"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='coorganizer_events',
        sync_backref=False,
    )
    track_organizers = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id,'
        ' Role.name == "track_organizer"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='track_organizer_events',
        sync_backref=False,
    )
    registrars = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "registrar"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='registrar_events',
        sync_backref=False,
    )
    moderators = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "moderator"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='moderator_events',
        sync_backref=False,
    )
    # staff
    users = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='events',
        sync_backref=False,
    )

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        original_image_url = kwargs.get('original_image_url')
        self.original_image_url = (self.set_default_event_image(
            kwargs.get('event_topic_id')) if original_image_url is None else
                                   original_image_url)
        # TODO(Areeb): Test for cleaning up of these on __init__
        self.description = clean_up_string(kwargs.get('description'))
        self.owner_description = clean_up_string(
            kwargs.get('owner_description'))
        self.code_of_conduct = clean_up_string(kwargs.get('code_of_conduct'))
        self.after_order_message = clean_up_string(
            kwargs.get('after_order_message'))

    def __repr__(self):
        return '<Event %r>' % self.name

    def __setattr__(self, name, value):
        allow_link = name == 'description' or 'owner_description' or 'after_order_message'
        if (name == 'owner_description' or name == 'description'
                or name == 'code_of_conduct' or name == 'after_order_message'):
            super().__setattr__(
                name, clean_html(clean_up_string(value),
                                 allow_link=allow_link))
        else:
            super().__setattr__(name, value)

    @classmethod
    def set_default_event_image(cls, event_topic_id):
        if event_topic_id is None:
            return None
        event_topic = EventTopic.query.filter_by(id=event_topic_id).first()
        return event_topic.system_image_url

    @property
    def fee(self):
        """
        Returns the fee as a percentage from 0 to 100 for this event
        """
        return get_fee(self.payment_country, self.payment_currency)

    @property
    def maximum_fee(self):
        """
        Returns the maximum fee for this event
        """
        return get_maximum_fee(self.payment_country, self.payment_currency)

    def notification_settings(self, user_id):
        try:
            return (EmailNotification.query.filter_by(
                user_id=(login.current_user.id if not user_id else int(user_id)
                         )).filter_by(event_id=self.id).first())
        except:
            return None

    def get_average_rating(self):
        avg = (db.session.query(func.avg(
            Feedback.rating)).filter_by(event_id=self.id).scalar())
        if avg is not None:
            avg = round(avg, 2)
        return avg

    def is_payment_enabled(self):
        return (self.can_pay_by_paypal or self.can_pay_by_stripe
                or self.can_pay_by_omise or self.can_pay_by_alipay
                or self.can_pay_by_cheque or self.can_pay_by_bank
                or self.can_pay_onsite or self.can_pay_by_paytm
                or self.can_pay_by_invoice)

    @property
    def average_rating(self):
        return self.get_average_rating()

    def get_owner(self):
        """returns owner of an event"""
        for role in self.roles:
            if role.role.name == Role.OWNER:
                return role.user
        return None

    def as_dict(self):
        return {c.name: getattr(self, c.name) for c in self.__table__.columns}

    @property
    def tickets_sold_object(self):
        obj = (db.session.query(Order.event_id).filter_by(
            event_id=self.id, status='completed').join(TicketHolder))
        return obj

    def calc_tickets_sold_count(self):
        """Calculate total number of tickets sold for the event"""
        return self.tickets_sold_object.count()

    def calc_tickets_sold_prev_month(self):
        """Calculate tickets sold in the previous month"""
        previous_month = datetime.now().month - 1
        return self.tickets_sold_object.filter_by(
            completed_at=previous_month).count()

    def calc_total_tickets_count(self):
        """Calculate total available tickets for all types of tickets"""
        total_available = (db.session.query(func.sum(
            Ticket.quantity)).filter_by(event_id=self.id).scalar())
        if total_available is None:
            total_available = 0
        return total_available

    def get_orders_query(self, start=None, end=None):
        query = Order.query.filter_by(event_id=self.id, status='completed')
        if start:
            query = query.filter(Order.completed_at > start)
        if end:
            query = query.filter(Order.completed_at < end)
        return query

    def calc_revenue(self, start=None, end=None):
        """Returns total revenues of all completed orders for the given event"""
        return (self.get_orders_query(start=start, end=end).with_entities(
            func.sum(Order.amount)).scalar() or 0)

    @property
    def chat_room_name(self):
        return re.sub('[^0-9a-zA-Z!]', '-', self.name) + '-' + self.identifier

    @property
    def tickets_available(self):
        return self.calc_total_tickets_count()

    @property
    def tickets_sold(self):
        return self.calc_tickets_sold_count()

    @property
    def revenue(self):
        return self.calc_revenue()

    @property
    def has_sessions(self):
        return Session.query.filter_by(event_id=self.id).count() > 0

    @property
    def has_speakers(self):
        return Speaker.query.filter_by(event_id=self.id).count() > 0

    @property
    def order_statistics(self):
        return Namespace(id=self.id)

    @property
    def general_statistics(self):
        return Namespace(id=self.id)

    @property
    def site_link(self):
        frontend_url = get_settings()['frontend_url']
        return f"{frontend_url}/e/{self.identifier}"

    @property
    def organizer_site_link(self):
        frontend_url = get_settings()['frontend_url']
        return f"{frontend_url}/events/{self.identifier}"

    @property
    def starts_at_tz(self):
        return self.starts_at.astimezone(pytz.timezone(self.timezone))

    @property
    def ends_at_tz(self):
        return self.ends_at.astimezone(pytz.timezone(self.timezone))

    @property
    def normalized_location(self):
        if self.location_name:
            return self.location_name
        elif self.online:
            return self.site_link
        return 'Location Not Announced'

    @property
    def event_location_status(self):
        if self.online:
            return 'Online (Please login to the platform to access the video room on the event page)'
        elif self.location_name:
            return self.location_name
        else:
            return 'Location Not Announced'

    @property
    def has_coordinates(self):
        return self.latitude and self.longitude

    @property
    def safe_video_stream(self):
        """Conditionally return video stream after applying access control"""
        stream = self.video_stream
        if stream and stream.user_can_access:
            return stream
        return None

    @property
    def notify_staff(self):
        """Who receive notifications about event"""
        return self.organizers + [self.owner]