Exemplo n.º 1
0
class TimestampMixin(object):
    created_at = db.Column(db.DateTime(),
                           default=get_current_time,
                           nullable=False)
    updated_at = db.Column(db.DateTime(),
                           default=None,
                           onupdate=get_current_time)
Exemplo n.º 2
0
class TimestampMixin(object):
    created_at = db.Column(db.DateTime(),
                           default=datetime.utcnow,
                           nullable=False)
    updated_at = db.Column(db.DateTime(),
                           default=None,
                           onupdate=datetime.utcnow)
Exemplo n.º 3
0
class ApplicationPeriods(TimestampMixin, db.Model):
    """
    represents the application periods of an impact
    """
    id = db.Column(UUID, primary_key=True)
    start_date = db.Column(db.DateTime(), nullable=True)
    end_date = db.Column(db.DateTime(), nullable=True)
    impact_id = db.Column(UUID, db.ForeignKey(Impact.id), index=True)

    def __init__(self, impact_id=None):
        self.id = str(uuid.uuid1())
        self.impact_id = impact_id

    def __repr__(self):
        return '<ApplicationPeriods %r>' % self.id
Exemplo n.º 4
0
class Impact(TimestampMixin, db.Model):
    id = db.Column(UUID, primary_key=True)
    status = db.Column(ImpactStatus,
                       nullable=False,
                       default='published',
                       index=True)
    disruption_id = db.Column(UUID, db.ForeignKey(Disruption.id))
    severity_id = db.Column(UUID, db.ForeignKey(Severity.id))
    messages = db.relationship('Message',
                               backref='impact',
                               lazy='joined',
                               cascade='delete')
    application_periods = db.relationship('ApplicationPeriods',
                                          backref='impact',
                                          lazy='joined',
                                          cascade='delete')
    severity = db.relationship('Severity', backref='impacts', lazy='joined')
    objects = db.relationship("PTobject",
                              secondary=associate_impact_pt_object,
                              lazy='joined',
                              order_by="PTobject.type, PTobject.uri")
    patterns = db.relationship('Pattern',
                               backref='impact',
                               lazy='joined',
                               cascade='delete')
    send_notifications = db.Column(db.Boolean,
                                   unique=False,
                                   nullable=False,
                                   default=True)
    version = db.Column(db.Integer, nullable=False, default=1)
    notification_date = db.Column(db.DateTime(), default=None, nullable=True)

    def __repr__(self):
        return '<Impact %r>' % self.id

    def __marshallable__(self):
        '''
        This method is added to solve the problem of impact without instance during creation of response json for Post..
        API post cannot fill url for impact and disruption in impact_fields
        When we have either one of them present in impact_fields, it works.
        '''
        d = {}
        d['id'] = self.id
        d['status'] = self.status
        d['disruption_id'] = self.disruption_id
        d['severity_id'] = self.severity_id
        d['objects'] = self.objects
        d['application_periods'] = self.application_periods
        d['severity'] = self.severity
        d['messages'] = self.messages
        d['application_period_patterns'] = self.patterns
        d['send_notifications'] = self.send_notifications
        d['notification_date'] = self.notification_date
        return d

    def __init__(self, objects=None):
        self.id = str(uuid.uuid1())

    def archive(self):
        """
        archive the impact, it will not be visible on any media
        """
        self.status = 'archived'

    def insert_object(self, object):
        """
        Adds an objectTC in a imapct.
        """
        self.objects.append(object)
        db.session.add(object)

    def upgrade_version(self):
        self.version = self.version + 1

    def insert_message(self, message):
        """
        Adds an message in a imapct.
        """
        self.messages.append(message)
        db.session.add(message)

    def delete_message(self, message):
        """
        delete a message in an impact.
        """
        self.messages.remove(message)
        db.session.delete(message)

    def delete_app_periods(self):
        for app_per in self.application_periods:
            db.session.delete(app_per)

    def delete_line_section(self):
        for pt_object in self.objects:
            if pt_object.type == 'line_section':
                line_section = LineSection.get_by_object_id(pt_object.id)
                if line_section:
                    db.session.delete(line_section)
                self.delete(pt_object)
                db.session.delete(pt_object)

    def insert_app_period(self, application_period):
        """
        Adds an ApplicationPeriods in a impact.
        """
        self.application_periods.append(application_period)
        db.session.add(application_period)

    def delete_patterns(self):
        for i in range(len(self.patterns), 0, -1):
            pattern = self.patterns[i - 1]
            pattern.delete_time_slots()
            self.patterns.remove(pattern)
            db.session.delete(pattern)

    def insert_pattern(self, pattern):
        """
        Adds a pattern of ApplicationPeriods in a impact.
        """
        self.patterns.append(pattern)
        db.session.add(pattern)

    @classmethod
    def get(cls, id, contributor_id):
        query = cls.query.filter_by(id=id, status='published')
        query = query.join(Disruption)
        query = query.filter(Disruption.contributor_id == contributor_id)
        return query.first_or_404()

    @classmethod
    @paginate()
    def all(cls, disruption_id, contributor_id):
        alias = aliased(Severity)
        query = cls.query.filter_by(status='published')
        query = query.filter(and_(cls.disruption_id == disruption_id))
        query = query.join(Disruption)
        query = query.filter(Disruption.contributor_id == contributor_id)
        return query.join(alias, Impact.severity).order_by(alias.priority)

    @classmethod
    def all_with_filter(cls, start_date, end_date, pt_object_type, uris,
                        contributor_id):
        filter_with_line_section = True
        pt_object_alias = aliased(PTobject)
        query = cls.query.filter(cls.status == 'published')
        query = query.join(Disruption)
        query = query.join(ApplicationPeriods)
        query = query.join(pt_object_alias, cls.objects)
        query = query.filter(Disruption.contributor_id == contributor_id)
        query = query.filter(
            and_(ApplicationPeriods.start_date <= end_date,
                 ApplicationPeriods.end_date >= start_date))
        query_line_section = query
        if pt_object_type or uris:
            alias_line = aliased(PTobject)
            alias_start_point = aliased(PTobject)
            alias_end_point = aliased(PTobject)
            alias_route = aliased(PTobject)
            alias_via = aliased(PTobject)

            query_line_section = query_line_section.filter(
                pt_object_alias.type == 'line_section')
            query_line_section = query_line_section.join(
                pt_object_alias.line_section)
            query_line_section = query_line_section.join(
                alias_line, LineSection.line_object_id == alias_line.id)
            query_line_section = query_line_section.join(
                alias_start_point,
                LineSection.start_object_id == alias_start_point.id)
            query_line_section = query_line_section.join(
                alias_end_point,
                LineSection.end_object_id == alias_end_point.id)
            query_line_section = query_line_section.outerjoin(
                alias_route, LineSection.routes)
            query_line_section = query_line_section.outerjoin(
                alias_via, LineSection.via)
        else:
            filter_with_line_section = False

        if pt_object_type:
            query = query.filter(pt_object_alias.type == pt_object_type)
            if pt_object_type == 'route':
                query_line_section = query_line_section.filter(
                    alias_route.type == pt_object_type)
            elif pt_object_type not in ['line_section', 'line', 'stop_area']:
                filter_with_line_section = False

        if uris:
            query = query.filter(pt_object_alias.uri.in_(uris))
            uri_filters = []
            uri_filters.append(alias_line.uri.in_(uris))
            uri_filters.append(alias_start_point.uri.in_(uris))
            uri_filters.append(alias_end_point.uri.in_(uris))
            uri_filters.append(alias_route.uri.in_(uris))
            uri_filters.append(alias_via.uri.in_(uris))
            query_line_section = query_line_section.filter(or_(*uri_filters))

        if filter_with_line_section:
            query = query.union_all(query_line_section)
        query = query.order_by("application_periods_1.start_date")
        return query.all()
