abkfenris/gage-web

View on GitHub
app/models/gage.py

Summary

Maintainability
A
1 hr
Test Coverage
"""
Gage model
"""
from flask import url_for
from geoalchemy2 import Geometry
from geoalchemy2.shape import to_shape

from app.database import db
from .sensor import Sensor
from .sample import Sample


gages_regions = db.Table('gages_regions',
    db.Column('gage', db.Integer, db.ForeignKey('gages.id')),
    db.Column('region', db.Integer, db.ForeignKey('regions.id'))
)


class Gage(db.Model):
    """
    A Gage is a collection of Sensors at a single location.

    Arguments:
        id (int): Primary key for Gage
        name (string): Nice name for gage
        slug (string): slug used in url
        point (Point): PostGIS Point object. Accepts WKT.
        river_id (int): Foreign key of ``River``.id that the Gage is on.
        river: ``River`` object
        user_id (int): Foreign key of ``User``.id that 'owns' the Gage.
        user: ``User`` object that `owns` the gage.
        visible (boolean): Allows a gage to not be seen on the front end
        zipcode (string): Zip code used to get the weather.
        local_town (string): Local town name, primarily used for getting the weather
        location (string): Descriptive location, often used when Gage is displayed on other pages
        elevation (int): The elevation of the Gage
        elevationUnits (string): Feet or Meters?
        backend_notes (text): Backend info for the Gage for admins.
        started (datetime): When samples started to be collected at this gage
        ended (datetime): If sampling at this gage has stopped, when?
        description (text): Long description for Gage that can contain HTML or Markdown within reason.
        key (string): Secret key that samples are signed with
        short_description (text): Short description for showing on other pages.
        regions: List of ``Region`` objects that this Gage is in.
        sensors: List of ``Sensor`` objects that are part of this Gage.
    """
    __tablename__ = 'gages'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80))
    slug = db.Column(db.String(80), unique=True)
    # primary_sensor_id = db.Column(db.Integer, db.ForeignKey('sensor.id'))
    point = db.Column(Geometry('POINT', 4326))

    river_id = db.Column(db.Integer, db.ForeignKey('rivers.id'))
    river = db.relationship('River', backref='gages')

    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    user = db.relationship('User', backref='gages')

    visible = db.Column(db.Boolean)
    zipcode = db.Column(db.String)
    local_town = db.Column(db.String)
    location = db.Column(db.Text)
    elevation = db.Column(db.Integer)
    elevationUnits = db.Column(db.String)
    backend_notes = db.Column(db.Text)
    started = db.Column(db.DateTime)
    ended = db.Column(db.DateTime)
    description = db.Column(db.Text)
    short_description = db.Column(db.Text)
    key = db.Column(db.String)

    regions = db.relationship('Region',
                              secondary=gages_regions,
                              backref=db.backref('gages', lazy='dynamic'))

    def latlon(self):
        """
        Returns a shapely point
        gage.latlon().y for latitude
        gage.latlon().x for longitude
        """
        latlon_point = to_shape(self.point)
        return latlon_point

    def to_json(self):
        """
        Creates a JSON Object from Gage. Used where multiple gages may be
        listed at once.
        """
        json_post = {
            'id': self.id,
            'name': self.name,
            'location': self.location,
            'html': url_for('main.gagepage',
                            slug=self.slug,
                            _external=True),
            'url': url_for('api.get_gage',
                           gid=self.id,
                           _external=True)
        }
        return json_post

    def to_long_json(self):
        """
        Cretes a JSON Object from Gage. Used where a single gage is displayed.
        """
        json_post = {
            'id': self.id,
            'name': self.name,
            'location': self.location,
            'url': url_for('api.get_gage',
                           gid=self.id,
                           _external=True),
            'html': url_for('main.gagepage',
                            slug=self.slug,
                            _external=True),
            'sensors': [sensor.to_gage_json() for sensor in self.sensors],
            'regions': [region.to_json() for region in self.regions]
        }
        return json_post

    def new_sample(self, stype, value, sdatetime):
        """
        Process a new sample for the gage, and finds the right ``Sensor`` that
        the ``Sample`` should be connected to. If no ``Sensor`` exists for the
        type of sample, then a new one is created.

        Arguments:
            stype (str): Sensor type
            value (float): Sample value
            sdatetime (datetime): Sample ``datetime`` object
        """
        sensor = Sensor.query.filter_by(gage_id=self.id).filter_by(stype=stype).first()
        if sensor == None:
            sensor = Sensor(gage_id=self.id,
                            stype=stype,
                            local=True)
            db.session.add(sensor)
            db.session.commit()
        sample = Sample(sensor_id=sensor.id, value=value, datetime=sdatetime)
        db.session.add(sample)
        db.session.commit()
        return sample

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