Пример #1
0
class AnnotationOnSpectrum(Base, AnnotationMixin):

    __tablename__ = 'annotations_on_spectra'

    create = AccessibleIfRelatedRowsAreAccessible(obj='read', spectrum='read')

    read = accessible_by_groups_members & AccessibleIfRelatedRowsAreAccessible(
        obj='read',
        spectrum='read',
    )

    update = delete = AccessibleIfUserMatches('author')

    spectrum_id = sa.Column(
        sa.ForeignKey('spectra.id', ondelete='CASCADE'),
        nullable=False,
        index=True,
        doc="ID of the Annotation's Spectrum.",
    )
    spectrum = relationship(
        'Spectrum',
        back_populates='annotations',
        doc="The Spectrum referred to by this annotation.",
    )

    __table_args__ = (UniqueConstraint('spectrum_id', 'origin'), )
Пример #2
0
class ObjAnalysis(Base, AnalysisMixin, WebhookMixin):
    """Analysis on an Obj with a set of results as JSON"""

    __tablename__ = 'obj_analyses'

    create = AccessibleIfRelatedRowsAreAccessible(obj='read')
    read = accessible_by_groups_members & AccessibleIfRelatedRowsAreAccessible(
        obj='read'
    )
    update = delete = AccessibleIfUserMatches('author')

    @declared_attr
    def obj_id(cls):
        return sa.Column(
            sa.ForeignKey('objs.id', ondelete='CASCADE'),
            nullable=False,
            index=True,
            doc="ID of the ObjAnalysis's Obj.",
        )

    @declared_attr
    def obj(cls):
        return relationship(
            'Obj',
            back_populates=cls.backref_name(),
            doc="The ObjAnalysis's Obj.",
        )
Пример #3
0
class Comment(Base, CommentMixin):
    """A comment made by a User or a Robot (via the API) on a Source."""

    create = AccessibleIfRelatedRowsAreAccessible(obj='read')

    read = accessible_by_groups_members & AccessibleIfRelatedRowsAreAccessible(
        obj='read')

    update = delete = AccessibleIfUserMatches('author')
Пример #4
0
class Annotation(Base, AnnotationMixin):
    """A sortable/searchable Annotation on a source, made by a filter or other robot,
    with a set of data as JSON"""

    create = AccessibleIfRelatedRowsAreAccessible(obj='read')
    read = accessible_by_groups_members & AccessibleIfRelatedRowsAreAccessible(
        obj='read')
    update = delete = AccessibleIfUserMatches('author')

    __table_args__ = (UniqueConstraint('obj_id', 'origin'), )
