class Role(models.Model): name = models.CharField(max_length=200, null=False, blank=False, verbose_name=_("name")) slug = models.SlugField(max_length=250, null=False, blank=True, verbose_name=_("slug")) permissions = TextArrayField(blank=True, null=True, default=[], verbose_name=_("permissions"), choices=MEMBERS_PERMISSIONS) order = models.IntegerField(default=10, null=False, blank=False, verbose_name=_("order")) # null=True is for make work django 1.7 migrations. project # field causes some circular dependencies, and due to this # it can not be serialized in one transactional migration. project = models.ForeignKey("projects.Project", null=True, blank=False, related_name="roles", verbose_name=_("project")) computable = models.BooleanField(default=True) def save(self, *args, **kwargs): if not self.slug: self.slug = slugify_uniquely(self.name, self.__class__) super().save(*args, **kwargs) class Meta: verbose_name = "role" verbose_name_plural = "roles" ordering = ["order", "slug"] unique_together = (("slug", "project"),) permissions = ( ("view_role", "Can view role"), ) def __str__(self): return self.name
class RuleConfiguration(JSONSerializable, TimestampedMixin, models.Model): """ Represents a team's preferences for a rule. """ rule = models.ForeignKey(Rule, related_name='configurations') team = models.ForeignKey(Team, related_name='configurations') enabled = models.BooleanField(u'Enabled for Team', default=True) # Groups to exclude from this rule exclude = TextArrayField() # JSON blob for storing preferences related to this rule configuration = JSONField(default={}, blank=True, null=True) class Meta: unique_together = ('rule', 'team') get_latest_by = 'created' @property def base_config(self): return self.rule.configuration @property def default_config(self): return Configuration(self.base_config) @property def config(self): return Configuration(self.base_config, self.configuration)
class Task(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin, models.Model): user_story = models.ForeignKey("userstories.UserStory", null=True, blank=True, related_name="tasks", verbose_name=_("user story")) ref = models.BigIntegerField(db_index=True, null=True, blank=True, default=None, verbose_name=_("ref")) owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, default=None, related_name="owned_tasks", verbose_name=_("owner")) status = models.ForeignKey("projects.TaskStatus", null=True, blank=True, related_name="tasks", verbose_name=_("status")) project = models.ForeignKey("projects.Project", null=False, blank=False, related_name="tasks", verbose_name=_("project")) milestone = models.ForeignKey("milestones.Milestone", null=True, blank=True, on_delete=models.SET_NULL, default=None, related_name="tasks", verbose_name=_("milestone")) created_date = models.DateTimeField(null=False, blank=False, verbose_name=_("created date"), default=timezone.now) modified_date = models.DateTimeField(null=False, blank=False, verbose_name=_("modified date")) finished_date = models.DateTimeField(null=True, blank=True, verbose_name=_("finished date")) subject = models.TextField(null=False, blank=False, verbose_name=_("subject")) us_order = models.IntegerField(null=False, blank=False, default=1, verbose_name=_("us order")) taskboard_order = models.IntegerField(null=False, blank=False, default=1, verbose_name=_("taskboard order")) description = models.TextField(null=False, blank=True, verbose_name=_("description")) assigned_to = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, default=None, related_name="tasks_assigned_to_me", verbose_name=_("assigned to")) attachments = generic.GenericRelation("attachments.Attachment") is_iocaine = models.BooleanField(default=False, null=False, blank=True, verbose_name=_("is iocaine")) external_reference = TextArrayField(default=None, verbose_name=_("external reference")) _importing = None class Meta: verbose_name = "task" verbose_name_plural = "tasks" ordering = ["project", "created_date", "ref"] # unique_together = ("ref", "project") permissions = ( ("view_task", "Can view task"), ) def save(self, *args, **kwargs): if not self._importing or not self.modified_date: self.modified_date = timezone.now() if not self.status: self.status = self.project.default_task_status return super().save(*args, **kwargs) def __str__(self): return "({1}) {0}".format(self.ref, self.subject)
class Audit(models.Model): """An audit on agency, made up of auditables""" GENERIC_AUDIT = u'ADT' DATA_CATALOG_VALIDATION = u'DCV' DATA_CATALOG_CRAWL = u'DCC' AUDIT_TYPE_CHOICES = ( (GENERIC_AUDIT, u'Generic Audit'), (DATA_CATALOG_VALIDATION, u'Data Catalog Validation'), (DATA_CATALOG_CRAWL, u'Data Catalog Crawl'), ) audit_type = models.CharField(max_length=3, choices=AUDIT_TYPE_CHOICES, default=GENERIC_AUDIT) agency = models.ForeignKey('Agency') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) notes = models.TextField( blank=True, help_text='You can record basic (unformatted text) notes here.') messages = TextArrayField( blank=True, null=True, default=list_default, editable=False, help_text='Stores messages generated when audit was run.') def __repr__(self): return u'<Audit({audit_type}): {identifier}>'.format( identifier=self.id, audit_type=self.get_audit_type_display()) def __str__(self): return u'{audit_type} for {identifier}'.format( audit_type=self.get_audit_type_display(), identifier=self.agency) class Meta: get_latest_by = 'created_at' ordering = ('-created_at', ) def get_absolute_url(self): return reverse('audit-detail', kwargs={'pk': str(self.pk)}) # @property # def url_inspections(self): # return URLInspection.objects.filter(probe__in=self.probe_set.all()) def error_list(self): error_list = [] for probe in self.probe_set.filter(errors__len__gt=0).only('errors'): error_list.extend(probe.errors) return error_list def error_count(self): return len(self.error_list())
class Probe(models.Model): """A component of an Audit that takes some initial data and stores a result of some tasks performed on that data """ GENERIC_PROBE = 0 URL_PROBE = 1 JSON_PROBE = 2 VALIDATION_PROBE = 3 PROBE_TYPE_CHOICES = ( (GENERIC_PROBE, 'Generic Probe'), (URL_PROBE, 'URL Probe'), (JSON_PROBE, 'JSON Probe'), (VALIDATION_PROBE, 'Validation Probe'), ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) probe_type = models.PositiveSmallIntegerField(choices=PROBE_TYPE_CHOICES, default=GENERIC_PROBE) previous = models.ForeignKey('self', related_name='next', blank=True, null=True, on_delete=models.SET_NULL) initial = hstore.DictionaryField(blank=True, null=True, default=dictionary_default) result = hstore.DictionaryField(blank=True, null=True, default=dictionary_default) errors = TextArrayField(blank=True, null=True, default=list_default) audit = models.ForeignKey('Audit', null=True, blank=True) objects = ProbeQuerySet.as_manager() def __repr__(self): return '<{0}: {1}>'.format(self.get_probe_type_display(), self.id) def __str__(self): return self.__repr__() class Meta: get_latest_by = 'created_at' ordering = ('-created_at', ) def error_count(self): return len(self.errors) def get_absolute_url(self): return reverse('probe-detail', kwargs={'pk': str(self.pk)})
class ScreenshotBundle(APIModel): ENCRYPTED_ID_KEY_TOKEN = 'screenshot-bundle' user = models.ForeignKey(User, related_name='+', on_delete=models.DO_NOTHING) screenshot_set = models.ForeignKey(ScreenshotSet, related_name='+', on_delete=models.DO_NOTHING) create_time = models.DateTimeField(auto_now_add=True) access_count = models.IntegerField(default=0) last_accessed_time = models.DateTimeField(null=True) import_time = models.DateTimeField(null=True, db_index=True) hq = models.NullBooleanField(null=True) upload_ids = TextArrayField() upload_names = TextArrayField() url = models.URLField(max_length=256, null=True) size_bytes = models.BigIntegerField(default=0) files_count = models.IntegerField(default=0) @property def file_basename(self): safe_version = re.sub(r'[^A-Za-z0-9._-]', '', self.screenshot_set.version) or 'unknown' return '%s_%s_%s' % (slugify(self.screenshot_set.name) or 'Screenshots', safe_version, self.screenshot_set.platform)
class State(models.Model): is_invalid = models.BooleanField(default=False) is_processed = models.BooleanField(default=False) raw_data = models.TextField(null=True, blank=True) comments = models.TextField(null=True, blank=True) school_id = models.IntegerField(null=True, blank=True) telephone = models.CharField(max_length=50, blank=True) date_of_visit = models.DateTimeField(default=timezone.now) session_id = models.CharField(max_length=100, unique=True) user = models.ForeignKey('users.User', blank=True, null=True) qg_type = models.ForeignKey('QuestionGroupType', blank=True, null=True) answers = TextArrayField(dimension=1, null=True, blank=True, default={}) def __unicode__(self): return str(self.date_of_visit) + " - " + str( self.qg_type.questiongroup.source.name)
class AppStoreApp(APIModel): ENCRYPTED_ID_KEY_TOKEN = 'appstoreapp' create_time = models.DateTimeField(auto_now_add=True) update_time = models.DateTimeField(auto_now=True) itunes_id = models.CharField(max_length=128, unique=True) bundle_id = models.CharField(max_length=128, unique=True) app_info_ingestion_time = models.DateTimeField(null=True) app_info_countries = TextArrayField(null=True) decorated_country = None decorated_info = None def __getattr__(self, attr): return getattr(self.decorated_info, attr) @property def itunes_url(self): return 'https://itunes.apple.com/us/app/id%s' % self.itunes_id @property def public_small_icon(self): return self.icon_60 @property def public_medium_icon(self): return self.icon_512 def to_dict(self): return { 'id': self.encrypted_id, 'country': self.country, 'version': self.version, 'names': { 'short': self.short_name, 'full': self.name, }, 'icon': { 'small': self.public_small_icon, 'medium': self.public_medium_icon, }, 'iTunesId': self.itunes_id, 'bundleId': self.bundle_id, 'developer': self.developer_name, }
class Item2(models.Model): tags = TextArrayField(default=[])
class Item(models.Model): tags = TextArrayField(default=lambda: [])
class UserStory(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin, models.Model): ref = models.BigIntegerField(db_index=True, null=True, blank=True, default=None, verbose_name=_("ref")) milestone = models.ForeignKey("milestones.Milestone", null=True, blank=True, default=None, related_name="user_stories", on_delete=models.SET_NULL, verbose_name=_("milestone")) project = models.ForeignKey("projects.Project", null=False, blank=False, related_name="user_stories", verbose_name=_("project")) owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, related_name="owned_user_stories", verbose_name=_("owner"), on_delete=models.SET_NULL) status = models.ForeignKey("projects.UserStoryStatus", null=True, blank=True, related_name="user_stories", verbose_name=_("status"), on_delete=models.SET_NULL) is_closed = models.BooleanField(default=False) points = models.ManyToManyField("projects.Points", null=False, blank=False, related_name="userstories", through="RolePoints", verbose_name=_("points")) backlog_order = models.IntegerField(null=False, blank=False, default=10000, verbose_name=_("backlog order")) sprint_order = models.IntegerField(null=False, blank=False, default=10000, verbose_name=_("sprint order")) kanban_order = models.IntegerField(null=False, blank=False, default=10000, verbose_name=_("sprint order")) created_date = models.DateTimeField(null=False, blank=False, verbose_name=_("created date"), default=timezone.now) modified_date = models.DateTimeField(null=False, blank=False, verbose_name=_("modified date")) finish_date = models.DateTimeField(null=True, blank=True, verbose_name=_("finish date")) subject = models.TextField(null=False, blank=False, verbose_name=_("subject")) description = models.TextField(null=False, blank=True, verbose_name=_("description")) assigned_to = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, default=None, related_name="userstories_assigned_to_me", verbose_name=_("assigned to")) client_requirement = models.BooleanField( default=False, null=False, blank=True, verbose_name=_("is client requirement")) team_requirement = models.BooleanField( default=False, null=False, blank=True, verbose_name=_("is team requirement")) attachments = generic.GenericRelation("attachments.Attachment") generated_from_issue = models.ForeignKey( "issues.Issue", null=True, blank=True, on_delete=models.SET_NULL, related_name="generated_user_stories", verbose_name=_("generated from issue")) external_reference = TextArrayField(default=None, verbose_name=_("external reference")) _importing = None class Meta: verbose_name = "user story" verbose_name_plural = "user stories" ordering = ["project", "backlog_order", "ref"] def save(self, *args, **kwargs): if not self._importing or not self.modified_date: self.modified_date = timezone.now() if not self.status: self.status = self.project.default_us_status super().save(*args, **kwargs) def __str__(self): return "({1}) {0}".format(self.ref, self.subject) def __repr__(self): return "<UserStory %s>" % (self.id) def get_role_points(self): return self.role_points def get_total_points(self): not_null_role_points = [ rp for rp in self.role_points.all() if rp.points.value is not None ] #If we only have None values the sum should be None if not not_null_role_points: return None total = 0.0 for rp in not_null_role_points: total += rp.points.value return total
class Project(ProjectDefaults, TaggedMixin, models.Model): name = models.CharField(max_length=250, null=False, blank=False, verbose_name=_("name")) slug = models.SlugField(max_length=250, unique=True, null=False, blank=True, verbose_name=_("slug")) description = models.TextField(null=False, blank=False, verbose_name=_("description")) created_date = models.DateTimeField(null=False, blank=False, verbose_name=_("created date"), default=timezone.now) modified_date = models.DateTimeField(null=False, blank=False, verbose_name=_("modified date")) owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=False, blank=False, related_name="owned_projects", verbose_name=_("owner")) members = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="projects", through="Membership", verbose_name=_("members"), through_fields=("project", "user")) total_milestones = models.IntegerField( default=0, null=False, blank=False, verbose_name=_("total of milestones")) total_story_points = models.FloatField( default=0, verbose_name=_("total story points")) is_backlog_activated = models.BooleanField( default=True, null=False, blank=True, verbose_name=_("active backlog panel")) is_kanban_activated = models.BooleanField( default=False, null=False, blank=True, verbose_name=_("active kanban panel")) is_wiki_activated = models.BooleanField( default=True, null=False, blank=True, verbose_name=_("active wiki panel")) is_issues_activated = models.BooleanField( default=True, null=False, blank=True, verbose_name=_("active issues panel")) videoconferences = models.CharField( max_length=250, null=True, blank=True, choices=choices.VIDEOCONFERENCES_CHOICES, verbose_name=_("videoconference system")) videoconferences_salt = models.CharField( max_length=250, null=True, blank=True, verbose_name=_("videoconference room salt")) creation_template = models.ForeignKey("projects.ProjectTemplate", related_name="projects", null=True, blank=True, default=None, verbose_name=_("creation template")) anon_permissions = TextArrayField(blank=True, null=True, default=[], verbose_name=_("anonymous permissions"), choices=ANON_PERMISSIONS) public_permissions = TextArrayField(blank=True, null=True, default=[], verbose_name=_("user permissions"), choices=MEMBERS_PERMISSIONS) is_private = models.BooleanField(default=True, null=False, blank=True, verbose_name=_("is private")) userstories_csv_uuid = models.CharField(max_length=32, editable=False, null=True, blank=True, default=None, db_index=True) tasks_csv_uuid = models.CharField(max_length=32, editable=False, null=True, blank=True, default=None, db_index=True) issues_csv_uuid = models.CharField(max_length=32, editable=False, null=True, blank=True, default=None, db_index=True) tags_colors = TextArrayField(dimension=2, null=False, blank=True, verbose_name=_("tags colors"), default=[]) _importing = None class Meta: verbose_name = "project" verbose_name_plural = "projects" ordering = ["name"] permissions = (("view_project", "Can view project"), ) def __str__(self): return self.name def __repr__(self): return "<Project {0}>".format(self.id) def save(self, *args, **kwargs): if not self._importing or not self.modified_date: self.modified_date = timezone.now() if not self.slug: base_name = "{}-{}".format(self.owner.username, self.name) base_slug = slugify_uniquely(base_name, self.__class__) slug = base_slug for i in arithmetic_progression(): if not type(self).objects.filter( slug=slug).exists() or i > 100: break slug = "{}-{}".format(base_slug, i) self.slug = slug if not self.videoconferences: self.videoconferences_salt = None super().save(*args, **kwargs) def get_roles(self): return self.roles.all() def get_users(self): user_model = get_user_model() members = self.memberships.values_list("user", flat=True) return user_model.objects.filter(id__in=list(members)) def update_role_points(self, user_stories=None): RolePoints = apps.get_model("userstories", "RolePoints") Role = apps.get_model("users", "Role") # Get all available roles on this project roles = self.get_roles().filter(computable=True) if roles.count() == 0: return # Iter over all project user stories and create # role point instance for new created roles. if user_stories is None: user_stories = self.user_stories.all() # Get point instance that represent a null/undefined # The current model allows duplicate values. Because # of it, we should get all poins with None as value # and use the first one. # In case of that not exists, creates one for avoid # unexpected errors. none_points = list(self.points.filter(value=None)) if none_points: null_points_value = none_points[0] else: name = slugify_uniquely_for_queryset("?", self.points.all(), slugfield="name") null_points_value = Points.objects.create(name=name, value=None, project=self) for us in user_stories: usroles = Role.objects.filter( role_points__in=us.role_points.all()).distinct() new_roles = roles.exclude(id__in=usroles) new_rolepoints = [ RolePoints(role=role, user_story=us, points=null_points_value) for role in new_roles ] RolePoints.objects.bulk_create(new_rolepoints) # Now remove rolepoints associated with not existing roles. rp_query = RolePoints.objects.filter( user_story__in=self.user_stories.all()) rp_query = rp_query.exclude( role__id__in=roles.values_list("id", flat=True)) rp_query.delete() def _get_user_stories_points(self, user_stories): role_points = [us.role_points.all() for us in user_stories] flat_role_points = itertools.chain(*role_points) flat_role_dicts = map( lambda x: {x.role_id: x.points.value if x.points.value else 0}, flat_role_points) return dict_sum(*flat_role_dicts) def _get_points_increment(self, client_requirement, team_requirement): last_milestones = self.milestones.order_by('-estimated_finish') last_milestone = last_milestones[0] if last_milestones else None if last_milestone: user_stories = self.user_stories.filter( created_date__gte=last_milestone.estimated_finish, client_requirement=client_requirement, team_requirement=team_requirement) else: user_stories = self.user_stories.filter( client_requirement=client_requirement, team_requirement=team_requirement) user_stories = user_stories.prefetch_related('role_points', 'role_points__points') return self._get_user_stories_points(user_stories) @property def project(self): return self @property def project(self): return self @property def future_team_increment(self): team_increment = self._get_points_increment(False, True) shared_increment = { key: value / 2 for key, value in self.future_shared_increment.items() } return dict_sum(team_increment, shared_increment) @property def future_client_increment(self): client_increment = self._get_points_increment(True, False) shared_increment = { key: value / 2 for key, value in self.future_shared_increment.items() } return dict_sum(client_increment, shared_increment) @property def future_shared_increment(self): return self._get_points_increment(True, True) @property def closed_points(self): return self.calculated_points["closed"] @property def defined_points(self): return self.calculated_points["defined"] @property def assigned_points(self): return self.calculated_points["assigned"] @property def calculated_points(self): user_stories = self.user_stories.all().prefetch_related( 'role_points', 'role_points__points') closed_user_stories = user_stories.filter(is_closed=True) assigned_user_stories = user_stories.filter(milestone__isnull=False) return { "defined": self._get_user_stories_points(user_stories), "closed": self._get_user_stories_points(closed_user_stories), "assigned": self._get_user_stories_points(assigned_user_stories), }
class Item(models.Model): tags = TextArrayField(default=defaultval)
class ChoicesModel(models.Model): choices = TextArrayField(choices=[("A", "A"), ("B", "B")])
class Sensor(JSONSerializable, TimestampedMixin, models.Model): uuid = UUIDField(u'UUID', primary_key=True) name = models.CharField(u'Name', max_length=250, null=True, blank=True) team = models.ForeignKey(Team, related_name='sensors') groups = TextArrayField(null=True, blank=True) active = models.BooleanField(u'Active', default=True, blank=False, null=False) cloud_key = models.CharField(u'Cloud Key', max_length=250, null=True, blank=True) class Meta: ordering = ('-created', ) get_latest_by = 'created' def __unicode__(self): return self.name or self.uuid @classmethod def create_from_payload(self, payload): """ Creates a new Sensor object from a JSON payload (reads off kafka queue for `sensor_new` events) """ try: team = Team.objects.get(identifier=payload.get('team')) except Team.DoesNotExist: return None # Find or create the sensor sensor, created = Sensor.objects.get_or_create(uuid=payload['sensor'], team=team) return sensor @property def _snapshot(self): return cache.get('%s_snapshot' % self.uuid) @property def snapshot(self): if self._snapshot: return self._snapshot snapshot = SnapshotAPI(self.team.identifier).sensor_state(self.uuid) # Prevent rapid fire of snapshot updates cache.set('%s_snapshot' % self.uuid, snapshot, 5) return snapshot @property def group(self): if self.groups: return self.groups[0] else: return None @group.setter def group(self, group): self.groups = [group] def set_properties_from_snapshot(self): self.cloud_key = self.get_cloud_key() self.name = self.get_hostname() def get_name(self): if not self.name: sync_sensor_hostname.apply_async(args=(self, )) return self.name def get_key(self): if not self.cloud_key: sync_sensor_cloud_key.apply_async(args=(self, )) return self.cloud_key @property def cloud_metadata(self): return self.snapshot.get('cloud_metadata') def get_hostname(self): # Hierarchy for sensor naming # AWS (Name) Tag -> Collector Hostname -> Sensor UUID name = None name = self.cloud_metadata.get('tags', {}).get('Name') if not name: name = self.snapshot.get('hostname', {}).get('hostname') return name def get_cloud_key(self): metadata = self.cloud_metadata if not metadata: return None return "%s.%s.%s" % ( metadata.get('provider') or metadata['type'], # Handle deprecated messages metadata['availability_zone'], metadata['instance_id'], )
class Project(ProjectDefaults, TaggedMixin, models.Model): name = models.CharField(max_length=250, null=False, blank=False, verbose_name=_("name")) slug = models.SlugField(max_length=250, unique=True, null=False, blank=True, verbose_name=_("slug")) description = models.TextField(null=False, blank=False, verbose_name=_("description")) created_date = models.DateTimeField(null=False, blank=False, verbose_name=_("created date"), default=timezone.now) modified_date = models.DateTimeField(null=False, blank=False, verbose_name=_("modified date")) owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=False, blank=False, related_name="owned_projects", verbose_name=_("owner")) members = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="projects", through="Membership", verbose_name=_("members"), through_fields=("project", "user")) total_milestones = models.IntegerField( null=True, blank=True, verbose_name=_("total of milestones")) total_story_points = models.FloatField( null=True, blank=True, verbose_name=_("total story points")) is_backlog_activated = models.BooleanField( default=True, null=False, blank=True, verbose_name=_("active backlog panel")) is_kanban_activated = models.BooleanField( default=False, null=False, blank=True, verbose_name=_("active kanban panel")) is_wiki_activated = models.BooleanField( default=True, null=False, blank=True, verbose_name=_("active wiki panel")) is_issues_activated = models.BooleanField( default=True, null=False, blank=True, verbose_name=_("active issues panel")) videoconferences = models.CharField( max_length=250, null=True, blank=True, choices=choices.VIDEOCONFERENCES_CHOICES, verbose_name=_("videoconference system")) videoconferences_extra_data = models.CharField( max_length=250, null=True, blank=True, verbose_name=_("videoconference extra data")) creation_template = models.ForeignKey("projects.ProjectTemplate", related_name="projects", null=True, blank=True, default=None, verbose_name=_("creation template")) anon_permissions = TextArrayField(blank=True, null=True, default=[], verbose_name=_("anonymous permissions"), choices=ANON_PERMISSIONS) public_permissions = TextArrayField(blank=True, null=True, default=[], verbose_name=_("user permissions"), choices=MEMBERS_PERMISSIONS) is_private = models.BooleanField(default=True, null=False, blank=True, verbose_name=_("is private")) userstories_csv_uuid = models.CharField(max_length=32, editable=False, null=True, blank=True, default=None, db_index=True) tasks_csv_uuid = models.CharField(max_length=32, editable=False, null=True, blank=True, default=None, db_index=True) issues_csv_uuid = models.CharField(max_length=32, editable=False, null=True, blank=True, default=None, db_index=True) tags_colors = TextArrayField(dimension=2, null=False, blank=True, verbose_name=_("tags colors"), default=[]) _importing = None class Meta: verbose_name = "project" verbose_name_plural = "projects" ordering = ["name"] permissions = (("view_project", "Can view project"), ) def __str__(self): return self.name def __repr__(self): return "<Project {0}>".format(self.id) def save(self, *args, **kwargs): if not self._importing or not self.modified_date: self.modified_date = timezone.now() if not self.slug: base_name = "{}-{}".format(self.owner.username, self.name) base_slug = slugify_uniquely(base_name, self.__class__) slug = base_slug for i in arithmetic_progression(): if not type(self).objects.filter( slug=slug).exists() or i > 100: break slug = "{}-{}".format(base_slug, i) self.slug = slug if not self.videoconferences: self.videoconferences_extra_data = None super().save(*args, **kwargs) def get_roles(self): return self.roles.all() def get_users(self): user_model = get_user_model() members = self.memberships.values_list("user", flat=True) return user_model.objects.filter(id__in=list(members)) def update_role_points(self, user_stories=None): RolePoints = apps.get_model("userstories", "RolePoints") Role = apps.get_model("users", "Role") # Get all available roles on this project roles = self.get_roles().filter(computable=True) if roles.count() == 0: return # Iter over all project user stories and create # role point instance for new created roles. if user_stories is None: user_stories = self.user_stories.all() # Get point instance that represent a null/undefined # The current model allows duplicate values. Because # of it, we should get all poins with None as value # and use the first one. # In case of that not exists, creates one for avoid # unexpected errors. none_points = list(self.points.filter(value=None)) if none_points: null_points_value = none_points[0] else: name = slugify_uniquely_for_queryset("?", self.points.all(), slugfield="name") null_points_value = Points.objects.create(name=name, value=None, project=self) for us in user_stories: usroles = Role.objects.filter( role_points__in=us.role_points.all()).distinct() new_roles = roles.exclude(id__in=usroles) new_rolepoints = [ RolePoints(role=role, user_story=us, points=null_points_value) for role in new_roles ] RolePoints.objects.bulk_create(new_rolepoints) # Now remove rolepoints associated with not existing roles. rp_query = RolePoints.objects.filter( user_story__in=self.user_stories.all()) rp_query = rp_query.exclude( role__id__in=roles.values_list("id", flat=True)) rp_query.delete() @property def project(self): return self def _get_q_watchers(self): return Q(notify_policies__project_id=self.id) & ~Q( notify_policies__notify_level=NotifyLevel.none) def get_watchers(self): return get_user_model().objects.filter(self._get_q_watchers()) def get_related_people(self): related_people_q = Q() ## - Owner if self.owner_id: related_people_q.add(Q(id=self.owner_id), Q.OR) ## - Watchers related_people_q.add(self._get_q_watchers(), Q.OR) ## - Apply filters related_people = get_user_model().objects.filter(related_people_q) ## - Exclude inactive and system users and remove duplicate related_people = related_people.exclude(is_active=False) related_people = related_people.exclude(is_system=True) related_people = related_people.distinct() return related_people def add_watcher(self, user, notify_level=NotifyLevel.all): notify_policy = create_notify_policy_if_not_exists(self, user) set_notify_policy_level(notify_policy, notify_level) def remove_watcher(self, user): notify_policy = get_notify_policy(self, user) set_notify_policy_level_to_ignore(notify_policy)
class TaggedMixin(models.Model): tags = TextArrayField(default=None, verbose_name=_("tags")) class Meta: abstract = True
class AppStoreAppInfo(APIModel): create_time = models.DateTimeField(auto_now_add=True) app = models.ForeignKey(AppStoreApp, related_name='+', db_index=False, on_delete=models.DO_NOTHING) data = hstore_field.HStoreField() itunes_id = data.long_property() bundle_id = data.string_property() mac_software = data.bool_property() name = data.string_property() description = data.string_property() release_notes = data.string_property() version = data.string_property() icon_60 = data.string_property() icon_100 = data.string_property() icon_512 = data.string_property() category = data.int_property() price = data.float_property() currency = data.string_property() size_bytes = data.long_property() rating = data.float_property() reviews_count = data.int_property() current_version_rating = data.float_property() current_version_reviews_count = data.int_property() content_rating = data.string_property() # 4+, etc. developer_id = data.long_property() developer_url = data.string_property() developer_name = data.string_property() categories = IntegerArrayField() screenshots = TextArrayField() ipad_screenshots = TextArrayField(null=True) release_date = models.DateTimeField() country = models.CharField(null=True, max_length=2) @property def short_name(self): return text.app_short_name(self.name) def to_tiny_dict(self): return { 'iTunesId': self.itunes_id, 'name': self.name, 'icon': { 'small': self.icon_60, }, 'developer': { 'id': self.developer_id, 'name': self.developer_name, }, } def to_dict(self): full_dict = self.to_tiny_dict() full_dict['bundleId'] = self.bundle_id full_dict['version'] = self.version full_dict['category'] = self.category full_dict['description'] = self.description full_dict['icon']['medium'] = self.icon_100 full_dict['icon']['large'] = self.icon_512 full_dict['developer']['url'] = self.developer_url full_dict['rating'] = self.rating full_dict['reviewCount'] = self.reviews_count full_dict['currentRating'] = self.current_version_rating full_dict['currentRatingStars'] = ''.join( [u'★'] * int(self.current_version_rating)) full_dict['currentReviewCount'] = self.current_version_reviews_count full_dict['screenshots'] = self.screenshots return full_dict
class ClusterCreationParams(models.Model): """ Definition of ClusterChoices model for retrieving cluster creation parameters from okeanos. Imported djorm_pgarray package is needed for custom Arrayfields. """ id = models.IntegerField("Id", primary_key=True, null=False, help_text="Id needed by ember.js store") user_id = models.ForeignKey(UserInfo, null=False, help_text="User ID") # Project name project_name = models.CharField("Project Name", max_length=255, null=True, help_text="Project name from" " which resources will be requested") # Maximum allowed vms vms_max = models.IntegerField("Max Vms", null=True, help_text="Maximum Allowed Virtual" " machines") # Available vms for user vms_av = IntegerArrayField() # ArrayField # Maximum allowed cpus cpu_max = models.IntegerField("Max Cpus", null=True, help_text="Maximum Allowed Cpus") # Available cpus cpu_av = models.IntegerField("Available Cpus", null=True, help_text="Available Cpus") # Maximum allowed ram ram_max = models.IntegerField("Max Ram", null=True, help_text="Maximum Allowed Ram") # Available ram ram_av = models.IntegerField("Available Ram", null=True, help_text="Available Ram") # Maximum allowed disk size disk_max = models.IntegerField("Max disk size", null=True, help_text="Max disk size") # Available disk size disk_av = models.IntegerField("Available disk size", null=True, help_text="Available disk size") # network net_av = models.IntegerField("Available Networks", null=True, help_text="Available Networks") # floating ips floatip_av = models.IntegerField("Available floating IPs", null=True, help_text="Available floating IPs") # Cpu choices cpu_choices = IntegerArrayField() # ArrayField # Ram choices ram_choices = IntegerArrayField() # ArrayField # Disk size choices disk_choices = IntegerArrayField() # ArrayField # Disk template choices disk_template = TextArrayField() # ArrayField # Operating system choices os_choices = TextArrayField() # ArrayField #ssh keys ssh_keys_names = TextArrayField() # ArrayField pending_status = models.NullBooleanField(default=False) class Meta: verbose_name = "Cluster" app_label = 'backend'
class SDKApp(APIModel): class Meta: app_label = 'lk' unique_together = ( 'user', 'bundle_id', ) ENCRYPTED_ID_KEY_TOKEN = 'sdk-app' user = models.ForeignKey(User, related_name='+', on_delete=models.DO_NOTHING) create_time = models.DateTimeField(auto_now_add=True) update_time = models.DateTimeField(auto_now=True) latest_track_time = models.DateTimeField(null=True) display_name = models.CharField(max_length=128, null=True) bundle_id = models.CharField(max_length=128, null=False) latest_debug_version = models.CharField(max_length=24, null=True) latest_prod_version = models.CharField(max_length=24, null=True) appstore_app = models.ForeignKey(AppStoreApp, null=True, related_name='+', on_delete=models.DO_NOTHING) appstore_app_country = models.CharField(max_length=2, null=True) super_config = TextArrayField(default=_default_super_config, null=False) almost_config = TextArrayField(default=_default_almost_config, null=False) config_parent = models.ForeignKey('self', null=True, related_name='config_children', on_delete=models.DO_NOTHING) products = hstore_field.HStoreField(null=True) config = products.bool_property() super_users = products.bool_property() # Decorated properties. decorated_label_counts = None decorated_config_children = None @property def name(self): if self.display_name: return self.display_name if self.appstore_app: return self.appstore_app.name return self.bundle_id @property def short_name(self): return text.app_short_name(self.name) def to_dict(self): products = [p for p in (self.products or {}) if getattr(self, p)] app = { 'id': self.encrypted_id, 'bundleId': self.bundle_id, 'iTunesId': self.appstore_app and self.appstore_app.itunes_id, 'names': { 'short': self.short_name, 'full': self.name, 'display': self.display_name, }, 'icons': { 'small': self.appstore_app and self.appstore_app.public_small_icon, 'medium': self.appstore_app and self.appstore_app.public_medium_icon, }, 'latestTrackTime': self.date_to_api_date(self.latest_track_time), 'latestVersion': { 'debug': self.latest_debug_version, 'prod': self.latest_prod_version, }, 'products': products, } if self.super_users: super_freq, super_time = self.super_config app['super'] = { 'freq': super_freq, 'time': super_time, } if self.decorated_label_counts is not None: # Return a simplified list here. app['stats'] = { 'active': self.decorated_label_counts.get('active-1m', 0), 'inactive': self.decorated_label_counts.get('inactive-1m', 0), } if self.super_users: app['stats']['super'] = self.decorated_label_counts.get( 'super', 0) app['stats']['almost'] = self.decorated_label_counts.get( 'almost', 0) app['stats']['fringe'] = self.decorated_label_counts.get( 'fringe', 0) if self.decorated_config_children: app['configChildren'] = [ a.to_dict() for a in self.decorated_config_children ] elif self.config_parent_id: app['configChild'] = True return app
class TextModel(models.Model): field = TextArrayField()
class MTextModel(models.Model): data = TextArrayField(dimension=2)
class Issue(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin, models.Model): ref = models.BigIntegerField(db_index=True, null=True, blank=True, default=None, verbose_name=_("ref")) owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, default=None, related_name="owned_issues", verbose_name=_("owner")) status = models.ForeignKey("projects.IssueStatus", null=False, blank=False, related_name="issues", verbose_name=_("status")) severity = models.ForeignKey("projects.Severity", null=False, blank=False, related_name="issues", verbose_name=_("severity")) priority = models.ForeignKey("projects.Priority", null=False, blank=False, related_name="issues", verbose_name=_("priority")) type = models.ForeignKey("projects.IssueType", null=False, blank=False, related_name="issues", verbose_name=_("type")) milestone = models.ForeignKey("milestones.Milestone", null=True, blank=True, default=None, related_name="issues", verbose_name=_("milestone")) project = models.ForeignKey("projects.Project", null=False, blank=False, related_name="issues", verbose_name=_("project")) created_date = models.DateTimeField(null=False, blank=False, verbose_name=_("created date"), default=timezone.now) modified_date = models.DateTimeField(null=False, blank=False, verbose_name=_("modified date")) finished_date = models.DateTimeField(null=True, blank=True, verbose_name=_("finished date")) subject = models.TextField(null=False, blank=False, verbose_name=_("subject")) description = models.TextField(null=False, blank=True, verbose_name=_("description")) assigned_to = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, default=None, related_name="issues_assigned_to_me", verbose_name=_("assigned to")) attachments = generic.GenericRelation("attachments.Attachment") external_reference = TextArrayField(default=None, verbose_name=_("external reference")) _importing = None class Meta: verbose_name = "issue" verbose_name_plural = "issues" ordering = ["project", "-id"] permissions = (("view_issue", "Can view issue"), ) def save(self, *args, **kwargs): if not self._importing or not self.modified_date: self.modified_date = timezone.now() if not self.status_id: self.status = self.project.default_issue_status if not self.type_id: self.type = self.project.default_issue_type if not self.severity_id: self.severity = self.project.default_severity if not self.priority_id: self.priority = self.project.default_priority return super().save(*args, **kwargs) def __str__(self): return "({1}) {0}".format(self.ref, self.subject) @property def is_closed(self): return self.status.is_closed
class Project(ProjectDefaults, TaggedMixin, models.Model): name = models.CharField(max_length=250, null=False, blank=False, verbose_name=_("name")) slug = models.SlugField(max_length=250, unique=True, null=False, blank=True, verbose_name=_("slug")) description = models.TextField(null=False, blank=False, verbose_name=_("description")) logo = models.FileField(upload_to=get_project_logo_file_path, max_length=500, null=True, blank=True, verbose_name=_("logo")) created_date = models.DateTimeField(null=False, blank=False, verbose_name=_("created date"), default=timezone.now) modified_date = models.DateTimeField(null=False, blank=False, verbose_name=_("modified date")) owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=False, blank=False, related_name="owned_projects", verbose_name=_("owner")) members = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="projects", through="Membership", verbose_name=_("members"), through_fields=("project", "user")) total_milestones = models.IntegerField( null=True, blank=True, verbose_name=_("total of milestones")) total_story_points = models.FloatField( null=True, blank=True, verbose_name=_("total story points")) is_backlog_activated = models.BooleanField( default=True, null=False, blank=True, verbose_name=_("active backlog panel")) is_kanban_activated = models.BooleanField( default=False, null=False, blank=True, verbose_name=_("active kanban panel")) is_wiki_activated = models.BooleanField( default=True, null=False, blank=True, verbose_name=_("active wiki panel")) is_issues_activated = models.BooleanField( default=True, null=False, blank=True, verbose_name=_("active issues panel")) videoconferences = models.CharField( max_length=250, null=True, blank=True, choices=choices.VIDEOCONFERENCES_CHOICES, verbose_name=_("videoconference system")) videoconferences_extra_data = models.CharField( max_length=250, null=True, blank=True, verbose_name=_("videoconference extra data")) creation_template = models.ForeignKey("projects.ProjectTemplate", related_name="projects", null=True, blank=True, default=None, verbose_name=_("creation template")) anon_permissions = TextArrayField(blank=True, null=True, default=[], verbose_name=_("anonymous permissions"), choices=ANON_PERMISSIONS) public_permissions = TextArrayField(blank=True, null=True, default=[], verbose_name=_("user permissions"), choices=MEMBERS_PERMISSIONS) is_private = models.BooleanField(default=True, null=False, blank=True, verbose_name=_("is private")) is_featured = models.BooleanField(default=False, null=False, blank=True, verbose_name=_("is featured")) is_looking_for_people = models.BooleanField( default=False, null=False, blank=True, verbose_name=_("is looking for people")) looking_for_people_note = models.TextField( default="", null=False, blank=True, verbose_name=_("loking for people note")) userstories_csv_uuid = models.CharField(max_length=32, editable=False, null=True, blank=True, default=None, db_index=True) tasks_csv_uuid = models.CharField(max_length=32, editable=False, null=True, blank=True, default=None, db_index=True) issues_csv_uuid = models.CharField(max_length=32, editable=False, null=True, blank=True, default=None, db_index=True) tags_colors = TextArrayField(dimension=2, default=[], null=False, blank=True, verbose_name=_("tags colors")) transfer_token = models.CharField(max_length=255, null=True, blank=True, default=None, verbose_name=_("project transfer token")) blocked_code = models.CharField(null=True, blank=True, max_length=255, choices=choices.BLOCKING_CODES + settings.EXTRA_BLOCKING_CODES, default=None, verbose_name=_("blocked code")) #Totals: totals_updated_datetime = models.DateTimeField( null=False, blank=False, auto_now_add=True, verbose_name=_("updated date time"), db_index=True) total_fans = models.PositiveIntegerField(null=False, blank=False, default=0, verbose_name=_("count"), db_index=True) total_fans_last_week = models.PositiveIntegerField( null=False, blank=False, default=0, verbose_name=_("fans last week"), db_index=True) total_fans_last_month = models.PositiveIntegerField( null=False, blank=False, default=0, verbose_name=_("fans last month"), db_index=True) total_fans_last_year = models.PositiveIntegerField( null=False, blank=False, default=0, verbose_name=_("fans last year"), db_index=True) total_activity = models.PositiveIntegerField(null=False, blank=False, default=0, verbose_name=_("count"), db_index=True) total_activity_last_week = models.PositiveIntegerField( null=False, blank=False, default=0, verbose_name=_("activity last week"), db_index=True) total_activity_last_month = models.PositiveIntegerField( null=False, blank=False, default=0, verbose_name=_("activity last month"), db_index=True) total_activity_last_year = models.PositiveIntegerField( null=False, blank=False, default=0, verbose_name=_("activity last year"), db_index=True) _importing = None class Meta: verbose_name = "project" verbose_name_plural = "projects" ordering = ["name", "id"] index_together = [ ["name", "id"], ] permissions = (("view_project", "Can view project"), ) def __str__(self): return self.name def __repr__(self): return "<Project {0}>".format(self.id) def save(self, *args, **kwargs): if not self._importing or not self.modified_date: self.modified_date = timezone.now() if not self.slug: base_name = "{}-{}".format(self.owner.username, self.name) base_slug = slugify_uniquely(base_name, self.__class__) slug = base_slug for i in arithmetic_progression(): if not type(self).objects.filter( slug=slug).exists() or i > 100: break slug = "{}-{}".format(base_slug, i) self.slug = slug if not self.is_backlog_activated: self.total_milestones = None self.total_story_points = None if not self.videoconferences: self.videoconferences_extra_data = None if not self.is_looking_for_people: self.looking_for_people_note = "" if self.anon_permissions == None: self.anon_permissions = [] if self.public_permissions == None: self.public_permissions = [] super().save(*args, **kwargs) def refresh_totals(self, save=True): now = timezone.now() self.totals_updated_datetime = now Like = apps.get_model("likes", "Like") content_type = apps.get_model( "contenttypes", "ContentType").objects.get_for_model(Project) qs = Like.objects.filter(content_type=content_type, object_id=self.id) self.total_fans = qs.count() qs_week = qs.filter(created_date__gte=now - relativedelta(weeks=1)) self.total_fans_last_week = qs_week.count() qs_month = qs.filter(created_date__gte=now - relativedelta(months=1)) self.total_fans_last_month = qs_month.count() qs_year = qs.filter(created_date__gte=now - relativedelta(years=1)) self.total_fans_last_year = qs_year.count() tl_model = apps.get_model("timeline", "Timeline") namespace = build_project_namespace(self) qs = tl_model.objects.filter(namespace=namespace) self.total_activity = qs.count() qs_week = qs.filter(created__gte=now - relativedelta(weeks=1)) self.total_activity_last_week = qs_week.count() qs_month = qs.filter(created__gte=now - relativedelta(months=1)) self.total_activity_last_month = qs_month.count() qs_year = qs.filter(created__gte=now - relativedelta(years=1)) self.total_activity_last_year = qs_year.count() if save: self.save() @cached_property def cached_user_stories(self): return list(self.user_stories.all()) def get_roles(self): return self.roles.all() def get_users(self): user_model = get_user_model() members = self.memberships.values_list("user", flat=True) return user_model.objects.filter(id__in=list(members)) def update_role_points(self, user_stories=None): RolePoints = apps.get_model("userstories", "RolePoints") Role = apps.get_model("users", "Role") # Get all available roles on this project roles = self.get_roles().filter(computable=True) if roles.count() == 0: return # Iter over all project user stories and create # role point instance for new created roles. if user_stories is None: user_stories = self.user_stories.all() # Get point instance that represent a null/undefined # The current model allows duplicate values. Because # of it, we should get all poins with None as value # and use the first one. # In case of that not exists, creates one for avoid # unexpected errors. none_points = list(self.points.filter(value=None)) if none_points: null_points_value = none_points[0] else: name = slugify_uniquely_for_queryset("?", self.points.all(), slugfield="name") null_points_value = Points.objects.create(name=name, value=None, project=self) for us in user_stories: usroles = Role.objects.filter( role_points__in=us.role_points.all()).distinct() new_roles = roles.exclude(id__in=usroles) new_rolepoints = [ RolePoints(role=role, user_story=us, points=null_points_value) for role in new_roles ] RolePoints.objects.bulk_create(new_rolepoints) # Now remove rolepoints associated with not existing roles. rp_query = RolePoints.objects.filter( user_story__in=self.user_stories.all()) rp_query = rp_query.exclude( role__id__in=roles.values_list("id", flat=True)) rp_query.delete() @property def project(self): return self def _get_q_watchers(self): return Q(notify_policies__project_id=self.id) & ~Q( notify_policies__notify_level=NotifyLevel.none) def get_watchers(self): return get_user_model().objects.filter(self._get_q_watchers()) def get_related_people(self): related_people_q = Q() ## - Owner if self.owner_id: related_people_q.add(Q(id=self.owner_id), Q.OR) ## - Watchers related_people_q.add(self._get_q_watchers(), Q.OR) ## - Apply filters related_people = get_user_model().objects.filter(related_people_q) ## - Exclude inactive and system users and remove duplicate related_people = related_people.exclude(is_active=False) related_people = related_people.exclude(is_system=True) related_people = related_people.distinct() return related_people def add_watcher(self, user, notify_level=NotifyLevel.all): notify_policy = create_notify_policy_if_not_exists(self, user) set_notify_policy_level(notify_policy, notify_level) def remove_watcher(self, user): notify_policy = get_notify_policy(self, user) set_notify_policy_level_to_ignore(notify_policy) def delete_related_content(self): from taiga.events.apps import (connect_events_signals, disconnect_events_signals) from taiga.projects.tasks.apps import (connect_all_tasks_signals, disconnect_all_tasks_signals) from taiga.projects.userstories.apps import ( connect_all_userstories_signals, disconnect_all_userstories_signals) from taiga.projects.issues.apps import (connect_all_issues_signals, disconnect_all_issues_signals) from taiga.projects.apps import (connect_memberships_signals, disconnect_memberships_signals) disconnect_events_signals() disconnect_all_issues_signals() disconnect_all_tasks_signals() disconnect_all_userstories_signals() disconnect_memberships_signals() try: self.tasks.all().delete() self.user_stories.all().delete() self.issues.all().delete() self.memberships.all().delete() self.roles.all().delete() finally: connect_events_signals() connect_all_issues_signals() connect_all_tasks_signals() connect_all_userstories_signals() connect_memberships_signals()
class SDKUser(APIModel): class Meta: app_label = 'lk' unique_together = ( 'app', 'unique_id', ) ENCRYPTED_ID_KEY_TOKEN = 'sdk-user' user = models.ForeignKey(User, related_name='+', on_delete=models.DO_NOTHING) app = models.ForeignKey(SDKApp, related_name='+', on_delete=models.DO_NOTHING) create_time = models.DateTimeField(auto_now_add=True) last_accessed_time = models.DateTimeField(auto_now_add=True) unique_id = models.CharField(max_length=128, null=True) name = models.CharField(max_length=128, null=True) email = models.CharField(max_length=128, null=True) screens = models.PositiveIntegerField(default=0) taps = models.PositiveIntegerField(default=0) visits = models.PositiveIntegerField(default=0) seconds = models.PositiveIntegerField(default=0) days_active_map = models.BigIntegerField(default=0) monthly_screens = models.PositiveIntegerField(default=0) monthly_taps = models.PositiveIntegerField(default=0) monthly_visits = models.PositiveIntegerField(default=0) monthly_seconds = models.PositiveIntegerField(default=0) monthly_days_active = models.PositiveIntegerField(default=0) labels = TextArrayField(null=True) data = hstore_field.HStoreField(null=True) def is_anonymous(self): return not (self.unique_id or self.name or self.email) @property def monthly_days_active_computed(self): return bitwise.num_bits_64(self.last_month_active_bitmap()) def last_month_active_bitmap(self, now_days_offset=0): offset = self.days_active_bitmap_offset_for_date( now_days_offset=now_days_offset) # This is DAYS_IN_MONTH - 1 here because today is bit 0. shift = offset - (DAYS_IN_MONTH - 1) days_active_map = (self.days_active_map or 0) & bitwise.BITS_64 shifted_map = bitwise.wrapping_right_shift_64(days_active_map, shift) return shifted_map & bitwise.flipped_bits_64(DAYS_IN_MONTH) def weekly_days_active(self, now_days_offset=0): return bitwise.num_bits_64( self.weekly_days_active_bitmap(now_days_offset=now_days_offset)) def weekly_days_active_bitmap(self, now_days_offset=0): return self.last_month_active_bitmap_reversed( now_days_offset=now_days_offset) & 0b1111111 def last_month_active_bitmap_reversed(self, now_days_offset=0): # You will get a DAYS_IN_MONTH-long bitmap, shifted so that: # today is (map & 1), yest. is (map & (1 << 1)), 2d ago is (map & (1 << 2)) return bitwise.reverse_bits( self.last_month_active_bitmap(now_days_offset=now_days_offset), DAYS_IN_MONTH) def days_active_bitmap_offset_for_date(self, now_date=None, now_days_offset=0): if now_date is None: now_date = datetime.now().date() if now_days_offset is not None: now_date += timedelta(days=now_days_offset) return (now_date - self.create_time.date()).days % 64 def days_active_bitmap_valid_bitmask(self, now_days_offset=0): # By default, this is tomorrow's offset. offset = self.days_active_bitmap_offset_for_date( now_days_offset=(1 + now_days_offset)) return bitwise.trailing_window_bitmask_64(offset, DAYS_IN_MONTH) @property def filtered_labels(self): if not self.labels: return [] labels = [] for label in ['super', 'almost', 'fringe']: if label in self.labels: labels.append(label) if 'active-1m' in self.labels: labels.append('active') else: labels.append('inactive') return labels def to_client_dict(self): return { 'name': self.name, 'uniqueId': self.unique_id, 'email': self.email, 'firstVisit': self.date_to_api_date(self.create_time), 'stats': { 'visits': self.monthly_visits, 'days': self.monthly_days_active_computed, }, 'labels': self.filtered_labels, } def to_dict(self, include_raw_labels=False): user = { 'id': self.encrypted_id, 'appId': SDKApp.encrypt_id(self.app_id), 'name': self.name, 'uniqueId': self.unique_id, 'email': self.email, 'latestVisit': self.date_to_api_date(self.last_accessed_time), 'firstVisit': self.date_to_api_date(self.create_time), 'stats': { 'screens': self.monthly_screens, 'taps': self.monthly_taps, 'visits': self.monthly_visits, 'seconds': self.monthly_seconds, 'days': self.monthly_days_active_computed, }, 'labels': self.filtered_labels, } if include_raw_labels: user['rawLabels'] = self.labels return user