src/cm/models.py
changeset 512 3764ea0fa1bc
parent 511 54d72b4da009
child 513 60da0b2cca9f
equal deleted inserted replaced
511:54d72b4da009 512:3764ea0fa1bc
    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 
    29 class TextManager(Manager):
    32 class TextManager(Manager):
    30     def create_text(self, title, format, content, note, name, email, tags, user=None, state='approved', **kwargs):
    33     def create_text(self, title, format, content, note, name, email, tags, user=None, state='approved', **kwargs):
    31         content = on_content_receive(content, format)
    34         content = on_content_receive(content, format)
    32         text = self.create(name=name, email=email, user=user, state=state)
    35         text = self.create(name=name, email=email, user=user, state=state)
    33         text_version = TextVersion.objects.create(title=title, format=format, content=content, text=text, note=note, name=name, email=email, tags=tags, user=user)
    36         text_version = TextVersion.objects.create(title=title, format=format, content=content, text=text, note=note, name=name, email=email, tags=tags, user=user)
   144         return text_version 
   147         return text_version 
   145         
   148         
   146     def __unicode__(self):
   149     def __unicode__(self):
   147         return self.title    
   150         return self.title    
   148 
   151 
   149 DEFAULT_INPUT_FORMAT = getattr(settings, 'DEFAULT_INPUT_FORMAT', DEFAULT_INPUT_FORMAT_PANDOC)
   152 class CommentManager(Manager):
   150 CHOICES_INPUT_FORMATS = getattr(settings, 'CHOICES_INPUT_FORMATS', CHOICES_INPUT_FORMATS_PANDOC)
   153     
       
   154     def duplicate(self, comment, text_version, reply_to=None, keep_dates=False):
       
   155         comment.id = None
       
   156         comment.text_version = text_version
       
   157         if reply_to:
       
   158             comment.reply_to = reply_to
       
   159         self.update_keys(comment)
       
   160         comment.save(keep_dates=keep_dates)
       
   161         return comment
       
   162     
       
   163 from cm.models_base import KEY_MAX_SIZE, generate_key
       
   164 
       
   165 class Comment(PermanentModel, AuthorModel):
       
   166     modified = models.DateTimeField()
       
   167     created = models.DateTimeField()
       
   168 
       
   169     # key to identify same comments across versions
       
   170     id_key = models.CharField(max_length=KEY_MAX_SIZE, db_index=True, default=generate_key)
       
   171 
       
   172     text_version = models.ForeignKey("TextVersion")
       
   173 
       
   174     # comment_set will be replies
       
   175     reply_to = models.ForeignKey("Comment", null=True, blank=True)
       
   176 
       
   177     title = models.TextField()
       
   178     content = models.TextField()
       
   179     content_html = models.TextField()
       
   180     
       
   181     format = models.CharField(_("Format:"), max_length=20, blank=False, default=DEFAULT_INPUT_FORMAT, choices=CHOICES_INPUT_FORMATS)
       
   182 
       
   183     tags = TagField()
       
   184 
       
   185     category = models.PositiveSmallIntegerField(default=0)
       
   186         
       
   187     start_wrapper = models.IntegerField(null=True, blank=True)
       
   188     end_wrapper = models.IntegerField(null=True, blank=True)
       
   189     start_offset = models.IntegerField(null=True, blank=True)
       
   190     end_offset = models.IntegerField(null=True, blank=True)
       
   191 
       
   192     objects = CommentManager()
       
   193     
       
   194     def save(self, keep_dates=False, **kwargs):
       
   195         if not keep_dates:
       
   196             now = datetime.now()
       
   197             if not self.id: 
       
   198                 self.created = now  
       
   199             self.modified = now 
       
   200         super(PermanentModel, self).save(**kwargs) 
       
   201             
       
   202     def __unicode__(self):
       
   203         return '<%d> %s [st_wrp:%s, st_ofs:%s, e_wrp:%s, e_ofs:%s]' % (self.id, self.title,  self.start_wrapper ,  self.start_offset,  self.end_wrapper,  self.end_offset, )    
       
   204         
       
   205     def is_reply(self):
       
   206         return self.reply_to != None
       
   207     
       
   208     def is_thread_full_visible(self, own_user=None):
       
   209         """
       
   210         own_user: comment belonging to this user are also visible 
       
   211         """
       
   212         if self.state == 'approved' or (own_user and self.user == own_user):
       
   213             if self.reply_to==None:
       
   214                 return True
       
   215             else:                
       
   216                 return self.reply_to.is_thread_full_visible(own_user)
       
   217         return False
       
   218                
       
   219     def is_scope_removed(self):
       
   220         #when scope is "removed" we will have 
       
   221         #self.start_wrapper == self.end_wrapper == self.start_offset == self.end_offset == -1
       
   222         return (self.start_wrapper == -1)  
       
   223                
       
   224     def top_comment(self):
       
   225         if self.reply_to == None :
       
   226             return self
       
   227         else : 
       
   228             return self.reply_to.top_comment()
       
   229     
       
   230     def depth(self):
       
   231         if self.reply_to == None :
       
   232             return 0
       
   233         else : 
       
   234             return 1 + self.reply_to.depth()
       
   235     
       
   236     def delete(self):
       
   237         PermanentModel.delete(self)
       
   238         # delete replies
       
   239         [c.delete() for c in self.comment_set.all()]
       
   240         
       
   241     def remove_scope(self):
       
   242         self.start_wrapper = self.end_wrapper = self.start_offset = self.end_offset = -1
       
   243         self.save()
       
   244         
       
   245 # http://docs.djangoproject.com/en/dev/topics/files/#topics-files
       
   246 
       
   247 # default conf values
       
   248 DEFAULT_CONF = {
       
   249                 'workspace_name' : 'Workspace',
       
   250                 'site_url' : settings.SITE_URL,
       
   251                 'email_from' : settings.DEFAULT_FROM_EMAIL,
       
   252                 }
       
   253 
       
   254 from cm.role_models import change_role_model
       
   255 
       
   256 class ConfigurationManager(models.Manager):
       
   257     def set_workspace_name(self, workspace_name):
       
   258         if workspace_name:
       
   259             self.set_key('workspace_name', workspace_name)
       
   260 
       
   261     def get_key(self, key, default_value=None):
       
   262         try:
       
   263             return self.get(key=key).value
       
   264         except Configuration.DoesNotExist:
       
   265             return DEFAULT_CONF.get(key, default_value)
       
   266 
       
   267     def del_key(self, key):
       
   268         try:
       
   269             self.get(key=key).delete()
       
   270         except Configuration.DoesNotExist:
       
   271             return None
       
   272         
       
   273     def set_key(self, key, value):
       
   274         conf, created = self.get_or_create(key=key)
       
   275         if created or conf.value != value:
       
   276             conf.value = value
       
   277             conf.save()
       
   278             if key == 'workspace_role_model':
       
   279                 change_role_model(value)
       
   280 
       
   281     def __getitem__(self, key):
       
   282         if not key.startswith('f_'):
       
   283             return self.get_key(key, None)
       
   284         else:
       
   285             return getattr(self,key)()
       
   286     
       
   287     def f_get_logo_url(self):
       
   288         key = self.get_key('workspace_logo_file_key', None)
       
   289         if key:
       
   290             attach = Attachment.objects.get(key=key)
       
   291             return attach.data.url
       
   292         else:
       
   293             return None 
       
   294     
       
   295 import base64
       
   296 
       
   297 class Configuration(models.Model):
       
   298     key = models.TextField(blank=False) # , unique=True cannot be added: creates error on mysql (?)
       
   299     raw_value = models.TextField(blank=False)
       
   300     
       
   301     def get_value(self):
       
   302         return pickle.loads(base64.b64decode(self.raw_value.encode('utf8')))
       
   303         
       
   304     def set_value(self, value):        
       
   305         self.raw_value = base64.b64encode(pickle.dumps(value, 0)).encode('utf8')
       
   306                 
       
   307     value = property(get_value, set_value)
       
   308                 
       
   309     objects = ConfigurationManager()
       
   310     
       
   311     def __unicode__(self):
       
   312         return '%s: %s' % (self.key, self.value)    
       
   313     
       
   314 ApplicationConfiguration = Configuration.objects     
   151 
   315 
   152 class TextVersionManager(KeyManager):
   316 class TextVersionManager(KeyManager):
   153 
   317 
   154     def duplicate(self, text_version, duplicate_comments=True):
   318     def duplicate(self, text_version, duplicate_comments=True):
   155         old_comment_set = set(text_version.comment_set.all())
   319         old_comment_set = set(text_version.comment_set.all())
   252         other_versions = TextVersion.objects.filter(text__exact=self.text).order_by('-created').filter(created__lt=self.created)
   416         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
   417         return other_versions[0] if other_versions else None
   254 
   418 
   255     def get_version_number(self):
   419     def get_version_number(self):
   256         return TextVersion.objects.filter(text__exact=self.text).order_by('created').filter(created__lte=self.created).count()
   420         return TextVersion.objects.filter(text__exact=self.text).order_by('created').filter(created__lte=self.created).count()
   257 
       
   258 class CommentManager(Manager):
       
   259     
       
   260     def duplicate(self, comment, text_version, reply_to=None, keep_dates=False):
       
   261         comment.id = None
       
   262         comment.text_version = text_version
       
   263         if reply_to:
       
   264             comment.reply_to = reply_to
       
   265         self.update_keys(comment)
       
   266         comment.save(keep_dates=keep_dates)
       
   267         return comment
       
   268     
       
   269 from cm.models_base import KEY_MAX_SIZE, generate_key
       
   270 
       
   271 class Comment(PermanentModel, AuthorModel):
       
   272     modified = models.DateTimeField()
       
   273     created = models.DateTimeField()
       
   274 
       
   275     # key to identify same comments across versions
       
   276     id_key = models.CharField(max_length=KEY_MAX_SIZE, db_index=True, default=generate_key)
       
   277 
       
   278     text_version = models.ForeignKey("TextVersion")
       
   279 
       
   280     # comment_set will be replies
       
   281     reply_to = models.ForeignKey("Comment", null=True, blank=True)
       
   282 
       
   283     title = models.TextField()
       
   284     content = models.TextField()
       
   285     content_html = models.TextField()
       
   286     
       
   287     format = models.CharField(_("Format:"), max_length=20, blank=False, default=DEFAULT_INPUT_FORMAT, choices=CHOICES_INPUT_FORMATS)
       
   288 
       
   289     tags = TagField()
       
   290 
       
   291     category = models.PositiveSmallIntegerField(default=0)
       
   292         
       
   293     start_wrapper = models.IntegerField(null=True, blank=True)
       
   294     end_wrapper = models.IntegerField(null=True, blank=True)
       
   295     start_offset = models.IntegerField(null=True, blank=True)
       
   296     end_offset = models.IntegerField(null=True, blank=True)
       
   297 
       
   298     objects = CommentManager()
       
   299     
       
   300     def save(self, keep_dates=False, **kwargs):
       
   301         if not keep_dates:
       
   302             now = datetime.now()
       
   303             if not self.id: 
       
   304                 self.created = now  
       
   305             self.modified = now 
       
   306         super(PermanentModel, self).save(**kwargs) 
       
   307             
       
   308     def __unicode__(self):
       
   309         return '<%d> %s [st_wrp:%s, st_ofs:%s, e_wrp:%s, e_ofs:%s]' % (self.id, self.title,  self.start_wrapper ,  self.start_offset,  self.end_wrapper,  self.end_offset, )    
       
   310         
       
   311     def is_reply(self):
       
   312         return self.reply_to != None
       
   313     
       
   314     def is_thread_full_visible(self, own_user=None):
       
   315         """
       
   316         own_user: comment belonging to this user are also visible 
       
   317         """
       
   318         if self.state == 'approved' or (own_user and self.user == own_user):
       
   319             if self.reply_to==None:
       
   320                 return True
       
   321             else:                
       
   322                 return self.reply_to.is_thread_full_visible(own_user)
       
   323         return False
       
   324                
       
   325     def is_scope_removed(self):
       
   326         #when scope is "removed" we will have 
       
   327         #self.start_wrapper == self.end_wrapper == self.start_offset == self.end_offset == -1
       
   328         return (self.start_wrapper == -1)  
       
   329                
       
   330     def top_comment(self):
       
   331         if self.reply_to == None :
       
   332             return self
       
   333         else : 
       
   334             return self.reply_to.top_comment()
       
   335     
       
   336     def depth(self):
       
   337         if self.reply_to == None :
       
   338             return 0
       
   339         else : 
       
   340             return 1 + self.reply_to.depth()
       
   341     
       
   342     def delete(self):
       
   343         PermanentModel.delete(self)
       
   344         # delete replies
       
   345         [c.delete() for c in self.comment_set.all()]
       
   346         
       
   347     def remove_scope(self):
       
   348         self.start_wrapper = self.end_wrapper = self.start_offset = self.end_offset = -1
       
   349         self.save()
       
   350         
       
   351 # http://docs.djangoproject.com/en/dev/topics/files/#topics-files
       
   352 
       
   353 # default conf values
       
   354 DEFAULT_CONF = {
       
   355                 'workspace_name' : 'Workspace',
       
   356                 'site_url' : settings.SITE_URL,
       
   357                 'email_from' : settings.DEFAULT_FROM_EMAIL,
       
   358                 }
       
   359 
       
   360 from cm.role_models import change_role_model
       
   361 
       
   362 class ConfigurationManager(models.Manager):
       
   363     def set_workspace_name(self, workspace_name):
       
   364         if workspace_name:
       
   365             self.set_key('workspace_name', workspace_name)
       
   366 
       
   367     def get_key(self, key, default_value=None):
       
   368         try:
       
   369             return self.get(key=key).value
       
   370         except Configuration.DoesNotExist:
       
   371             return DEFAULT_CONF.get(key, default_value)
       
   372 
       
   373     def del_key(self, key):
       
   374         try:
       
   375             self.get(key=key).delete()
       
   376         except Configuration.DoesNotExist:
       
   377             return None
       
   378         
       
   379     def set_key(self, key, value):
       
   380         conf, created = self.get_or_create(key=key)
       
   381         if created or conf.value != value:
       
   382             conf.value = value
       
   383             conf.save()
       
   384             if key == 'workspace_role_model':
       
   385                 change_role_model(value)
       
   386 
       
   387     def __getitem__(self, key):
       
   388         if not key.startswith('f_'):
       
   389             return self.get_key(key, None)
       
   390         else:
       
   391             return getattr(self,key)()
       
   392     
       
   393     def f_get_logo_url(self):
       
   394         key = self.get_key('workspace_logo_file_key', None)
       
   395         if key:
       
   396             attach = Attachment.objects.get(key=key)
       
   397             return attach.data.url
       
   398         else:
       
   399             return None 
       
   400     
       
   401 import base64
       
   402 
       
   403 class Configuration(models.Model):
       
   404     key = models.TextField(blank=False) # , unique=True cannot be added: creates error on mysql (?)
       
   405     raw_value = models.TextField(blank=False)
       
   406     
       
   407     def get_value(self):
       
   408         return pickle.loads(base64.b64decode(self.raw_value.encode('utf8')))
       
   409         
       
   410     def set_value(self, value):        
       
   411         self.raw_value = base64.b64encode(pickle.dumps(value, 0)).encode('utf8')
       
   412                 
       
   413     value = property(get_value, set_value)
       
   414                 
       
   415     objects = ConfigurationManager()
       
   416     
       
   417     def __unicode__(self):
       
   418         return '%s: %s' % (self.key, self.value)    
       
   419     
       
   420 ApplicationConfiguration = Configuration.objects     
       
   421 
   421 
   422 class AttachmentManager(KeyManager):
   422 class AttachmentManager(KeyManager):
   423     def create_attachment(self, text_version, filename, data):
   423     def create_attachment(self, text_version, filename, data):
   424         attach = self.create(text_version=text_version)
   424         attach = self.create(text_version=text_version)
   425         ff = ContentFile(data)
   425         ff = ContentFile(data)