class User(AbstractUser): BASE, VIP, PREMIUM = range(1, 4) SUB_TYPES = ((BASE, 'Base subscription'), (VIP, 'VIP subscription'), (PREMIUM, 'Premium subscription')) SEX_CHOICES = (('M', 'Male'), ('F', 'Female')) sex = models.CharField(max_length=1, choices=SEX_CHOICES, null=True) age = models.PositiveSmallIntegerField( null=True, validators=[MinValueValidator(18), MaxValueValidator(150)]) preferred_sex = models.CharField(max_length=1, choices=SEX_CHOICES, null=True) preferred_age_min = models.PositiveSmallIntegerField(default=18) preferred_age_max = models.PositiveSmallIntegerField(default=150) description = models.CharField(max_length=2000, null=True, blank=True) profile_pic = models.ImageField(upload_to='avatars', null=True) relations = models.ManyToManyField('self', through='Relationship', symmetrical=False) location = models.OneToOneField('Location', null=True, on_delete=models.CASCADE) subscription = models.PositiveSmallIntegerField(choices=SUB_TYPES, default=BASE) swipes_per_day = models.PositiveIntegerField(null=True) search_radius = models.PositiveIntegerField(null=True) @property def h**o(self) -> bool: return self.preferred_sex == self.sex @property def opposite_sex(self) -> str: return 'M' if self.sex == 'F' else 'F' def add_relation(self, to_user, status: int): relation, created = Relationship.objects.get_or_create( from_user=self, to_user=to_user, defaults={'status': status}) return relation, created def _get_user_relations(self, status: int): return self.relations.filter(to_users__from_user=self, to_users__status=status) def _get_related(self, status: int): return self.relations.filter(from_users__to_user=self, from_users__status=status) def get_user_likes(self): return self._get_user_relations(Relationship.LIKED) def get_user_dislikes(self): return self._get_user_relations(Relationship.DISLIKED) def get_related_likes(self): return self._get_related(Relationship.LIKED) def get_related_dislikes(self): return self._get_related(Relationship.DISLIKED) def get_matched_list(self): return self.relations.filter( to_users__from_user=self, to_users__status=Relationship.LIKED, from_users__to_user=self, from_users__status=Relationship.LIKED, ) def is_matched(self, other) -> bool: return Relationship.objects.filter( from_user=self, to_user=other, status=Relationship.LIKED ).exists() and \ Relationship.objects.filter( from_user=other, to_user=self, status=Relationship.LIKED ).exists() def get_chat_id(self, other): return Chat.objects.filter(participants=self.id).intersection( Chat.objects.filter(participants=other.id)).first() @classmethod def get_subscription_swipes(cls, subscription: int): swipes = {cls.BASE: 20, cls.VIP: 100, cls.PREMIUM: 2147483647} return swipes[subscription] @classmethod def get_subscription_radius(cls, subscription: int): radius = {cls.BASE: 10, cls.VIP: 25, cls.PREMIUM: 2147483647} return radius[subscription]
class Member(models.Model): """ Class model represents the Neighbourhood Watch registered member for the particular tenant. """ ''' METADATA ''' class Meta: app_label = 'tenant_foundation' db_table = 'nwapp_members' verbose_name = _('Member') verbose_name_plural = _('Members') default_permissions = () permissions = () ''' CONSTANTS ''' class MEMBER_STATE: ACTIVE = 'active' INACTIVE = 'inactive' class MEMBER_TYPE_OF: RESIDENTIAL = 1 BUSINESS = 2 COMMUNITY_CARES = 3 class MEMBER_DEACTIVATION_REASON: NOT_SPECIFIED = 0 OTHER = 1 BLACKLISTED = 2 MOVED = 3 DECEASED = 4 DO_NOT_CONTACT = 5 ''' CHOICES ''' MEMBER_STATE_CHOICES = ( (MEMBER_STATE.ACTIVE, _('Active')), (MEMBER_STATE.INACTIVE, _('Inactive')), ) MEMBER_TYPE_OF_CHOICES = ( (MEMBER_TYPE_OF.BUSINESS, _('Business')), (MEMBER_TYPE_OF.RESIDENTIAL, _('Residential')), (MEMBER_TYPE_OF.COMMUNITY_CARES, _('Community Cares')), ) MEMBER_DEACTIVATION_REASON_CHOICES = ( (MEMBER_DEACTIVATION_REASON.BLACKLISTED, _('Blacklisted')), (MEMBER_DEACTIVATION_REASON.MOVED, _('Moved')), (MEMBER_DEACTIVATION_REASON.DECEASED, _('Deceased')), (MEMBER_DEACTIVATION_REASON.DO_NOT_CONTACT, _('Do not contact')), (MEMBER_DEACTIVATION_REASON.NOT_SPECIFIED, _('Not specified')), (MEMBER_DEACTIVATION_REASON.OTHER, _('Other')), ) ''' OBJECT MANAGERS ''' objects = MemberManager() ''' MODEL FIELDS ''' # SYSTEM FIELDS user = models.OneToOneField( SharedUser, help_text=_('The user whom is a member.'), related_name="member", on_delete=models.CASCADE, primary_key=True, ) type_of = models.PositiveSmallIntegerField( _("Type of"), help_text=_('The type of member this is.'), choices=MEMBER_TYPE_OF_CHOICES, db_index=True, ) # STATE FIELDS state = models.CharField( _('State'), help_text=_('The state of this member.'), max_length=15, choices=MEMBER_STATE_CHOICES, default=MEMBER_STATE.ACTIVE, blank=True, db_index=True, ) deactivation_reason = models.PositiveSmallIntegerField( _("Deactivation reason"), help_text=_('The reason why this member was deactivated.'), blank=True, choices=MEMBER_DEACTIVATION_REASON_CHOICES, default=MEMBER_DEACTIVATION_REASON.NOT_SPECIFIED ) deactivation_reason_other = models.CharField( _("Deactivation reason (other)"), max_length=2055, help_text=_('The reason why this member was deactivated which was not in the list.'), blank=True, null=True, default="" ) # MISC FIELDS avatar_image = models.ForeignKey( "PrivateImageUpload", help_text=_('The avatar image of this member.'), related_name="members", on_delete=models.SET_NULL, blank=True, null=True, ) watch = models.ForeignKey( "Watch", help_text=_('The watch this member belongs to.'), related_name="members", on_delete=models.SET_NULL, blank=True, null=True, ) # AUDITING FIELDS uuid = models.CharField( _("UUID"), help_text=_('The unique identifier we want to release to the public to identify this unique record.'), default=uuid.uuid4, editable=False, max_length=63, # Do not change unique=True, db_index=True, ) created_at = models.DateTimeField(auto_now_add=True, db_index=True) created_by = models.ForeignKey( SharedUser, help_text=_('The user whom created this object.'), related_name="created_members", on_delete=models.SET_NULL, blank=True, null=True, ) created_from = models.GenericIPAddressField( _("Created from"), help_text=_('The IP address of the creator.'), blank=True, null=True ) created_from_is_public = models.BooleanField( _("Is the IP "), help_text=_('Is creator a public IP and is routable.'), default=False, blank=True ) created_from_position = models.PointField( _("Created from position"), help_text=_('The latitude and longitude coordinates for the creator.'), srid=4326, geography=True, null=True, blank=True, ) last_modified_at = models.DateTimeField(auto_now=True) last_modified_by = models.ForeignKey( SharedUser, help_text=_('The user whom modified this object last.'), related_name="last_modified_members", on_delete=models.SET_NULL, blank=True, null=True, ) last_modified_from = models.GenericIPAddressField( _("Last modified from"), help_text=_('The IP address of the modifier.'), blank=True, null=True ) last_modified_from_is_public = models.BooleanField( _("Is the IP "), help_text=_('Is modifier a public IP and is routable.'), default=False, blank=True ) last_modified_from_position = models.PointField( _("Last modified from position"), help_text=_('The latitude and longitude coordinates for the last modified user.'), srid=4326, geography=True, null=True, blank=True, ) # SEARCHABLE FIELDS indexed_text = models.CharField( _("Indexed Text"), max_length=1023, help_text=_('The searchable content text used by the keyword searcher function.'), blank=True, null=True, db_index=True, unique=True ) """ MODEL FUNCTIONS """ def __str__(self): ''' Override the `casting` function so we output the following string when an object gets casted to a string. ''' return self.user.get_full_name() def get_role_label(self): return self.user.role_label @transaction.atomic def save(self, *args, **kwargs): ''' Override the `save` function to support extra functionality of our model. ''' if self.created_from: self.created_from_position = get_point_from_ip(self.created_from) if self.last_modified_from: self.last_modified_from_position = get_point_from_ip(self.last_modified_from) ''' Finally call the parent function which handles saving so we can carry out the saving operation by Django in our ORM. ''' super(Member, self).save(*args, **kwargs) def get_full_name(self): return self.user.get_full_name() def get_pretty_state(self): return str(dict(Member.MEMBER_STATE_CHOICES).get(self.state)) def get_pretty_type_of(self): return str(dict(Member.MEMBER_TYPE_OF_CHOICES).get(self.type_of)) def get_pretty_deactivation_reason(self): return str(dict(Member.MEMBER_DEACTIVATION_REASON_CHOICES).get(self.deactivation_reason)) def invalidate(self, method_name): #TODO: IMPLEMENT """ Function used to clear the cache for the cached property functions. """ try: pass # if method_name == 'fullname': # del self.fullname # else: # raise Exception("Method name not found.") except AttributeError: pass def invalidate_all(self): self.invalidate("fullname") @staticmethod def get_searchable_content(member): """ Utility function which refreshes the searchable content used when searching for `keywords`. """ text = member.user.slug + " " if member.contact: text += member.contact.get_searchable_content() if member.address: text += " " + member.address.get_searchable_content() if member.metric: text += " " + member.metric.get_searchable_content() if member.watch: text += " " + member.watch.get_searchable_content() return text @staticmethod def seed(tenant, length=25): from faker import Faker from shared_foundation.models import SharedUser, SharedGroup from tenant_foundation.models import Member from tenant_foundation.models import MemberAddress from tenant_foundation.models import MemberContact from tenant_foundation.models import MemberMetric from tenant_foundation.models import MemberComment from tenant_foundation.models import Watch from tenant_foundation.models import StreetAddressRange from tenant_foundation.models import HowHearAboutUsItem from tenant_foundation.models import ExpectationItem from tenant_foundation.models import MeaningItem results = [] faker = Faker('en_CA') for i in range(0,length): try: first_name = faker.first_name() last_name = faker.last_name() street_address = StreetAddressRange.objects.random() organization_name = faker.company() organization_type_of = faker.pyint(min_value=2, max_value=4, step=1) user = SharedUser.objects.create( tenant=tenant, email = faker.safe_email(), first_name = first_name, middle_name = None, last_name = last_name, ) user.groups.add(SharedGroup.GROUP_MEMBERSHIP.MEMBER) member = Member.objects.create( user=user, type_of=street_address.watch.type_of, watch=street_address.watch, ) member_contact = MemberContact.objects.create( member=member, is_ok_to_email=True, is_ok_to_text=True, organization_name=organization_name, organization_type_of=organization_type_of, first_name=user.first_name, last_name=user.last_name, email=user.email, primary_phone=faker.phone_number(), secondary_phone=faker.phone_number(), ) member_address = MemberAddress.objects.create( member=member, country="Canada", province="Ontario", city=faker.city(), street_number=faker.pyint( min_value=street_address.street_number_start, max_value=street_address.street_number_end, step=1 ), street_name=street_address.street_name, apartment_unit=faker.pyint( min_value=1, max_value=1000, step=1 ), street_type=street_address.street_type, street_type_other=street_address.street_type_other, street_direction=street_address.street_direction, postal_code=faker.postalcode(), ) member_metric = MemberMetric.objects.create( member = member, how_did_you_hear = HowHearAboutUsItem.objects.random(), how_did_you_hear_other = faker.company(), expectation = ExpectationItem.objects.random(), expectation_other = faker.company(), meaning = MeaningItem.objects.random(), meaning_other = faker.company(), # gender= # willing_to_volunteer= another_household_member_registered=False, year_of_birth=faker.pyint(min_value=1920, max_value=1990, step=1), total_household_count=faker.pyint(min_value=2, max_value=6, step=1), over_18_years_household_count = faker.pyint(min_value=0, max_value=1, step=1), organization_employee_count = faker.pyint(min_value=0, max_value=10, step=1), organization_founding_year=faker.pyint(min_value=1920, max_value=1990, step=1), ) results.append(member) except Exception as e: print(e) pass return results def promote_to_area_coordinator(self, defaults): """ - defaults - has_signed_area_coordinator_agreement - has_signed_conflict_of_interest_agreement - has_signed_code_of_conduct_agreement - has_signed_confidentiality_agreement - police_check_date - created_by - created_from - created_from_is_public - last_modified_by - last_modified_from - last_modified_from_is_public """ from django.template.loader import render_to_string # HTML / TXT from django.utils import timezone from shared_foundation.models import SharedGroup from tenant_foundation.models import AreaCoordinator has_signed_area_coordinator_agreement = defaults.get('has_signed_area_coordinator_agreement', None) has_signed_conflict_of_interest_agreement = defaults.get('has_signed_conflict_of_interest_agreement', None) has_signed_code_of_conduct_agreement = defaults.get('has_signed_code_of_conduct_agreement', None) has_signed_confidentiality_agreement = defaults.get('has_signed_confidentiality_agreement', None) police_check_date = defaults.get('police_check_date', None) created_by = defaults.get('created_by', None) created_from = defaults.get('created_from', None) created_from_is_public = defaults.get('created_from_is_public', None) last_modified_by = defaults.get('last_modified_by', None) last_modified_from = defaults.get('last_modified_from', None) last_modified_from_is_public = defaults.get('last_modified_from_is_public', None) # Defensive code. assert self.user != None assert isinstance(has_signed_area_coordinator_agreement, bool) assert isinstance(has_signed_conflict_of_interest_agreement, bool) assert isinstance(has_signed_code_of_conduct_agreement, bool) assert isinstance(has_signed_confidentiality_agreement, bool) assert police_check_date != None # Get the text agreement which will be signed. area_coordinator_agreement = render_to_string('account/area_coordinator_agreement/2019_05_01.txt', {}) if has_signed_area_coordinator_agreement else None conflict_of_interest_agreement = render_to_string('account/conflict_of_interest_agreement/2019_05_01.txt', {}) if has_signed_conflict_of_interest_agreement else None code_of_conduct_agreement = render_to_string('account/code_of_conduct_agreement/2019_05_01.txt', {}) if has_signed_code_of_conduct_agreement else None confidentiality_agreement = render_to_string('account/confidentiality_agreement/2019_05_01.txt', {}) if has_signed_confidentiality_agreement else None # Create or update our model. area_coordinator, created = AreaCoordinator.objects.update_or_create( user=self.user, defaults={ 'user': self.user, 'watch': self.watch, 'type_of': self.type_of, 'has_signed_area_coordinator_agreement': has_signed_area_coordinator_agreement, 'area_coordinator_agreement': area_coordinator_agreement, 'area_coordinator_agreement_signed_on': timezone.now(), 'has_signed_conflict_of_interest_agreement': has_signed_conflict_of_interest_agreement, 'conflict_of_interest_agreement': conflict_of_interest_agreement, 'conflict_of_interest_agreement_signed_on': timezone.now(), 'has_signed_code_of_conduct_agreement': has_signed_code_of_conduct_agreement, 'code_of_conduct_agreement': code_of_conduct_agreement, 'code_of_conduct_agreement_signed_on': timezone.now(), 'has_signed_confidentiality_agreement': has_signed_confidentiality_agreement, 'confidentiality_agreement': confidentiality_agreement, 'confidentiality_agreement_signed_on': timezone.now(), 'police_check_date': police_check_date, 'created_by': created_by, 'created_from': created_from, 'created_from_is_public': created_from_is_public, 'created_from_position': get_point_from_ip(created_from), 'last_modified_by': last_modified_by, 'last_modified_from': last_modified_from, 'last_modified_from_is_public': last_modified_from_is_public, 'last_modified_from_position': get_point_from_ip(last_modified_from), } ) # Set the user's role to be a area coordinator after clearing the # previous group memberships. area_coordinator.user.groups.clear() area_coordinator.user.groups.add(SharedGroup.GROUP_MEMBERSHIP.AREA_COORDINATOR) return area_coordinator def promote_to_associate(self, defaults): """ - defaults - has_signed_associate_agreement - has_signed_conflict_of_interest_agreement - has_signed_code_of_conduct_agreement - has_signed_confidentiality_agreement - police_check_date - created_by - created_from - created_from_is_public - last_modified_by - last_modified_from - last_modified_from_is_public """ from django.template.loader import render_to_string # HTML / TXT from django.utils import timezone from shared_foundation.models import SharedGroup from tenant_foundation.models import Associate has_signed_associate_agreement = defaults.get('has_signed_associate_agreement', None) has_signed_conflict_of_interest_agreement = defaults.get('has_signed_conflict_of_interest_agreement', None) has_signed_code_of_conduct_agreement = defaults.get('has_signed_code_of_conduct_agreement', None) has_signed_confidentiality_agreement = defaults.get('has_signed_confidentiality_agreement', None) police_check_date = defaults.get('police_check_date', None) created_by = defaults.get('created_by', None) created_from = defaults.get('created_from', None) created_from_is_public = defaults.get('created_from_is_public', None) last_modified_by = defaults.get('last_modified_by', None) last_modified_from = defaults.get('last_modified_from', None) last_modified_from_is_public = defaults.get('last_modified_from_is_public', None) # Defensive code. assert self.user != None assert isinstance(has_signed_associate_agreement, bool) assert isinstance(has_signed_conflict_of_interest_agreement, bool) assert isinstance(has_signed_code_of_conduct_agreement, bool) assert isinstance(has_signed_confidentiality_agreement, bool) assert police_check_date != None # Get the text agreement which will be signed. associate_agreement = render_to_string('account/associate_agreement/2019_05_01.txt', {}) if has_signed_associate_agreement else None conflict_of_interest_agreement = render_to_string('account/conflict_of_interest_agreement/2019_05_01.txt', {}) if has_signed_conflict_of_interest_agreement else None code_of_conduct_agreement = render_to_string('account/code_of_conduct_agreement/2019_05_01.txt', {}) if has_signed_code_of_conduct_agreement else None confidentiality_agreement = render_to_string('account/confidentiality_agreement/2019_05_01.txt', {}) if has_signed_confidentiality_agreement else None # Create or update our model. associate, created = Associate.objects.update_or_create( user=self.user, defaults={ 'user': self.user, 'watch': self.watch, 'type_of': self.type_of, 'has_signed_associate_agreement': has_signed_associate_agreement, 'associate_agreement': associate_agreement, 'associate_agreement_signed_on': timezone.now(), 'has_signed_conflict_of_interest_agreement': has_signed_conflict_of_interest_agreement, 'conflict_of_interest_agreement': conflict_of_interest_agreement, 'conflict_of_interest_agreement_signed_on': timezone.now(), 'has_signed_code_of_conduct_agreement': has_signed_code_of_conduct_agreement, 'code_of_conduct_agreement': code_of_conduct_agreement, 'code_of_conduct_agreement_signed_on': timezone.now(), 'has_signed_confidentiality_agreement': has_signed_confidentiality_agreement, 'confidentiality_agreement': confidentiality_agreement, 'confidentiality_agreement_signed_on': timezone.now(), 'police_check_date': police_check_date, 'created_by': created_by, 'created_from': created_from, 'created_from_is_public': created_from_is_public, 'created_from_position': get_point_from_ip(created_from), 'last_modified_by': last_modified_by, 'last_modified_from': last_modified_from, 'last_modified_from_is_public': last_modified_from_is_public, 'last_modified_from_position': get_point_from_ip(last_modified_from), } ) # Set the user's role to be a area coordinator after clearing the # previous group memberships. associate.user.groups.clear() associate.user.groups.add(SharedGroup.GROUP_MEMBERSHIP.ASSOCIATE) return associate def promote_to_staff(self, defaults): """ - defaults - role_id - has_signed_staff_agreement - has_signed_conflict_of_interest_agreement - has_signed_code_of_conduct_agreement - has_signed_confidentiality_agreement - police_check_date - created_by - created_from - created_from_is_public - last_modified_by - last_modified_from - last_modified_from_is_public """ from django.template.loader import render_to_string # HTML / TXT from django.utils import timezone from shared_foundation.models import SharedGroup from tenant_foundation.models import Staff role_id = defaults.get('role_id', None) has_signed_staff_agreement = defaults.get('has_signed_staff_agreement', None) has_signed_conflict_of_interest_agreement = defaults.get('has_signed_conflict_of_interest_agreement', None) has_signed_code_of_conduct_agreement = defaults.get('has_signed_code_of_conduct_agreement', None) has_signed_confidentiality_agreement = defaults.get('has_signed_confidentiality_agreement', None) police_check_date = defaults.get('police_check_date', None) created_by = defaults.get('created_by', None) created_from = defaults.get('created_from', None) created_from_is_public = defaults.get('created_from_is_public', None) last_modified_by = defaults.get('last_modified_by', None) last_modified_from = defaults.get('last_modified_from', None) last_modified_from_is_public = defaults.get('last_modified_from_is_public', None) # Defensive code. assert self.user != None assert isinstance(role_id, int) assert isinstance(has_signed_staff_agreement, bool) assert isinstance(has_signed_conflict_of_interest_agreement, bool) assert isinstance(has_signed_code_of_conduct_agreement, bool) assert isinstance(has_signed_confidentiality_agreement, bool) assert police_check_date != None # Get the text agreement which will be signed. staff_agreement = render_to_string('account/staff_agreement/2019_05_01.txt', {}) if has_signed_staff_agreement else None conflict_of_interest_agreement = render_to_string('account/conflict_of_interest_agreement/2019_05_01.txt', {}) if has_signed_conflict_of_interest_agreement else None code_of_conduct_agreement = render_to_string('account/code_of_conduct_agreement/2019_05_01.txt', {}) if has_signed_code_of_conduct_agreement else None confidentiality_agreement = render_to_string('account/confidentiality_agreement/2019_05_01.txt', {}) if has_signed_confidentiality_agreement else None # Create or update our model. staff, created = Staff.objects.update_or_create( user=self.user, defaults={ 'user': self.user, 'has_signed_staff_agreement': has_signed_staff_agreement, 'staff_agreement': staff_agreement, 'staff_agreement_signed_on': timezone.now(), 'has_signed_conflict_of_interest_agreement': has_signed_conflict_of_interest_agreement, 'conflict_of_interest_agreement': conflict_of_interest_agreement, 'conflict_of_interest_agreement_signed_on': timezone.now(), 'has_signed_code_of_conduct_agreement': has_signed_code_of_conduct_agreement, 'code_of_conduct_agreement': code_of_conduct_agreement, 'code_of_conduct_agreement_signed_on': timezone.now(), 'has_signed_confidentiality_agreement': has_signed_confidentiality_agreement, 'confidentiality_agreement': confidentiality_agreement, 'confidentiality_agreement_signed_on': timezone.now(), 'police_check_date': police_check_date, 'created_by': created_by, 'created_from': created_from, 'created_from_is_public': created_from_is_public, 'created_from_position': get_point_from_ip(created_from), 'last_modified_by': last_modified_by, 'last_modified_from': last_modified_from, 'last_modified_from_is_public': last_modified_from_is_public, 'last_modified_from_position': get_point_from_ip(last_modified_from), } ) # Set the user's role to be after clearing the previous group memberships. staff.user.groups.clear() staff.user.groups.add(role_id) return staff
class Ambulance(PublishMixin, UpdatedByModel): # TODO: Should we consider denormalizing Ambulance to avoid duplication with AmbulanceUpdate? equipmentholder = models.OneToOneField(EquipmentHolder, on_delete=models.CASCADE, verbose_name=_('equipmentholder')) # ambulance properties identifier = models.CharField(_('identifier'), max_length=50, unique=True) # TODO: Should we add an active flag? capability = models.CharField(_('capability'), max_length=1, choices=make_choices(AmbulanceCapability)) # status status = models.CharField(_('status'), max_length=2, choices=make_choices(AmbulanceStatus), default=AmbulanceStatus.UK.name) # location orientation = models.FloatField(_('orientation'), default=0.0) location = models.PointField(_('location'), srid=4326, default=defaults['location']) # timestamp timestamp = models.DateTimeField(_('timestamp'), default=timezone.now) # active active = models.BooleanField(_('active'), default=True) # default value for _loaded_values _loaded_values = None @classmethod def from_db(cls, db, field_names, values): # call super instance = super(Ambulance, cls).from_db(db, field_names, values) # store the original field values on the instance instance._loaded_values = dict(zip(field_names, values)) # return instance return instance def save(self, *args, **kwargs): # creation? created = self.pk is None # loaded_values? loaded_values = self._loaded_values is not None # create equipment holder? try: if created or self.equipmentholder is None: self.equipmentholder = EquipmentHolder.objects.create() except EquipmentHolder.DoesNotExist: self.equipmentholder = EquipmentHolder.objects.create() # has location changed? has_moved = False if (not loaded_values) or \ calculate_distance(self._loaded_values['location'], self.location) > stationary_radius: has_moved = True # calculate orientation only if location has changed and orientation has not changed if has_moved and loaded_values and self._loaded_values[ 'orientation'] == self.orientation: # TODO: should we allow for a small radius before updating direction? self.orientation = calculate_orientation( self._loaded_values['location'], self.location) # logger.debug('< {} - {} = {}'.format(self._loaded_values['location'], # self.location, # self.orientation)) # logger.debug('loaded_values: {}'.format(loaded_values)) # logger.debug('_loaded_values: {}'.format(self._loaded_values)) # if comment, capability, status or location changed # model_changed = False if has_moved or \ self._loaded_values['status'] != self.status or \ self._loaded_values['capability'] != self.capability or \ self._loaded_values['comment'] != self.comment: # save to Ambulance super().save(*args, **kwargs) # logger.debug('SAVED') # save to AmbulanceUpdate data = { k: getattr(self, k) for k in ('capability', 'status', 'orientation', 'location', 'timestamp', 'comment', 'updated_by', 'updated_on') } data['ambulance'] = self obj = AmbulanceUpdate(**data) obj.save() # logger.debug('UPDATE SAVED') # # model changed # model_changed = True # if identifier changed # NOTE: self._loaded_values is NEVER None because has_moved is True elif self._loaded_values['identifier'] != self.identifier: # save only to Ambulance super().save(*args, **kwargs) # logger.debug('SAVED') # # model changed # model_changed = True # # Did the model change? # if model_changed: # # # publish to mqtt # # from mqtt.publish import SingletonPublishClient # SingletonPublishClient().publish_ambulance(self) # # # logger.debug('PUBLISHED ON MQTT') # just created? if created: # invalidate permissions cache from mqtt.cache_clear import mqtt_cache_clear mqtt_cache_clear() def publish(self, **kwargs): # publish to mqtt from mqtt.publish import SingletonPublishClient SingletonPublishClient().publish_ambulance(self, **kwargs) def delete(self, *args, **kwargs): # invalidate permissions cache from mqtt.cache_clear import mqtt_cache_clear mqtt_cache_clear() # delete from Ambulance super().delete(*args, **kwargs) def get_absolute_url(self): return reverse('ambulance:detail', kwargs={'pk': self.id}) def __str__(self): return ('Ambulance {}(id={}) ({}) [{}]:\n' + ' Status: {}\n' + ' Location: {} @ {}\n' + ' Updated: {} by {}').format( self.identifier, self.id, AmbulanceCapability[self.capability].value, self.comment, AmbulanceStatus[self.status].value, self.location, self.timestamp, self.updated_by, self.updated_on)
class AggregateNeighborhood(AggregateSummaryModel): location = models.OneToOneField(Neighborhood, related_name='aggregates')
class GeoUser(models.Model): id = models.AutoField(primary_key=True) user = models.OneToOneField(CustomUser, on_delete=models.CASCADE) home_location = models.PointField() current_location = models.PointField()
class Artist(models.Model): artist_id = models.OneToOneField(CustomUser, on_delete=models.DO_NOTHING, primary_key=True) genre = models.CharField(max_length=15) band_name = models.CharField(max_length=100)
class FacilityCoordinates(CoordinatesValidatorMixin, GISAbstractBase): """ Location derived by the use of GPS satellites and GPS device or receivers. It is three dimensional. The three-dimensional readings from a GPS device are latitude, longitude, and attitude. The date/time the reading is done is also important, as is the source and method of the reading. """ facility = gis_models.OneToOneField( Facility, related_name='facility_coordinates_through', unique=True) coordinates = gis_models.PointField() source = gis_models.ForeignKey( GeoCodeSource, null=True, blank=True, help_text="where the geo code came from", on_delete=gis_models.PROTECT) method = gis_models.ForeignKey( GeoCodeMethod, null=True, blank=True, help_text="Method used to obtain the geo codes. e.g" " taken with GPS device") collection_date = gis_models.DateTimeField(default=timezone.now) @property def simplify_coordinates(self): return { "coordinates": [ float('%.2f' % round(self.coordinates[0], 2)), float('%.2f' % round(self.coordinates[1], 2)) ] } def validate_coordinates_decimal_places_at_least_six(self): if (len(str(self.coordinates[0])) < 7 or len(str(self.coordinates[1])) < 7): raise ValidationError({ "coordinates": ["Please provide at-least 6 decimal places number. "] }) @property def json_features(self): return { "geometry": self.simplify_coordinates, } def clean(self): self.validate_coordinates_decimal_places_at_least_six() self.validate_long_and_lat_within_kenya() self.validate_long_and_lat_within_county( self.facility.ward.constituency.county) self.validate_long_and_lat_within_constituency( self.facility.ward.constituency) self.validate_long_and_lat_within_ward( self.facility.ward) super(FacilityCoordinates, self).clean() def __str__(self): return "{}:{}:{}".format(self.facility, self.source, self.method) class Meta(GISAbstractBase.Meta): verbose_name_plural = 'facility coordinates' verbose_name = 'facility coordinates'
class Office(models.Model): telephone = models.CharField(max_length=48) account_number = models.CharField(max_length=10, unique=True) organisation = models.ForeignKey("Organisation", on_delete=models.CASCADE) location = models.OneToOneField("Location", null=True, on_delete=models.CASCADE) categories = models.ManyToManyField(Category)
class ProductViewCount(models.Model): product = models.OneToOneField(Product) count = models.PositiveIntegerField(default=0)
class Signal(CreatedUpdatedModel): SOURCE_DEFAULT_ANONYMOUS_USER = '******' # we need an unique id for external systems. # TODO SIG-563 rename `signal_id` to `signal_uuid` to be more specific. signal_id = models.UUIDField(default=uuid.uuid4, db_index=True) source = models.CharField(max_length=128, default=SOURCE_DEFAULT_ANONYMOUS_USER) text = models.CharField(max_length=3000) text_extra = models.CharField(max_length=10000, default='', blank=True) location = models.OneToOneField('signals.Location', related_name='signal', null=True, on_delete=models.SET_NULL) status = models.OneToOneField('signals.Status', related_name='signal', null=True, on_delete=models.SET_NULL) category_assignment = models.OneToOneField('signals.CategoryAssignment', related_name='signal', null=True, on_delete=models.SET_NULL) categories = models.ManyToManyField('signals.Category', through='signals.CategoryAssignment') reporter = models.OneToOneField('signals.Reporter', related_name='signal', null=True, on_delete=models.SET_NULL) priority = models.OneToOneField('signals.Priority', related_name='signal', null=True, on_delete=models.SET_NULL) directing_departments_assignment = models.OneToOneField( 'signals.SignalDepartments', related_name='directing_department_signal', null=True, on_delete=models.SET_NULL) routing_assignment = models.OneToOneField('signals.SignalDepartments', related_name='routing_signal', null=True, on_delete=models.SET_NULL) user_assignment = models.OneToOneField( 'users.SignalUser', related_name='user_assignment_signal', null=True, on_delete=models.SET_NULL) # Date of the incident. incident_date_start = models.DateTimeField(null=False) incident_date_end = models.DateTimeField(null=True) # Date action is expected operational_date = models.DateTimeField(null=True) # Date we should have reported back to reporter. expire_date = models.DateTimeField(null=True) # file will be saved to MEDIA_ROOT/uploads/2015/01/30 upload = ArrayField(models.FileField(upload_to='uploads/%Y/%m/%d/'), null=True) # TODO: remove extra_properties = JSONField(null=True) # SIG-884 parent = models.ForeignKey(to='self', related_name='children', null=True, blank=True, on_delete=models.SET_NULL) objects = SignalQuerySet.as_manager() actions = SignalManager() @property def image(self): """ Field for backwards compatibility. The attachment table replaces the old 'image' property """ attachment = self.attachments.filter(is_image=True).first() return attachment.file if attachment else "" @property def image_crop(self): attachment = self.attachments.filter(is_image=True).first() return attachment.image_crop if self.image else '' class Meta: permissions = ( ('sia_read', 'Leesrechten algemeen'), # SIG-2192 ('sia_write', 'Schrijfrechten algemeen'), # SIG-2194 ('sia_split', 'Splitsen van een melding'), # SIG-2192 ('sia_signal_create_initial', 'Melding aanmaken'), # SIG-2192 ('sia_signal_create_note', 'Notitie toevoegen bij een melding'), # SIG-2192 ('sia_signal_change_status', 'Wijzigen van status van een melding'), # SIG-2192 ('sia_signal_change_category', 'Wijzigen van categorie van een melding'), # SIG-2192 ('sia_signal_export', 'Meldingen exporteren'), # SIG-2192 ('sia_signal_report', 'Rapportage beheren'), # SIG-2192 ) ordering = ('created_at', ) indexes = [ models.Index(fields=['created_at']), models.Index(fields=['id', 'parent']), ] def __init__(self, *args, **kwargs): super(Signal, self).__init__(*args, **kwargs) if not self.signal_id: self.signal_id = uuid.uuid4() def __str__(self): """Identifying string. DO NOT expose sensitive stuff here. """ # Fix for bug SIG-2486 Timezones were not consistently shown created_at = self.created_at field_timezone = timezone.get_current_timezone( ) if settings.USE_TZ else None if timezone.is_aware(created_at) and field_timezone: created_at = created_at.astimezone(field_timezone) elif timezone.is_aware(created_at): created_at = timezone.make_naive(created_at, utc) return f'{self.id} - ' \ f'{self.status.state if self.status else ""} - ' \ f'{self.location.buurt_code if self.location else ""} - ' \ f'{created_at.isoformat()}' @property def sia_id(self): """SIA identifier used for external communication. :returns: str """ return 'SIA-{id}'.format(id=self.id) def get_fqdn_image_crop_url(self): """Get FQDN image crop url. :returns: url (str) or None """ if not self.image_crop: return None is_swift = isinstance(self.image_crop.storage, SwiftStorage) if is_swift: return self.image_crop.url # Generated temp url from Swift Object Store. else: # Generating a fully qualified url ourself. current_site = Site.objects.get_current() is_local = 'localhost' in current_site.domain or settings.DEBUG fqdn_url = '{scheme}://{domain}{path}'.format( scheme='http' if is_local else 'https', domain=current_site.domain, path=self.image_crop.url) return fqdn_url def is_parent(self): # If we have children we are a parent return self.children.exists() def is_child(self): # If we have a parent we are a child return self.parent is not None @property def siblings(self): if self.is_child(): # If we are a child return all siblings siblings_qs = self.parent.children.all() if self.pk: # Exclude myself if possible return siblings_qs.exclude(pk=self.pk) return siblings_qs # Return a non queryset return self.__class__.objects.none() def _validate(self): if self.is_parent() and self.is_child(): # We cannot be a parent and a child at once raise ValidationError('Cannot be a parent and a child at the once') if self.parent and self.parent.is_child(): # The parent of this Signal cannot be a child of another Signal raise ValidationError('A child of a child is not allowed') if (self.pk is None and self.is_child() and self.siblings.count() >= settings.SIGNAL_MAX_NUMBER_OF_CHILDREN): # we are a new child and our parent already has the max number of children raise ValidationError( 'Maximum number of children reached for the parent Signal') def save(self, *args, **kwargs): self._validate() super(Signal, self).save(*args, **kwargs) @property def type_assignment(self): return self.types.first() if self.types.exists() else None
class ShipmentCarrierAssignment(models.Model): assignment = models.OneToOneField('ShipmentAssignment', null=True, blank=True)
class Project(ModelWithSlugMixin, CloneableModelMixin, TimeStampedModel): STATUS_CHOICES = ( ('not-started', _('Not Started')), ('active', _('Active')), ('complete', _('Complete')), ) LINK_TYPE_CHOICES = ( ('event', _('Event')), ('section', _('Section')), ('external', _('External URL')), ) LAYOUT_CHOICES = ( ('generic', _('Default (classic)')), ('shareabouts', _('Shareabouts Map')), ) title = models.TextField(blank=True) slug = models.CharField(max_length=128, blank=True) public = models.BooleanField(default=False, blank=True) status = models.CharField( help_text=_("A string representing the project's status"), choices=STATUS_CHOICES, default='not-started', max_length=32, blank=True) location = models.TextField(help_text=_( "The general location of the project, e.g. \"Philadelphia, PA\", \"Clifton Heights, Louisville, KY\", \"4th St. Corridor, Brooklyn, NY\", etc." ), default='', blank=True) contact = models.TextField( help_text=_("The contact information for the project"), default='', blank=True) owner = models.ForeignKey('Profile', related_name='projects') details = JSONField(blank=True, default=dict) theme = models.ForeignKey('Theme', related_name='projects', null=True, blank=True, on_delete=models.SET_NULL) layout = models.CharField(max_length=20, choices=LAYOUT_CHOICES, default='generic') cover_img_url = models.URLField(_('Cover Image URL'), blank=True, max_length=2048) logo_img_url = models.URLField(_('Logo Image URL'), blank=True, max_length=2048) template = models.ForeignKey( 'Project', help_text=_("The project, if any, that this one is based off of"), null=True, blank=True, on_delete=models.SET_NULL) geometry = models.GeometryField(null=True, blank=True) expires_at = models.DateTimeField(null=True, blank=True) payment_type = models.CharField(max_length=20, blank=True) customer = models.OneToOneField('moonclerk.Customer', blank=True, null=True, related_name='project') payments = GenericRelation('moonclerk.Payment', content_type_field='item_type', object_id_field='item_id') # NOTE: These may belong in a separate model, but are on the project for # now. I think the model would be called a Highlight. happening_now_description = models.TextField(blank=True) happening_now_link_type = models.CharField(max_length=16, choices=LINK_TYPE_CHOICES, blank=True) happening_now_link_url = models.CharField(max_length=2048, blank=True) get_involved_description = models.TextField(blank=True) get_involved_link_type = models.CharField(max_length=16, choices=LINK_TYPE_CHOICES, blank=True) get_involved_link_url = models.CharField(max_length=2048, blank=True) # Project activity last_opened_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, related_name='+') last_opened_at = models.DateTimeField(null=True, blank=True) last_saved_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, related_name='+') last_saved_at = models.DateTimeField(null=True, blank=True) objects = ProjectManager() class Meta: unique_together = [('owner', 'slug')] def __str__(self): return self.title def get_summary(self): for section in self.sections.all(): if section.type == 'text': return section.details.get('content', '') def mark_opened_by(self, user, opened_at=None): # TODO: This could just be done in the cache. self.last_opened_at = opened_at or now() self.last_opened_by = user if (user and user.is_authenticated()) else None self.save() def mark_closed(self): self.mark_opened_by(None) def is_opened_by(self, user): two_minutes = timedelta(minutes=2) return self.last_opened_by == user and ( now() - self.last_opened_at) < two_minutes def get_opened_by(self): two_minutes = timedelta(minutes=2) if self.last_opened_at and (now() - self.last_opened_at) < two_minutes: return self.last_opened_by else: return None def natural_key(self): return self.owner.natural_key() + (self.slug, ) def get_slug_basis(self): """ Get the string off that will be slugified to construct the slug. """ return self.title def get_all_slugs(self): """ Generate the set of all mututally unique slugs with respect to this model. """ return [p.slug for p in self.owner.projects.all()] def slug_exists(self, slug): return self.owner.projects.filter(slug__iexact=slug).exists() def clone(self, *args, **kwargs): new_inst = super(Project, self).clone(*args, **kwargs) for e in self.events.all(): e.clone(project=new_inst) for s in self.sections.all(): s.clone(project=new_inst) return new_inst def owned_by(self, obj): UserAuth = auth.get_user_model() if isinstance(obj, UserAuth): try: obj = obj.profile except Profile.DoesNotExist: return False return (self.owner == obj) def editable_by(self, obj): UserAuth = auth.get_user_model() if hasattr(obj, 'is_authenticated') and not obj.is_authenticated(): return False if isinstance(obj, UserAuth): try: obj = obj.profile except Profile.DoesNotExist: return False if obj.auth.is_superuser: return True return self.owned_by(obj) or (obj in self.owner.members.all()) def reset_trial_period(self): if hasattr(settings, 'TRIAL_DURATION'): duration = settings.TRIAL_DURATION if not isinstance(duration, timedelta): duration = timedelta(seconds=duration) self.expires_at = now() + duration def save(self, *args, **kwargs): if self.pk is None: # Creating... if self.expires_at is None: self.reset_trial_period() return super(Project, self).save(*args, **kwargs)
class Profile(ModelWithSlugMixin, TimeStampedModel): name = models.CharField(max_length=128, blank=True, help_text=_('The full name of the person or team')) slug = models.CharField( max_length=128, unique=True, blank=True, help_text= _('A short name that will be used in URLs for projects owned by this profile' )) email = models.EmailField( blank=True, help_text=_('Contact email address of the profile holder')) description = models.TextField(blank=True, default='') avatar_url = models.URLField(blank=True, null=True) # projects (reverse, Project) # User-profile specific auth = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='profile', null=True, blank=True, on_delete=models.CASCADE) affiliation = models.CharField(max_length=256, blank=True, default='') teams = models.ManyToManyField('Profile', related_name='members', blank=True, limit_choices_to={'auth__isnull': True}) # Team-profile specific # members (reverse, Profile) # Feature flags/versions class Versions: AMETHYST = 1 BISTRE = 2 PROJECT_EDITOR_VERSION_CHOICES = ( (Versions.AMETHYST, "Amethyst"), (Versions.BISTRE, "Bistre"), ) project_editor_version = models.PositiveIntegerField( choices=PROJECT_EDITOR_VERSION_CHOICES, default=Versions.BISTRE) objects = ProfileManager() def __str__(self): return self.slug if self.auth is None else self.auth.username def natural_key(self): return (self.slug, ) def get_slug_basis(self): return self.name def get_all_slugs(self): return set([p['slug'] for p in Profile.objects.all().values('slug')]) def slug_exists(self, slug): return Profile.objects.filter(slug__iexact=slug).exists() def is_user_profile(self): return self.auth is not None def is_owned_by(self, user): return (user.id == self.auth_id) def has_member(self, user): members = list(self.members.all()) if user.id in [profile.auth_id for profile in members]: return True else: return any(profile.has_member(user) for profile in members) def is_synced_with_auth(self, auth=None): auth = auth or self.auth if self.email != auth.email: return False return True def save(self, **kwargs): super(Profile, self).save(**kwargs) if self.auth and not self.is_synced_with_auth(): self.auth.username = self.slug self.auth.email = self.email self.auth.save() def authorizes(self, user): """ Test whether a given authenticated user is allowed to perform actions on behalf of this profile. """ if user.is_superuser: return True if self.is_owned_by(user): return True if self.has_member(user): return True return False
class UserProfile(models.Model): # https://docs.djangoproject.com/en/dev/topics/auth/#creating-users # This field is required. user = models.OneToOneField(User, related_name="profile") email_announcements = models.BooleanField(default=True) default_location = models.PointField(null=True, blank=True, help_text='Default center point') # default to private default_view_authority = models.ForeignKey( 'ObjectAuthority', default=1, verbose_name='Share Preference', help_text='Your default sharing settings for your maps and media') contacts = models.ManyToManyField( 'auth.User', related_name='%(app_label)s_%(class)s_related', blank=True, verbose_name="Users You're Following") date_created = models.DateTimeField(default=datetime.now) time_stamp = models.DateTimeField(default=datetime.now, db_column='last_updated') objects = models.GeoManager() class Meta: app_label = 'site' @classmethod def update_location(self, profile, point): profile.default_location = point profile.save() return True @classmethod def create(cls, user): # create a new profile: profile = UserProfile() profile.email_announcements = True profile.default_view_authority = ObjectAuthority.objects.get(id=1) profile.user = user profile.save() # create a default project: default_project = Project() default_project.slug = 'default-' + user.username default_project.name = 'My First Project' default_project.description = 'Default Local Ground project' default_project.last_updated_by = user default_project.access_authority = ObjectAuthority.objects.get(id=1) default_project.owner = user default_project.save() # create map: StyledMap.create(center=GEOSGeometry( '{"type": "Point", "coordinates": [-122, 38]}'), zoom=6, last_updated_by=default_project.owner, owner=default_project.owner, project=default_project, slug=uuid.uuid4().hex, name='Untitled Map') return profile def can_view(self, user=None, access_key=None): if user.is_authenticated(): return True def can_edit(self, user): if user.is_authenticated(): return True def can_manage(self, user): if user.is_authenticated(): return True
class StationBasin(Garea, GGRS87Mixin, BasinMixin): """A subbasin defined by a measuring station.""" river_basin = models.ForeignKey(RiverBasin, on_delete=models.CASCADE) station = models.OneToOneField(Station, on_delete=models.CASCADE)
class UserProfile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) phone = models.CharField(max_length=20, blank=True, null=True) def __str__(self): return f"{self.user}'s profile"
class CustomUser(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) role_num = models.ForeignKey(Role, on_delete=models.DO_NOTHING)
class SignupToken(models.Model): uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) referrer = models.CharField(max_length=255, blank=True, null=True) user = models.OneToOneField(User, on_delete=models.PROTECT, null=True)
class Profile(models.Model): user = models.OneToOneField(User, unique=True) country = CountryField(verbose_name=_("Country"), null=True, blank=True) affiliation = models.CharField(verbose_name=_("Affiliation"), max_length=250, null=True, blank=True) telephone = models.CharField(verbose_name=_("Telephone"), max_length=20, null=True, blank=True) address1 = models.CharField(verbose_name=_("Address1"), max_length=50, null=True, blank=True) address2 = models.CharField(verbose_name=_("Address2"), max_length=50, null=True, blank=True) city = models.CharField(verbose_name=_("City"), max_length=50, null=True, blank=True) state = models.CharField(verbose_name=_("State"), max_length=80, null=True, blank=True) postal = models.CharField(verbose_name=_("Postal code"), max_length=10, null=True, blank=True) url = models.CharField(verbose_name=_("URL"), max_length=100, null=True, blank=True) gisday = models.NullBooleanField(verbose_name=_("Attending GIS Day"), blank=True, null=True) def get_all_fields(self): """Returns a list of all field names on the instance.""" fields = [] for f in self._meta.fields: fname = f.name # resolve picklists/choices, with get_xyz_display() function get_choice = 'get_' + fname + '_display' if hasattr(self, get_choice): value = getattr(self, get_choice)() else: try: value = getattr(self, fname) except User.DoesNotExist: value = None # only display fields with values and skip some fields entirely if f.editable and value and f.name not in ('id', 'status', 'workshop', 'user', 'complete'): fields.append({ 'label': f.verbose_name, 'name': f.name, 'value': value, }) return fields def __unicode__(self): return self.user.username
class Avaliacao(models.Model): OPCOES = ( ('favoravel', 'Favorável'), ('aceitavel', 'Aceitável'), ('critica', 'Crítica'), ) ponto = models.OneToOneField('Ponto') acesso = models.CharField("Condição de Acesso", choices=OPCOES, max_length=10) acesso_desc = models.TextField("Justificativa Acesso") abrigo = models.CharField("Condição do Abrigo", choices=OPCOES, max_length=10) abrigo_desc = models.TextField("Justificativa Abrigo") piso = models.CharField("Condição do Piso", choices=OPCOES, max_length=10) piso_desc = models.TextField("Justificativa Piso") rampa = models.CharField("Condição das Rampas", choices=OPCOES, max_length=10) rampa_desc = models.TextField("Justificativa Rampas") calcada = models.CharField("Condição das Calçadas", choices=OPCOES, max_length=10) calcada_desc = models.TextField("Justificativa Calçada") plataforma = models.CharField("Condição das Plataformas", choices=OPCOES, max_length=10) plataforma_desc = models.TextField("Justificativa Plataformas") transito = models.CharField("Condição do Trânsito de Usuários", choices=OPCOES, max_length=10) transito_desc = models.TextField("Justificativa Trânsito") equipamento = models.CharField("Condição dos Equipamentos", choices=OPCOES, max_length=10) equipamento_desc = models.TextField("Justificativa Equipamentos") identificacao = models.CharField("Condição de Identificação", choices=OPCOES, max_length=10) identificacao_desc = models.TextField("Justificativa Identificação") piso_tatil = models.CharField("Condição do Piso Tátil", choices=OPCOES, max_length=10) piso_tatil_desc = models.TextField("Justificativa Piso Tátil") linhas = models.CharField("Condição de Identificação das Linhas de Ônibus", choices=OPCOES, max_length=10) linhas_desc = models.TextField("Justificativa Identificação das Linhas") logradouro = models.CharField("Condição de Identificação do Logradouro", choices=OPCOES, max_length=10) logradouro_desc = models.TextField("Justificativa Logradouro") objects = models.GeoManager() def final(self): resultado = [ self.acesso, self.abrigo, self.piso, self.rampa, self.calcada, self.plataforma, self.transito, self.equipamento, self.identificacao, self.piso_tatil, self.linhas, self.logradouro ] pontuacao = resultado.count('favoravel') * 2 \ + resultado.count('aceitavel') * 1 if pontuacao >= 14: return 'favoravel' elif pontuacao >= 7: return 'aceitavel' else: return 'critica' def __str__(self): return 'Avaliação do Ponto %s' % self.ponto class Meta: verbose_name = "Avaliação" verbose_name_plural = "Avaliações"
class TreeResource(ResourceSummaryModel): """ resource results for a specific tree. should get updated whenever a tree does. """ tree = models.OneToOneField(Tree, primary_key=True) def __unicode__(self): return '%s' % (self.tree)
class Trek(StructureRelated, PicturesMixin, PublishableMixin, MapEntityMixin, Topology): topo_object = models.OneToOneField(Topology, parent_link=True, db_column='evenement') departure = models.CharField(verbose_name=_(u"Departure"), max_length=128, blank=True, help_text=_(u"Departure description"), db_column='depart') arrival = models.CharField(verbose_name=_(u"Arrival"), max_length=128, blank=True, help_text=_(u"Arrival description"), db_column='arrivee') description_teaser = models.TextField( verbose_name=_(u"Description teaser"), blank=True, help_text=_(u"A brief summary (map pop-ups)"), db_column='chapeau') description = models.TextField(verbose_name=_(u"Description"), blank=True, db_column='description', help_text=_(u"Complete description")) ambiance = models.TextField(verbose_name=_(u"Ambiance"), blank=True, db_column='ambiance', help_text=_(u"Main attraction and interest")) access = models.TextField(verbose_name=_(u"Access"), blank=True, db_column='acces', help_text=_(u"Best way to go")) disabled_infrastructure = models.TextField( verbose_name=_(u"Disabled infrastructure"), db_column='handicap', blank=True, help_text=_(u"Any specific infrastructure")) duration = models.FloatField( verbose_name=_(u"Duration"), default=0, blank=True, db_column='duree', help_text=_(u"In decimal hours (ex. 1.5 for 1 h 30)"), validators=[MinValueValidator(0)]) is_park_centered = models.BooleanField( verbose_name=_(u"Is in the midst of the park"), db_column='coeur', help_text=_(u"Crosses center of park")) advised_parking = models.CharField(verbose_name=_(u"Advised parking"), max_length=128, blank=True, db_column='parking', help_text=_(u"Where to park")) parking_location = models.PointField(verbose_name=_(u"Parking location"), db_column='geom_parking', srid=settings.SRID, spatial_index=False, blank=True, null=True) public_transport = models.TextField( verbose_name=_(u"Public transport"), blank=True, db_column='transport', help_text=_(u"Train, bus (see web links)")) advice = models.TextField(verbose_name=_(u"Advice"), blank=True, db_column='recommandation', help_text=_(u"Risks, danger, best period, ...")) themes = models.ManyToManyField(Theme, related_name="treks", db_table="o_r_itineraire_theme", blank=True, null=True, verbose_name=_(u"Themes"), help_text=_(u"Main theme(s)")) networks = models.ManyToManyField('TrekNetwork', related_name="treks", db_table="o_r_itineraire_reseau", blank=True, null=True, verbose_name=_(u"Networks"), help_text=_(u"Hiking networks")) practice = models.ForeignKey('Practice', related_name="treks", blank=True, null=True, verbose_name=_(u"Practice"), db_column='pratique') accessibilities = models.ManyToManyField( 'Accessibility', related_name="treks", db_table="o_r_itineraire_accessibilite", blank=True, null=True, verbose_name=_(u"Accessibilities")) route = models.ForeignKey('Route', related_name='treks', blank=True, null=True, verbose_name=_(u"Route"), db_column='parcours') difficulty = models.ForeignKey('DifficultyLevel', related_name='treks', blank=True, null=True, verbose_name=_(u"Difficulty"), db_column='difficulte') web_links = models.ManyToManyField('WebLink', related_name="treks", db_table="o_r_itineraire_web", blank=True, null=True, verbose_name=_(u"Web links"), help_text=_(u"External resources")) related_treks = models.ManyToManyField( 'self', through='TrekRelationship', verbose_name=_(u"Related treks"), symmetrical=False, help_text=_(u"Connections between treks"), related_name='related_treks+') # Hide reverse attribute parent = models.ForeignKey('self', verbose_name=_(u"Parent"), db_column='parent', blank=True, null=True, related_name='children') information_desks = models.ManyToManyField( tourism_models.InformationDesk, related_name='treks', db_table="o_r_itineraire_renseignement", blank=True, null=True, verbose_name=_(u"Information desks"), help_text=_(u"Where to obtain information")) points_reference = models.MultiPointField( verbose_name=_(u"Points of reference"), db_column='geom_points_reference', srid=settings.SRID, spatial_index=False, blank=True, null=True) source = models.ManyToManyField('common.RecordSource', null=True, blank=True, related_name='treks', verbose_name=_("Source"), db_table='o_r_itineraire_source') eid = models.CharField(verbose_name=_(u"External id"), max_length=128, blank=True, db_column='id_externe') eid2 = models.CharField(verbose_name=_(u"Second external id"), max_length=128, blank=True, db_column='id_externe2') objects = Topology.get_manager_cls(models.GeoManager)() category_id_prefix = 'T' class Meta: db_table = 'o_t_itineraire' verbose_name = _(u"Trek") verbose_name_plural = _(u"Treks") ordering = ['name'] def __unicode__(self): return self.name @models.permalink def get_document_public_url(self): """ Override ``geotrek.common.mixins.PublishableMixin`` """ return ('trekking:trek_document_public', [], { 'lang': get_language(), 'pk': self.pk, 'slug': self.slug }) @property def related(self): return self.related_treks.exclude(deleted=True).exclude( pk=self.pk).distinct() @classproperty def related_verbose_name(cls): return _("Related treks") @property def relationships(self): # Does not matter if a or b return TrekRelationship.objects.filter(trek_a=self) @property def published_relationships(self): return self.relationships.filter(trek_b__published=True) @property def poi_types(self): if settings.TREKKING_TOPOLOGY_ENABLED: # Can't use values_list and must add 'ordering' because of bug: # https://code.djangoproject.com/ticket/14930 values = self.pois.values('ordering', 'type') else: values = self.pois.values('type') pks = [value['type'] for value in values] return POIType.objects.filter(pk__in=set(pks)) @property def length_kilometer(self): return "%.1f" % (self.length / 1000.0) @property def networks_display(self): return ', '.join([unicode(n) for n in self.networks.all()]) @property def districts_display(self): return ', '.join([unicode(d) for d in self.districts]) @property def themes_display(self): return ', '.join([unicode(n) for n in self.themes.all()]) @property def city_departure(self): cities = self.cities return unicode(cities[0]) if len(cities) > 0 else '' def kml(self): """ Exports trek into KML format, add geometry as linestring and POI as place marks """ kml = simplekml.Kml() # Main itinerary geom3d = self.geom_3d.transform(4326, clone=True) # KML uses WGS84 line = kml.newlinestring(name=self.name, description=plain_text(self.description), coords=geom3d.coords) line.style.linestyle.color = simplekml.Color.red # Red line.style.linestyle.width = 4 # pixels # Place marks for poi in self.pois: place = poi.geom_3d.transform(settings.API_SRID, clone=True) kml.newpoint(name=poi.name, description=plain_text(poi.description), coords=[place.coords]) return kml._genkml() def has_geom_valid(self): """A trek should be a LineString, even if it's a loop. """ return super(Trek, self).has_geom_valid( ) and self.geom.geom_type.lower() == 'linestring' @property def duration_pretty(self): return trekking_tags.duration(self.duration) @classproperty def duration_pretty_verbose_name(cls): return _("Formated duration") @classmethod def path_treks(cls, path): treks = cls.objects.existing().filter(aggregations__path=path) # The following part prevents conflict with default trek ordering # ProgrammingError: SELECT DISTINCT ON expressions must match initial ORDER BY expressions return treks.order_by('topo_object').distinct('topo_object') @classmethod def topology_treks(cls, topology): if settings.TREKKING_TOPOLOGY_ENABLED: qs = cls.overlapping(topology) else: area = topology.geom.buffer(settings.TREK_POI_INTERSECTION_MARGIN) qs = cls.objects.existing().filter(geom__intersects=area) return qs @classmethod def published_topology_treks(cls, topology): return cls.topology_treks(topology).filter(published=True) # Rando v1 compat @property def usages(self): return [self.practice] if self.practice else [] @classmethod def get_create_label(cls): return _(u"Add a new trek") @property def children_id(self): return list( self.children.order_by('name').values_list('id', flat=True)) @property def previous_id(self): if self.parent is None: return None children = self.parent.children_id try: return children[children.index(self.id) - 1] except IndexError: return None @property def next_id(self): if self.parent is None: return None children = self.parent.children_id try: return children[children.index(self.id) + 1] except IndexError: return None def clean(self): if self.parent and self.parent == self: raise ValidationError(_(u"Cannot use itself as parent trek.")) if self.parent and self.parent.parent: raise ValidationError( _(u"Cannot use a a child trek as parent trek.")) @property def prefixed_category_id(self): if settings.SPLIT_TREKS_CATEGORIES_BY_PRACTICE and self.practice: return '{prefix}{id}'.format(prefix=self.category_id_prefix, id=self.practice.id) else: return self.category_id_prefix def distance(self, to_cls): if self.practice and self.practice.distance is not None: return self.practice.distance else: return settings.TOURISM_INTERSECTION_MARGIN def is_public(self): return self.any_published or (self.parent and self.parent.any_published) def save(self, *args, **kwargs): if self.pk is not None and kwargs.get('update_fields', None) is None: field_names = set() for field in self._meta.concrete_fields: if not field.primary_key and not hasattr(field, 'through'): field_names.add(field.attname) old_trek = Trek.objects.get(pk=self.pk) if self.geom is not None and old_trek.geom.equals_exact( self.geom, tolerance=0.00001): field_names.remove('geom') if self.geom_3d is not None and old_trek.geom_3d.equals_exact( self.geom_3d, tolerance=0.00001): field_names.remove('geom_3d') return super(Trek, self).save(update_fields=field_names, *args, **kwargs) super(Trek, self).save(*args, **kwargs)
class AggregateZipCode(AggregateSummaryModel): location = models.OneToOneField(ZipCode, related_name='aggregates')
class POI(StructureRelated, PicturesMixin, PublishableMixin, MapEntityMixin, Topology): topo_object = models.OneToOneField(Topology, parent_link=True, db_column='evenement') description = models.TextField(verbose_name=_(u"Description"), db_column='description', help_text=_(u"History, details, ...")) type = models.ForeignKey('POIType', related_name='pois', verbose_name=_(u"Type"), db_column='type') eid = models.CharField(verbose_name=_(u"External id"), max_length=128, blank=True, db_column='id_externe') class Meta: db_table = 'o_t_poi' verbose_name = _(u"POI") verbose_name_plural = _(u"POI") # Override default manager objects = Topology.get_manager_cls(POIManager)() def __unicode__(self): return u"%s (%s)" % (self.name, self.type) @models.permalink def get_document_public_url(self): """ Override ``geotrek.common.mixins.PublishableMixin`` """ return ('trekking:poi_document_public', [], { 'lang': get_language(), 'pk': self.pk, 'slug': self.slug }) def save(self, *args, **kwargs): super(POI, self).save(*args, **kwargs) # Invalidate treks map for trek in self.treks.all(): try: os.remove(trek.get_map_image_path()) except OSError: pass @property def type_display(self): return unicode(self.type) @property def serializable_type(self): return { 'label': self.type.label, 'pictogram': self.type.get_pictogram_url() } @classmethod def path_pois(cls, path): return cls.objects.existing().filter( aggregations__path=path).distinct('pk') @classmethod def topology_pois(cls, topology): if settings.TREKKING_TOPOLOGY_ENABLED: qs = cls.overlapping(topology) else: area = topology.geom.buffer(settings.TREK_POI_INTERSECTION_MARGIN) qs = cls.objects.existing().filter(geom__intersects=area) return qs @classmethod def published_topology_pois(cls, topology): return cls.topology_pois(topology).filter(published=True) def distance(self, to_cls): return settings.TOURISM_INTERSECTION_MARGIN
class LonelyPerson(models.Model): only_friend = models.OneToOneField(Person, on_delete=models.CASCADE)
class Service(StructureRelated, MapEntityMixin, Topology): topo_object = models.OneToOneField(Topology, parent_link=True, db_column='evenement') type = models.ForeignKey('ServiceType', related_name='services', verbose_name=_(u"Type"), db_column='type') eid = models.CharField(verbose_name=_(u"External id"), max_length=128, blank=True, db_column='id_externe') class Meta: db_table = 'o_t_service' verbose_name = _(u"Service") verbose_name_plural = _(u"Services") # Override default manager objects = Topology.get_manager_cls(ServiceManager)() def __unicode__(self): return unicode(self.type) @property def name(self): return self.type.name @property def name_display(self): s = u'<a data-pk="%s" href="%s" title="%s">%s</a>' % ( self.pk, self.get_detail_url(), self.name, self.name) if self.type.published: s = u'<span class="badge badge-success" title="%s">☆</span> ' % _( "Published") + s elif self.type.review: s = u'<span class="badge badge-warning" title="%s">☆</span> ' % _( "Waiting for publication") + s return s @classproperty def name_verbose_name(cls): return _("Type") @property def type_display(self): return unicode(self.type) @property def serializable_type(self): return { 'label': self.type.label, 'pictogram': self.type.get_pictogram_url() } @classmethod def path_services(cls, path): return cls.objects.existing().filter( aggregations__path=path).distinct('pk') @classmethod def topology_services(cls, topology): if settings.TREKKING_TOPOLOGY_ENABLED: qs = cls.overlapping(topology) else: area = topology.geom.buffer(settings.TREK_POI_INTERSECTION_MARGIN) qs = cls.objects.existing().filter(geom__intersects=area) if isinstance(topology, Trek): qs = qs.filter(type__practices=topology.practice) return qs @classmethod def published_topology_services(cls, topology): return cls.topology_services(topology).filter(type__published=True) def distance(self, to_cls): return settings.TOURISM_INTERSECTION_MARGIN
class Coordinates(models.Model): hotel = models.OneToOneField(Hotels, on_delete=models.CASCADE) lat = models.DecimalField(max_digits=10, decimal_places=7) lon = models.DecimalField(max_digits=10, decimal_places=7)
class GWWell(models.Model): """ 7.6.38 GW_Well A shaft or hole sunk, dug or drilled into the Earth to observe, extract or inject water (after IGH1397).""" gw_well_name = models.TextField(null=False, blank=False, verbose_name="gwWellName", help_text="Name or ID of the well.") gw_well_location = models.PointField( null=False, blank=False, verbose_name="gwWellLocation", help_text="Surface location of the well.") gw_well_contribution_zone = models.GeometryField( null=True, blank=True, verbose_name="gwWellContributionZone", help_text="The area or volume surrounding a pumping well" "or other discharge site that encompasses all areas" "and features that supply groundwater to the well" "or discharge site.") gw_well_construction = models.ForeignKey( Borehole, null=True, blank=True, on_delete=models.SET_NULL, verbose_name="gwWellConstruction", help_text="Construction details for a well.") gw_well_total_length = models.FloatField( null=True, blank=True, verbose_name="gwWellTotalLength", help_text="Total length of the well from reference elevation.") gw_well_status = models.ForeignKey( WellStatusTypeTerm, null=True, blank=True, on_delete=models.SET_NULL, verbose_name="gwWellStatus", help_text="Status of the well, Can be new, unfinished, " "reconditioned, deepened, not in use, standby," "unknown, abandoned dry, abandoned" "insufficient, abandoned quality. (gwml1)") gw_well_static_water_depth = models.OneToOneField( Quantity, null=True, blank=True, on_delete=models.SET_NULL, verbose_name="gwWellStaticWaterDepth", help_text="Depth of the fluid body (e.g. piezometric level).", related_name='gw_well_static_water_depth') gw_well_licence = models.OneToOneField( GWLicence, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='gwWellLicence', help_text= 'Licence relating to the drilling of the well or to the extraction of groundwater.' ) gw_well_constructed_depth = models.OneToOneField( Quantity, null=True, blank=True, on_delete=models.SET_NULL, verbose_name="gwWellConstructedDepth", help_text="Constructed depth of the well.", related_name='gw_well_constructed_depth')
class UserProfile(models.Model): user = models.OneToOneField(User, unique=True, on_delete=models.CASCADE) age = models.IntegerField()
class LandUseAgreementCompensations(NameModel): """ In Finnish: Maankäyttökorvaus """ # In Finnish: Maankäyttösopimus land_use_agreement = models.OneToOneField( LandUseAgreement, related_name="compensations", verbose_name=_("Land use agreement"), null=True, on_delete=models.CASCADE, ) # In Finnish: Rahakorvaus cash_compensation = models.DecimalField( verbose_name=_("Cash compensation"), decimal_places=2, max_digits=12, blank=True, null=True, ) # In Finnish: Maakorvaus land_compensation = models.DecimalField( verbose_name=_("Land compensation"), decimal_places=2, max_digits=12, blank=True, null=True, ) # In Finnish: Muu korvaus other_compensation = models.DecimalField( verbose_name=_("Other compensation"), decimal_places=2, max_digits=12, blank=True, null=True, ) # In Finnish: Ensimmäisen maksuerän korotus first_installment_increase = models.DecimalField( verbose_name=_("First installment increase"), decimal_places=2, max_digits=12, blank=True, null=True, ) # In Finnish: Katualueen hankinta-arvo street_acquisition_value = models.DecimalField( verbose_name=_("Street acquisition value"), decimal_places=2, max_digits=12, blank=True, null=True, ) # In Finnish: Katualueen pinta-ala street_area = models.DecimalField( decimal_places=2, max_digits=12, blank=True, null=True ) # In Finnish: Puistoalueen hankinta-arvo park_acquisition_value = models.DecimalField( verbose_name=_("Park acquisition value"), decimal_places=2, max_digits=12, blank=True, null=True, ) # In Finnish: Puistoalueen pinta-ala park_area = models.DecimalField( decimal_places=2, max_digits=12, blank=True, null=True ) # In Finnish: Muun alueen hankinta-arvo other_acquisition_value = models.DecimalField( verbose_name=_("Other acquisition value"), decimal_places=2, max_digits=12, blank=True, null=True, ) # In Finnish: Muun alueen pinta-ala other_area = models.DecimalField( decimal_places=2, max_digits=12, blank=True, null=True )