class RequestRate(models.Model): """Implements a rate limit per IP. value is increased at every request by the amount the request specifies, which is meant to be the average number of seconds until the same request could be made again. value decreases at a rate of 1 per second until it is a 0. """ name = models.CharField(max_length=20) ipaddr = models.IPAddressField(blank=True, null=True) last_update = models.DateTimeField(auto_now_add=True) value = models.FloatField() objects = RequestRateManager() def update(self): this_update = datetime.datetime.now() td = this_update - self.last_update time_delta_sec = (float(td.days) * 3600.0 * 60.0 + float(td.seconds) + float(td.microseconds) / 1000000.0) self.value -= time_delta_sec if self.value < 0: self.value = 0 self.last_update = this_update def request(self, seconds, max_value): self.update() if self.value + seconds < max_value: self.value += seconds self.save() return True else: self.save() return False
class Checkin(models.Model): date = models.DateTimeField(_('Checkin date'), auto_now_add=True) place = models.ForeignKey(CheckinPlace, blank=True, null=True) user = models.ForeignKey(User) is_valid = models.BooleanField(default=False) # Checkin infos lng = models.FloatField() lat = models.FloatField() accuracy = models.FloatField(default=20000) timestamp = models.DateTimeField(_('Checkin date'), auto_now_add=True) useragent = models.CharField(max_length=250, default="Unknown") visitor_ip = models.IPAddressField(blank=True, null=True) extra_data = models.TextField(blank=True, null=True) def distance(self): try: place = CheckinPlace.objects.filter(pk=self.place.id).distance( Point(self.lng, self.lat))[0] if place.distance.m > 999: return '~%0.3f km' % place.distance.km else: return '~%0.3f m' % place.distance.m except: return "Unknown" def __unicode__(self): title = self.is_valid and 'Valid checkin' or 'Invalid checkin' return u"%s at %s" % (title, self.place) class Meta: ordering = ('-date', )
class Survey(models.Model): """ Survey base questions. """ school = models.ForeignKey(School) street = models.CharField(max_length=50, blank=True, null=True) cross_st = models.CharField('Cross street', max_length=50, blank=True, null=True) nr_vehicles = models.IntegerField('Number of Vehicles', blank=True, null=True) nr_licenses = models.IntegerField('Number of License', blank=True, null=True) ip = models.IPAddressField('IP Address', blank=True, null=True) # Mile, shortest driving distance, not walk/bike distance distance = models.FloatField(null=True) created = models.DateTimeField(null=True) modified = models.DateTimeField(auto_now=True, null=True) user = models.ForeignKey(User, null=True) # GeoDjango location = models.PointField(geography=True, blank=True, null=True, default='POINT(0 0)') # default SRS 4326 objects = models.GeoManager() def __unicode__(self): return u'%s' % (self.id) def update_location(self): if len(self.street) > 0 and len(self.cross_st) > 0: school_cross = self.school.get_intersections() crosses = school_cross.filter( Q( Q(st_name_1__iexact=self.street) & Q(st_name_2__iexact=self.cross_st)) | Q( Q(st_name_2__iexact=self.street) & Q(st_name_1__iexact=self.cross_st))) crosses = list(crosses) if len(crosses): self.location = crosses[0].geometry self.location.transform(4326) else: print 'No Intersection' def update_distance(self): from maps import get_driving_distance try: self.distance = get_driving_distance(self.school.geometry, self.location) except: pass
class Author(models.Model): objects = AuthorManager() # Data user = models.ForeignKey(User, **OPT) ip_address = models.IPAddressField(**OPT) user_agent = models.TextField(**OPT) referer = models.TextField(**OPT) created = models.DateTimeField(auto_now_add=True) def __str__(self): return "{} ({})".format(self.user, self.ip_address)
class Visit(AuditableModel): visitor = models.ForeignKey(User, verbose_name=strings.VISIT_VISITOR, related_name='visits', null=True, blank=True) visitor_ip = models.IPAddressField(verbose_name=strings.VISIT_IP_ADDRESS, null=True, blank=True) country_code = models.CharField(verbose_name=strings.VISIT_COUNTRY_CODE, max_length=2, null=True, blank=True) user_agent = models.CharField(verbose_name=strings.VISIT_USER_AGENT, max_length=256, null=True, blank=True) # Generic FK to any other model, Circuit, Place, etc... content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey('content_type', 'object_id') def __unicode__(self): return self.visitor_ip def update_data(self, request, commit=True): self.user_agent = request.META.get('HTTP_USER_AGENT', None) geo = GeoIP(settings.GEOIP_DATABASE) self.country_code = geo.country_code_by_addr( request.META.get('REMOTE_ADDR', None)) self.visitor_ip = request.META.get('REMOTE_ADDR', None) if hasattr(request, 'user') and request.user.is_authenticated(): self.visitor = request.user if commit: self.save() class Meta: verbose_name = strings.VISIT_VERBOSE_NAME verbose_name_plural = strings.VISIT_VERBOSE_NAME_PLURAL @staticmethod def create_visit(request, content_object): visit = Visit(content_object=content_object) visit.update_data(request)
class Submission(models.Model): optional = dict(null=True, default=None, blank=True) # Meta submission_id = models.CharField(max_length=64, default=generate_id) user = models.ForeignKey(User, related_name='submitted_route', **optional) ip_address = models.IPAddressField(**optional) user_agent = models.CharField(max_length=1024, **optional) transportation = models.ForeignKey(Transportation, related_name='history', **optional) # Submitted data parent = models.ForeignKey('self', **optional) data_version = models.IntegerField(default=1) raw_geojson = models.TextField() raw_source = models.TextField(**optional) # Parsed data province = models.CharField(max_length=5, choices=PROVINCES, **optional) city = models.CharField(max_length=256, **optional) company = models.CharField(max_length=256, **optional) number = models.CharField(max_length=64, **optional) origin = models.CharField(max_length=256, **optional) destination = models.CharField(max_length=256, **optional) route = models.MultiLineStringField(srid=4326, **optional) parsed_ok = models.NullBooleanField(**optional) parsed_date = models.DateTimeField(**optional) parsed_error = models.CharField(max_length=1024, **optional) source = models.CharField(max_length=100, **optional) # Internal active = models.BooleanField(default=True) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) def __unicode__(self): return '{} {} - {} - {}'.format(self.company, self.number, self.city, self.user) class Meta: ordering = ('-updated', ) def to_geojson(self): from . import utils return utils.to_geojson(self)
class Hit(models.Model): session = models.ForeignKey(Session) location = models.ForeignKey('accounts.Location', null=True) path = models.CharField(max_length=255) referrer = models.TextField(blank=True) verb = models.CharField(max_length=6) response_code = models.PositiveIntegerField() timestamp = models.DateTimeField(default=datetime.now) ip_address = models.IPAddressField() coords = models.PointField(null=True) hit_number = models.PositiveIntegerField() objects = HitManager() def save(self, *args, **kwargs): g = GeoIP() self.coords = g.geos(self.ip_address) super(Hit, self).save(*args, **kwargs)
class DonePlace(AuditableModel): """ Relation between places and users, where users explicitly mark a place as visited or done """ place = models.ForeignKey(Place, verbose_name=strings.DONE_PLACE_PLACE, related_name='done_place_records' ) user = models.ForeignKey(User, verbose_name=strings.DONE_PLACE_USER, related_name='done_place_records' ) ipaddr = models.IPAddressField( verbose_name=strings.DONE_PLACE_IPADDR, null=True, blank=True ) coordinates = models.PointField( verbose_name=strings.DONE_PLACE_COORDINATES, null=True, blank=True ) created_inplace = models.NullBooleanField( verbose_name=strings.DONE_PLACE_CREATED_INPLACE, null=True, blank=True ) def __unicode__(self): return strings.DONE_PLACE_UNICODE % { 'user':self.user.get_full_name(), 'place':self.place.name, } class Meta: verbose_name = strings.DONE_PLACE_VERBOSE_NAME verbose_name_plural = strings.DONE_PLACE_VERBOSE_NAME_PLURAL unique_together = (('user', 'place'), )
class Asset(models.Model): title = models.CharField( 'Asset Title', max_length=100, ) category = models.CharField('Asset Category', max_length=1, default='p', choices=ASSET_CATEGORIES) ip = models.IPAddressField('IP Address', blank=True, null=True) # GeoDjango location = models.PointField(geography=True, blank=True, null=True, default='POINT(0 0)') # default SRS 4326 objects = models.GeoManager() def __unicode__(self): return u'%s' % (self.id) def get_absolute_url(self): return "/asset/%i/" % self.id
class Comment(models.Model): """ Comment left on the map for a particular location. """ description = models.TextField() user_name = models.CharField(max_length=50, blank=True, null=True) user_email = models.EmailField(max_length=75, blank=True, null=True) admin_key = models.CharField(max_length=12, blank=True, null=True) followup = models.CharField(max_length=1, default='n', choices=FOLLOWUP_CHOICES) ip = models.IPAddressField('IP Address', blank=True, null=True) last_modified = models.DateTimeField(editable=False, auto_now=True) location = models.PointField(geography=True, blank=True, null=True, default='POINT (0 0)') # default SRS 4326 objects = models.GeoManager() class Meta: verbose_name = _('Comment') verbose_name_plural = _('Comments') def __unicode__(self): return "%i" % (self.pk) def save(self, *args, **kwargs): # self.description += self.user_email # no geometry, potential spam if self.location == GEOSGeometry('POINT(0 0)'): self.followup = 'm' super(Comment, self).save(*args, **kwargs)
class Hit(models.Model): article = models.ForeignKey(Article) date = models.DateTimeField(default=datetime.datetime.now) ip_address = models.IPAddressField() user = models.ForeignKey(User, blank=True, null=True)
class Shareditem(models.Model): """ Parent model for all shared items on the page. The class is using multiple managers for * inheritance and selecting subclasses (default 'objects'), and * for spatial queries ('geo_objects'). """ ITEMTYPES = ( ("i", "Idea"), ("m", "Meeting Note"), ("n", "Newspaper Article"), ("e", "Photo or Video"), # legacy: was 'External Media' ("d", "Data"), ) # used in template tags, added here for maintenance reasons ITEMTYPES_PLURAL = { "i": "Ideas", "m": "Meeting Notes", "n": "Newspaper Articles", "e": "Photos & Videos", "d": "Data", } desc = MarkupField( "Description", help_text= "Please see the <a href='#'>Text formatting cheat sheet</a> for help.") itemtype = models.CharField( max_length=1, choices=ITEMTYPES, ) station = models.ForeignKey("Station", verbose_name="Related Station", null=True, blank=True) theme = models.ForeignKey("Theme", verbose_name="Related Theme", null=True, blank=True) author = models.ForeignKey(User, on_delete=models.SET(get_sentinel_user)) ip = models.IPAddressField(default="127.0.0.1") created = models.DateTimeField(auto_now_add=True) last_modified = models.DateTimeField(auto_now_add=True, auto_now=True) rating = RatingField(range=5, can_change_vote=True) objects = InheritanceManager() geometry = models.PointField(geography=True, null=True, blank=True) # default SRS 4326 geo_objects = models.GeoManager() class Meta: ordering = ("-created", "author") get_latest_by = "created" def __unicode__(self): return u"%i" % self.id # child model per itemtype CHILDMODELS = { "i": "idea", "m": "meetingnote", "n": "newsarticle", "e": "media", "d": "data", } @permalink def get_absolute_url(self): return ("%s_detail" % (Shareditem.CHILDMODELS[self.itemtype]), None, { "id": self.id, }) def get_comment_count(self): # workaround for problem with for_model method and inheritance contenttype = ContentType.objects.get_for_model(self) return Comment.objects.filter(content_type=contenttype.id, object_pk=self.id).count() def get_child_contenttype(self): return ContentType.objects.get( app_label="participation", model=Shareditem.CHILDMODELS[self.itemtype])
class Bookmark(Feature): description = models.TextField(default="", null=True, blank=True) latitude = models.FloatField() longitude = models.FloatField() altitude = models.FloatField() heading = models.FloatField(default=0) tilt = models.FloatField(default=0) roll = models.FloatField(default=0) altitudeMode = models.FloatField(default=1) ip = models.IPAddressField(default="0.0.0.0", null=True, blank=True) publicstate = models.TextField(default="{}") @property def kml(self): camera = "<Camera>\n" camera_params = [ "latitude", "longitude", "altitude", "heading", "tilt", "roll", "altitudeMode" ] for p in camera_params: val = self.__dict__[p] if val is not None: camera += " <%s>%s</%s>\n" % (p, val, p) camera += " </Camera>\n" return """ <Placemark id="%s"> <visibility>1</visibility> <name>%s</name> <styleUrl>#%s-default</styleUrl> <ExtendedData> <Data name="descr"><value>%s</value></Data> </ExtendedData> %s </Placemark> """ % (self.uid, escape( self.name), self.model_uid(), escape(self.description), camera) @property def kml_style(self): return """ <Style id="%s-default"> <!-- invisible --> <BalloonStyle> <bgColor>ffeeeeee</bgColor> <text> <![CDATA[ <h3>$[name]</h3> <p>$[descr]</p> ]]> </text> </BalloonStyle> <IconStyle> <scale>0.0</scale> </IconStyle> <LabelStyle> <scale>0.0</scale> </LabelStyle> </Style> """ % (self.model_uid()) class Options: manipulators = [] optional_manipulators = [] verbose_name = 'Bookmark' form = 'madrona.bookmarks.forms.BookmarkForm' icon_url = 'bookmarks/images/bookmark.png' form_template = 'bookmarks/form.html' show_template = 'bookmarks/show.html'
class Message(models.Model): """ Message data """ class Meta(): ordering = ['-date_add'] get_latest_by = 'date_add' verbose_name = _('Message') verbose_name_plural = _('Messages') # Message types REQUEST = 1 OFFER = 2 INFO = 3 TYPES_CHOICE = ( (REQUEST, _("Help requests")), (OFFER, _("Help offers")), # (INFO, _("Informatial message")) ) # Message status NEW = 1 UNVERIFIED = 2 VERIFIED = 3 PENDING = 4 CLOSED = 6 MESSAGE_STATUS = ((NEW, _('New')), (UNVERIFIED, _('Unverified')), (VERIFIED, _('Verified')), (PENDING, _('Pending')), (CLOSED, _('Closed'))) # Managers objects = PassThroughGeoManager.for_queryset_class(MessageQueryset)() # Main message fields title = models.CharField(max_length=200, verbose_name=_('title'), blank=True) message = models.TextField(verbose_name=_('Message')) # Additional message information. This is important for message, but # useless for engine. additional_info = JSONField(blank=True, default='', verbose_name=_("Additional info")) # Message type. Only moderator can change this type. messageType = models.IntegerField( choices=TYPES_CHOICE, db_column='message_type', verbose_name=_('Message type'), ) # Link to message author. It can be anonymous for engine, so this will be # link to settings.ANONYMOUS_USER_ID user = models.ForeignKey( User, verbose_name=_("User"), editable=False, db_column='user_id', ) # Optional fields # Message original source source = models.CharField(max_length=255, verbose_name=_("source"), blank=True) is_virtual = models.BooleanField(default=False, verbose_name=_('Is virtual')) # Moderator's fields # Message can be inactive, i.e. not 'closed' and no more information can be # added. is_active = models.BooleanField(default=False, verbose_name=_('active')) # Is it urgent message? is_important = models.BooleanField(default=False, verbose_name=_('important')) is_anonymous = models.BooleanField(default=True, verbose_name=_('hide contacts')) is_removed = models.BooleanField(default=False, verbose_name=_('removed')) allow_feedback = models.BooleanField(default=True, verbose_name=_('allow feedback')) status = models.SmallIntegerField(choices=MESSAGE_STATUS, verbose_name=_('status'), default=NEW, blank=True, null=True) #Internal fields date_add = models.DateTimeField(auto_now_add=True, db_column='date_add', editable=False) last_edit = models.DateTimeField(auto_now=True, db_column='date_modify', editable=False) expired_date = models.DateTimeField(verbose_name=_("expired at"), blank=True, null=True) edit_key = models.CharField(max_length=40, blank=True) sender_ip = models.IPAddressField(blank=True, null=True, editable=False, verbose_name=_("sender IP")) address = models.CharField(verbose_name=_('Address'), max_length=250, blank=True) location = models.MultiPointField(verbose_name=_('On map'), blank=True, null=True) # Links to core models category = models.ManyToManyField(Category, symmetrical=False, verbose_name=_("message categories"), null=True, blank=True) def __unicode__(self): return self.title or "Untitled" def save(self, *args, **kwargs): self.full_clean() super(Message, self).save(*args, **kwargs) def get_sender_name(self): """ Format sender name based on is_anonymous flag """ first_name = self.additional_info['first_name'].capitalize() last_name = self.additional_info['last_name'].capitalize() if self.is_anonymous and last_name: last_name = last_name[0] return "%s %s" % (first_name, last_name) def get_absolute_url(self): return reverse_lazy("message-details", args=[str(self.pk)])
class WeatherStation(models.Model): name = models.CharField(max_length=100) location = models.ForeignKey(Location, null=True, blank=True) abbreviation = models.CharField(max_length=20) bom_abbreviation = models.CharField(max_length=4) ip_address = models.IPAddressField() port = models.PositiveIntegerField(default=43000) last_scheduled = models.DateTimeField() last_reading = models.DateTimeField() battery_voltage = models.DecimalField(max_digits=3, decimal_places=1) connect_every = models.PositiveSmallIntegerField(default=15) active = models.BooleanField(default=False) stay_connected = models.BooleanField(default=False,verbose_name="Persistant connection") class Meta: ordering=['-last_reading'] def last_reading_local(self): # TODO: use pytz reading = (timezone.localtime(self.last_reading) + timedelta(hours=8)).isoformat().rsplit(":", 2)[0] return reading def last_reading_time(self): # 24hr format time return self.last_reading_local().split("T")[1].replace(":", "") def reload(self): new_self = self.__class__.objects.get(pk=self.pk) #return new_self # You may want to clear out the old dict first or perform a selective merge self.__dict__.update(new_self.__dict__) def rain_since_nine_am(self): import datetime import pytz tz = pytz.timezone('Australia/Perth') now = timezone.make_aware(datetime.datetime.now(),tz) if now.time() > datetime.time(9): last_9am = now.replace(hour=9,minute=0,second=0,microsecond=0) else: yesterday = now - datetime.timedelta(hours=24) last_9am = yesterday.replace(hour=9,minute=0,second=0,microsecond=0) try: rainfall_stats = self.readings.filter(rainfall__gt=0,date__gte=last_9am).aggregate(Min('rainfall'),Max('rainfall')) #.earliest('date') return rainfall_stats['rainfall__max'] - rainfall_stats['rainfall__min'] except: return 0 def save_weather_data(self, raw_data, last_reading=None): """ Convert NVP format to django record """ if last_reading is None: last_reading = timezone.now() # Data is stored in NVP format separated by the pipe symbol '|'. # |<NAME>=<VALUE>| items = raw_data.split('|') data = {} for item in items: if (item != ''): try: key, value = item.split('=') data[key] = value except: pass EMPTY = Decimal('0.00') # Create a weather reading.from the retrieved data. reading = WeatherObservation() reading.temperature_min = data.get('TN') or EMPTY reading.temperature_max = data.get('TX') or EMPTY reading.temperature = data.get('T') or EMPTY reading.temperature_deviation = data.get('TS') or EMPTY reading.temperature_outliers = data.get('TO') or 0 reading.pressure_min = data.get('QFEN') or EMPTY reading.pressure_max = data.get('QFEX') or EMPTY reading.pressure = data.get('QFE') or EMPTY reading.pressure_deviation = data.get('QFES') or EMPTY reading.pressure_outliers = data.get('QFEO') or 0 reading.humidity_min = data.get('HN') or EMPTY reading.humidity_max = data.get('HX') or EMPTY reading.humidity = data.get('H') or EMPTY reading.humidity_deviation = data.get('HS') or EMPTY reading.humidity_outliers = data.get('HO') or 0 reading.wind_direction_min = data.get('DN') or EMPTY reading.wind_direction_max = data.get('DX') or EMPTY reading.wind_direction = data.get('D') or EMPTY reading.wind_direction_deviation = data.get('DS') or EMPTY reading.wind_direction_outliers = data.get('DO') or 0 #10.3.11.100 #10.159.8.67 if (data.get('SN')): reading.wind_speed_min = Decimal(data.get('SN')) * KNOTS_TO_MS or 0 reading.wind_speed_min_kn = Decimal(data.get('SN')) or 0 reading.wind_speed_deviation = Decimal(data.get('SS')) * KNOTS_TO_MS or 0 reading.wind_speed_outliers = data.get('SO') or 0 reading.wind_speed_deviation_kn = Decimal(data.get('SS')) or 0 if (data.get('SX')): reading.wind_speed_max = Decimal(data.get('SX')) * KNOTS_TO_MS or 0 reading.wind_speed_max_kn = Decimal(data.get('SX')) or 0 if (data.get('S')): reading.wind_speed = Decimal(data.get('S')) * KNOTS_TO_MS or 0 reading.wind_speed_kn = Decimal(data.get('S')) or 0 reading.rainfall = data.get('R') or EMPTY try: reading.dew_point = dew_point(float(reading.temperature), float(reading.humidity)) reading.actual_rainfall = actual_rainfall(Decimal(reading.rainfall), self, last_reading) reading.actual_pressure = actual_pressure(float(reading.temperature), float(reading.pressure), float(self.location.height)) except Exception, e: logger.error("We didnt get enough data to do these calculations because %s"%e) reading.raw_data = raw_data reading.station = self reading.save() self.last_reading = last_reading self.battery_voltage = data.get('BV', EMPTY) or EMPTY self.save() return reading