Exemplo n.º 5
0
class Disruption(TimestampMixin, db.Model):
    __tablename__ = 'disruption'
    id = db.Column(UUID, primary_key=True)
    reference = db.Column(db.Text, unique=False, nullable=True)
    note = db.Column(db.Text, unique=False, nullable=True)
    status = db.Column(DisruptionStatus,
                       nullable=False,
                       default='published',
                       index=True)
    start_publication_date = db.Column(db.DateTime(), nullable=True)
    end_publication_date = db.Column(db.DateTime(), nullable=True)
    impacts = db.relationship('Impact',
                              backref='disruption',
                              lazy='joined',
                              cascade='delete')
    cause_id = db.Column(UUID, db.ForeignKey(Cause.id))
    cause = db.relationship('Cause', backref='disruption', lazy='joined')
    tags = db.relationship("Tag",
                           secondary=associate_disruption_tag,
                           backref="disruptions",
                           lazy='joined')
    client_id = db.Column(UUID, db.ForeignKey(Client.id), nullable=False)
    client = db.relationship('Client', backref='disruptions')
    contributor_id = db.Column(UUID,
                               db.ForeignKey(Contributor.id),
                               nullable=False)
    contributor = db.relationship('Contributor',
                                  backref='disruptions',
                                  lazy='joined')
    version = db.Column(db.Integer, nullable=False, default=1)
    localizations = db.relationship("PTobject",
                                    secondary=associate_disruption_pt_object,
                                    backref="disruptions",
                                    lazy='joined')
    properties = db.relationship('AssociateDisruptionProperty',
                                 lazy='joined',
                                 back_populates='disruption',
                                 cascade='delete')

    def __repr__(self):
        return '<Disruption %r>' % self.id

    def __init__(self):
        self.id = str(uuid.uuid1())

    def upgrade_version(self):
        self.version = self.version + 1

    def archive(self):
        """
        archive the disruption, it will not be visible on any media
        """
        self.status = 'archived'
        for impact in self.impacts:
            impact.archive()

    def is_published(self):
        return self.status == 'published'

    def is_draft(self):
        return self.status == 'draft'

    def is_last_impact(self, impact_id):
        nb_impacts = list(
            filter(lambda x: x.status != 'archived', self.impacts))
        return len(nb_impacts) == 1 and nb_impacts[0].id == impact_id

    @classmethod
    def get(cls, id, contributor_id):
        return cls.query.filter((cls.id == id)
                                and (cls.contributor == contributor_id)
                                and (cls.status != 'archived')).first_or_404()

    @classmethod
    def get_query_with_args(cls,
                            contributor_id,
                            publication_status,
                            ends_after_date,
                            ends_before_date,
                            tags,
                            uri,
                            line_section,
                            statuses,
                            application_status=application_status_values,
                            query=None,
                            cause_category_id=None,
                            current_time=None):
        if current_time is None: current_time = get_current_time()
        if (query is None):
            query = cls.query

        query = query.filter(
            and_(cls.contributor_id == contributor_id,
                 cls.status.in_(statuses)))

        if cause_category_id:
            query = query.join(cls.cause)
            query = query.filter(Cause.category_id == cause_category_id)

        if ends_after_date:
            query = query.filter(cls.end_publication_date >= ends_after_date)

        if ends_before_date:
            query = query.filter(cls.end_publication_date <= ends_before_date)

        if tags:
            query = query.filter(cls.tags.any(Tag.id.in_(tags)))

        if uri:
            query = query.join(cls.impacts)
            query = query.filter(Impact.status == 'published')
            query = query.join(Impact.objects)

            # Here add a new query to find impacts with line_section having uri as line
            if line_section:
                query_line_section = query
                query_line_section = query_line_section.filter(
                    and_(PTobject.type == "line_section",
                         PTobject.uri.like(uri + ":%")))

            query = query.filter(PTobject.uri == uri)

        publication_availlable_filters = {
            'past':
            and_(cls.end_publication_date != None,
                 cls.end_publication_date < current_time),
            'ongoing':
            and_(
                cls.start_publication_date <= current_time,
                or_(cls.end_publication_date == None,
                    cls.end_publication_date >= current_time)),
            'coming':
            Disruption.start_publication_date > current_time
        }
        publication_status = set(publication_status)
        if len(publication_status) == len(publication_status_values):
            # For a query by uri use union with the query for line_section
            if uri and line_section:
                query = query.union(query_line_section)

        else:
            filters = [
                publication_availlable_filters[status]
                for status in publication_status
            ]
            query = query.filter(or_(*filters))

            # For a query by uri use union with the query for line_section
            if uri and line_section:
                query_line_section = query_line_section.filter(or_(*filters))
                query = query.union(query_line_section)

        application_status = set(application_status)
        if len(application_status) != len(application_status_values):
            query = query.join(cls.impacts)
            query = query.filter(Impact.status == 'published')
            query = query.join(Impact.application_periods)
            application_availlable_filters = {
                'past':
                ApplicationPeriods.end_date < current_time,
                'ongoing':
                and_(ApplicationPeriods.start_date <= current_time,
                     ApplicationPeriods.end_date >= current_time),
                'coming':
                ApplicationPeriods.start_date > current_time
            }
            filters = [
                application_availlable_filters[status]
                for status in application_status
            ]
            query = query.filter(or_(*filters))
        return query.order_by(cls.end_publication_date, cls.id)

    @classmethod
    @paginate()
    def all_with_post_filter(cls,
                             contributor_id,
                             application_status,
                             publication_status,
                             ends_after_date,
                             ends_before_date,
                             tags,
                             uri,
                             line_section,
                             statuses,
                             ptObjectFilter,
                             cause_category_id,
                             application_period,
                             current_time=None):
        if current_time is None: current_time = get_current_time()
        query = cls.query
        object_types = []
        uris = []
        line_section_uris = []
        if uri_is_not_in_pt_object_filter(uri=uri,
                                          pt_object_filter=ptObjectFilter):
            return cls.query.filter('1=0')
        if ptObjectFilter is not None:
            for key, objectIds in ptObjectFilter.iteritems():
                object_type = key[:-1]
                object_types.append(object_type)
                uris = uris + objectIds
                if object_type == 'line':
                    line_section_uris = [
                        objectId + ':%' for objectId in objectIds
                    ]
                    line_section = False

            uris_filter = and_(
                cls.impacts.any(
                    Impact.objects.any(PTobject.type.in_(object_types))),
                cls.impacts.any(Impact.objects.any(PTobject.uri.in_(uris))))
            if len(line_section_uris):
                query = cls.query.filter(
                    or_(
                        uris_filter,
                        cls.impacts.any(
                            Impact.objects.any(
                                or_(*[
                                    PTobject.uri.like(objectId)
                                    for objectId in line_section_uris
                                ])))))
            else:
                query = cls.query.filter(uris_filter)
        if application_period is not None:
            query = cls.query.filter(
                cls.impacts.any(
                    Impact.application_periods.any(
                        or_(
                            and_(
                                ApplicationPeriods.start_date >=
                                application_period['begin'],
                                ApplicationPeriods.start_date <=
                                application_period['end']),
                            and_(
                                ApplicationPeriods.end_date >=
                                application_period['begin'],
                                ApplicationPeriods.end_date <=
                                application_period['end']),
                            and_(
                                ApplicationPeriods.start_date <=
                                application_period['begin'],
                                ApplicationPeriods.end_date >=
                                application_period['end'])))))
        return cls.get_query_with_args(contributor_id=contributor_id,
                                       application_status=application_status,
                                       publication_status=publication_status,
                                       ends_after_date=ends_after_date,
                                       ends_before_date=ends_before_date,
                                       tags=tags,
                                       uri=uri,
                                       line_section=line_section,
                                       statuses=statuses,
                                       query=query,
                                       cause_category_id=cause_category_id,
                                       current_time=current_time)

    @classmethod
    @paginate()
    def all_with_filter(cls, contributor_id, publication_status,
                        ends_after_date, ends_before_date, tags, uri,
                        line_section, statuses):

        return cls.get_query_with_args(contributor_id=contributor_id,
                                       publication_status=publication_status,
                                       ends_after_date=ends_after_date,
                                       ends_before_date=ends_before_date,
                                       tags=tags,
                                       uri=uri,
                                       line_section=line_section,
                                       statuses=statuses)

    @property
    def publication_status(self):
        current_time = utils.get_current_time()
        # Past
        if (self.end_publication_date != None) and (self.end_publication_date <
                                                    current_time):
            return "past"
        # ongoing
        if self.start_publication_date <= current_time\
                and (self.end_publication_date == None or self.end_publication_date >= current_time):
            return "ongoing"
        # Coming
        if self.start_publication_date > current_time:
            return "coming"

    @classmethod
    def traffic_report_filter(cls, contributor_id):
        query = cls.query.filter(cls.status == 'published')
        query = query.filter(cls.contributor_id == contributor_id)
        query = query.filter(
            between(get_current_time(), cls.start_publication_date,
                    cls.end_publication_date))
        return query.all()