Пример #5
0
class SourceNotification(Base):

    create = read = AccessibleIfRelatedRowsAreAccessible(source='read')
    update = delete = AccessibleIfUserMatches('sent_by')

    groups = relationship(
        "Group",
        secondary="group_notifications",
        cascade="save-update, merge, refresh-expire, expunge",
        passive_deletes=True,
    )
    sent_by_id = sa.Column(
        sa.ForeignKey("users.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
        doc="The ID of the User who sent this notification.",
    )
    sent_by = relationship(
        "User",
        back_populates="source_notifications",
        foreign_keys=[sent_by_id],
        doc="The User who sent this notification.",
    )
    source_id = sa.Column(
        sa.ForeignKey("objs.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
        doc="ID of the target Obj.",
    )
    source = relationship('Obj',
                          back_populates='obj_notifications',
                          doc='The target Obj.')

    additional_notes = sa.Column(sa.String(), nullable=True)
    level = sa.Column(sa.String(), nullable=False)
Пример #6
0
class SurveyEfficiencyForObservations(Base, SurveyEfficiencyAnalysisMixin):
    """A request for an SurveyEfficiencyAnalysis from a set of observations."""

    __tablename__ = 'survey_efficiency_for_observations'

    create = AccessibleIfRelatedRowsAreAccessible(gcnevent='read')

    read = accessible_by_groups_members & AccessibleIfRelatedRowsAreAccessible(
        gcnevent='read')

    gcnevent = relationship(
        'GcnEvent',
        back_populates='survey_efficiency_analyses',
        doc="The target GcnEvent.",
    )
    gcnevent_id = sa.Column(
        sa.ForeignKey('gcnevents.id', ondelete='CASCADE'),
        nullable=False,
        index=True,
        doc="ID of the target GcnEvent.",
    )

    localization = relationship(
        'Localization',
        back_populates='survey_efficiency_analyses',
        doc="The target Localization.",
    )
    localization_id = sa.Column(
        sa.ForeignKey('localizations.id', ondelete='CASCADE'),
        nullable=False,
        index=True,
        doc="ID of the target Localization.",
    )

    instrument_id = sa.Column(
        sa.ForeignKey('instruments.id', ondelete="CASCADE"),
        nullable=False,
        doc='Instrument ID',
    )

    instrument = relationship(
        "Instrument",
        foreign_keys=instrument_id,
        doc="The Instrument that this efficiency analysis belongs to",
    )
Пример #7
0
class SurveyEfficiencyForObservationPlan(Base, SurveyEfficiencyAnalysisMixin):
    """A request for an SurveyEfficiencyAnalysis from an observation plan."""

    __tablename__ = 'survey_efficiency_for_observation_plans'

    create = AccessibleIfRelatedRowsAreAccessible(observation_plan='read')

    read = accessible_by_groups_members & AccessibleIfRelatedRowsAreAccessible(
        observation_plan='read')

    observation_plan_id = sa.Column(
        sa.ForeignKey('eventobservationplans.id', ondelete="CASCADE"),
        nullable=False,
        doc='Event observation plan ID',
    )

    observation_plan = relationship(
        "EventObservationPlan",
        foreign_keys=observation_plan_id,
        doc=
        "The EventObservationPlan that this survey efficiency analysis belongs to",
    )
Пример #8
0
class Comment(Base, CommentMixin):
    """A comment made by a User or a Robot (via the API) on a Source."""

    create = AccessibleIfRelatedRowsAreAccessible(obj='read')

    read = accessible_by_groups_members & AccessibleIfRelatedRowsAreAccessible(
        obj='read')

    update = delete = AccessibleIfUserMatches('author')

    obj_id = sa.Column(
        sa.ForeignKey('objs.id', ondelete='CASCADE'),
        nullable=False,
        index=True,
        doc="ID of the Comment's Obj.",
    )

    obj = relationship(
        'Obj',
        back_populates='comments',
        doc="The Comment's Obj.",
    )
Пример #9
0
class CommentOnGCN(Base, CommentMixin):

    __tablename__ = 'comments_on_gcns'

    create = AccessibleIfRelatedRowsAreAccessible(gcn='read')

    read = accessible_by_groups_members & AccessibleIfRelatedRowsAreAccessible(
        spectrum='read', )

    update = delete = AccessibleIfUserMatches('author')

    gcn_id = sa.Column(
        sa.ForeignKey('gcnevents.id', ondelete='CASCADE'),
        nullable=False,
        index=True,
        doc="ID of the Comment's GCN.",
    )
    gcn = relationship(
        'GcnEvent',
        back_populates='comments',
        doc="The GcnEvent referred to by this comment.",
    )
Пример #10
0
class CommentOnShift(Base, CommentMixin):

    __tablename__ = 'comments_on_shifts'

    create = AccessibleIfRelatedRowsAreAccessible(shift='read')

    read = accessible_by_groups_members & AccessibleIfRelatedRowsAreAccessible(
        shift='read', )

    update = delete = AccessibleIfUserMatches('author')

    shift_id = sa.Column(
        sa.ForeignKey('shifts.id', ondelete='CASCADE'),
        nullable=False,
        index=True,
        doc="ID of the Comment's Shift.",
    )
    shift = relationship(
        'Shift',
        back_populates='comments',
        doc="The Shift referred to by this comment.",
    )
Пример #11
0
class CommentOnSpectrum(Base, CommentMixin):

    __tablename__ = 'comments_on_spectra'

    create = AccessibleIfRelatedRowsAreAccessible(obj='read', spectrum='read')

    read = accessible_by_groups_members & AccessibleIfRelatedRowsAreAccessible(
        obj='read',
        spectrum='read',
    )

    update = delete = AccessibleIfUserMatches('author')

    obj_id = sa.Column(
        sa.ForeignKey('objs.id', ondelete='CASCADE'),
        nullable=False,
        index=True,
        doc="ID of the Comment's Obj.",
    )

    obj = relationship(
        'Obj',
        back_populates='comments_on_spectra',
        doc="The Comment's Obj.",
    )

    spectrum_id = sa.Column(
        sa.ForeignKey('spectra.id', ondelete='CASCADE'),
        nullable=False,
        index=True,
        doc="ID of the Comment's Spectrum.",
    )
    spectrum = relationship(
        'Spectrum',
        back_populates='comments',
        doc="The Spectrum referred to by this comment.",
    )
Пример #12
0
class Filter(Base):
    """An alert filter that operates on a Stream. A Filter is associated
    with exactly one Group, and a Group may have multiple operational Filters.
    """

    # TODO: Track filter ownership and allow owners to update, delete filters
    create = (read) = (
        update
    ) = delete = accessible_by_group_members & AccessibleIfRelatedRowsAreAccessible(
        stream="read")

    name = sa.Column(sa.String,
                     nullable=False,
                     unique=False,
                     doc="Filter name.")
    stream_id = sa.Column(
        sa.ForeignKey("streams.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
        doc="ID of the Filter's Stream.",
    )
    stream = relationship(
        "Stream",
        foreign_keys=[stream_id],
        back_populates="filters",
        doc="The Filter's Stream.",
    )
    group_id = sa.Column(
        sa.ForeignKey("groups.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
        doc="ID of the Filter's Group.",
    )
    group = relationship(
        "Group",
        foreign_keys=[group_id],
        back_populates="filters",
        doc="The Filter's Group.",
    )
    candidates = relationship(
        'Candidate',
        back_populates='filter',
        cascade='save-update, merge, refresh-expire, expunge',
        passive_deletes=True,
        order_by="Candidate.passed_at",
        doc="Candidates that have passed the filter.",
    )
Пример #13
0
class DefaultObservationPlanRequest(Base):
    """A default request for an EventObservationPlan."""

    # TODO: Make read-accessible via target groups
    create = read = AccessibleIfRelatedRowsAreAccessible(allocation="read")
    update = delete = (
        (AccessibleIfUserMatches('allocation.group.users')
         | AccessibleIfUserMatches('requester'))
        & read) | CustomUserAccessControl(updatable_by_token_with_listener_acl)

    requester_id = sa.Column(
        sa.ForeignKey('users.id', ondelete='SET NULL'),
        nullable=True,
        index=True,
        doc=
        "ID of the User who requested the default observation plan request.",
    )

    requester = relationship(
        User,
        back_populates='default_observationplan_requests',
        doc="The User who requested the default requests.",
        foreign_keys=[requester_id],
    )

    payload = sa.Column(
        psql.JSONB,
        nullable=False,
        doc="Content of the default observation plan request.",
    )

    allocation_id = sa.Column(sa.ForeignKey('allocations.id',
                                            ondelete='CASCADE'),
                              nullable=False,
                              index=True)
    allocation = relationship('Allocation',
                              back_populates='default_observation_plans')

    target_groups = relationship(
        'Group',
        secondary='default_observationplan_groups',
        passive_deletes=True,
        doc=
        'Groups to share the resulting data from this default request with.',
    )
Пример #14
0
class Thumbnail(Base):
    """Thumbnail image centered on the location of an Obj."""

    create = read = AccessibleIfRelatedRowsAreAccessible(obj='read')

    # TODO delete file after deleting row
    type = sa.Column(thumbnail_types,
                     doc='Thumbnail type (e.g., ref, new, sub, dr8, ps1, ...)')
    file_uri = sa.Column(
        sa.String(),
        nullable=True,
        index=False,
        unique=False,
        doc="Path of the Thumbnail on the machine running SkyPortal.",
    )
    public_url = sa.Column(
        sa.String(),
        nullable=True,
        index=False,
        unique=False,
        doc="Publically accessible URL of the thumbnail.",
    )
    origin = sa.Column(sa.String,
                       nullable=True,
                       doc="Origin of the Thumbnail.")
    obj = relationship(
        'Obj',
        back_populates='thumbnails',
        uselist=False,
        doc="The Thumbnail's Obj.",
    )
    obj_id = sa.Column(
        sa.ForeignKey('objs.id', ondelete='CASCADE'),
        index=True,
        nullable=False,
        doc="ID of the thumbnail's obj.",
    )
    is_grayscale = sa.Column(
        sa.Boolean(),
        nullable=False,
        default=False,
        doc=
        "Boolean indicating whether the thumbnail is (mostly) grayscale or not.",
    )
Пример #15
0
class Allocation(Base):
    """An allocation of observing time on a robotic instrument."""

    create = (read) = (
        update
    ) = delete = accessible_by_group_members & AccessibleIfRelatedRowsAreAccessible(
        instrument='read')

    pi = sa.Column(sa.String, doc="The PI of the allocation's proposal.")
    proposal_id = sa.Column(
        sa.String,
        doc="The ID of the proposal associated with this allocation.")
    start_date = sa.Column(sa.DateTime,
                           doc='The UTC start date of the allocation.')
    end_date = sa.Column(sa.DateTime,
                         doc='The UTC end date of the allocation.')
    hours_allocated = sa.Column(sa.Float,
                                nullable=False,
                                doc='The number of hours allocated.')
    requests = relationship(
        'FollowupRequest',
        back_populates='allocation',
        doc='The requests made against this allocation.',
        passive_deletes=True,
    )
    observation_plans = relationship(
        'ObservationPlanRequest',
        back_populates='allocation',
        doc='The observing plan requests for this allocation.',
        passive_deletes=True,
    )
    group_id = sa.Column(
        sa.ForeignKey('groups.id', ondelete='CASCADE'),
        index=True,
        doc='The ID of the Group the allocation is associated with.',
        nullable=False,
    )
    group = relationship(
        'Group',
        back_populates='allocations',
        doc='The Group the allocation is associated with.',
    )

    instrument_id = sa.Column(
        sa.ForeignKey('instruments.id', ondelete='CASCADE'),
        index=True,
        doc="The ID of the Instrument the allocation is associated with.",
        nullable=False,
    )
    instrument = relationship(
        'Instrument',
        back_populates='allocations',
        doc="The Instrument the allocation is associated with.",
    )

    _altdata = sa.Column(
        EncryptedType(JSONType, cfg['app.secret_key'], AesEngine, 'pkcs5'))

    @property
    def altdata(self):
        if self._altdata is None:
            return {}
        else:
            return json.loads(self._altdata)

    @altdata.setter
    def altdata(self, value):
        self._altdata = value
Пример #16
0
class ObservationPlanRequest(Base):
    """A request for an EventObservationPlan."""

    # TODO: Make read-accessible via target groups
    create = read = AccessibleIfRelatedRowsAreAccessible(gcnevent="read",
                                                         allocation="read")
    update = delete = (
        (AccessibleIfUserMatches('allocation.group.users')
         | AccessibleIfUserMatches('requester'))
        & read) | CustomUserAccessControl(updatable_by_token_with_listener_acl)

    requester_id = sa.Column(
        sa.ForeignKey('users.id', ondelete='SET NULL'),
        nullable=True,
        index=True,
        doc="ID of the User who requested the follow-up.",
    )

    requester = relationship(
        User,
        back_populates='observationplan_requests',
        doc="The User who requested the follow-up.",
        foreign_keys=[requester_id],
    )

    last_modified_by_id = sa.Column(
        sa.ForeignKey('users.id', ondelete='SET NULL'),
        nullable=True,
        doc="The ID of the User who last modified the request.",
    )

    last_modified_by = relationship(
        User,
        doc="The user who last modified the request.",
        foreign_keys=[last_modified_by_id],
    )

    gcnevent = relationship(
        'GcnEvent',
        back_populates='observationplan_requests',
        doc="The target GcnEvent.",
    )
    gcnevent_id = sa.Column(
        sa.ForeignKey('gcnevents.id', ondelete='CASCADE'),
        nullable=False,
        index=True,
        doc="ID of the target GcnEvent.",
    )

    localization = relationship(
        'Localization',
        back_populates='observationplan_requests',
        doc="The target Localization.",
    )
    localization_id = sa.Column(
        sa.ForeignKey('localizations.id', ondelete='CASCADE'),
        nullable=False,
        index=True,
        doc="ID of the target Localization.",
    )

    payload = sa.Column(psql.JSONB,
                        nullable=False,
                        doc="Content of the observation plan request.")

    status = sa.Column(
        sa.String(),
        nullable=False,
        default="pending submission",
        index=True,
        doc="The status of the request.",
    )

    allocation_id = sa.Column(sa.ForeignKey('allocations.id',
                                            ondelete='CASCADE'),
                              nullable=False,
                              index=True)
    allocation = relationship('Allocation', back_populates='observation_plans')

    observation_plans = relationship(
        'EventObservationPlan',
        passive_deletes=True,
        doc='Observation plans associated with this request.',
    )

    target_groups = relationship(
        'Group',
        secondary='observationplan_groups',
        passive_deletes=True,
        doc='Groups to share the resulting data from this request with.',
    )

    transactions = relationship(
        'FacilityTransaction',
        back_populates='observation_plan_request',
        passive_deletes=True,
        order_by="FacilityTransaction.created_at.desc()",
    )

    @property
    def instrument(self):
        return self.allocation.instrument
Пример #17
0
    Returns
    -------
    tax : `skyportal.models.Taxonomy`
       The requested Taxonomy.
    """

    return (Taxonomy.query.filter(Taxonomy.id == taxonomy_id).filter(
        Taxonomy.groups.any(
            Group.id.in_([g.id
                          for g in user_or_token.accessible_groups]))).all())


# To create or read a classification, you must have read access to the
# underlying taxonomy, and be a member of at least one of the
# classification's target groups
ok_if_tax_and_obj_readable = AccessibleIfRelatedRowsAreAccessible(
    taxonomy='read', obj='read')


class Taxonomy(Base):
    """An ontology within which Objs can be classified."""

    # TODO: Add ownership logic to taxonomy
    read = accessible_by_groups_members

    __tablename__ = 'taxonomies'
    name = sa.Column(
        sa.String,
        nullable=False,
        doc='Short string to make this taxonomy memorable to end users.',
    )
    hierarchy = sa.Column(
Пример #18
0
class FollowupRequest(Base):
    """A request for follow-up data (spectroscopy, photometry, or both) using a
    robotic instrument."""

    # TODO: Make read-accessible via target groups
    create = read = AccessibleIfRelatedRowsAreAccessible(obj="read",
                                                         allocation="read")
    update = delete = (
        (AccessibleIfUserMatches('allocation.group.users')
         | AccessibleIfUserMatches('requester'))
        & read) | CustomUserAccessControl(updatable_by_token_with_listener_acl)

    requester_id = sa.Column(
        sa.ForeignKey('users.id', ondelete='SET NULL'),
        nullable=True,
        index=True,
        doc="ID of the User who requested the follow-up.",
    )

    requester = relationship(
        User,
        back_populates='followup_requests',
        doc="The User who requested the follow-up.",
        foreign_keys=[requester_id],
    )

    last_modified_by_id = sa.Column(
        sa.ForeignKey('users.id', ondelete='SET NULL'),
        nullable=True,
        doc="The ID of the User who last modified the request.",
    )

    last_modified_by = relationship(
        User,
        doc="The user who last modified the request.",
        foreign_keys=[last_modified_by_id],
    )

    obj = relationship('Obj',
                       back_populates='followup_requests',
                       doc="The target Obj.")
    obj_id = sa.Column(
        sa.ForeignKey('objs.id', ondelete='CASCADE'),
        nullable=False,
        index=True,
        doc="ID of the target Obj.",
    )

    payload = sa.Column(psql.JSONB,
                        nullable=False,
                        doc="Content of the followup request.")

    status = sa.Column(
        sa.String(),
        nullable=False,
        default="pending submission",
        index=True,
        doc="The status of the request.",
    )

    allocation_id = sa.Column(sa.ForeignKey('allocations.id',
                                            ondelete='CASCADE'),
                              nullable=False,
                              index=True)
    allocation = relationship('Allocation', back_populates='requests')

    transactions = relationship(
        'FacilityTransaction',
        back_populates='followup_request',
        passive_deletes=True,
        order_by="FacilityTransaction.created_at.desc()",
    )

    target_groups = relationship(
        'Group',
        secondary='request_groups',
        passive_deletes=True,
        doc='Groups to share the resulting data from this request with.',
    )

    photometry = relationship('Photometry', back_populates='followup_request')
    spectra = relationship('Spectrum', back_populates='followup_request')

    @property
    def instrument(self):
        return self.allocation.instrument
Пример #19
0
class ClassicalAssignment(Base):
    """Assignment of an Obj to an Observing Run as a target."""

    create = read = update = delete = AccessibleIfRelatedRowsAreAccessible(
        obj='read', run='read')

    requester_id = sa.Column(
        sa.ForeignKey("users.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
        doc="The ID of the User who created this assignment.",
    )
    requester = relationship(
        "User",
        back_populates="assignments",
        foreign_keys=[requester_id],
        doc="The User who created this assignment.",
    )

    last_modified_by_id = sa.Column(
        sa.ForeignKey("users.id", ondelete="SET NULL"),
        nullable=True,
        default=None,
        index=True,
    )
    last_modified_by = relationship("User", foreign_keys=[last_modified_by_id])

    obj = relationship('Obj',
                       back_populates='assignments',
                       doc='The assigned Obj.')
    obj_id = sa.Column(
        sa.ForeignKey('objs.id', ondelete='CASCADE'),
        nullable=False,
        index=True,
        doc='ID of the assigned Obj.',
    )

    comment = sa.Column(
        sa.String(),
        doc="A comment on the assignment. "
        "Typically a justification for the request, "
        "or instructions for taking the data.",
    )
    status = sa.Column(
        sa.String(),
        nullable=False,
        default="pending",
        doc='Status of the assignment [done, not done, pending].',
    )
    priority = sa.Column(
        followup_priorities,
        nullable=False,
        doc='Priority of the request (1 = lowest, 5 = highest).',
    )
    spectra = relationship(
        "Spectrum",
        back_populates="assignment",
        doc="Spectra produced by the assignment.",
    )
    photometry = relationship(
        "Photometry",
        back_populates="assignment",
        doc="Photometry produced by the assignment.",
    )

    run = relationship(
        'ObservingRun',
        back_populates='assignments',
        doc="The ObservingRun this target was assigned to.",
    )
    run_id = sa.Column(
        sa.ForeignKey('observingruns.id', ondelete='CASCADE'),
        nullable=False,
        index=True,
        doc="ID of the ObservingRun this target was assigned to.",
    )

    @hybrid_property
    def instrument(self):
        """The instrument in use on the assigned ObservingRun."""
        return self.run.instrument

    @property
    def rise_time(self):
        """The UTC time at which the object rises on this run."""
        target = self.obj.target
        return self.run.rise_time(target)

    @property
    def set_time(self):
        """The UTC time at which the object sets on this run."""
        target = self.obj.target
        return self.run.set_time(target)