Gage   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 157
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 12
c 5
b 0
f 0
dl 0
loc 157
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __repr__() 0 2 1
A __str__() 0 2 1
A new_sample() 0 22 2
A geojson() 0 23 3
A to_long_json() 0 18 3
A to_json() 0 17 1
A latlon() 0 8 1
1
"""
2
Gage model
3
"""
4
from flask import url_for
5
from geoalchemy2 import Geometry
6
from geoalchemy2.shape import to_shape
7
8
from app.database import db
9
from .sensor import Sensor
10
from .sample import Sample
11
12
13
gages_regions = db.Table('gages_regions',
14
    db.Column('gage', db.Integer, db.ForeignKey('gages.id')),
15
    db.Column('region', db.Integer, db.ForeignKey('regions.id'))
16
)
17
18
19
class Gage(db.Model):
20
    """
21
    A Gage is a collection of Sensors at a single location.
22
23
    Arguments:
24
        id (int): Primary key for Gage
25
        name (string): Nice name for gage
26
        slug (string): slug used in url
27
        point (Point): PostGIS Point object. Accepts WKT.
28
        river_id (int): Foreign key of ``River``.id that the Gage is on.
29
        river: ``River`` object
30
        user_id (int): Foreign key of ``User``.id that 'owns' the Gage.
31
        user: ``User`` object that `owns` the gage.
32
        visible (boolean): Allows a gage to not be seen on the front end
33
        zipcode (string): Zip code used to get the weather.
34
        local_town (string): Local town name, primarily used for getting the weather
35
        location (string): Descriptive location, often used when Gage is displayed on other pages
36
        elevation (int): The elevation of the Gage
37
        elevationUnits (string): Feet or Meters?
38
        backend_notes (text): Backend info for the Gage for admins.
39
        started (datetime): When samples started to be collected at this gage
40
        ended (datetime): If sampling at this gage has stopped, when?
41
        description (text): Long description for Gage that can contain HTML or Markdown within reason.
42
        key (string): Secret key that samples are signed with
43
        short_description (text): Short description for showing on other pages.
44
        regions: List of ``Region`` objects that this Gage is in.
45
        sensors: List of ``Sensor`` objects that are part of this Gage.
46
    """
47
    __tablename__ = 'gages'
48
49
    id = db.Column(db.Integer, primary_key=True, index=True)
50
    name = db.Column(db.String(80))
51
    slug = db.Column(db.String(80), unique=True, index=True)
52
    # primary_sensor_id = db.Column(db.Integer, db.ForeignKey('sensor.id'))
53
    point = db.Column(Geometry('POINT', 4326))
54
55
    river_id = db.Column(db.Integer, db.ForeignKey('rivers.id'), index=True)
56
    river = db.relationship('River', backref='gages')
57
58
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), index=True)
59
    user = db.relationship('User', backref='gages')
60
61
    visible = db.Column(db.Boolean)
62
    zipcode = db.Column(db.String)
63
    local_town = db.Column(db.String)
64
    location = db.Column(db.Text)
65
    elevation = db.Column(db.Integer)
66
    elevationUnits = db.Column(db.String)
67
    backend_notes = db.Column(db.Text)
68
    started = db.Column(db.DateTime)
69
    ended = db.Column(db.DateTime)
70
    description = db.Column(db.Text)
71
    short_description = db.Column(db.Text)
72
    key = db.Column(db.String)
73
74
    regions = db.relationship('Region',
75
                              secondary=gages_regions,
76
                              backref=db.backref('gages', lazy='dynamic'))
77
78
    def latlon(self):
79
        """
80
        Returns a shapely point
81
        gage.latlon().y for latitude
82
        gage.latlon().x for longitude
83
        """
84
        latlon_point = to_shape(self.point)
85
        return latlon_point
86
87
    def to_json(self):
88
        """
89
        Creates a JSON Object from Gage. Used where multiple gages may be
90
        listed at once.
91
        """
92
        json_post = {
93
            'id': self.id,
94
            'name': self.name,
95
            'location': self.location,
96
            'html': url_for('main.gagepage',
97
                            slug=self.slug,
98
                            _external=True),
99
            'url': url_for('api.get_gage',
100
                           gid=self.id,
101
                           _external=True)
102
        }
103
        return json_post
104
105
    def to_long_json(self):
106
        """
107
        Cretes a JSON Object from Gage. Used where a single gage is displayed.
108
        """
109
        json_post = {
110
            'id': self.id,
111
            'name': self.name,
112
            'location': self.location,
113
            'url': url_for('api.get_gage',
114
                           gid=self.id,
115
                           _external=True),
116
            'html': url_for('main.gagepage',
117
                            slug=self.slug,
118
                            _external=True),
119
            'sensors': [sensor.to_gage_json() for sensor in self.sensors],
120
            'regions': [region.to_json() for region in self.regions]
121
        }
122
        return json_post
123
124
    def geojson(self):
125
        """
126
        Creates a GeoJSON Feature from the gage
127
        """
128
        point = self.latlon()
129
        geojson = {
130
            'type': 'Feature',
131
            'geometry': {
132
                'type': 'Point',
133
                'coordinates': [point.x, point.y]
134
            },
135
            'properties': {
136
                'name': self.name,
137
                'location': self.location,
138
                'id': self.id,
139
                'html': url_for('main.gagepage',
140
                                slug=self.slug,
141
                                _external=True),
142
                'sensors': [sensor.to_gage_json() for sensor in self.sensors],
143
                'regions': [region.to_json() for region in self.regions]
144
            }
145
        }
146
        return geojson
147
148
    def new_sample(self, stype, value, sdatetime):
149
        """
150
        Process a new sample for the gage, and finds the right ``Sensor`` that
151
        the ``Sample`` should be connected to. If no ``Sensor`` exists for the
152
        type of sample, then a new one is created.
153
154
        Arguments:
155
            stype (str): Sensor type
156
            value (float): Sample value
157
            sdatetime (datetime): Sample ``datetime`` object
158
        """
159
        sensor = Sensor.query.filter_by(gage_id=self.id).filter_by(stype=stype).first()
160
        if sensor == None:
161
            sensor = Sensor(gage_id=self.id,
162
                            stype=stype,
163
                            local=True)
164
            db.session.add(sensor)
165
            db.session.commit()
166
        sample = Sample(sensor_id=sensor.id, value=value, datetime=sdatetime)
167
        db.session.add(sample)
168
        db.session.commit()
169
        return sample
170
171
    def __repr__(self):
172
        return '<Gage %r>' % self.name
173
174
    def __str__(self):
175
        return self.name