class StaffFile(OrderingBaseModel, File): PHOTO_TYPE_FEATURED = 'featured' PHOTO_TYPE_OTHER = 'other' PHOTO_TYPE_CHOICES = ( (PHOTO_TYPE_FEATURED, 'Featured'), (PHOTO_TYPE_OTHER, 'Other'), ) staff = models.ForeignKey(Staff, on_delete=models.CASCADE) photo_type = models.CharField(max_length=50, choices=PHOTO_TYPE_CHOICES) objects = FileManager() def save(self, *args, **kwargs): if self.position is None: # Append try: last = StaffFile.objects.order_by('-position')[0] last.position = last.position or 0 self.position = last.position + 1 except IndexError: # First row self.position = 0 return super(StaffFile, self).save(*args, **kwargs) class Meta: ordering = ('position', ) app_label = 'staff'
class SpeakerFile(File): PHOTO_TYPE_PROFESSIONAL = 'professional' PHOTO_TYPE_FUN = 'fun' PHOTO_TYPE_CHOICES = ( (PHOTO_TYPE_PROFESSIONAL, 'Professional'), (PHOTO_TYPE_FUN, 'Fun'), ) speaker = models.ForeignKey(Speaker) photo_type = models.CharField(max_length=50, choices=PHOTO_TYPE_CHOICES) position = models.IntegerField(blank=True) objects = FileManager() def save(self, *args, **kwargs): if self.position is None: # Append try: last = SpeakerFile.objects.order_by('-position')[0] self.position = last.position + 1 except IndexError: # First row self.position = 0 return super(SpeakerFile, self).save(*args, **kwargs) class Meta: ordering = ('position', ) app_label = 'speakers'
class StaffFile(OrderingBaseModel, File): staff = models.ForeignKey(Staff) photo_type = models.CharField(max_length=50, choices=( ('featured', 'Featured'), ('other', 'Other'), )) objects = FileManager() def save(self, *args, **kwargs): if self.position is None: # Append try: last = StaffFile.objects.order_by('-position')[0] last.position = last.position or 0 self.position = last.position + 1 except IndexError: # First row self.position = 0 return super(StaffFile, self).save(*args, **kwargs) class Meta: ordering = ('position', ) app_label = 'staff'
class Image(File): case_study = models.ForeignKey(CaseStudy) file_ptr = models.OneToOneField(File, related_name="%(app_label)s_%(class)s_related") file_type = models.CharField( _('File type'), max_length=50, choices=( ('featured','Featured Screenshot'), ('screenshot','Screenshot'), ('homepage', 'Homepage Image'), ('other','Other'), ), default='other', ) position = models.IntegerField(blank=True) objects = FileManager() def save(self, *args, **kwargs): if self.position is None: # Append try: last = Image.objects.order_by('-position')[0] self.position = last.position + 1 except IndexError: # First row self.position = 0 return super(Image, self).save(*args, **kwargs) class Meta: ordering = ('position',) app_label = 'case_studies'
class Photo(File): project = models.ForeignKey(Project, related_name="%(app_label)s_%(class)s_related", on_delete=models.CASCADE) title = models.CharField(_(u'title'), max_length=200, blank=True) photo_description = models.TextField(_(u'Photo Description'), null=True, blank=True) objects = FileManager() def __unicode__(self): return self.title
class Documents(File): project = models.ForeignKey(Project, related_name="%(app_label)s_%(class)s_related", on_delete=models.CASCADE) type = models.ForeignKey(DocumentType, blank=True, on_delete=models.CASCADE) other = models.CharField(_(u'other'), max_length=200, blank=True) document_dt = models.DateField(_(u'Document Date'), null=True, blank=True) objects = FileManager() def __unicode__(self): return self.type
class TeamMembers(File): project = models.ForeignKey(Project, related_name="%(app_label)s_%(class)s_related", on_delete=models.CASCADE) first_name = models.CharField(_(u'First Name'), max_length=200, blank=True) last_name = models.CharField(_(u'Last Name'), max_length=200, blank=True) title = models.CharField(_(u'Title'), max_length=200, blank=True) role = models.CharField(_(u'Role'), max_length=200, blank=True) team_description = models.TextField(_(u'Description'), null=True, blank=True) objects = FileManager() def __unicode__(self): return self.title
class Documents(File): project = models.ForeignKey(Project, related_name="%(app_label)s_%(class)s_related", on_delete=models.CASCADE) # renamed from type to doc_type because type clashes with the type in Files on upload doc_type = models.ForeignKey(DocumentType, blank=True, null=True, on_delete=models.CASCADE) other = models.CharField(_(u'other'), max_length=200, blank=True) document_dt = models.DateField(_(u'Document Date'), null=True, blank=True) objects = FileManager() class Meta: verbose_name = _("Document") verbose_name_plural = _("Documents")
class Image(File): FILE_TYPE_FEATURED = 'featured' FILE_TYPE_SCREENSHOT = 'screenshot' FILE_TYPE_HOMEPAGE = 'homepage' FILE_TYPE_OTHER = 'other' FILE_TYPE_CHOICES = ( (FILE_TYPE_FEATURED, 'Featured Screenshot'), (FILE_TYPE_SCREENSHOT, 'Screenshot'), (FILE_TYPE_HOMEPAGE, 'Homepage Image'), (FILE_TYPE_OTHER, 'Other'), ) case_study = models.ForeignKey(CaseStudy, on_delete=models.CASCADE) file_ptr = models.OneToOneField( File, related_name="%(app_label)s_%(class)s_related", on_delete=models.CASCADE, parent_link=True) file_type = models.CharField( _('File type'), max_length=50, choices=FILE_TYPE_CHOICES, default=FILE_TYPE_OTHER, ) position = models.IntegerField(blank=True) objects = FileManager() def save(self, *args, **kwargs): if self.position is None: # Append try: last = Image.objects.order_by('-position')[0] self.position = last.position + 1 except IndexError: # First row self.position = 0 return super(Image, self).save(*args, **kwargs) class Meta: ordering = ('position', ) app_label = 'case_studies'
class File(TendenciBaseModel): file = models.FileField("", max_length=260, upload_to=file_directory) guid = models.CharField(max_length=40) name = models.CharField(max_length=250, blank=True) description = models.TextField(blank=True) content_type = models.ForeignKey(ContentType, blank=True, null=True) # file type - image, video, or text... f_type = models.CharField(max_length=20, blank=True, null=True) object_id = models.IntegerField(blank=True, null=True) is_public = models.BooleanField(default=True) group = models.ForeignKey( Group, null=True, default=get_default_group, on_delete=models.SET_NULL) tags = TagField(null=True, blank=True) categories = GenericRelation(CategoryItem, object_id_field="object_id", content_type_field="content_type") file_cat = models.ForeignKey('FilesCategory', verbose_name=_("Files Category"), related_name="file_cat", null=True, on_delete=models.SET_NULL) file_sub_cat = models.ForeignKey('FilesCategory', verbose_name=_("Files Sub Category"), related_name="file_subcat", null=True, on_delete=models.SET_NULL) perms = GenericRelation( ObjectPermission, object_id_field="object_id", content_type_field="content_type") objects = FileManager() class Meta: permissions = (("view_file", _("Can view file")),) app_label = 'files' def __init__(self, *args, **kwargs): super(File, self).__init__(*args, **kwargs) self._originaldict = {} for field_name in self._meta.get_all_field_names(): if isinstance(self._meta.get_field_by_name(field_name)[0], ManyToOneRel): continue # preventing circular reference if hasattr(self, field_name): value = getattr(self, field_name) # skip Manager type objects if not isinstance(value, models.Manager): self._originaldict[field_name] = value def has_changed(self): """ Loop through key fields and return True if a key field has changed. """ for field_name in self._originaldict.keys(): if getattr(self, field_name) != self._originaldict[field_name]: return True return False @models.permalink def get_absolute_url(self): return ("file", [self.pk]) @models.permalink def get_absolute_download_url(self): return ("file", [self.pk, 'download']) def __unicode__(self): return self.get_name() @property def category_set(self): items = {} for cat in self.categories.select_related('category__name', 'parent__name'): if cat.category: items["category"] = cat.category elif cat.parent: items["sub_category"] = cat.parent return items def save(self, *args, **kwargs): created = False if not self.id: self.guid = unicode(uuid.uuid1()) created = True self.f_type = self.type() super(File, self).save(*args, **kwargs) if self.is_public_file(): set_s3_file_permission(self.file, public=True) else: set_s3_file_permission(self.file, public=False) cache_set = cache.get("files_cache_set.%s" % self.pk) if cache_set is not None: # TODO remove cached images cache.delete_many(cache.get("files_cache_set.%s" % self.pk)) cache.delete("files_cache_set.%s" % self.pk) # send notification to administrator(s) and module recipient(s) if created: recipients = get_notice_recipients('module', 'files', 'filerecipients') site_display_name = get_setting('site', 'global', 'sitedisplayname') site_url = get_setting('site', 'global', 'siteurl') if recipients and notification: notification_params = { 'object': self, 'SITE_GLOBAL_SITEDISPLAYNAME': site_display_name, 'SITE_GLOBAL_SITEURL': site_url, } if self.owner: notification_params['author'] = self.owner.get_full_name() or self.owner notification.send_emails(recipients, 'file_added', notification_params) def delete(self, *args, **kwargs): # Related objects # Import related objects here to prevent circular references from tendenci.apps.pages.models import Page from tendenci.apps.events.models import Event from tendenci.apps.stories.models import Story pages = Page.objects.filter(header_image=self.pk) events = Event.objects.filter(image=self.pk) stories = Story.objects.filter(image=self.pk) # Set foreign key of related objects to None for page in pages: page.header_image = None page.save() for event in events: event.image = None event.save() for story in stories: story.image = None story.save() # roll back the transaction to fix the error for postgresql #"current transaction is aborted, commands ignored until # end of transaction block" #connection._rollback() # comment it out because this line of code leads to IntegrityError for files that inherit File's model. # send notification to administrator(s) and module recipient(s) if self.file: recipients = get_notice_recipients('module', 'files', 'filerecipients') site_display_name = get_setting('site', 'global', 'sitedisplayname') if self.owner: owner = self.owner.get_full_name() or self.owner else: owner = "Unknown" if recipients and notification: notification.send_emails(recipients, 'file_deleted', { 'object': self, 'author': owner, 'SITE_GLOBAL_SITEDISPLAYNAME': site_display_name, }) # delete actual file; do not save() self.instance self.file.delete(save=False) # delete database record super(File, self).delete(*args, **kwargs) def basename(self): return os.path.basename(unicode(self.file.name)) def ext(self): return os.path.splitext(self.basename())[-1] def get_name(self): return self.name or os.path.splitext(self.basename())[0] def get_name_ext(self): return "%s%s" % (self.get_name(), self.ext()) def type(self): ext = self.ext().lower() # map file-type to extension types = { 'image': ('.jpg', '.jpeg', '.gif', '.png', '.tif', '.tiff', '.bmp'), 'text': ('.txt', '.doc', '.docx'), 'spreadsheet': ('.csv', '.xls', '.xlsx'), 'powerpoint': ('.ppt', '.pptx'), 'pdf': ('.pdf'), 'video': ('.wmv', '.mov', '.mpg', '.mp4', '.m4v'), 'zip': ('.zip'), } # if file ext. is recognized # return icon for type in types: if ext in types[type]: return type return None def mime_type(self): types = { # list of uncommon mimetypes 'application/msword': ('.doc', '.docx'), 'application/ms-powerpoint': ('.ppt', '.pptx'), 'application/ms-excel': ('.xls', '.xlsx'), 'video/x-ms-wmv': ('.wmv'), } # add mimetypes for type in types: for ext in types[type]: mimetypes.add_type(type, ext) # guess mimetype mimetype = mimetypes.guess_type(self.file.name)[0] return mimetype def icon(self): # if we don't know the type # we can't find an icon [to represent the file] if not self.type(): return None # assign icons directory icons_dir = os.path.join(settings.LOCAL_STATIC_URL, 'images/icons') # map file-type to image file icons = { 'text': 'icon-ms-word-2007.gif', 'spreadsheet': 'icon-ms-excel-2007.gif', 'powerpoint': 'icon-ms-powerpoint-2007.gif', 'image': 'icon-ms-image-2007.png', 'pdf': 'icon-pdf.png', 'video': 'icon-wmv.png', 'zip': 'icon-zip.gif', } # return image path return icons_dir + '/' + icons[self.type()] def get_file_from_remote_storage(self): return cStringIO.StringIO(default_storage.open(self.file.name).read()) def image_dimensions(self): try: if hasattr(settings, 'USE_S3_STORAGE') and settings.USE_S3_STORAGE: im = Image.open(self.get_file_from_remote_storage()) else: im = Image.open(self.file.path) return im.size except Exception: return (0, 0) def get_size(self): try: return self.file.size except: return 0 def read(self): """Returns a file's text data For now this only considers pdf files. if the file cannot be read this will return an empty string. """ if not settings.USE_S3_STORAGE: if not os.path.exists(self.file.path): return unicode() if settings.INDEX_FILE_CONTENT: if self.type() == 'pdf': try: return extract_pdf(self.file.file) except: return unicode() return unicode() def is_public_file(self): return all([ self.is_public, self.allow_anonymous_view, self.status, self.status_detail.lower() == "active"]) def get_file_public_url(self): if self.is_public_file(): return self.get_full_url() return None def get_full_url(self): """ This link can be used for the performance reason but it doesn't have the security check. Use carefully. """ if hasattr(settings, 'USE_S3_STORAGE') and settings.USE_S3_STORAGE: return self.file.url else: return "%s%s" % (settings.MEDIA_URL, self.file) def get_content(self): if self.content_type and self.object_id: try: model = self.content_type.model_class() return model.objects.get(pk=self.object_id) except: return None else: for r_object in self._meta.get_all_related_objects(): if hasattr(self, r_object.name): return getattr(self, r_object.name) return None def get_binary(self, **kwargs): """ Returns binary in encoding base64. """ from tendenci.apps.files.utils import build_image size = kwargs.get('size') or self.image_dimensions() binary = build_image(self.file, size, 'FILE_IMAGE_PRE_KEY') return b64encode(binary)