Exemplo n.º 6
0
class Disruption(TimestampMixin, db.Model):
    __tablename__ = 'disruption'
    id = db.Column(UUID, primary_key=True)
    reference = db.Column(db.Text, unique=False, nullable=True)
    note = db.Column(db.Text, unique=False, nullable=True)
    status = db.Column(DisruptionStatus,
                       nullable=False,
                       default='published',
                       index=True)
    start_publication_date = db.Column(db.DateTime(), nullable=True)
    end_publication_date = db.Column(db.DateTime(), nullable=True)
    impacts = db.relationship('Impact',
                              backref='disruption',
                              lazy='dynamic',
                              cascade='delete')
    cause_id = db.Column(UUID, db.ForeignKey(Cause.id))
    cause = db.relationship('Cause', backref='disruption', lazy='joined')
    tags = db.relationship("Tag",
                           secondary=associate_disruption_tag,
                           backref="disruptions")
    client_id = db.Column(UUID, db.ForeignKey(Client.id), nullable=False)
    client = db.relationship('Client', backref='disruptions', lazy='joined')
    contributor_id = db.Column(UUID,
                               db.ForeignKey(Contributor.id),
                               nullable=False)
    contributor = db.relationship('Contributor',
                                  backref='disruptions',
                                  lazy='joined')
    version = db.Column(db.Integer, nullable=False, default=1)
    localizations = db.relationship("PTobject",
                                    secondary=associate_disruption_pt_object,
                                    backref="disruptions")
    properties = db.relationship('AssociateDisruptionProperty',
                                 lazy='joined',
                                 back_populates='disruption',
                                 cascade='delete')

    def __repr__(self):
        return '<Disruption %r>' % self.id

    def __init__(self):
        self.id = str(uuid.uuid1())

    def upgrade_version(self):
        self.version = self.version + 1

    def archive(self):
        """
        archive the disruption, it will not be visible on any media
        """
        self.status = 'archived'
        for impact in self.impacts:
            impact.archive()

    def is_published(self):
        return self.status == 'published'

    def is_draft(self):
        return self.status == 'draft'

    @classmethod
    def get(cls, id, contributor_id):
        return cls.query.filter((cls.id == id)
                                and (cls.contributor == contributor_id)
                                and (cls.status != 'archived')).first_or_404()

    @classmethod
    @paginate()
    def all_with_filter(cls, contributor_id, publication_status, tags, uri,
                        statuses):
        availlable_filters = {
            'past':
            and_(cls.end_publication_date != None,
                 cls.end_publication_date < get_current_time()),
            'ongoing':
            and_(
                cls.start_publication_date <= get_current_time(),
                or_(cls.end_publication_date == None,
                    cls.end_publication_date >= get_current_time())),
            'coming':
            Disruption.start_publication_date > get_current_time()
        }
        query = cls.query.filter(
            and_(cls.contributor_id == contributor_id,
                 cls.status.in_(statuses)))

        if tags:
            query = query.filter(cls.tags.any(Tag.id.in_(tags)))

        if uri:
            query = query.join(cls.impacts)
            query = query.filter(Impact.status == 'published')
            query = query.join(Impact.objects)

            #Here add a new query to find impacts with line =_section having uri as line, start_point or end_point
            filters = []
            alias_line = aliased(PTobject)
            alias_start_point = aliased(PTobject)
            alias_end_point = aliased(PTobject)
            alias_route = aliased(PTobject)
            alias_via = aliased(PTobject)
            query_line_section = query
            query_line_section = query_line_section.join(PTobject.line_section)
            query_line_section = query_line_section.join(
                alias_line, LineSection.line_object_id == alias_line.id)
            filters.append(alias_line.uri == uri)
            query_line_section = query_line_section.join(
                PTobject, LineSection.object_id == PTobject.id)
            query_line_section = query_line_section.join(
                alias_start_point,
                LineSection.start_object_id == alias_start_point.id)
            filters.append(alias_start_point.uri == uri)
            query_line_section = query_line_section.join(
                alias_end_point,
                LineSection.end_object_id == alias_end_point.id)
            filters.append(alias_end_point.uri == uri)
            query_line_section = query_line_section.join(
                alias_route, LineSection.routes)
            filters.append(alias_route.uri == uri)
            query_line_section = query_line_section.join(
                alias_via, LineSection.via)
            filters.append(alias_via.uri == uri)
            query_line_section = query_line_section.filter(or_(*filters))

            query = query.filter(PTobject.uri == uri)

        publication_status = set(publication_status)
        if len(publication_status) == len(publication_status_values):
            #For a query by uri use union with the query for line_section
            if uri:
                query = query.union_all(query_line_section)

        else:
            filters = [
                availlable_filters[status] for status in publication_status
            ]
            query = query.filter(or_(*filters))
            #For a query by uri use union with the query for line_section
            if uri:
                query_line_section = query_line_section.filter(or_(*filters))
                query = query.union_all(query_line_section)

        return query.order_by(cls.end_publication_date, cls.id)

    @property
    def publication_status(self):
        current_time = utils.get_current_time()
        # Past
        if (self.end_publication_date != None) and (self.end_publication_date <
                                                    current_time):
            return "past"
        # ongoing
        if self.start_publication_date <= current_time\
            and (self.end_publication_date == None or self.end_publication_date >= current_time):
            return "ongoing"
        # Coming
        if self.start_publication_date > current_time:
            return "coming"