src/cm/models.py
changeset 514 f99c7f7401b0
parent 513 60da0b2cca9f
child 515 0be906e586e6
equal deleted inserted replaced
513:60da0b2cca9f 514:f99c7f7401b0
    24 from tagging.fields import TagField
    24 from tagging.fields import TagField
    25 import pickle
    25 import pickle
    26 from django.db import connection
    26 from django.db import connection
    27 from datetime import datetime
    27 from datetime import datetime
    28 
    28 
    29 DEFAULT_INPUT_FORMAT = getattr(settings, 'DEFAULT_INPUT_FORMAT', DEFAULT_INPUT_FORMAT_PANDOC)
       
    30 CHOICES_INPUT_FORMATS = getattr(settings, 'CHOICES_INPUT_FORMATS', CHOICES_INPUT_FORMATS_PANDOC)
       
    31 
       
    32 class TextManager(Manager):
    29 class TextManager(Manager):
    33     def create_text(self, title, format, content, note, name, email, tags, user=None, state='approved', **kwargs):
    30     def create_text(self, title, format, content, note, name, email, tags, user=None, state='approved', **kwargs):
    34         content = on_content_receive(content, format)
    31         content = on_content_receive(content, format)
    35         text = self.create(name=name, email=email, user=user, state=state)
    32         text = self.create(name=name, email=email, user=user, state=state)
    36         text_version = TextVersion.objects.create(title=title, format=format, content=content, text=text, note=note, name=name, email=email, tags=tags, user=user)
    33         text_version = TextVersion.objects.create(title=title, format=format, content=content, text=text, note=note, name=name, email=email, tags=tags, user=user)
   146         text_version.edit(new_title, new_format, new_content, new_tags, new_note, keep_comments, cancel_modified_scopes)        
   143         text_version.edit(new_title, new_format, new_content, new_tags, new_note, keep_comments, cancel_modified_scopes)        
   147         return text_version 
   144         return text_version 
   148         
   145         
   149     def __unicode__(self):
   146     def __unicode__(self):
   150         return self.title    
   147         return self.title    
       
   148 
       
   149 DEFAULT_INPUT_FORMAT = getattr(settings, 'DEFAULT_INPUT_FORMAT', DEFAULT_INPUT_FORMAT_PANDOC)
       
   150 CHOICES_INPUT_FORMATS = getattr(settings, 'CHOICES_INPUT_FORMATS', CHOICES_INPUT_FORMATS_PANDOC)
       
   151 
       
   152 class TextVersionManager(KeyManager):
       
   153 
       
   154     def duplicate(self, text_version, duplicate_comments=True):
       
   155         old_comment_set = set(text_version.comment_set.all())
       
   156         text_version.id = None
       
   157         
       
   158         # generate new key
       
   159         text_version.key = self._gen_key()
       
   160         text_version.adminkey = self._gen_adminkey()
       
   161         
       
   162         text_version.save()
       
   163         
       
   164         duplicate_text_version = text_version
       
   165         
       
   166         if duplicate_comments:
       
   167             old_comment_map = {}
       
   168             while len(old_comment_set):
       
   169                 for c in old_comment_set:
       
   170                     if not c.reply_to or c.reply_to.id in old_comment_map:
       
   171                         old_id = c.id
       
   172                         old_comment_set.remove(c)
       
   173                         reply_to = None
       
   174                         if c.reply_to:                            
       
   175                             reply_to = old_comment_map[c.reply_to.id]  
       
   176                         c2 = Comment.objects.duplicate(c, duplicate_text_version, reply_to, keep_dates=True)
       
   177                         old_comment_map[old_id] = c2
       
   178                         break
       
   179                  
       
   180         return duplicate_text_version
       
   181         
       
   182 class TextVersion(AuthorModel, KeyModel):
       
   183     modified = models.DateTimeField(auto_now=True)
       
   184     created = models.DateTimeField(auto_now_add=True)
       
   185 
       
   186     title = models.TextField(ugettext_lazy("Title"))
       
   187     format = models.CharField(ugettext_lazy("Format"), max_length=20, blank=False, default=DEFAULT_INPUT_FORMAT, choices=CHOICES_INPUT_FORMATS)
       
   188     content = models.TextField(ugettext_lazy("Content"))
       
   189     tags = TagField(ugettext_lazy("Tags"), max_length=1000)
       
   190 
       
   191     note = models.CharField(ugettext_lazy("Note"), max_length=100, null=True, blank=True)
       
   192 
       
   193     mod_posteriori = models.BooleanField(ugettext_lazy('Moderation a posteriori?'), default=True)
       
   194 
       
   195     from django.utils.safestring import mark_safe
       
   196 
       
   197     category_1 = models.CharField(ugettext_lazy("Label for the first category of comments"), help_text=mark_safe(_("Paragraphs including at least one comment of this category will have a vertical bar with this color: ") + '<span style="width: 2px; height: 5px; background-color: #1523f4">&nbsp;</span><br />' + _("Leave blank to use the value configured for the workspace.") + '<br />' + _("To disable this category for this text whatever the configuration for the workspace, enter: ") + '<em>none</em>'), max_length=20, null=True, blank=True)
       
   198     category_2 = models.CharField(ugettext_lazy("Label for the second category of comments"), help_text=mark_safe(_("Paragraphs including at least one comment of this category will have a vertical bar with this color: ") + '<span style="width: 2px; height: 5px; background-color: #f4154f">&nbsp;</span><br />' + _("Leave blank to use the value configured for the workspace. ") + '<br />' + _("To disable this category for this text whatever the configuration for the workspace, enter: ") + '<em>none</em>'), max_length=20, null=True, blank=True)
       
   199     category_3 = models.CharField(ugettext_lazy("Label for the third category of comments"), help_text=mark_safe(_("Paragraphs including at least one comment of this category will have a vertical bar with this color: ") + '<span style="width: 2px; height: 5px; background-color: #09ff09">&nbsp;</span><br />' + _("Leave blank to use the value configured for the workspace. ") + '<br />' + _("To disable this category for this text whatever the configuration for the workspace, enter: ") + '<em>none</em>'), max_length=20, null=True, blank=True)
       
   200     category_4 = models.CharField(ugettext_lazy("Label for the fourth category of comments"), help_text=mark_safe(_("Paragraphs including at least one comment of this category will have a vertical bar with this color: ") + '<span style="width: 2px; height: 5px; background-color: #bc39cf">&nbsp;</span><br />' + _("Leave blank to use the value configured for the workspace. ") + '<br />' + _("To disable this category for this text whatever the configuration for the workspace, enter: ") + '<em>none</em>'), max_length=20, null=True, blank=True)
       
   201     category_5 = models.CharField(ugettext_lazy("Label for the fifth category of comments"), help_text=mark_safe(_("Paragraphs including at least one comment of this category will have a vertical bar with this color: ") + '<span style="width: 2px; height: 5px; background-color: #ffbd08">&nbsp;</span><br />' + _("Leave blank to use the value configured for the workspace. ") + '<br />' + _("To disable this category for this text whatever the configuration for the workspace, enter: ") + '<em>none</em>'), max_length=20, null=True, blank=True)
       
   202 
       
   203     text = models.ForeignKey("Text")
       
   204 
       
   205     objects = TextVersionManager()
       
   206     
       
   207     def get_content(self, format='html'):
       
   208         return pandoc_convert(self.content, self.format, format)
       
   209 
       
   210     def get_comments(self):
       
   211         "Warning: data access without security"
       
   212         return self.comment_set.filter(reply_to=None, deleted=False)
       
   213 
       
   214     def get_replies(self):
       
   215         "Warning: data access without security"
       
   216         return self.comment_set.filter(~Q(reply_to == None), Q(deleted=False))
       
   217     
       
   218     def __unicode__(self):
       
   219         return '<%d> %s' % (self.id, self.title)    
       
   220 
       
   221     def edit(self, new_title, new_format, new_content, new_tags=None, new_note=None, keep_comments=True, cancel_modified_scopes=True):
       
   222         new_content = on_content_receive(new_content, new_format) 
       
   223         if not keep_comments :
       
   224             self.comment_set.all().delete()
       
   225         elif self.content != new_content or new_format != self.format:
       
   226             comments = self.get_comments() ;
       
   227             tomodify_comments, toremove_comments = compute_new_comment_positions(self.content, self.format, new_content, new_format, comments)
       
   228             [comment.save(keep_dates=True) for comment in tomodify_comments]
       
   229             if cancel_modified_scopes :
       
   230                 [comment.remove_scope() for comment in toremove_comments]
       
   231             else :
       
   232                 [comment.delete() for comment in toremove_comments]
       
   233                 
       
   234         self.title = new_title
       
   235         if new_tags:
       
   236             self.tags = new_tags
       
   237         if new_note:
       
   238             self.note = new_note
       
   239         self.content = new_content
       
   240         self.format = new_format
       
   241         self.save()
       
   242 
       
   243     def get_next_version(self):        
       
   244         other_versions = TextVersion.objects.filter(text__exact=self.text).order_by('created').filter(created__gt=self.created)
       
   245         return other_versions[0] if other_versions else None 
       
   246         if other_versions:
       
   247             return 
       
   248         else:
       
   249             return None
       
   250 
       
   251     def get_previous_version(self):
       
   252         other_versions = TextVersion.objects.filter(text__exact=self.text).order_by('-created').filter(created__lt=self.created)
       
   253         return other_versions[0] if other_versions else None
       
   254 
       
   255     def get_version_number(self):
       
   256         return TextVersion.objects.filter(text__exact=self.text).order_by('created').filter(created__lte=self.created).count()
   151 
   257 
   152 class CommentManager(Manager):
   258 class CommentManager(Manager):
   153     
   259     
   154     def duplicate(self, comment, text_version, reply_to=None, keep_dates=False):
   260     def duplicate(self, comment, text_version, reply_to=None, keep_dates=False):
   155         comment.id = None
   261         comment.id = None
   309     objects = ConfigurationManager()
   415     objects = ConfigurationManager()
   310     
   416     
   311     def __unicode__(self):
   417     def __unicode__(self):
   312         return '%s: %s' % (self.key, self.value)    
   418         return '%s: %s' % (self.key, self.value)    
   313     
   419     
   314 class TextVersionManager(KeyManager):
       
   315 
       
   316     def duplicate(self, text_version, duplicate_comments=True):
       
   317         old_comment_set = set(text_version.comment_set.all())
       
   318         text_version.id = None
       
   319         
       
   320         # generate new key
       
   321         text_version.key = self._gen_key()
       
   322         text_version.adminkey = self._gen_adminkey()
       
   323         
       
   324         text_version.save()
       
   325         
       
   326         duplicate_text_version = text_version
       
   327         
       
   328         if duplicate_comments:
       
   329             old_comment_map = {}
       
   330             while len(old_comment_set):
       
   331                 for c in old_comment_set:
       
   332                     if not c.reply_to or c.reply_to.id in old_comment_map:
       
   333                         old_id = c.id
       
   334                         old_comment_set.remove(c)
       
   335                         reply_to = None
       
   336                         if c.reply_to:                            
       
   337                             reply_to = old_comment_map[c.reply_to.id]  
       
   338                         c2 = Comment.objects.duplicate(c, duplicate_text_version, reply_to, keep_dates=True)
       
   339                         old_comment_map[old_id] = c2
       
   340                         break
       
   341                  
       
   342         return duplicate_text_version
       
   343         
       
   344 class TextVersion(AuthorModel, KeyModel):
       
   345     modified = models.DateTimeField(auto_now=True)
       
   346     created = models.DateTimeField(auto_now_add=True)
       
   347 
       
   348     title = models.TextField(ugettext_lazy("Title"))
       
   349     format = models.CharField(ugettext_lazy("Format"), max_length=20, blank=False, default=DEFAULT_INPUT_FORMAT, choices=CHOICES_INPUT_FORMATS)
       
   350     content = models.TextField(ugettext_lazy("Content"))
       
   351     tags = TagField(ugettext_lazy("Tags"), max_length=1000)
       
   352 
       
   353     note = models.CharField(ugettext_lazy("Note"), max_length=100, null=True, blank=True)
       
   354 
       
   355     mod_posteriori = models.BooleanField(ugettext_lazy('Moderation a posteriori?'), default=True)
       
   356 
       
   357     from django.utils.safestring import mark_safe
       
   358 
       
   359     category_1 = models.CharField(ugettext_lazy("Label for the first category of comments"), help_text=mark_safe(_("Paragraphs including at least one comment of this category will have a vertical bar with this color: ") + '<span style="width: 2px; height: 5px; background-color: #1523f4">&nbsp;</span><br />' + _("Leave blank to use the value configured for the workspace.") + '<br />' + _("To disable this category for this text whatever the configuration for the workspace, enter: ") + '<em>none</em>'), max_length=20, null=True, blank=True)
       
   360     category_2 = models.CharField(ugettext_lazy("Label for the second category of comments"), help_text=mark_safe(_("Paragraphs including at least one comment of this category will have a vertical bar with this color: ") + '<span style="width: 2px; height: 5px; background-color: #f4154f">&nbsp;</span><br />' + _("Leave blank to use the value configured for the workspace. ") + '<br />' + _("To disable this category for this text whatever the configuration for the workspace, enter: ") + '<em>none</em>'), max_length=20, null=True, blank=True)
       
   361     category_3 = models.CharField(ugettext_lazy("Label for the third category of comments"), help_text=mark_safe(_("Paragraphs including at least one comment of this category will have a vertical bar with this color: ") + '<span style="width: 2px; height: 5px; background-color: #09ff09">&nbsp;</span><br />' + _("Leave blank to use the value configured for the workspace. ") + '<br />' + _("To disable this category for this text whatever the configuration for the workspace, enter: ") + '<em>none</em>'), max_length=20, null=True, blank=True)
       
   362     category_4 = models.CharField(ugettext_lazy("Label for the fourth category of comments"), help_text=mark_safe(_("Paragraphs including at least one comment of this category will have a vertical bar with this color: ") + '<span style="width: 2px; height: 5px; background-color: #bc39cf">&nbsp;</span><br />' + _("Leave blank to use the value configured for the workspace. ") + '<br />' + _("To disable this category for this text whatever the configuration for the workspace, enter: ") + '<em>none</em>'), max_length=20, null=True, blank=True)
       
   363     category_5 = models.CharField(ugettext_lazy("Label for the fifth category of comments"), help_text=mark_safe(_("Paragraphs including at least one comment of this category will have a vertical bar with this color: ") + '<span style="width: 2px; height: 5px; background-color: #ffbd08">&nbsp;</span><br />' + _("Leave blank to use the value configured for the workspace. ") + '<br />' + _("To disable this category for this text whatever the configuration for the workspace, enter: ") + '<em>none</em>'), max_length=20, null=True, blank=True)
       
   364 
       
   365     text = models.ForeignKey("Text")
       
   366 
       
   367     objects = TextVersionManager()
       
   368     
       
   369     def get_content(self, format='html'):
       
   370         return pandoc_convert(self.content, self.format, format)
       
   371 
       
   372     def get_comments(self):
       
   373         "Warning: data access without security"
       
   374         return self.comment_set.filter(reply_to=None, deleted=False)
       
   375 
       
   376     def get_replies(self):
       
   377         "Warning: data access without security"
       
   378         return self.comment_set.filter(~Q(reply_to == None), Q(deleted=False))
       
   379     
       
   380     def __unicode__(self):
       
   381         return '<%d> %s' % (self.id, self.title)    
       
   382 
       
   383     def edit(self, new_title, new_format, new_content, new_tags=None, new_note=None, keep_comments=True, cancel_modified_scopes=True):
       
   384         new_content = on_content_receive(new_content, new_format) 
       
   385         if not keep_comments :
       
   386             self.comment_set.all().delete()
       
   387         elif self.content != new_content or new_format != self.format:
       
   388             comments = self.get_comments() ;
       
   389             tomodify_comments, toremove_comments = compute_new_comment_positions(self.content, self.format, new_content, new_format, comments)
       
   390             [comment.save(keep_dates=True) for comment in tomodify_comments]
       
   391             if cancel_modified_scopes :
       
   392                 [comment.remove_scope() for comment in toremove_comments]
       
   393             else :
       
   394                 [comment.delete() for comment in toremove_comments]
       
   395                 
       
   396         self.title = new_title
       
   397         if new_tags:
       
   398             self.tags = new_tags
       
   399         if new_note:
       
   400             self.note = new_note
       
   401         self.content = new_content
       
   402         self.format = new_format
       
   403         self.save()
       
   404 
       
   405     def get_next_version(self):        
       
   406         other_versions = TextVersion.objects.filter(text__exact=self.text).order_by('created').filter(created__gt=self.created)
       
   407         return other_versions[0] if other_versions else None 
       
   408         if other_versions:
       
   409             return 
       
   410         else:
       
   411             return None
       
   412 
       
   413     def get_previous_version(self):
       
   414         other_versions = TextVersion.objects.filter(text__exact=self.text).order_by('-created').filter(created__lt=self.created)
       
   415         return other_versions[0] if other_versions else None
       
   416 
       
   417     def get_version_number(self):
       
   418         return TextVersion.objects.filter(text__exact=self.text).order_by('created').filter(created__lte=self.created).count()
       
   419 
       
   420 class AttachmentManager(KeyManager):
   420 class AttachmentManager(KeyManager):
   421     def create_attachment(self, text_version, filename, data):
   421     def create_attachment(self, text_version, filename, data):
   422         attach = self.create(text_version=text_version)
   422         attach = self.create(text_version=text_version)
   423         ff = ContentFile(data)
   423         ff = ContentFile(data)
   424         attach.data.save(filename, ff)
   424         attach.data.save(filename, ff)