models.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. from django.core.urlresolvers import reverse
  4. from django.db import models
  5. from django.utils import timezone
  6. from .fields import CommaSeparatedCharField
  7. from .utils import add_one_year, ANGLES, merge_intervals
  8. class Contrib(models.Model):
  9. CONTRIB_CONNECT = 'connect'
  10. CONTRIB_SHARE = 'share'
  11. id = models.AutoField(primary_key=True, blank=False, null=False)
  12. name = models.CharField(
  13. 'Nom / Pseudo',
  14. max_length=30)
  15. contrib_type = models.CharField(
  16. 'Type de contribution',
  17. max_length=10, choices=(
  18. (CONTRIB_CONNECT, 'Me raccorder à internet'),
  19. (CONTRIB_SHARE, 'Partager une partie de ma connexion')
  20. ), default=None)
  21. latitude = models.FloatField()
  22. longitude = models.FloatField()
  23. phone = models.CharField(
  24. 'Téléphone',
  25. max_length=30, blank=True, default='')
  26. email = models.EmailField(blank=True)
  27. access_type = models.CharField(
  28. 'Type de connexion',
  29. max_length=10, blank=True, choices=(
  30. ('vdsl', 'ADSL'),
  31. ('vdsl', 'VDSL'),
  32. ('fiber', 'Fibre optique'),
  33. ('cable', 'Coaxial (FTTLA)'),
  34. ))
  35. floor = models.PositiveIntegerField(
  36. 'étage',
  37. blank=True, null=True)
  38. floor_total = models.PositiveIntegerField(
  39. "mombre d'étages",
  40. blank=True, null=True)
  41. orientations = CommaSeparatedCharField(
  42. blank=True, null=True, max_length=100)
  43. roof = models.BooleanField(
  44. 'accès au toît',
  45. default=False)
  46. comment = models.TextField(
  47. 'commentaire',
  48. blank=True, null=True)
  49. privacy_name = models.BooleanField(
  50. 'nom/pseudo public',
  51. default=False)
  52. privacy_email = models.BooleanField(
  53. 'email public',
  54. default=False)
  55. privacy_coordinates = models.BooleanField(
  56. 'coordonnées GPS publiques',
  57. default=True)
  58. privacy_place_details = models.BooleanField(
  59. 'étage/orientations publiques',
  60. default=True)
  61. privacy_comment = models.BooleanField(
  62. 'commentaire public',
  63. default=False)
  64. date = models.DateTimeField(
  65. "date d'enregistrement",
  66. auto_now_add=True)
  67. expiration_date = models.DateTimeField(
  68. "date d'expiration",
  69. null=True, blank=True)
  70. STATUS_TOSTUDY = 'TOSTUDY'
  71. STATUS_TOCONNECT = 'TOCONNECT'
  72. STATUS_CONNECTED = 'CONNECTED'
  73. STATUS_WONTCONNECT = 'WONTCONNECT'
  74. CONNECTABILITY = (
  75. (STATUS_TOSTUDY, 'à étudier'),
  76. (STATUS_TOCONNECT, 'à connecter'),
  77. (STATUS_CONNECTED, 'connecté'),
  78. (STATUS_WONTCONNECT, 'pas connectable'),
  79. )
  80. status = models.CharField(
  81. blank=True,
  82. null=True,
  83. max_length=250,
  84. choices=CONNECTABILITY,
  85. default=STATUS_TOSTUDY)
  86. class Meta:
  87. managed = True
  88. db_table = 'contribs'
  89. verbose_name = 'contribution'
  90. PRIVACY_MAP = {
  91. 'name': 'privacy_name',
  92. 'comment': 'privacy_comment',
  93. 'floor': 'privacy_place_details',
  94. 'floor_total': 'privacy_place_details',
  95. 'orientations': 'privacy_place_details',
  96. 'roof': 'privacy_place_details',
  97. 'angles': 'privacy_place_details',
  98. }
  99. PUBLIC_FIELDS = set(PRIVACY_MAP.keys())
  100. def __str__(self):
  101. return '#{} {}'.format(self.pk, self.name)
  102. @property
  103. def angles(self):
  104. """Return a list of (start, stop) angles from cardinal orientations
  105. """
  106. # Cleanup
  107. if self.orientations is None:
  108. return []
  109. orientations = [o for o in self.orientations if o in ANGLES.keys()]
  110. # Hack to make leaflet-semicircle happy (drawing a full circle only
  111. # works with (0, 360))
  112. if len(orientations) == 8:
  113. return [[0, 360]]
  114. angles = [ANGLES[orientation] for orientation in orientations]
  115. angles.sort(key=lambda i: i[0]) # sort by x
  116. return merge_intervals(angles)
  117. def get_postponed_expiration_date(self, from_date):
  118. """ Computes the new expiration date
  119. :param from_date: reference datetime frow where we add our extra delay.
  120. """
  121. return add_one_year(from_date)
  122. def clean(self):
  123. # usefull only for data imported from bottle version
  124. if not self.date:
  125. self.date = timezone.now()
  126. if not self.expiration_date:
  127. self.expiration_date = self.get_postponed_expiration_date(
  128. self.date)
  129. def save(self, *args, **kwargs):
  130. if not self.pk: # New instance
  131. self.date = timezone.now()
  132. self.expiration_date = self.get_postponed_expiration_date(
  133. self.date)
  134. super().save(*args, **kwargs)
  135. def is_public(self):
  136. return self.privacy_coordinates
  137. def _may_be_public(self, field):
  138. return field in self.PUBLIC_FIELDS
  139. def _is_public(self, field):
  140. return getattr(self, self.PRIVACY_MAP[field])
  141. def get_public_field(self, field):
  142. """ Gets safely an attribute in its public form (if any)
  143. :param field: The field name
  144. :return: the field value, or None, if the field is private
  145. """
  146. if self._may_be_public(field) and self._is_public(field):
  147. v = getattr(self, field)
  148. if hasattr(v, '__call__'):
  149. return v()
  150. else:
  151. return v
  152. else:
  153. return None
  154. def get_absolute_url(self, request=None):
  155. """ Get absolute url
  156. :type param: request
  157. :param: if mentioned, will be used to provide a full URL (starting with
  158. "http://" or "https://")
  159. """
  160. url = '{}#{}'.format(
  161. reverse('display_map'), self.pk)
  162. if request:
  163. return request.build_absolute_uri(url)
  164. else:
  165. return url