class Migration(migrations.Migration): # replaces = [ # ('crudity', '0001_initial'), # ('crudity', '0003_v1_7__sync_job_user'), # ] initial = True dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('contenttypes', '0001_initial'), ('auth', '0001_initial'), ('creme_core', '0001_initial'), ] operations = [ migrations.CreateModel( name='History', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('created', creme_fields.CreationDateTimeField( default=now, verbose_name='Creation date', editable=False, blank=True)), ('action', models.CharField(max_length=100, verbose_name='Action')), ('source', models.CharField(max_length=100, verbose_name='Source')), ('description', models.TextField(null=True, verbose_name='Description', blank=True)), ('entity', models.ForeignKey(verbose_name='Entity', to='creme_core.CremeEntity', on_delete=CASCADE)), ('user', creme_fields.CremeUserForeignKey(default=None, blank=True, to=settings.AUTH_USER_MODEL, null=True, verbose_name='Owner')), ], options={ 'verbose_name': 'History', 'verbose_name_plural': 'History', }, bases=(models.Model, ), ), migrations.CreateModel( name='WaitingAction', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('action', models.CharField(max_length=100, verbose_name='Action')), ('source', models.CharField(max_length=100, verbose_name='Source')), ('data', models.TextField(null=True, blank=True)), ('subject', models.CharField(max_length=100, verbose_name='Subject')), ('ct', creme_fields.CTypeForeignKey(verbose_name="Ressource's type", to='contenttypes.ContentType')), ('user', creme_fields.CremeUserForeignKey(default=None, blank=True, to=settings.AUTH_USER_MODEL, null=True, verbose_name='Owner')), ], options={ 'verbose_name': 'Waiting action', 'verbose_name_plural': 'Waiting actions', }, bases=(models.Model, ), ), ]
class UserMessage(CremeModel): title = models.CharField(_('Title'), max_length=200) body = models.TextField(_('Message body')) creation_date = models.DateTimeField(_('Creation date')) priority = models.ForeignKey( UserMessagePriority, verbose_name=_('Priority'), on_delete=models.PROTECT, ) sender = creme_fields.CremeUserForeignKey( verbose_name=_('Sender'), related_name='sent_assistants_messages_set', ) recipient = creme_fields.CremeUserForeignKey( verbose_name=_('Recipient'), related_name='received_assistants_messages_set', ) email_sent = models.BooleanField(default=False) entity_content_type = creme_fields.EntityCTypeForeignKey( null=True, related_name='+', editable=False, ) entity = models.ForeignKey( CremeEntity, null=True, related_name='assistants_messages', editable=False, on_delete=models.CASCADE, ).set_tags(viewable=False) creme_entity = creme_fields.RealEntityForeignKey( ct_field='entity_content_type', fk_field='entity', ) creation_label = _('Create a message') save_label = _('Save the message') class Meta: app_label = 'assistants' verbose_name = _('User message') verbose_name_plural = _('User messages') def __str__(self): return self.title @classmethod @atomic def create_messages(cls, users, title, body, priority_id, sender, entity): """Create UserMessages instances to sent to several users. Notice that teams are treated as several Users. @param users: A sequence of CremeUser objects ; duplicates are removed. """ users_map = {} for user in users: if user.is_team: users_map.update(user.teammates) else: users_map[user.id] = user build_msg = partial( cls, creation_date=now(), title=title, body=body, priority_id=priority_id, sender=sender, creme_entity=entity, ) cls.objects.bulk_create( build_msg(recipient=user) for user in users_map.values()) from ..creme_jobs import usermessages_send_type usermessages_send_type.refresh_job() @classmethod def send_mails(cls, job): from django.conf import settings from django.core.mail import EmailMessage, get_connection usermessages = [*cls.objects.filter(email_sent=False)] if not usermessages: return subject_format = gettext('User message from Creme: {}') body_format = gettext('{user} sent you the following message:\n{body}') EMAIL_SENDER = settings.EMAIL_SENDER messages = [ EmailMessage( subject_format.format(msg.title), body_format.format(user=msg.sender, body=msg.body), EMAIL_SENDER, [msg.recipient.email], ) for msg in usermessages if msg.recipient.email ] try: with get_connection() as connection: connection.send_messages(messages) except Exception as e: logger.critical('Error while sending user-messages emails (%s)', e) JobResult.objects.create( job=job, messages=[ gettext('An error occurred while sending emails'), gettext('Original error: {}').format(e), ], ) cls.objects.filter(pk__in=[m.id for m in usermessages]) \ .update(email_sent=True)
class Migration(migrations.Migration): # replaces = [ # ('activities', '0001_initial'), # ('activities', '0006_v1_7__charfields_not_nullable_1'), # ('activities', '0007_v1_7__charfields_not_nullable_2'), # ('activities', '0008_v1_7__textfields_not_null_1'), # ('activities', '0009_v1_7__textfields_not_null_2'), # ('activities', '0010_v1_7__colorfield'), # ] initial = True dependencies = [ ('auth', '0001_initial'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('creme_core', '0001_initial'), ] operations = [ migrations.CreateModel( name='ActivityType', fields=[ ('id', models.CharField(max_length=100, serialize=False, editable=False, primary_key=True)), ('name', models.CharField(max_length=100, verbose_name='Name')), ('default_day_duration', models.IntegerField(verbose_name='Default day duration')), ('default_hour_duration', creme_fields.DurationField( max_length=15, verbose_name='Default hour duration')), ('is_custom', models.BooleanField(default=True, editable=False)), ], options={ 'ordering': ('name', ), 'verbose_name': 'Type of activity', 'verbose_name_plural': 'Types of activity', }, bases=(models.Model, ), ), migrations.CreateModel( name='ActivitySubType', fields=[ ('id', models.CharField(max_length=100, serialize=False, editable=False, primary_key=True)), ('name', models.CharField(max_length=100, verbose_name='Name')), ('is_custom', models.BooleanField(default=True, editable=False)), ('type', models.ForeignKey(verbose_name='Type of activity', to='activities.ActivityType', on_delete=CASCADE)), ], options={ 'ordering': ('name', ), 'verbose_name': 'Sub-type of activity', 'verbose_name_plural': 'Sub-types of activity', }, bases=(models.Model, ), ), migrations.CreateModel( name='Status', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('name', models.CharField(max_length=100, verbose_name='Name')), ('description', models.TextField(verbose_name='Description')), ('is_custom', models.BooleanField(default=True)), ], options={ 'ordering': ('name', ), 'verbose_name': 'Status of activity', 'verbose_name_plural': 'Status of activity', }, bases=(models.Model, ), ), migrations.CreateModel( name='Calendar', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('name', models.CharField(max_length=100, verbose_name='Name')), ('is_default', models.BooleanField(default=False, verbose_name='Is default?')), ('is_custom', models.BooleanField(default=True, editable=False)), ('is_public', models.BooleanField(default=False, verbose_name='Is public?')), # ('color', models.CharField(default='c1d9ec', max_length=100, verbose_name='Color')), ('color', creme_fields.ColorField(max_length=6, verbose_name='Color')), ('user', creme_fields.CremeUserForeignKey( verbose_name='Calendar owner', to=settings.AUTH_USER_MODEL)), ], options={ 'ordering': ['name'], 'verbose_name': 'Calendar', 'verbose_name_plural': 'Calendars', }, bases=(models.Model, ), ), migrations.CreateModel( name='Activity', fields=[ ('cremeentity_ptr', models.OneToOneField( parent_link=True, auto_created=True, primary_key=True, serialize=False, to='creme_core.CremeEntity', on_delete=CASCADE, )), ('title', models.CharField(max_length=100, verbose_name='Title')), ('start', models.DateTimeField(null=True, verbose_name='Start', blank=True)), ('end', models.DateTimeField(null=True, verbose_name='End', blank=True)), ('description', models.TextField(verbose_name='Description', blank=True)), ('minutes', models.TextField(verbose_name='Minutes', blank=True)), ('place', models.CharField(max_length=500, verbose_name='Activity place', blank=True)), ('duration', models.PositiveIntegerField(null=True, verbose_name='Duration (in hour)', blank=True)), ('is_all_day', models.BooleanField(blank=True, default=False, verbose_name='All day?')), ('busy', models.BooleanField(default=False, verbose_name='Busy?')), ('floating_type', models.PositiveIntegerField(default=1, verbose_name='Floating type', editable=False)), ('type', models.ForeignKey(on_delete=PROTECT, verbose_name='Activity type', to='activities.ActivityType')), ('sub_type', models.ForeignKey(on_delete=SET_NULL, verbose_name='Activity sub-type', blank=True, to='activities.ActivitySubType', null=True)), # ('status', models.ForeignKey(on_delete=SET_NULL, verbose_name='Status', blank=True, to='activities.Status', null=True)), ('status', models.ForeignKey(on_delete=CREME_REPLACE_NULL, verbose_name='Status', blank=True, to='activities.Status', null=True)), ('calendars', models.ManyToManyField( verbose_name='Calendars', editable=False, to='activities.Calendar')), # blank=True ], options={ 'swappable': 'ACTIVITIES_ACTIVITY_MODEL', 'ordering': ('-start', ), 'verbose_name': 'Activity', 'verbose_name_plural': 'Activities', }, bases=('creme_core.cremeentity', ), ), ]
class Migration(migrations.Migration): # replaces = [ # ('assistants', '0001_initial'), # ('assistants', '0006_v2_0__real_entity_fks_1'), # ('assistants', '0007_v2_0__real_entity_fks_2'), # ('assistants', '0008_v2_0__real_entity_fks_3'), # ] initial = True dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('auth', '0001_initial'), ('contenttypes', '0001_initial'), ] operations = [ migrations.CreateModel( name='Action', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('title', models.CharField(max_length=200, verbose_name='Title')), ('is_ok', models.BooleanField( default=False, verbose_name='Expected reaction has been done', editable=False)), ('description', models.TextField(verbose_name='Source action', blank=True)), ('creation_date', creme_fields.CreationDateTimeField( default=now, verbose_name='Creation date', editable=False, blank=True)), ('expected_reaction', models.TextField(verbose_name='Target action', blank=True)), ('deadline', models.DateTimeField(verbose_name='Deadline')), ('validation_date', models.DateTimeField(verbose_name='Validation date', null=True, editable=False, blank=True)), # ('entity_id', models.PositiveIntegerField(editable=False)), ('entity', models.ForeignKey( editable=False, on_delete=CASCADE, to='creme_core.CremeEntity', related_name='assistants_actions', )), # ('entity_content_type', models.ForeignKey(related_name='action_entity_set', editable=False, to='contenttypes.ContentType', on_delete=CASCADE)), ('entity_content_type', creme_fields.EntityCTypeForeignKey( editable=False, on_delete=CASCADE, related_name='+', to='contenttypes.ContentType', )), ('user', creme_fields.CremeUserForeignKey( verbose_name='Owner user', to=settings.AUTH_USER_MODEL)), ], options={ 'verbose_name': 'Action', 'verbose_name_plural': 'Actions', }, bases=(models.Model, ), ), migrations.CreateModel( name='Alert', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('title', models.CharField(max_length=200, verbose_name='Title')), ('description', models.TextField(verbose_name='Description', blank=True)), ('is_validated', models.BooleanField(default=False, verbose_name='Validated', editable=False)), ('reminded', models.BooleanField(default=False, editable=False, verbose_name='Notification sent')), ('trigger_date', models.DateTimeField(verbose_name='Trigger date')), # ('entity_id', models.PositiveIntegerField(editable=False)), ('entity', models.ForeignKey( editable=False, on_delete=CASCADE, to='creme_core.CremeEntity', related_name='assistants_alerts', )), # ('entity_content_type', models.ForeignKey(related_name='alert_entity_set', editable=False, to='contenttypes.ContentType', on_delete=CASCADE)), ('entity_content_type', creme_fields.EntityCTypeForeignKey( editable=False, on_delete=CASCADE, related_name='+', to='contenttypes.ContentType', )), ('user', creme_fields.CremeUserForeignKey( verbose_name='Owner user', to=settings.AUTH_USER_MODEL)), ], options={ 'verbose_name': 'Alert', 'verbose_name_plural': 'Alerts', }, bases=(models.Model, ), ), migrations.CreateModel( name='Memo', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('content', models.TextField(verbose_name='Content')), ('on_homepage', models.BooleanField(default=False, blank=True, verbose_name='Displayed on homepage')), ('creation_date', creme_fields.CreationDateTimeField( default=now, verbose_name='Creation date', editable=False, blank=True)), # ('entity_id', models.PositiveIntegerField(editable=False)), ('entity', models.ForeignKey( editable=False, on_delete=CASCADE, to='creme_core.CremeEntity', related_name='assistants_memos', )), # ('entity_content_type', models.ForeignKey(related_name='memo_entity_set', editable=False, to='contenttypes.ContentType', on_delete=CASCADE)), ('entity_content_type', creme_fields.EntityCTypeForeignKey( editable=False, on_delete=CASCADE, related_name='+', to='contenttypes.ContentType', )), ('user', creme_fields.CremeUserForeignKey( verbose_name='Owner user', to=settings.AUTH_USER_MODEL)), ], options={ 'verbose_name': 'Memo', 'verbose_name_plural': 'Memos', }, bases=(models.Model, ), ), migrations.CreateModel( name='ToDo', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('title', models.CharField(max_length=200, verbose_name='Title')), ('is_ok', models.BooleanField(default=False, verbose_name='Done ?', editable=False)), ('reminded', models.BooleanField(default=False, editable=False, verbose_name='Notification sent')), ('description', models.TextField(verbose_name='Description', blank=True)), ('creation_date', creme_fields.CreationDateTimeField( default=now, verbose_name='Creation date', editable=False, blank=True)), ('deadline', models.DateTimeField(null=True, verbose_name='Deadline', blank=True)), # ('entity_id', models.PositiveIntegerField(editable=False)), ('entity', models.ForeignKey( editable=False, on_delete=CASCADE, to='creme_core.CremeEntity', related_name='assistants_todos', )), # ('entity_content_type', models.ForeignKey(related_name='todo_entity_set', editable=False, to='contenttypes.ContentType', on_delete=CASCADE)), ('entity_content_type', creme_fields.EntityCTypeForeignKey( editable=False, on_delete=CASCADE, related_name='+', to='contenttypes.ContentType', )), ('user', creme_fields.CremeUserForeignKey( verbose_name='Owner user', to=settings.AUTH_USER_MODEL)), ], options={ 'verbose_name': 'Todo', 'verbose_name_plural': 'Todos', }, bases=(models.Model, ), ), migrations.CreateModel( name='UserMessagePriority', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('title', models.CharField(max_length=200, verbose_name='Title')), ('is_custom', models.BooleanField(default=True)), ], options={ 'ordering': ('title', ), 'verbose_name': 'Priority of user message', 'verbose_name_plural': 'Priorities of user message', }, bases=(models.Model, ), ), migrations.CreateModel( name='UserMessage', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('title', models.CharField(max_length=200, verbose_name='Title')), ('body', models.TextField(verbose_name='Message body')), ('creation_date', models.DateTimeField(verbose_name='Creation date')), ('email_sent', models.BooleanField(default=False)), # ('entity_id', models.PositiveIntegerField(null=True)), ('entity', models.ForeignKey( editable=False, on_delete=CASCADE, to='creme_core.CremeEntity', related_name='assistants_messages', null=True, )), # ('entity_content_type', models.ForeignKey(to='contenttypes.ContentType', null=True, on_delete=CASCADE)), ('entity_content_type', creme_fields.EntityCTypeForeignKey( editable=False, on_delete=CASCADE, related_name='+', to='contenttypes.ContentType', null=True, )), ('priority', models.ForeignKey(on_delete=PROTECT, verbose_name='Priority', to='assistants.UserMessagePriority')), ('recipient', creme_fields.CremeUserForeignKey( to=settings.AUTH_USER_MODEL, verbose_name='Recipient', related_name='received_assistants_messages_set', )), ('sender', creme_fields.CremeUserForeignKey( to=settings.AUTH_USER_MODEL, verbose_name='Sender', related_name='sent_assistants_messages_set', )), ], options={ 'verbose_name': 'User message', 'verbose_name_plural': 'User messages', }, bases=(models.Model, ), ), ]
class ToDo(CremeModel): title = models.CharField(_('Title'), max_length=200) is_ok = models.BooleanField(_('Done ?'), editable=False, default=False) reminded = models.BooleanField( _('Notification sent'), editable=False, default=False) # Needed by creme_core.core.reminder description = models.TextField(_('Description'), blank=True) creation_date = creme_fields.CreationDateTimeField(_('Creation date'), editable=False) deadline = models.DateTimeField(_('Deadline'), blank=True, null=True) user = creme_fields.CremeUserForeignKey(verbose_name=_('Owner user')) entity_content_type = creme_fields.EntityCTypeForeignKey(related_name='+', editable=False) entity = models.ForeignKey( CremeEntity, related_name='assistants_todos', editable=False, on_delete=models.CASCADE, ).set_tags(viewable=False) creme_entity = creme_fields.RealEntityForeignKey( ct_field='entity_content_type', fk_field='entity') objects = ToDoManager() creation_label = _('Create a todo') save_label = _('Save the todo') class Meta: app_label = 'assistants' verbose_name = _('Todo') verbose_name_plural = _('Todos') def __str__(self): return self.title def get_edit_absolute_url(self): return reverse('assistants__edit_todo', args=(self.id, )) # @staticmethod # def get_todos(entity): # warnings.warn('ToDo.get_todos() is deprecated.', DeprecationWarning) # return ToDo.objects.filter(entity_id=entity.id).select_related('user') # @staticmethod # def get_todos_for_home(user): # warnings.warn('ToDo.get_todos_for_home() is deprecated ; ' # 'use ToDo.objects.filter_by_user() instead.', # DeprecationWarning # ) # return ToDo.objects.filter(user__in=[user] + user.teams)\ # .select_related('user') # @staticmethod # def get_todos_for_ctypes(ct_ids, user): # warnings.warn('ToDo.get_todos_for_ctypes() is deprecated.', DeprecationWarning) # return ToDo.objects.filter(entity_content_type__in=ct_ids, # user__in=[user] + user.teams # ).select_related('user') def get_related_entity(self): # For generic views return self.creme_entity @property def to_be_reminded(self): return self.deadline and not self.is_ok and not self.reminded
class Memo(creme_models.CremeModel): content = models.TextField(_('Content')) on_homepage = models.BooleanField(_('Displayed on homepage'), blank=True, default=False) creation_date = creme_fields.CreationDateTimeField(_('Creation date'), editable=False) user = creme_fields.CremeUserForeignKey(verbose_name=_('Owner user')) # entity_content_type = models.ForeignKey(ContentType, related_name='memo_entity_set', editable=False, on_delete=models.CASCADE) # entity_id = models.PositiveIntegerField(editable=False).set_tags(viewable=False) # creme_entity = GenericForeignKey(ct_field='entity_content_type', fk_field='entity_id') entity_content_type = creme_fields.EntityCTypeForeignKey(related_name='+', editable=False) entity = models.ForeignKey( creme_models.CremeEntity, related_name='assistants_memos', editable=False, on_delete=models.CASCADE, ).set_tags(viewable=False) creme_entity = creme_fields.RealEntityForeignKey( ct_field='entity_content_type', fk_field='entity') objects = MemoManager() creation_label = _('Create a memo') save_label = _('Save the memo') class Meta: app_label = 'assistants' verbose_name = _('Memo') verbose_name_plural = _('Memos') def __str__(self): # NB: translate for unicode can not take 2 arguments... return ellipsis(self.content.strip().replace('\n', ''), 25) def get_edit_absolute_url(self): return reverse('assistants__edit_memo', args=(self.id, )) @staticmethod def get_memos(entity): warnings.warn('Memo.get_memos() is deprecated.', DeprecationWarning) return Memo.objects.filter(entity_id=entity.id).select_related('user') @staticmethod def get_memos_for_home(user): warnings.warn('Memo.get_memos_for_home() is deprecated.', DeprecationWarning) return Memo.objects.filter(on_homepage=True, user__in=[user] + user.teams, # entity__is_deleted=False, ) \ .select_related('user') @staticmethod def get_memos_for_ctypes(ct_ids, user): warnings.warn('Memo.get_memos_for_ctypes() is deprecated.', DeprecationWarning) return Memo.objects.filter(entity_content_type__in=ct_ids, user__in=[user] + user.teams) \ .select_related('user') def get_related_entity(self): # For generic views return self.creme_entity
class Calendar(CremeModel): name = models.CharField(_('Name'), max_length=100) is_default = models.BooleanField(_('Is default?'), default=False) is_custom = models.BooleanField(default=True, editable=False).set_tags( viewable=False) # Used by creme_config is_public = models.BooleanField(default=False, verbose_name=_('Is public?')) user = core_fields.CremeUserForeignKey(verbose_name=_('Calendar owner')) color = core_fields.ColorField(_('Color')) objects = CalendarManager() _enable_default_checking = True creation_label = _('Create a calendar') save_label = _('Save the calendar') class Meta: app_label = 'activities' verbose_name = _('Calendar') verbose_name_plural = _('Calendars') ordering = ['name'] def __str__(self): return self.name @property def get_color(self): # TODO: rename (safe_color ?) "Color can be null, so in this case a default color is used in templates." return self.color or DEFAULT_CALENDAR_COLOR def delete(self, using=None, keep_parents=False): super().delete(using=using, keep_parents=keep_parents) if self.is_default: # Sadly we cannot update() on a slice... for def_cal in Calendar.objects.filter( user=self.user).order_by('id')[:1]: def_cal.is_default = True def_cal._enable_default_checking = False def_cal.save() @classmethod def new_color(cls): warnings.warn( 'Calendar.new_color() is deprecated ; ' 'use Calendar.objects.new_color() instead.', DeprecationWarning) return COLOR_POOL[cls.objects.count() % len(COLOR_POOL)] @classmethod def _create_default_calendar(cls, user, *, is_public=False): warnings.warn( 'Calendar._create_default_calendar() is deprecated ; ' 'use Calendar.objects.create_default_calendar() instead.', DeprecationWarning) cal = Calendar( name=gettext("{user}'s calendar").format(user=user), user=user, is_default=True, is_custom=False, is_public=is_public, color=cls.new_color(), ) cal._enable_default_checking = False cal.save() return cal @staticmethod def get_user_calendars(user): warnings.warn('Calendar.get_user_calendars() is deprecated.', DeprecationWarning) calendars = list(Calendar.objects.filter(user=user)) if not calendars: calendars.append(Calendar._create_default_calendar(user)) return calendars @classmethod def get_user_default_calendar(cls, user): "Returns the default user calendar ; creates it if necessary." warnings.warn( 'Calendar.get_user_default_calendar() is deprecated ; ' 'use Calendar.objects.get_default_calendar() instead.', DeprecationWarning) calendars = cls.objects.filter(user=user) if not calendars: cal = cls._create_default_calendar(user) else: defaults = [c for c in calendars if c.is_default] if not defaults: cal = calendars[0] cal.is_default = True cal._enable_default_checking = False cal.save() # TODO: update_fields=['is_default'] else: cal = defaults[0] if len(defaults) > 1: cls.objects.filter(user=user).exclude(id=cal.id).update( is_default=False) return cal def save(self, *args, **kwargs): mngr = type(self).objects if not self.color: # self.color = self.new_color() self.color = mngr.new_color() check = self._enable_default_checking if check and not self.is_default and \ not mngr.filter(user=self.user, is_default=True).exists(): self.is_default = True super().save(*args, **kwargs) if check and self.is_default: mngr.filter(user=self.user, is_default=True) \ .exclude(id=self.id) \ .update(is_default=False)
class Calendar(CremeModel): name = models.CharField(_('Name'), max_length=100) is_default = models.BooleanField(_('Is default?'), default=False) # Used by creme_config is_custom = models.BooleanField(default=True, editable=False).set_tags(viewable=False) is_public = models.BooleanField(default=False, verbose_name=_('Is public?')) user = core_fields.CremeUserForeignKey(verbose_name=_('Calendar owner')) color = core_fields.ColorField(_('Color')) objects = CalendarManager() _enable_default_checking = True creation_label = _('Create a calendar') save_label = _('Save the calendar') class Meta: app_label = 'activities' verbose_name = _('Calendar') verbose_name_plural = _('Calendars') ordering = ['name'] def __str__(self): return self.name @property def get_color(self): # TODO: rename (safe_color ?) "Color can be null, so in this case a default color is used in templates." return self.color or DEFAULT_CALENDAR_COLOR def delete(self, using=None, keep_parents=False): super().delete(using=using, keep_parents=keep_parents) if self.is_default: # Sadly we cannot update() on a slice... for def_cal in Calendar.objects.filter(user=self.user).order_by('id')[:1]: def_cal.is_default = True def_cal._enable_default_checking = False def_cal.save() def save(self, *args, **kwargs): mngr = type(self).objects if not self.color: self.color = mngr.new_color() check = self._enable_default_checking if ( check and not self.is_default and not mngr.filter(user=self.user, is_default=True).exists() ): self.is_default = True super().save(*args, **kwargs) if check and self.is_default: mngr.filter(user=self.user, is_default=True) \ .exclude(id=self.id) \ .update(is_default=False)