models.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. from django.db import models
  4. from .fields import CommaSeparatedCharField
  5. from .utils import ANGLES, merge_intervals
  6. class Contrib(models.Model):
  7. CONTRIB_CONNECT = 'connect'
  8. CONTRIB_SHARE = 'share'
  9. id = models.AutoField(primary_key=True, blank=False, null=False)
  10. name = models.CharField(
  11. 'Nom / Pseudo',
  12. max_length=30)
  13. contrib_type = models.CharField(
  14. 'Type de contribution',
  15. max_length=10, choices=(
  16. (CONTRIB_CONNECT, 'Me raccorder au réseau expérimental'),
  17. (CONTRIB_SHARE, 'Partager une partie de ma connexion')
  18. ))
  19. latitude = models.FloatField(blank=True, null=True)
  20. longitude = models.FloatField(blank=True, null=True)
  21. phone = models.CharField(
  22. 'Téléphone',
  23. max_length=30, blank=True, default='')
  24. email = models.EmailField(blank=True)
  25. access_type = models.CharField(
  26. 'Type de connexion',
  27. max_length=10, blank=True, choices=(
  28. ('vdsl', 'ADSL'),
  29. ('vdsl', 'VDSL'),
  30. ('fiber', 'Fibre optique'),
  31. ('cable', 'Coaxial (FTTLA)'),
  32. ))
  33. connect_local = models.NullBooleanField(
  34. 'Accès internet',
  35. default=False, null=True)
  36. connect_internet = models.NullBooleanField(
  37. 'Services locaux',
  38. default=False, null=True)
  39. bandwidth = models.FloatField(
  40. 'débit total',
  41. blank=True, null=True)
  42. share_part = models.FloatField(
  43. 'débit partagé',
  44. blank=True, null=True)
  45. floor = models.PositiveIntegerField(
  46. 'étage',
  47. blank=True, null=True)
  48. floor_total = models.PositiveIntegerField(
  49. "mombre d'étages",
  50. blank=True, null=True)
  51. orientations = CommaSeparatedCharField(
  52. blank=True, null=True, max_length=100)
  53. roof = models.BooleanField(
  54. 'accès au toît',
  55. default=False)
  56. comment = models.TextField(
  57. 'commentaire',
  58. blank=True, null=True)
  59. privacy_name = models.BooleanField(
  60. 'nom/pseudo public',
  61. default=False)
  62. privacy_email = models.BooleanField(
  63. 'email public',
  64. default=False)
  65. privacy_coordinates = models.BooleanField(
  66. 'coordonnées GPS publiques',
  67. default=True)
  68. privacy_place_details = models.BooleanField(
  69. 'étage/orientations publiques',
  70. default=True)
  71. privacy_comment = models.BooleanField(
  72. 'commentaire public',
  73. default=False)
  74. date = models.DateTimeField(auto_now_add=True)
  75. STATUS_TOSTUDY = 'TOSTUDY'
  76. STATUS_TOCONNECT = 'TOCONNECT'
  77. STATUS_CONNECTED = 'CONNECTED'
  78. STATUS_WONTCONNECT = 'WONTCONNECT'
  79. CONNECTABILITY = (
  80. (STATUS_TOSTUDY, 'à étudier'),
  81. (STATUS_TOCONNECT, 'à connecter'),
  82. (STATUS_CONNECTED, 'connecté'),
  83. (STATUS_WONTCONNECT, 'pas connectable'),
  84. )
  85. status = models.CharField(
  86. blank=True,
  87. null=True,
  88. max_length=250,
  89. choices=CONNECTABILITY,
  90. default=STATUS_TOSTUDY)
  91. class Meta:
  92. managed = True
  93. db_table = 'contribs'
  94. verbose_name = 'contribution'
  95. PRIVACY_MAP = {
  96. 'name': 'privacy_name',
  97. 'comment': 'privacy_comment',
  98. 'floor': 'privacy_place_details',
  99. 'floor_total': 'privacy_place_details',
  100. 'orientations': 'privacy_place_details',
  101. 'roof': 'privacy_place_details',
  102. 'angles': 'privacy_place_details',
  103. }
  104. PUBLIC_FIELDS = set(PRIVACY_MAP.keys())
  105. def __str__(self):
  106. return '#{} {}'.format(self.pk, self.name)
  107. def angles(self):
  108. """Return a list of (start, stop) angles from cardinal orientations
  109. """
  110. # Cleanup
  111. if self.orientations is None:
  112. return []
  113. orientations = [o for o in self.orientations if o in ANGLES.keys()]
  114. # Hack to make leaflet-semicircle happy (drawing a full circle only
  115. # works with (0, 360))
  116. if len(orientations) == 8:
  117. return [[0, 360]]
  118. angles = [ANGLES[orientation] for orientation in self.orientations]
  119. angles.sort(key=lambda i: i[0]) # sort by x
  120. return merge_intervals(angles)
  121. def is_public(self):
  122. return not self.privacy_coordinates
  123. def _may_be_public(self, field):
  124. return field in self.PUBLIC_FIELDS
  125. def _is_public(self, field):
  126. return getattr(self, self.PRIVACY_MAP[field])
  127. def get_public_field(self, field):
  128. """ Gets safely an attribute in its public form (if any)
  129. :param field: The field name
  130. :return: the field value, or None, if the field is private
  131. """
  132. if self._may_be_public(field) and self._is_public(field):
  133. v = getattr(self, field)
  134. if hasattr(v, '__call__'):
  135. return v()
  136. else:
  137. return v
  138. else:
  139. return None