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)
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)
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
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()
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()
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"