class Organization(TimeStampedModel): """ Organization model. """ partner = models.ForeignKey(Partner, null=True, blank=False) uuid = models.UUIDField(blank=False, null=False, default=uuid4, editable=False, verbose_name=_('UUID')) key = models.CharField(max_length=255) name = models.CharField(max_length=255) marketing_url_path = models.CharField(max_length=255, null=True, blank=True) description = models.TextField(null=True, blank=True) homepage_url = models.URLField(max_length=255, null=True, blank=True) logo_image_url = models.URLField(null=True, blank=True) banner_image_url = models.URLField(null=True, blank=True) certificate_logo_image_url = models.URLField( null=True, blank=True, help_text=_('Logo to be displayed on certificates. If this logo is the same as ' 'logo_image_url, copy and paste the same value to both fields.') ) tags = TaggableManager( blank=True, help_text=_('Pick a tag from the suggestions. To make a new tag, add a comma after the tag name.'), ) class Meta: unique_together = ( ('partner', 'key'), ('partner', 'uuid'), ) def __str__(self): return '{key}: {name}'.format(key=self.key, name=self.name) @property def marketing_url(self): if self.marketing_url_path: return urljoin(self.partner.marketing_site_url_root, self.marketing_url_path) return None
class Book(models.Model): name = models.CharField(max_length=200, unique=True) slug = models.SlugField(max_length=200, blank=True, null=True) first_published = models.DateField(blank=True, null=True) publisher = models.CharField(max_length=200, blank=True, null=True) ISBN = models.CharField(max_length=50, blank=True, null=True) edition = models.CharField(max_length=100, blank=True, null=True) page_count = models.IntegerField(blank=True, null=True) author = models.CharField(max_length=200) user = models.ForeignKey(User, related_name="books_added") genre = TaggableManager( verbose_name="Genre", help_text= "Select from suggestions as you type the name of the genre. If there is no genre you are looking for type comma after writing it.", through=None, blank=False) about = RichTextField() language = models.CharField(max_length=200) original_language = models.CharField(max_length=200, blank=True, null=True) cover = models.ImageField(upload_to=upload_to, null=True) create_date = models.DateTimeField(auto_now_add=True) class Meta: ordering = ('-create_date', ) verbose_name = 'Book' verbose_name_plural = 'Books' def __str__(self): return self.name def save(self, *args, **kwargs): self.slug = slugify(unidecode(self.name)) super(Book, self).save(*args, **kwargs) def get_absolute_url(self): return reverse('book', args=[self.slug])
class Lomba(models.Model): #Contains all the lomba COMP_LEVEL = (("lokal", "Lokal"), ("nasional", "Nasional"), ("internasional", "Internasional")) PARTI_LEVEL = (("sd", "SD"), ("smp", "SMP"), ("sma", "SMA"), ("univ", "Universitas"), ("umum", "Umum")) name = models.CharField(max_length=200) description = models.TextField(max_length=3000) category = models.ForeignKey('Kategori', on_delete=models.SET_NULL, null=True) jumlahhadiah = models.DecimalField(max_digits=12, decimal_places=2) created = models.DateTimeField(default=timezone.now) deadline = models.DateField() tanggalpelaksanaan = models.DateField() location = models.CharField(max_length=200) owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) contact = models.CharField(max_length=200) owner_email = models.EmailField(null=True) visited = models.IntegerField(default=0) link = models.URLField(null=True) tags = TaggableManager( help_text="ex: Teknologi, Inovasi... (Pisahkan dengan Koma)", blank=True) competitions_level = models.CharField( max_length=50, choices=COMP_LEVEL, default='nasional', ) participant_level = models.CharField( max_length=50, choices=PARTI_LEVEL, default='umum', ) image = models.ImageField(upload_to='poster/', blank=True, null=True) slug = models.SlugField(blank=True, null=True, max_length=255) def save(self, *args, **kwargs): if not self.slug and self.name: self.slug = slugify(self.name) super(Lomba, self).save(*args, **kwargs) def __str__(self): return self.name def get_absolute_url(self): return reverse('competitions:detail_lomba', kwargs={ 'pk': self.pk, 'slug': self.slug }) @property def days_remaining(self): today = date.today() result = self.deadline - today if result.days > 0: return result.days else: return abs(result.days) @property def get_photo_url(self): if self.image and hasattr(self.image, 'url'): return self.image.url else: return "/static/images/AyoLomba!.png"
class Plugin (models.Model): """ Plugins model """ # dates created_on = models.DateTimeField(_('Created on'), auto_now_add=True, editable=False ) modified_on = models.DateTimeField(_('Modified on'), editable=False ) # owners created_by = models.ForeignKey(User, verbose_name=_('Created by'), related_name = 'plugins_created_by') author = models.CharField(_('Author'), help_text=_('This is the plugin\'s original author, if different from the uploader, this field will appear in the XML and in the web GUI'), max_length=256) email = models.EmailField(_('Author email')) homepage = models.URLField(_('Plugin homepage'), blank=True, null=True) # Support repository = models.URLField(_('Code repository'), blank=True, null=True) tracker = models.URLField(_('Tracker'), blank=True, null=True) owners = models.ManyToManyField(User, null=True, blank=True) # name, desc etc. package_name = models.CharField(_('Package Name'), help_text=_('This is the plugin\'s internal name, equals to the main folder name'), max_length=256, unique=True, editable=False) name = models.CharField(_('Name'), help_text=_('Must be unique'), max_length=256, unique=True) description = models.TextField(_('Description')) icon = models.ImageField(_('Icon'), blank=True, null=True, upload_to=PLUGINS_STORAGE_PATH) # downloads (soft trigger from versions) downloads = models.IntegerField(_('Downloads'), default=0, editable=False) # Flags featured = models.BooleanField(_('Featured'), default=False, db_index=True) deprecated = models.BooleanField(_('Deprecated'), default=False, db_index=True) # Managers objects = models.Manager() base_objects = BasePluginManager() approved_objects = ApprovedPlugins() stable_objects = StablePlugins() experimental_objects = ExperimentalPlugins() featured_objects = FeaturedPlugins() fresh_objects = FreshPlugins() unapproved_objects = UnapprovedPlugins() deprecated_objects = DeprecatedPlugins() popular_objects = PopularPlugins() most_downloaded_objects = MostDownloadedPlugins() most_voted_objects = MostVotedPlugins() most_rated_objects = MostRatedPlugins() rating = AnonymousRatingField(range=5, use_cookies=True, can_change_vote=True, allow_delete=True) tags = TaggableManager(blank=True) @property def approved(self): """ Returns True if the plugin has at least one approved version """ return self.pluginversion_set.filter(approved=True).count() > 0 @property def trusted(self): """ Returns True if the plugin's author has plugins.can_approve permission Purpose of this decorator is to show/hide buttons in the template """ return self.created_by.has_perm('plugins.can_approve') @property def stable(self): """ Returns the latest stable and approved version """ try: return self.pluginversion_set.filter(approved=True, experimental=False).order_by('-version')[0] except: return None @property def experimental(self): """ Returns the latest experimental and approved version """ try: return self.pluginversion_set.filter(approved=True, experimental=True).order_by('-version')[0] except: return None @property def editors(self): """ Returns a list of users that can edit the plugin: creator and owners """ l = [o for o in self.owners.all()] l.append(self.created_by) return l @property def approvers(self): """ Returns a list of editor users that can approve a version """ return [l for l in self.editors if l.has_perm('plugins.can_approve')] @property def avg_vote(self): """ Returns the rating_score/(rating_votes+0.001) value, this calculation is also available in manager's queries as "average_vote". This property is still useful when the object is not loaded through a manager, for example in related objects. """ return self.rating_score/(self.rating_votes+0.001) class Meta: ordering = ('name',) # ABP: Note: this permission should belong to the # PluginVersion class. I left it here because it # doesn't really matters where it is. Just be # sure you query for it using the 'plugins' class # instead of the 'pluginversion' class. permissions = ( ("can_approve", "Can approve plugins versions"), ) def get_absolute_url(self): return reverse('plugin_detail', args=(self.package_name,)) def __unicode__(self): return "[%s] %s" % (self.pk ,self.name) def __str__(self): return self.__unicode__() def clean(self): """ Validates: * Checks that package_name respect regexp [A-Za-z][A-Za-z0-9-_]+ * checks for case-insensitive unique package_name """ from django.core.exceptions import ValidationError if not re.match(r'^[A-Za-z][A-Za-z0-9-_]+$', self.package_name): raise ValidationError(unicode(_('Plugin package_name (which equals to the main plugin folder inside the zip file) must start with an ASCII letter and can contain only ASCII letters, digits and the - and _ signs.'))) if self.pk: qs = Plugin.objects.filter(name__iexact=self.name).exclude(pk=self.pk) else: qs = Plugin.objects.filter(name__iexact=self.name) if qs.count(): raise ValidationError(unicode(_('A plugin with a similar name (%s) already exists (the name only differs in case).') % qs.all()[0].name)) if self.pk: qs = Plugin.objects.filter(package_name__iexact=self.package_name).exclude(pk=self.pk) else: qs = Plugin.objects.filter(package_name__iexact=self.package_name) if qs.count(): raise ValidationError(unicode(_('A plugin with a similar package_name (%s) already exists (the package_name only differs in case).') % qs.all()[0].package_name)) def save(self, keep_date=False, *args, **kwargs): """ Soft triggers: * updates modified_on if keep_date is not set """ if self.pk and not keep_date: import logging logging.debug('Updating modified_on for the Plugin instance') self.modified_on = datetime.datetime.now() if not self.pk: self.modified_on = datetime.datetime.now() super(Plugin, self).save(*args, **kwargs)
class Share(models.Model): user = models.ForeignKey(User, default=1, on_delete=models.CASCADE) tags = TaggableManager(_(u'Tags'), blank=True) type = models.ForeignKey(Pygment, verbose_name=_(u'Pygment type'), blank=True, null=True, on_delete=models.SET_NULL) title = models.CharField(_(u'Title'), max_length=255, blank=True, null=True) slug = models.SlugField(_(u'Slug'), max_length=255, blank=True, null=True, db_index=True) url = models.CharField(_(u'Url'), max_length=255, blank=True, null=True) description = models.TextField(_(u'Description'), blank=True, null=True) content = models.TextField(_(u'Content'), blank=True, null=True) password = models.CharField(max_length=64, blank=True, db_index=True) disabled = models.BooleanField(default=False, db_index=True) hidden = models.BooleanField(default=False, db_index=True) personal = models.BooleanField(_(u'Personal'), default=False) json = models.JSONField(_(u'Json content'), default={}) expired_on = models.DateField(_(u'Expired on'), blank=True, null=True) view_count = models.IntegerField(default=0, editable=False) time_created = models.DateTimeField(auto_now_add=True, editable=False) time_updated = models.DateTimeField(auto_now=True, editable=False) time_delete = models.DateField(default=None, blank=True, null=True) # def rm_files(self): # try: # if self.thumbnail and self.pk: # log.debug("Request to delete thumbnail: %s" % self.thumbnail) # os.remove(os.path.join(settings.MEDIA_ROOT, self.thumbnail)) # if self.file and self.pk: # log.debug("Request to delete file: %s" % self.file.name) # os.remove(os.path.join(settings.MEDIA_ROOT, self.file.name)) # except Exception as e: # log.error('Cannot remove files for share with id: %s. Error: %s' % (self.pk, e)) def save(self, *args, **kwargs): # if self.description is not None: # self.description_html = markdown(self.description, extensions=['codehilite']) # # if not self.pk: # expl = self.title.split('/') # if len(expl) > 1: # self.title = expl[0] # self.slug = self.unique_slug(slugify(expl[1])) # # if not self.title and self.file_name: # if self.file_type == 'image': # file_type = 'Picture' # else: # file_type = 'File' # self.title = _(u'%s: %s' % (file_type, self.file_name)) # elif not self.title and self.url: # self.title = _(u'Url to: %s %s' % (self.url[:32], '...' if len(self.url) > 32 else '')) # # self.type = self.file_type() # self.get_title() super(Share, self).save() if self.slug is None: self.slug = self.short_id super(Share, self).save() # def process_file(self): # filename, file_extension = os.path.splitext(self.file) # file_name = "%s%s" % (slugify(filename), file_extension) @property def download_url(self): return reverse('share:download_file', args=[self.short_id]) @property def base_url(self): return reverse('share:snippet', args=[self.short_id]) @property def redirect_url(self): return reverse('share:link_redirect', args=[self.short_id]) @property def view(self): if self.url and self.video_link is False: return self.redirect_url else: return self.base_url @property def allow_change(self): if self.user: return True else: return False def unique_slug(self, slug, counter=0): if counter > 0: unique_slug = "%s%s" % (slug, counter) else: unique_slug = slug if self.id: my_id = self.id else: my_id = 0 if Share.objects.filter(slug=unique_slug).exclude(id=my_id).exists(): counter += 1 return self.unique_slug(slug, counter) else: return unique_slug @property def short_id(self): if self.slug: return self.slug else: hashids = Hashids(salt=settings.SECRET_KEY, min_length=4) return hashids.encrypt(self.id) def get_absolute_url(self): return '/%s/%s' % ('share', self.short_id) # def file_type(self): # if self.file_name is not None: # filename, file_extension = os.path.splitext(self.file_name) # if file_extension.lower() in ['.jpg', '.jpeg', '.gif', '.png']: # return 'image' # else: # return 'file' # return self.type @property def video_link(self): if self.url: try: match = detect_backend(self.url) print(match) if match: return True except: pass return False def __str__(self): return self.title
class Item(models.Model): """ Item is a content, is a link """ section = models.ForeignKey(Section, verbose_name=_('Section'), null=True, blank=True) title = models.CharField(verbose_name=_('Title'), max_length=255) is_editors_choice = models.BooleanField( verbose_name=_('Is editors choice'), default=False) description = models.TextField(verbose_name=_('Description'), blank=True) issue = models.ForeignKey(Issue, verbose_name=_('Issue of digest'), null=True, blank=True) resource = models.ForeignKey(Resource, verbose_name=_('Resource'), null=True, blank=True) link = models.URLField(verbose_name=_('URL'), max_length=255) additionally = models.CharField(verbose_name=_('Additional info'), max_length=255, blank=True, null=True) related_to_date = models.DateField( verbose_name=_('Date'), help_text=_('For example, publication date of the news on the source'), default=datetime.datetime.today) status = models.CharField(verbose_name=_('Status'), max_length=10, choices=ITEM_STATUS_CHOICES, default=ITEM_STATUS_DEFAULT) language = models.CharField(verbose_name='Язык новости', max_length=2, choices=ITEM_LANGUAGE_CHOICES, default=ITEM_LANGUAGE_DEFAULT) created_at = models.DateField(verbose_name=_('Created date'), auto_now_add=True) modified_at = models.DateTimeField(verbose_name=_('modified date'), null=True, blank=True) activated_at = models.DateTimeField(verbose_name=_('Activated date'), default=datetime.datetime.now) priority = models.PositiveIntegerField(verbose_name=_('Priority'), default=0) user = models.ForeignKey(User, verbose_name=_('Who added item'), editable=False, null=True, blank=True) article_path = models.FilePathField(verbose_name=_('Article path'), blank=True) tags = TaggableManager(blank=True) keywords = TaggableManager(verbose_name=_('Keywords'), through=KeywordGFK, blank=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._disable_signals = False def save(self, *args, **kwargs): try: if self.issue is None and self.created_at is not None: date_from, date_to = get_start_end_of_week(self.created_at) issue = Issue.objects.filter(date_from=date_from, date_to=date_to) if issue.count() == 0: # если нет выпуска, то создадим old_issue = Issue.objects.latest('date_to') cnt_issue = int(old_issue.title.replace('Выпуск ', '')) + 1 new_issue = Issue( title='Выпуск %s' % cnt_issue, date_from=date_from, date_to=date_to, ) new_issue.save() self.issue = new_issue elif issue.count() == 1: self.issue = issue[0] else: raise Exception('Many issues are on one week') except Exception as e: logger.error('Many issues are on one week: {0}'.format(e)) super(Item, self).save(*args, **kwargs) def save_without_signals(self): """ This allows for updating the model from code running inside post_save() signals without going into an infinite loop: """ self._disable_signals = True self.save() self._disable_signals = False @property def cls_check(self): try: item = ItemClsCheck.objects.get(item=self) item.check_cls() except (ObjectDoesNotExist, ItemClsCheck.DoesNotExist): item = ItemClsCheck(item=self) item.save() item.check_cls(force=True) return item.score @property def link_type(self): global LIBRARY_SECTIONS if LIBRARY_SECTIONS is None: load_library_sections() if any((x == self.section_id for x in LIBRARY_SECTIONS)): return 'library' else: return 'article' @property def text(self): nonempty_path = self.article_path is not None and self.article_path if nonempty_path and os.path.exists(self.article_path): with open(self.article_path, 'r') as fio: result = fio.read() else: try: resp = requests.get(self.link) text = resp.text try: result = Document( text, min_text_length=50, positive_keywords=','.join( settings.DATASET_POSITIVE_KEYWORDS), negative_keywords=','.join( settings.DATASET_NEGATIVE_KEYWORDS)).summary() except Unparseable: result = text except (KeyError, requests.exceptions.RequestException, requests.exceptions.Timeout, requests.exceptions.TooManyRedirects) as e: result = '' self.article_path = os.path.join(settings.DATASET_ROOT, '{0}.html'.format(self.id)) with open(self.article_path, 'w') as fio: fio.write(result) self.save() return result def get_data4cls(self, status=False): result = { 'link': self.link, 'data': { 'language': self.language, 'title': self.title, 'description': self.description, 'article': self.text, 'type': self.link_type, } } if status: result['data']['label'] = self.status == 'active' return result data4cls = property(get_data4cls) @property def internal_link(self): return reverse('digest:item', kwargs={'pk': self.pk}) @property def tags_as_links(self): return [(x.name, build_url('digest:feed', params={'tag': x.name})) for x in self.tags.all()] @property def tags_as_str(self): if self.tags and self.tags.all(): result = ','.join([x.name for x in self.tags.all()]) else: result = 'Without tag' return result @property def keywords_as_str(self): return ', '.join(list({x.name for x in self.keywords.all()})[:13]) def __str__(self): return self.title class Meta: verbose_name = _('News') verbose_name_plural = _('News')
class JobSeeker(models.Model): YEAR_CHOICE = [(str(year), str(year)) for year in reversed(range(1950, 2050))] EXP_CHOICE = [((exp), (exp)) for exp in range(1, 20)] RECRUITER_ACTION = ( ('not_interested', 'Not Interested'), ('interested', 'Interested'), ('not_answered', 'Not Answered'), ) TEAM_LEADER_ACTION = ( ('rejected', 'Rejected'), ('shortlisted', 'Shortlisted'), ('waiting', 'Put on Hold'), ) serial_number = models.CharField(max_length=20, null=True, blank=True) resume2 = models.CharField(max_length=15, null=True, blank=True) #Django custom user name = models.CharField(max_length=60) contact_number = models.CharField(max_length=100, blank=True, null=True) #name of the user email = models.EmailField(blank=True, null=True) work_exp = models.DecimalField(decimal_places=2, max_digits=6, null=True, blank=True, default=Decimal(0)) analytics_in_exp = models.DecimalField(decimal_places=2, max_digits=6, null=True, blank=True, default=Decimal(0)) current_location = models.ForeignKey(City, blank=True, null=True, related_name="+") corrected_location = models.ForeignKey(CorrectedCity, blank=True, null=True) nearest_city = models.CharField(max_length=250, blank=True, null=True) preferred_location = models.CharField( max_length=250, blank=True, null=True ) #do you want your professional info to be shared among others ? ctc = models.CharField(max_length=20, null=True, blank=True) current_employer = models.CharField(max_length=150, blank=True, null=True) current_designation = models.ForeignKey(Designation, null=True, blank=True) skills = TaggableManager() ug_course = models.TextField(blank=True, null=True) ug_course2 = models.TextField(blank=True, null=True) ug_institute_name = models.CharField(max_length=100, blank=True, null=True) tier1 = models.NullBooleanField(default=False) ug_passing_year = models.CharField(max_length=100, choices=YEAR_CHOICE, blank=True, null=True) pg_course = models.CharField(max_length=100, blank=True, null=True) correct_pg_course = models.CharField(max_length=100, blank=True, null=True) pg_institute_name = models.CharField(max_length=100, blank=True, null=True) pg_tier1 = models.NullBooleanField(default=False) pg_passing_year = models.CharField(max_length=10, choices=YEAR_CHOICE, blank=True, null=True) resume = models.FileField(upload_to="resume", blank=True, null=True, default="/media/resume/resume2.pdf" ) #file field to store location of resume profile_photo = models.ImageField( upload_to="profile_photos", default="/static/images/default_profile_picture.png", blank=True, null=True ) #file field to store profile photo #Discourse username of the user address = models.TextField(blank=True, null=True) slug = AutoSlugField(populate_from="name", unique=True) expected_ctc = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True) profile_cover_pic = models.FileField( upload_to="profile_cover_pic", default="/static/images/default_cover_picture.png", blank=True, null=True) #were the rules served to you. Obsolete field #your highest qualification #is UG regular ? #your PG college ? about_me = models.TextField(blank=True, null=True) mail_sent_to_preferred = models.NullBooleanField(null=True, blank=True) ready_to_relocate = models.NullBooleanField(null=True, blank=True) notice_period = models.IntegerField(null=True, blank=True) #mail_to_company = models.NullBooleanField(null=True,blank=True) # is_shortlisted = models.NullBooleanField(blank=True,null=True) # is_rejected = models.NullBooleanField(blank=True,null=True) #mail_sent_to_shortlisted = models.NullBooleanField(blank=True,null=True) # action_by_recruiter = models.CharField(max_length = 20, blank = True, null = True, choices = RECRUITER_ACTION) # action_by_team_leader = models.CharField(max_length = 20, blank = True, null = True, choices = TEAM_LEADER_ACTION) def get_absolute_url(self): return reverse('jobseeker:profile', kwargs={"slug": self.slug}) def get_image_url(self): return self.profile_photo.url def get_resume_url(self): return self.resume.url def __unicode__(self): return self.name
class Project(models.Model): name = models.CharField(max_length=64, blank=False) projecttype = models.ForeignKey('ProjectType', null=True, blank=True, on_delete=models.SET_NULL) start = models.DateField(null=True, blank=True) end = models.DateField(null=True, blank=True) participants = models.ManyToManyField( 'Participant', through='ProjectParticipation', through_fields=["project", "participant"]) companies = models.ManyToManyField('Company', through='ProjectCompany', related_name='projects', through_fields=["project", "company"]) parent = models.ForeignKey('Project', null=True, blank=True, on_delete=models.SET_NULL) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) image = models.ImageField(upload_to=settings.PROJECT_IMAGES, null=True, blank=True) file = models.FileField(upload_to=settings.PROJECT_FILES, null=True, blank=True) tags = TaggableManager(blank=True) #slug = models.SlugField(max_length=31, unique=True, null=True) content = RichTextField(config_name='example', null=True, blank=True) links = GenericRelation(Link) def _save(self, *args, **kwargs): #self.slug = slugify(self.name, allow_unicode=True) return super(Project, self).save(*args, **kwargs) def image_tag(self): return mark_safe('<img src="/media/%s" width="150" height="150" />' % (self.image)) image_tag.short_description = 'Image' def __str__(self): if self.parent: return str(self.parent) + " - " + self.name return self.name def download(self): pass @property def slug(self): return str(self.id) def get_absolute_url(self): return reverse('project-detail', args=[str(self.slug)]) def add_participant(self, participant, role=None, company=None): from kww_app.models import Participant if not isinstance(participant, Participant): return False from kww_app.models import ProjectParticipation prj_participation, created = ProjectParticipation.objects.get_or_create( project=self, participant=participant, role=role, company=company, ) return prj_participation def add_company(self, company): from kww_app.models import Company if not isinstance(company, Company): return False from kww_app.models import ProjectCompany prj_company, created = ProjectCompany.objects.get_or_create( project=self, company=company, ) return prj_company
class CourseRun(TimeStampedModel): """ CourseRun model. """ uuid = models.UUIDField(default=uuid4, editable=False, verbose_name=_('UUID')) course = models.ForeignKey(Course, related_name='course_runs') key = models.CharField(max_length=255, unique=True) status = models.CharField(max_length=255, null=False, blank=False, db_index=True, choices=CourseRunStatus.choices, validators=[CourseRunStatus.validator]) title_override = models.CharField( max_length=255, default=None, null=True, blank=True, help_text= _("Title specific for this run of a course. Leave this value blank to default to the parent course's title." )) start = models.DateTimeField(null=True, blank=True, db_index=True) end = models.DateTimeField(null=True, blank=True, db_index=True) enrollment_start = models.DateTimeField(null=True, blank=True) enrollment_end = models.DateTimeField(null=True, blank=True, db_index=True) announcement = models.DateTimeField(null=True, blank=True) short_description_override = models.CharField( max_length=255, default=None, null=True, blank=True, help_text=_( "Short description specific for this run of a course. Leave this value blank to default to " "the parent course's short_description attribute.")) full_description_override = models.TextField( default=None, null=True, blank=True, help_text=_( "Full description specific for this run of a course. Leave this value blank to default to " "the parent course's full_description attribute.")) staff = SortedManyToManyField(Person, blank=True, related_name='courses_staffed') min_effort = models.PositiveSmallIntegerField( null=True, blank=True, help_text= _('Estimated minimum number of hours per week needed to complete a course run.' )) max_effort = models.PositiveSmallIntegerField( null=True, blank=True, help_text= _('Estimated maximum number of hours per week needed to complete a course run.' )) weeks_to_complete = models.PositiveSmallIntegerField( null=True, blank=True, help_text=_( 'Estimated number of weeks needed to complete this course run.')) language = models.ForeignKey(LanguageTag, null=True, blank=True) transcript_languages = models.ManyToManyField( LanguageTag, blank=True, related_name='transcript_courses') pacing_type = models.CharField(max_length=255, db_index=True, null=True, blank=True, choices=CourseRunPacing.choices, validators=[CourseRunPacing.validator]) syllabus = models.ForeignKey(SyllabusItem, default=None, null=True, blank=True) # TODO Ditch this, and fallback to the course card_image_url = models.URLField(null=True, blank=True) video = models.ForeignKey(Video, default=None, null=True, blank=True) video_translation_languages = models.ManyToManyField(LanguageTag, blank=True, related_name='+') learner_testimonials = models.TextField(blank=True, null=True) slug = models.CharField(max_length=255, blank=True, null=True, db_index=True) hidden = models.BooleanField(default=False) mobile_available = models.BooleanField(default=False) course_overridden = models.BooleanField( default=False, help_text= _('Indicates whether the course relation has been manually overridden.' )) reporting_type = models.CharField(max_length=255, choices=ReportingType.choices, default=ReportingType.mooc) eligible_for_financial_aid = models.BooleanField(default=True) license = models.CharField(max_length=255, blank=True, db_index=True) outcome_override = models.TextField( default=None, blank=True, null=True, help_text=_( "'What You Will Learn' description for this particular course run. Leave this value blank to default " "to the parent course's Outcome attribute.")) tags = TaggableManager( blank=True, help_text= _('Pick a tag from the suggestions. To make a new tag, add a comma after the tag name.' ), ) objects = CourseRunQuerySet.as_manager() def _enrollable_paid_seats(self): """ Return a QuerySet that may be used to fetch the enrollable paid Seats (Seats with price > 0 and no prerequisites) associated with this CourseRun. """ return self.seats.exclude( type__in=Seat.SEATS_WITH_PREREQUISITES).filter(price__gt=0.0) def has_enrollable_paid_seats(self): """ Return a boolean indicating whether or not enrollable paid Seats (Seats with price > 0 and no prerequisites) are available for this CourseRun. """ return len(self._enrollable_paid_seats()[:1]) > 0 def is_current_and_still_upgradeable(self): """ Return true if 1. Today is after the run start (or start is none) and two weeks from the run end (or end is none) 2. The run has a seat that is still enrollable and upgradeable and false otherwise """ now = datetime.datetime.now(pytz.UTC) two_weeks = datetime.timedelta(days=14) after_start = (not self.start) or (self.start and self.start < now) ends_in_more_than_two_weeks = (not self.end) or ( self.end.date() and now.date() <= self.end.date() - two_weeks) if after_start and ends_in_more_than_two_weeks: paid_seat_enrollment_end = self.get_paid_seat_enrollment_end() if paid_seat_enrollment_end and now < paid_seat_enrollment_end: return True return False def get_paid_seat_enrollment_end(self): """ Return the final date for which an unenrolled user may enroll and purchase a paid Seat for this CourseRun, or None if the date is unknown or enrollable paid Seats are not available. """ seats = list( self._enrollable_paid_seats().order_by('-upgrade_deadline')) if len(seats) == 0: # Enrollable paid seats are not available for this CourseRun. return None # An unenrolled user may not enroll and purchase paid seats after the course has ended. deadline = self.end # An unenrolled user may not enroll and purchase paid seats after enrollment has ended. if self.enrollment_end and (deadline is None or self.enrollment_end < deadline): deadline = self.enrollment_end # Note that even though we're sorting in descending order by upgrade_deadline, we will need to look at # both the first and last record in the result set to determine which Seat has the latest upgrade_deadline. # We consider Null values to be > than non-Null values, and Null values may sort to the top or bottom of # the result set, depending on the DB backend. latest_seat = seats[ -1] if seats[-1].upgrade_deadline is None else seats[0] if latest_seat.upgrade_deadline and ( deadline is None or latest_seat.upgrade_deadline < deadline): deadline = latest_seat.upgrade_deadline return deadline def enrollable_seats(self, types=None): """ Returns seats, of the given type(s), that can be enrolled in/purchased. Arguments: types (list of seat type names): Type of seats to limit the returned value to. Returns: List of Seats """ now = datetime.datetime.now(pytz.UTC) enrollable_seats = [] if self.end and now > self.end: return enrollable_seats if self.enrollment_start and self.enrollment_start > now: return enrollable_seats if self.enrollment_end and now > self.enrollment_end: return enrollable_seats types = types or Seat.SEAT_TYPES for seat in self.seats.all(): if seat.type in types and (not seat.upgrade_deadline or now < seat.upgrade_deadline): enrollable_seats.append(seat) return enrollable_seats @property def has_enrollable_seats(self): """ Return a boolean indicating whether or not enrollable Seats are available for this CourseRun. """ return len(self.enrollable_seats()) > 0 @property def image_url(self): return self.course.image_url @property def program_types(self): """ Exclude unpublished and deleted programs from list so we don't identify that program type if not available """ program_statuses_to_exclude = (ProgramStatus.Unpublished, ProgramStatus.Deleted) associated_programs = [] for program in self.programs.exclude( status__in=program_statuses_to_exclude): if self not in program.excluded_course_runs.all(): associated_programs.append(program) return [program.type.name for program in associated_programs] @property def marketing_url(self): if self.slug: path = 'course/{slug}'.format(slug=self.slug) return urljoin(self.course.partner.marketing_site_url_root, path) return None @property def title(self): return self.title_override or self.course.title @title.setter def title(self, value): # Treat empty strings as NULL value = value or None self.title_override = value @property def short_description(self): return self.short_description_override or self.course.short_description @short_description.setter def short_description(self, value): # Treat empty strings as NULL value = value or None self.short_description_override = value @property def full_description(self): return self.full_description_override or self.course.full_description @full_description.setter def full_description(self, value): # Treat empty strings as NULL value = value or None self.full_description_override = value @property def outcome(self): return self.outcome_override or self.course.outcome @outcome.setter def outcome(self, value): # Treat empty strings as NULL value = value or None self.outcome_override = value @property def subjects(self): return self.course.subjects @property def authoring_organizations(self): return self.course.authoring_organizations @property def sponsoring_organizations(self): return self.course.sponsoring_organizations @property def prerequisites(self): return self.course.prerequisites @property def programs(self): return self.course.programs # pylint: disable=no-member @property def seat_types(self): return [seat.type for seat in self.seats.all()] @property def type(self): seat_types = set(self.seat_types) mapping = ( ('credit', {'credit'}), ('professional', {'professional', 'no-id-professional'}), ('verified', {'verified'}), ('honor', {'honor'}), ('audit', {'audit'}), ) for course_run_type, matching_seat_types in mapping: if matching_seat_types & seat_types: return course_run_type logger.debug( 'Unable to determine type for course run [%s]. Seat types are [%s]', self.key, seat_types) return None @property def level_type(self): return self.course.level_type @property def availability(self): now = datetime.datetime.now(pytz.UTC) upcoming_cutoff = now + datetime.timedelta(days=60) if self.end and self.end <= now: return _('Archived') elif self.start and self.end and (self.start <= now < self.end): return _('Current') elif self.start and (now < self.start < upcoming_cutoff): return _('Starting Soon') else: return _('Upcoming') @classmethod def search(cls, query): """ Queries the search index. Args: query (str) -- Elasticsearch querystring (e.g. `title:intro*`) Returns: SearchQuerySet """ query = clean_query(query) return SearchQuerySet().models(cls).raw_search(query).load_all() def __str__(self): return '{key}: {title}'.format(key=self.key, title=self.title) def save(self, *args, **kwargs): suppress_publication = kwargs.pop('suppress_publication', False) is_publishable = ( self.course.partner.has_marketing_site and waffle.switch_is_active('publish_course_runs_to_marketing_site') and # Pop to clean the kwargs for the base class save call below not suppress_publication) if is_publishable: publisher = CourseRunMarketingSitePublisher(self.course.partner) previous_obj = CourseRun.objects.get( id=self.id) if self.id else None if not self.slug: # If we are publishing this object to marketing site, # let's make sure slug is defined self.slug = slugify(self.title) with transaction.atomic(): super(CourseRun, self).save(*args, **kwargs) publisher.publish_obj(self, previous_obj=previous_obj) else: logger.info('Course run [%s] is not publishable.', self.key) super(CourseRun, self).save(*args, **kwargs)
class TagsMixin(models.Model): """ Mixin for adding tags to a model. """ # Make association with tags optional. if TaggableManager is not None: tags = TaggableManager(blank=True) else: tags = None class Meta: abstract = True def similar_objects(self, num=None, **filters): """ Find similar objects using related tags. """ tags = self.tags if not tags: return [] content_type = ContentType.objects.get_for_model(self.__class__) filters['content_type'] = content_type # can't filter, see # - https://github.com/alex/django-taggit/issues/32 # - http://django-taggit.readthedocs.org/en/latest/api.html#TaggableManager.similar_objects # # Otherwise this would be possible: # return tags.similar_objects(**filters) lookup_kwargs = tags._lookup_kwargs() lookup_keys = sorted(lookup_kwargs) qs = tags.through.objects.values(*lookup_kwargs.keys()) qs = qs.annotate(n=models.Count('pk')) qs = qs.exclude(**lookup_kwargs) subq = tags.all() qs = qs.filter(tag__in=list(subq)) qs = qs.order_by('-n') # from https://github.com/alex/django-taggit/issues/32#issuecomment-1002491 if filters is not None: qs = qs.filter(**filters) if num is not None: qs = qs[:num] # Normal taggit code continues # TODO: This all feels like a bit of a hack. items = {} if len(lookup_keys) == 1: # Can we do this without a second query by using a select_related() # somehow? f = tags.through._meta.get_field_by_name(lookup_keys[0])[0] objs = f.rel.to._default_manager.filter(**{ "%s__in" % f.rel.field_name: [r["content_object"] for r in qs] }) for obj in objs: items[(getattr(obj, f.rel.field_name),)] = obj else: preload = {} for result in qs: preload.setdefault(result['content_type'], set()) preload[result["content_type"]].add(result["object_id"]) for ct, obj_ids in preload.items(): ct = ContentType.objects.get_for_id(ct) for obj in ct.model_class()._default_manager.filter(pk__in=obj_ids): items[(ct.pk, obj.pk)] = obj results = [] for result in qs: obj = items[ tuple(result[k] for k in lookup_keys) ] obj.similar_tags = result["n"] results.append(obj) return results
class Content(MP_Node): HASH_LENGTH = 8 TYPE_PAGE = 'page' TYPE_GALLERY = 'gallery' type_choices = ( (TYPE_PAGE, _(u'Page')), (TYPE_GALLERY, _(u'Gallery')), ) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='content_user') tags = TaggableManager(_(u'Tags'), through=PostTaggedItem, blank=True, related_name='content_tags') title = models.CharField(_(u'Title'), max_length=255, default='') url = models.CharField(_(u'Path'), max_length=255, default='', editable=False, db_index=True) slug = models.SlugField(verbose_name=_(u'Slug'), max_length=255, db_index=True) template = models.CharField(_(u'Template'), choices=settings.VCMS_TEMPLATES, max_length=100, default='content_view') meta_keywords = models.CharField(_(u'Meta keywords'), max_length=255, default='', blank=True) meta_description = models.CharField(_(u'Meta description'), max_length=255, default='', blank=True) enabled = models.BooleanField(_(u'Enabled'), default=True, db_index=True) hidden = models.BooleanField(_(u'Is hidden'), default=False, db_index=True) category = models.ManyToManyField(Category, verbose_name=_(u'Category'), blank=True) type = models.CharField(max_length=64, choices=type_choices, db_index=True, default=TYPE_PAGE) image = models.ImageField(upload_to='content/%Y/%m/%d', blank=True) date_published = models.DateField(_(u'Date published'), default=timezone.now, db_index=True) content = RichTextUploadingField(_(u'Content'), blank=True) comments = models.BooleanField(_(u'Allow comments'), default=False) language = models.CharField(_(u'Language'), choices=settings.LANGUAGES, default=settings.LANGUAGE_CODE, max_length=5) json = models.JSONField(_(u'Json content'), default={}, editable=False) rating = models.IntegerField(_(u'Rating'), default=0) show_count = models.IntegerField(_(u'Show count'), default=0) view_count = models.IntegerField(_(u'View count'), default=0) node_order_by = ['date_published'] class Meta: verbose_name = _(u'Content') verbose_name_plural = _(u'Content') def __str__(self): return self.title def allow_comment(self): return self.comments @property def hash(self): return id_to_hash(self.id, length=self.HASH_LENGTH) @property def parent(self): return 1 @property def short_content(self): result = re.findall(r"(?si)<p>(.*?)<\/p>", self.content) try: return result[0] except Exception as e: # print(re.sub('<[^<]+?>', '', self.content)) return '' @property def long_content(self): return self.content def get_upload_path(self, filename): return 'content/%s/%s' % (datetime.now().strftime("%Y/%m"), filename) def __unique_slug(self, slug, my_id, counter=1): counter += 1 gen_slug = "%s-%s" % (slug, counter) exists = self._default_manager.filter(slug=gen_slug).exclude(id=my_id) if exists: return self.__unique_slug(slug, my_id, counter) else: return gen_slug def update_url(self): url = self.slug parent = self.get_parent(update=True) if parent: url = "%s/%s" % (parent.url, self.slug) if self.url != url: Content.objects.filter(id=self.pk).update(url=url) children = self.get_children() for child in children: child.update_url() def save(self, *args, **kwargs): update_slug = False if self.pk is not None: old = Content.objects.get(pk=self.pk) if old.slug != self.slug: update_slug = True else: update_slug = True if update_slug is True: self.slug = unique_slug( Content, 'slug', self.slug, query={'type': self.type} # Content, 'slug', self.slug, query={'parent': self.parent, 'type': self.type} ) super(Content, self).save(*args, **kwargs) if update_slug is True: self.update_url() def reverse(self): if self.language == settings.LANGUAGE_CODE: prefix = '' else: prefix = '/%s' % self.language return prefix + reverse('content_page', args=[self.url])
class Image(models.Model): user = models.ForeignKey(User) gallery = models.ForeignKey(Gallery, related_name="images") uploaded = models.DateTimeField(auto_now_add=True) title = models.CharField(max_length=256, null=True, blank=True) tags = TaggableManager(blank=True) uuid = ShortUUIDField(db_index=True) original = models.ImageField(upload_to=set_image_name_on_upload, ) _view_mapping = { "view.3d.180": "view_3d_180", "view.3d": "view_3d_360", "view.3d.360": "view_3d_360", "view.3d.sphere": "view_3d_360", "view.sphere": "view_3d_360", "view.pano": "view_2d_pano", "view.pan": "view_2d_pano", "view.panorama": "view_2d_pano", "view.panoramic": "view_2d_pano", } view_flags = BitField(flags=( ('view_3d_180', '180 Degrees 3D'), ('view_3d_360', '360 Degrees 3D'), ('view_2d_pano', 'Panoramic'), ), null=True) # for multiple tags we use the first view_default = models.CharField(max_length=32, null=True, blank=True) def self_uuid(self): return self.uuid full_fixed = ImageSpecField( source="original", processors=[Transpose()], format="JPEG", ) bigger = ImageSpecField( source="full_fixed", processors=[ResizeToCover(1440, 1080, upscale=False)], format="JPEG", options={ 'quality': 80, 'prefix': "b" }) default = ImageSpecField( source="full_fixed", processors=[ResizeToCover(720, 540, upscale=False)], format="JPEG", options={ 'quality': 80, 'prefix': "d" }) preview = ImageSpecField(source="full_fixed", processors=[SmartResize(320, 240)], format="JPEG", options={ 'quality': 80, 'prefix': "p" }) thumb = ImageSpecField( source="full_fixed", processors=[SmartResize(160, 120)], format="JPEG", options={ 'quality': 60, 'prefix': "t" }, ) tiny_thumb = ImageSpecField( source="full_fixed", processors=[SmartResize(80, 60)], format="JPEG", options={ 'quality': 40, 'prefix': "tt" }, ) AVAIL_SIZES = [ "full_fixed", "bigger", "default", "preview", "thumb", "tiny_thumb" ] AVAIL_INTS = [0, 1, 2, 3, 4, 5] exif_data = models.ManyToManyField("EXIFEntry", blank=True) exif_timestamp = models.DateTimeField(null=True, blank=True) @property def uuid_as_b64(self): return base64.b64encode(self.uuid) def query_exif(self, only_when_empty=True, do_empty=False): image = IMG.open(self.original) if do_empty: self.exif_data.clear() if only_when_empty: do = not self.exif_data.exists() else: do = True if do: try: exif_raw = image._getexif() except: # no usable exif return # I guess this deals with the compactness, so it needs to be decoded? if exif_raw: exif_decoded = { TAGS.get(k): v for k, v in exif_raw.iteritems() } out = [] for key, value in exif_decoded.iteritems(): ek, ck = ExifKey.objects.get_or_create(key=key) ev, cv = ExifValue.objects.get_or_create(value=value) ee, ce = EXIFEntry.objects.get_or_create(key=ek, value=ev) self.exif_data.add(ee) if key == "DateTime": value_stf = datetime.strptime(value, "%Y:%m:%d %H:%M:%S") self.exif_timestamp = value_stf self.save() else: pass # no exif def cached_full_fixed(self): generator = ImageCacheFile(self.full_fixed) return generator.generate() def cached_bigger(self): generator = ImageCacheFile(self.bigger) return generator.generate() def cached_default(self): generator = ImageCacheFile(self.default) return generator.generate() def cached_preview(self): generator = ImageCacheFile(self.preview) return generator.generate() def cached_thumb(self): generator = ImageCacheFile(self.thumb) return generator.generate() def cached_tiny_thumb(self): generator = ImageCacheFile(self.tiny_thumb) return generator.generate() def get_next_by_gallery_ordering(self): gallery = self.gallery gallery_sort = gallery.display_sort_string if gallery_sort == ['uploaded']: try: return self.get_next_by_uploaded(gallery=gallery) except: return None if gallery_sort == ['-uploaded']: try: return self.get_previous_by_uploaded(gallery=gallery) except: return None # todo add EXIF based sorting def get_prev_by_gallery_ordering(self): gallery = self.gallery gallery_sort = gallery.display_sort_string if gallery_sort == ['uploaded']: try: return self.get_previous_by_uploaded(gallery=gallery) except: return None if gallery_sort == ['-uploaded']: try: return self.get_next_by_uploaded(gallery=gallery) except: return None
class Post(TranslatableModel): """ Blog post """ author = models.ForeignKey(User, verbose_name=_('Author'), null=True, blank=True) date_created = models.DateTimeField(auto_now_add=True) date_modified = models.DateTimeField(auto_now=True) date_published = models.DateTimeField(_('Published Since'), default=timezone.now) date_published_end = models.DateTimeField(_('Published Until'), null=True, blank=True) publish = models.BooleanField(_('Publish'), default=False) categories = models.ManyToManyField(BlogCategory, verbose_name=_('category'), related_name='blog_posts',) main_image = FilerImageField(verbose_name=_('Main image'), blank=True, null=True) main_image_thumbnail = models.ForeignKey(ThumbnailOption, verbose_name=_('Main image thumbnail'), related_name='blog_post_thumbnail', blank=True, null=True) main_image_full = models.ForeignKey(ThumbnailOption, verbose_name=_('Main image full'), related_name='blog_post_full', blank=True, null=True) translations = TranslatedFields( title=models.CharField(_('Title'), max_length=255), slug=models.SlugField(_('slug'), blank=True, db_index=True), abstract=HTMLField(_('Text')), meta={'unique_together': (('language_code', 'slug'),)} ) content = PlaceholderField("post_content") objects = GenericDateTaggedManager() tags = TaggableManager(blank=True) class Meta: verbose_name = _('blog article') verbose_name_plural = _('blog articles') ordering = ("-date_published", "-date_created") def __unicode__(self): return self.safe_translation_getter('title') def save(self, *args, **kwargs): super(Post, self).save(*args, **kwargs) for lang in self.get_available_languages(): self.set_current_language(lang) if not self.slug and self.title: self.slug = slugify(self.title) self.save_translations() def get_absolute_url(self): kwargs = {'year': self.date_published.year, 'month': self.date_published.month, 'day': self.date_published.day, 'slug': self.slug} return reverse('djangocms_blog:post-detail', kwargs=kwargs) def thumbnail_options(self): if self.main_image_thumbnail_id: return self.main_image_thumbnail.as_dict else: return settings.BLOG_IMAGE_THUMBNAIL_SIZE def get_full_url(self): s = Site.objects.get_current() if s.domain.find('http') > -1: return "%s%s" % (s.domain, self.get_absolute_url()) else: return "http://%s%s" % (s.domain, self.get_absolute_url()) def full_image_options(self): if self.main_image_fulll_id: return self.main_image_full.as_dict else: return settings.BLOG_IMAGE_FULL_SIZE
class Ticket(models.Model): """ To allow a ticket to be entered as quickly as possible, only the bare minimum fields are required. These basically allow us to sort and manage the ticket. The user can always go back and enter more information later. A good example of this is when a customer is on the phone, and you want to give them a ticket ID as quickly as possible. You can enter some basic info, save the ticket, give the customer the ID and get off the phone, then add in further detail at a later time (once the customer is not on the line). Note that assigned_to is optional - unassigned tickets are displayed on the dashboard to prompt users to take ownership of them. """ OPEN_STATUS = 1 REOPENED_STATUS = 2 RESOLVED_STATUS = 3 CLOSED_STATUS = 4 DUPLICATE_STATUS = 5 STATUS_CHOICES = ( (OPEN_STATUS, _('Open')), (REOPENED_STATUS, _('Reopened')), (RESOLVED_STATUS, _('Resolved')), (CLOSED_STATUS, _('Closed')), (DUPLICATE_STATUS, _('Duplicate')), ) PRIORITY_CHOICES = ( (1, _('1. Critical')), (2, _('2. High')), (3, _('3. Normal')), (4, _('4. Low')), (5, _('5. Very Low')), ) title = models.CharField( _('Title'), max_length=200, ) queue = models.ForeignKey( Queue, verbose_name=_('Queue'), ) created = models.DateTimeField( _('Created'), blank=True, help_text=_('Date this ticket was first created'), ) modified = models.DateTimeField( _('Modified'), blank=True, help_text=_('Date this ticket was most recently changed.'), ) submitter_email = models.EmailField( _('Submitter E-Mail'), blank=True, null=True, help_text=_('The submitter will receive an email for all public ' 'follow-ups left for this task.'), ) assigned_to = models.ForeignKey( User, related_name='assigned_to', blank=True, null=True, verbose_name=_('Assigned to'), limit_choices_to={'is_staff': True} if HELPDESK_STAFF_ONLY_TICKET_OWNERS else None, ) status = models.IntegerField( _('Status'), choices=STATUS_CHOICES, default=OPEN_STATUS, ) on_hold = models.BooleanField( _('On Hold'), blank=True, default=False, help_text=_('If a ticket is on hold, it will not automatically be ' 'escalated.'), ) description = models.TextField( _('Description'), blank=True, null=True, help_text=_('The content of the customers query.'), ) resolution = models.TextField( _('Resolution'), blank=True, null=True, help_text=_('The resolution provided to the customer by our staff.'), ) priority = models.IntegerField( _('Priority'), choices=PRIORITY_CHOICES, default=3, blank=3, help_text=_('1 = Highest Priority, 5 = Low Priority'), ) due_date = models.DateTimeField( _('Due on'), blank=True, null=True, ) last_escalation = models.DateTimeField( blank=True, null=True, editable=False, help_text=_( 'The date this ticket was last escalated - updated ' 'automatically by management/commands/escalate_tickets.py.'), ) def _get_assigned_to(self): """ Custom property to allow us to easily print 'Unassigned' if a ticket has no owner, or the users name if it's assigned. If the user has a full name configured, we use that, otherwise their username. """ if not self.assigned_to: return _('Unassigned') else: if self.assigned_to.get_full_name(): return self.assigned_to.get_full_name() else: return self.assigned_to.username get_assigned_to = property(_get_assigned_to) def _get_ticket(self): """ A user-friendly ticket ID, which is a combination of ticket ID and queue slug. This is generally used in e-mail subjects. """ return u"[%s]" % (self.ticket_for_url) ticket = property(_get_ticket) def _get_ticket_for_url(self): """ A URL-friendly ticket ID, used in links. """ return u"%s-%s" % (self.queue.slug, self.id) ticket_for_url = property(_get_ticket_for_url) def _get_priority_img(self): """ Image-based representation of the priority """ from django.conf import settings return u"%shelpdesk/priorities/priority%s.png" % (settings.MEDIA_URL, self.priority) get_priority_img = property(_get_priority_img) def _get_priority_span(self): """ A HTML <span> providing a CSS_styled representation of the priority. """ from django.utils.safestring import mark_safe return mark_safe(u"<span class='priority%s'>%s</span>" % (self.priority, self.priority)) get_priority_span = property(_get_priority_span) def _get_status(self): """ Displays the ticket status, with an "On Hold" message if needed. """ held_msg = '' if self.on_hold: held_msg = _(' - On Hold') return u'%s%s' % (self.get_status_display(), held_msg) get_status = property(_get_status) def _get_ticket_url(self): """ Returns a publicly-viewable URL for this ticket, used when giving a URL to the submitter of a ticket. """ from django.contrib.sites.models import Site from django.core.urlresolvers import reverse site = Site.objects.get_current() return u"http://%s%s?ticket=%s&email=%s" % ( site.domain, reverse('helpdesk_public_view'), self.ticket_for_url, self.submitter_email) ticket_url = property(_get_ticket_url) def _get_staff_url(self): """ Returns a staff-only URL for this ticket, used when giving a URL to a staff member (in emails etc) """ from django.contrib.sites.models import Site from django.core.urlresolvers import reverse site = Site.objects.get_current() return u"http://%s%s" % (site.domain, reverse('helpdesk_view', args=[self.id])) staff_url = property(_get_staff_url) def _can_be_resolved(self): """ Returns a boolean. True = any dependencies are resolved False = There are non-resolved dependencies """ OPEN_STATUSES = (Ticket.OPEN_STATUS, Ticket.REOPENED_STATUS) return TicketDependency.objects.filter(ticket=self).filter( depends_on__status__in=OPEN_STATUSES).count() == 0 can_be_resolved = property(_can_be_resolved) if HAS_TAGGING_SUPPORT: tags = TagField(blank=True) elif HAS_TAGGIT_SUPPORT: tags = TaggableManager(blank=True) class Meta: get_latest_by = "created" def __unicode__(self): return u'%s' % self.title def get_absolute_url(self): return ('helpdesk_view', (self.id, )) get_absolute_url = models.permalink(get_absolute_url) def save(self, *args, **kwargs): if not self.id: # This is a new ticket as no ID yet exists. self.created = datetime.now() if not self.priority: self.priority = 3 self.modified = datetime.now() super(Ticket, self).save(*args, **kwargs)
class Proposal(ProposalBase): BASIC_LEVEL, INTERMEDIATE_LEVEL, ADVANCED_LEVEL = "basic", "intermediate", "advanced" PROPOSAL_LEVELS = ( (BASIC_LEVEL, _("Básico")), (INTERMEDIATE_LEVEL, _("Intermedio")), (ADVANCED_LEVEL, _("Avanzado")), ) PROPOSAL_LANGUAGES = ( ("es", _("Español")), ("en", _("Inglés")), ) PROPOSAL_DURATIONS = ( (15, _("15 minutos")), (30, _("30 minutos")), ) audience_level = models.CharField(verbose_name=_("Nivel de la audiencia"), choices=PROPOSAL_LEVELS, null=True, default=BASIC_LEVEL, max_length=32) language = models.CharField(verbose_name=_("Idioma"), max_length=2, choices=PROPOSAL_LANGUAGES, default="es") duration = models.PositiveIntegerField(verbose_name=_("Duración"), choices=PROPOSAL_DURATIONS, default=30, null=True, blank=True) tags = TaggableManager( verbose_name=_("Etiquetas"), help_text=_("Lista de etiquetas separadas por comas."), blank=True) @property def avg_property(self): return self.avg() @property def completed_reviews_property(self): return self.reviews.filter(finished=True).count() @property def assigned_reviews_property(self): return self.reviews.count() @property def tag_list_property(self): return u", ".join(tag.name for tag in self.tags.all()) @property def renormalization_O0_property(self): return self.renormalization_O0() @property def renormalization_O1_property(self): return self.renormalization_O1() def avg(self): data = [ review.avg() for review in self.reviews.filter(finished=True) if review.avg() is not None ] if data: return sum(data) / len(data) return None def renormalization_O0(self): """Renormalization with order 0. Average value of 0""" relevance, interest, newness = [], [], [] for review in self.reviews.all(): reviewer = Reviewer.objects.get(user=review.user) mean = reviewer.mean() if reviewer.num_reviews() <= 1: continue relevance.append((review.relevance or 0) - mean) interest.append((review.interest or 0) - mean) newness.append((review.newness or 0) - mean) return np.mean(interest + relevance + newness) def renormalization_O1(self): """Renormalization with order 1. Expand the value to get the same standard deviation for everyone""" relevance, interest, newness = [], [], [] for review in self.reviews.all(): reviewer = Reviewer.objects.get(user=review.user) std = reviewer.std() if reviewer.num_reviews() <= 1 or std < 0.75: continue relevance.append((review.relevance or 0) - std) interest.append((review.interest or 0) - std) newness.append((review.newness or 0) - std) return np.mean(interest + relevance + newness)
class Article(TranslatableModel, PublishingModel, SpaceaweModel, SearchModel): uuid = models.UUIDField(primary_key=False, default=uuid.uuid4, editable=False) code = models.CharField( max_length=4, blank=False, db_index=True, help_text= 'The 4 digit code that identifies the Article, in the format "YY##": year, folowed by sequential number.' ) categories = models.ManyToManyField( Category, blank=True, related_name='articles', limit_choices_to={'translations__language_code': 'en'}) original_news = models.ManyToManyField( Institution, through='OriginalNews', related_name='scoops', ) objects = ArticleManager() tags = TaggableManager(blank=True) @property def main_visual(self): result = None images = self.images.all() if images: result = images[0].file return result @property def translated_credit(self): result = '' if self.translation_credit_text and self.translation_credit_url: result = '<a href="%s">%s</a>' % (self.translation_credit_url, self.translation_credit_text) elif self.translation_credit_text: result = self.translation_credit_text elif self.translation_credit_url: result = '<a href="%s">%s</a>' % (self.translation_credit_url, self.translation_credit_url) return result # def get_absolute_url_full(self): # return utils.get_qualified_url(self.get_absolute_url()) # def download_url(self, resource): # return os.path.join(settings.MEDIA_URL, self.media_key(), 'download', self.download_key() + '.' + resource) # def download_path(self, resource): # return os.path.join(settings.MEDIA_ROOT, self.media_key(), 'download', self.download_key() + '.' + resource) def story_expanded(self): result = self.story for entry in self._get_glossary_entries()[0]: search_text = r'<glossary slug="%s">(.*?)</glossary>' % entry.slug replace_text = '<a class="glossary" href="/glossary/%s" title="%s">\\1</a>' % ( entry.slug, entry.short_description, ) result = re.sub(search_text, replace_text, result) return result # return re.sub(r'<glossary slug="(.*?)">(.*?)</glossary>', '<a class="glossary" href="/glossary/\\1" title="Hooray!">\\2</a>', self.story) #TODO: cache the result def _get_glossary_entries(self): present = [] missing = [] for slug in re.findall(r'<glossary slug="(.*?)">.*?</glossary>', self.story): entries = GlossaryEntry.objects.filter( # translations__language_code__in=get_active_language_choices(), translations__language_code=self.language_code, translations__slug=slug) if entries: present.append(entries[0]) else: missing.append(slug) return (present, missing) # #TODO: cache the result # def _get_glossary_entries(self): # present = [] # missing = [] # for code in re.findall(r'<glossary code="(.*?)">.*?</glossary>', self.story): # entries = GlossaryEntry.objects.filter(code=code) # if entries: # present.append(entries[0]) # else: # missing.append(code) # return (present, missing) def get_glossary_entries(self): return self._get_glossary_entries()[0] def get_glossary_entries_missing(self): return self._get_glossary_entries()[1] def is_translation_fallback(self): return not self.has_translation(self.language_code) @classmethod def add_prefetch_related(self, qs, prefix=""): # add _after_ qs.filter! see django docs on prefetch_related if prefix: prefix += '__' qs = qs.prefetch_related('%stranslations' % prefix) qs = qs.prefetch_related('%scategories' % prefix) qs = qs.prefetch_related('%scategories__translations' % prefix) qs = qs.prefetch_related('%simages' % prefix) return qs def __str__(self): return self.code + ': ' + self.title def get_absolute_url(self): if settings.SHORT_NAME == 'unawe2': return reverse('news:spacescoops-detail', kwargs={ 'code': self.code, 'slug': self.slug, }) else: return reverse('scoops:detail', kwargs={ 'code': self.code, 'slug': self.slug, }) class Meta(PublishingModel.Meta): verbose_name = 'space scoop'
class CourseRun(TimeStampedModel): """ CourseRun model. """ uuid = models.UUIDField(default=uuid4, editable=False, verbose_name=_('UUID')) course = models.ForeignKey(Course, related_name='course_runs') key = models.CharField(max_length=255, unique=True) status = models.CharField(max_length=255, null=False, blank=False, db_index=True, choices=CourseRunStatus.choices, validators=[CourseRunStatus.validator]) title_override = models.CharField( max_length=255, default=None, null=True, blank=True, help_text= _("Title specific for this run of a course. Leave this value blank to default to the parent course's title." )) start = models.DateTimeField(null=True, blank=True, db_index=True) end = models.DateTimeField(null=True, blank=True, db_index=True) enrollment_start = models.DateTimeField(null=True, blank=True) enrollment_end = models.DateTimeField(null=True, blank=True, db_index=True) announcement = models.DateTimeField(null=True, blank=True) short_description_override = models.CharField( max_length=255, default=None, null=True, blank=True, help_text=_( "Short description specific for this run of a course. Leave this value blank to default to " "the parent course's short_description attribute.")) full_description_override = models.TextField( default=None, null=True, blank=True, help_text=_( "Full description specific for this run of a course. Leave this value blank to default to " "the parent course's full_description attribute.")) staff = SortedManyToManyField(Person, blank=True, related_name='courses_staffed') min_effort = models.PositiveSmallIntegerField( null=True, blank=True, help_text= _('Estimated minimum number of hours per week needed to complete a course run.' )) max_effort = models.PositiveSmallIntegerField( null=True, blank=True, help_text= _('Estimated maximum number of hours per week needed to complete a course run.' )) weeks_to_complete = models.PositiveSmallIntegerField( null=True, blank=True, help_text=_( 'Estimated number of weeks needed to complete this course run.')) language = models.ForeignKey(LanguageTag, null=True, blank=True) transcript_languages = models.ManyToManyField( LanguageTag, blank=True, related_name='transcript_courses') pacing_type = models.CharField(max_length=255, db_index=True, null=True, blank=True, choices=CourseRunPacing.choices, validators=[CourseRunPacing.validator]) syllabus = models.ForeignKey(SyllabusItem, default=None, null=True, blank=True) card_image_url = models.URLField(null=True, blank=True) video = models.ForeignKey(Video, default=None, null=True, blank=True) slug = models.CharField(max_length=255, blank=True, null=True, db_index=True) hidden = models.BooleanField(default=False) mobile_available = models.BooleanField(default=False) course_overridden = models.BooleanField( default=False, help_text= _('Indicates whether the course relation has been manually overridden.' )) reporting_type = models.CharField(max_length=255, choices=ReportingType.choices, default=ReportingType.mooc) tags = TaggableManager( blank=True, help_text= _('Pick a tag from the suggestions. To make a new tag, add a comma after the tag name.' ), ) objects = CourseRunQuerySet.as_manager() def _enrollable_paid_seats(self): """ Return a QuerySet that may be used to fetch the enrollable paid Seats (Seats with price > 0 and no prerequisites) associated with this CourseRun. """ return self.seats.exclude( type__in=Seat.SEATS_WITH_PREREQUISITES).filter(price__gt=0.0) def has_enrollable_paid_seats(self): """ Return a boolean indicating whether or not enrollable paid Seats (Seats with price > 0 and no prerequisites) are available for this CourseRun. """ return len(self._enrollable_paid_seats()[:1]) > 0 def get_paid_seat_enrollment_end(self): """ Return the final date for which an unenrolled user may enroll and purchase a paid Seat for this CourseRun, or None if the date is unknown or enrollable paid Seats are not available. """ seats = list( self._enrollable_paid_seats().order_by('-upgrade_deadline')) if len(seats) == 0: # Enrollable paid seats are not available for this CourseRun. return None # An unenrolled user may not enroll and purchase paid seats after the course has ended. deadline = self.end # An unenrolled user may not enroll and purchase paid seats after enrollment has ended. if self.enrollment_end and (deadline is None or self.enrollment_end < deadline): deadline = self.enrollment_end # Note that even though we're sorting in descending order by upgrade_deadline, we will need to look at # both the first and last record in the result set to determine which Seat has the latest upgrade_deadline. # We consider Null values to be > than non-Null values, and Null values may sort to the top or bottom of # the result set, depending on the DB backend. latest_seat = seats[ -1] if seats[-1].upgrade_deadline is None else seats[0] if latest_seat.upgrade_deadline and ( deadline is None or latest_seat.upgrade_deadline < deadline): deadline = latest_seat.upgrade_deadline return deadline @property def program_types(self): """ Exclude unpublished and deleted programs from list so we don't identify that program type if not available """ program_statuses_to_exclude = (ProgramStatus.Unpublished, ProgramStatus.Deleted) associated_programs = [] for program in self.programs.exclude( status__in=program_statuses_to_exclude): if self not in program.excluded_course_runs.all(): associated_programs.append(program) return [program.type.name for program in associated_programs] @property def marketing_url(self): if self.slug: path = 'course/{slug}'.format(slug=self.slug) return urljoin(self.course.partner.marketing_site_url_root, path) return None @property def title(self): return self.title_override or self.course.title @title.setter def title(self, value): # Treat empty strings as NULL value = value or None self.title_override = value @property def short_description(self): return self.short_description_override or self.course.short_description @short_description.setter def short_description(self, value): # Treat empty strings as NULL value = value or None self.short_description_override = value @property def full_description(self): return self.full_description_override or self.course.full_description @full_description.setter def full_description(self, value): # Treat empty strings as NULL value = value or None self.full_description_override = value @property def subjects(self): return self.course.subjects @property def authoring_organizations(self): return self.course.authoring_organizations @property def sponsoring_organizations(self): return self.course.sponsoring_organizations @property def prerequisites(self): return self.course.prerequisites @property def programs(self): return self.course.programs # pylint: disable=no-member @property def seat_types(self): return [seat.type for seat in self.seats.all()] @property def type(self): seat_types = set(self.seat_types) mapping = ( ('credit', {'credit'}), ('professional', {'professional', 'no-id-professional'}), ('verified', {'verified'}), ('honor', {'honor'}), ('audit', {'audit'}), ) for course_run_type, matching_seat_types in mapping: if matching_seat_types & seat_types: return course_run_type logger.debug( 'Unable to determine type for course run [%s]. Seat types are [%s]', self.key, seat_types) return None @property def level_type(self): return self.course.level_type @property def availability(self): now = datetime.datetime.now(pytz.UTC) upcoming_cutoff = now + datetime.timedelta(days=60) if self.end and self.end <= now: return _('Archived') elif self.start and self.end and (self.start <= now < self.end): return _('Current') elif self.start and (now < self.start < upcoming_cutoff): return _('Starting Soon') else: return _('Upcoming') @classmethod def search(cls, query): """ Queries the search index. Args: query (str) -- Elasticsearch querystring (e.g. `title:intro*`) Returns: SearchQuerySet """ query = clean_query(query) return SearchQuerySet().models(cls).raw_search(query).load_all() def __str__(self): return '{key}: {title}'.format(key=self.key, title=self.title)
class Entry(Trazabilidad): LIVE_STATUS = 1 DRAFT_STATUS = 2 HIDDEN_STATUS = 3 STATUS_CHOICES = ( (LIVE_STATUS, 'Live'), (DRAFT_STATUS, 'Draft'), (HIDDEN_STATUS, 'Hidden'), ) # Campos principales title = models.CharField('Título', max_length=250) summary = models.TextField('Resumen', blank=True) body = DraceditorField('Contenido') extend = models.TextField('Extendido', blank=True) pub_date = models.DateTimeField(default=datetime.datetime.now) # Campos para generar el html generado con markdown summary_html = models.TextField(editable=False, blank=True) body_html = models.TextField(editable=False, blank=True) extend_html = models.TextField(editable=False, blank=True) # Metadata enable_comments = models.BooleanField(default=True) cover = models.URLField(blank=True) slug = models.SlugField(unique_for_date='pub_date') status = models.IntegerField(choices=STATUS_CHOICES, default=LIVE_STATUS) featured = models.BooleanField(default=False) # Taxonomía category = models.ForeignKey(Category) tags = TaggableManager() # Seguimiento autor = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='entradas', editable=False) class Meta: verbose_name_plural = 'Entradas' verbose_name = 'Entrada' ordering = ['-id', '-pub_date'] unique_together = ('slug', 'category') get_latest_by = 'pub_date' def __str__(self): return self.title def save(self, force_insert=False, force_update=False, **kwargs): from django.core.cache import cache self.body_html = markdown.markdown(self.body, output_format='html5', lazy_ol=True, extensions=MD_EXT) if self.summary: self.summary_html = markdown.markdown(self.summary, output_format='html5', lazy_ol=True, extensions=MD_EXT) if self.extend: self.extend_html = markdown.markdown(self.extend, output_format='html5', lazy_ol=True, extensions=MD_EXT) cache.clear() super(Entry, self).save(force_insert, force_update) def resumen(self): if self.summary: return safe(striptags(self.summary)) else: return safe(striptags(truncatechars_html(self.body_html, 250))) def get_absolute_url(self): return reverse('entry_detail', kwargs={ 'cat': self.category.slug, 'slug': self.slug }) def get_tags(self): tags = [] for tag in self.tags.all(): tags.append(str(tag)) return tags def get_status(self): return self.status def get_autor(self): return self.autor def siguiente(self): try: return self.get_next_by_pub_date() except self.DoesNotExist: return None def anterior(self): try: return self.get_previous_by_pub_date() except self.DoesNotExist: return None
class Post(KnockerModel, BlogMetaMixin, TranslatableModel): """ Blog post """ author = models.ForeignKey( dj_settings.AUTH_USER_MODEL, verbose_name=_("author"), null=True, blank=True, related_name="djangocms_blog_post_author", on_delete=models.PROTECT, ) date_created = models.DateTimeField(_("created"), auto_now_add=True) date_modified = models.DateTimeField(_("last modified"), auto_now=True) date_published = models.DateTimeField(_("published since"), null=True, blank=True) date_published_end = models.DateTimeField(_("published until"), null=True, blank=True) date_featured = models.DateTimeField(_("featured date"), null=True, blank=True) categories = models.ManyToManyField("djangocms_blog.BlogCategory", verbose_name=_("category"), related_name="blog_posts", blank=True) enable_comments = models.BooleanField( verbose_name=_("enable comments on post"), default=get_setting("ENABLE_COMMENTS")) sites = models.ManyToManyField( "sites.Site", verbose_name=_("Site(s)"), blank=True, help_text=_("Select sites in which to show the post. " "If none is set it will be " "visible in all the configured sites."), ) app_config = AppHookConfigField(BlogConfig, null=True, verbose_name=_("app. config")) translations = TranslatedFields( title=models.CharField(_("title"), max_length=752), slug=models.SlugField(_("slug"), max_length=752, blank=True, db_index=True, allow_unicode=True), subtitle=models.CharField(verbose_name=_("subtitle"), max_length=767, blank=True, default=""), abstract=HTMLField(_("abstract"), blank=True, default="", configuration="BLOG_ABSTRACT_CKEDITOR"), main_image=FilerImageField( verbose_name=_("main image"), blank=True, null=True, on_delete=models.SET_NULL, related_name="djangocms_blog_post_image", ), main_image_thumbnail=models.ForeignKey( thumbnail_model, verbose_name=_("main image thumbnail"), related_name="djangocms_blog_post_thumbnail", on_delete=models.SET_NULL, blank=True, null=True, ), main_image_full=models.ForeignKey( thumbnail_model, verbose_name=_("main image full"), related_name="djangocms_blog_post_full", on_delete=models.SET_NULL, blank=True, null=True, ), meta_description=models.TextField( verbose_name=_("post meta description"), blank=True, default=""), meta_keywords=models.TextField(verbose_name=_("post meta keywords"), blank=True, default=""), meta_title=models.CharField( verbose_name=_("post meta title"), help_text=_("used in title tag and social sharing"), max_length=2000, blank=True, default="", ), post_text=HTMLField(_("text"), default="", blank=True, configuration="BLOG_POST_TEXT_CKEDITOR"), meta={"unique_together": (("language_code", "slug"), )}, is_publish=models.BooleanField(_('publish'), default=False), ) media = PlaceholderField("media", related_name="media") content = PlaceholderField("post_content", related_name="post_content") liveblog = PlaceholderField("live_blog", related_name="live_blog") enable_liveblog = models.BooleanField( verbose_name=_("enable liveblog on post"), default=False) objects = GenericDateTaggedManager() tags = TaggableManager(blank=True, related_name="djangocms_blog_tags") related = SortedManyToManyField("self", verbose_name=_("Related Posts"), blank=True, symmetrical=False) _metadata = { "title": "get_title", "description": "get_description", "keywords": "get_keywords", "og_description": "get_description", "twitter_description": "get_description", "gplus_description": "get_description", "locale": "get_locale", "image": "get_image_full_url", "image_width": "get_image_width", "image_height": "get_image_height", "object_type": "get_meta_attribute", "og_type": "get_meta_attribute", "og_app_id": "get_meta_attribute", "og_profile_id": "get_meta_attribute", "og_publisher": "get_meta_attribute", "og_author_url": "get_meta_attribute", "og_author": "get_meta_attribute", "twitter_type": "get_meta_attribute", "twitter_site": "get_meta_attribute", "twitter_author": "get_meta_attribute", "gplus_type": "get_meta_attribute", "gplus_author": "get_meta_attribute", "published_time": "date_published", "modified_time": "date_modified", "expiration_time": "date_published_end", "tag": "get_tags", "url": "get_absolute_url", } class Meta: verbose_name = _("blog article") verbose_name_plural = _("blog articles") ordering = ("-date_published", "-date_created") get_latest_by = "date_published" def __str__(self): default = gettext("Post (no translation)") return self.safe_translation_getter("title", any_language=True, default=default) @property def guid(self, language=None): if not language: language = self.get_current_language() base_string = "-{0}-{2}-{1}-".format( language, self.app_config.namespace, self.safe_translation_getter("slug", language_code=language, any_language=True), ) return hashlib.sha256(force_bytes(base_string)).hexdigest() @property def date(self): if self.date_featured: return self.date_featured return self.date_published def save(self, *args, **kwargs): """ Handle some auto configuration during save """ if self.safe_translation_getter( "is_publish") and self.date_published is None: self.date_published = timezone.now() if not self.slug and self.title: self.slug = slugify(self.title) super().save(*args, **kwargs) def save_translation(self, translation, *args, **kwargs): """ Handle some auto configuration during save """ if not translation.slug and translation.title: translation.slug = slugify(translation.title) super().save_translation(translation, *args, **kwargs) def get_absolute_url(self, lang=None): lang = _get_language(self, lang) with switch_language(self, lang): category = self.categories.first() kwargs = {} if self.date_published: current_date = self.date_published else: current_date = self.date_created urlconf = get_setting("PERMALINK_URLS")[ self.app_config.url_patterns] if "<year>" in urlconf: kwargs["year"] = current_date.year if "<month>" in urlconf: kwargs["month"] = "%02d" % current_date.month if "<day>" in urlconf: kwargs["day"] = "%02d" % current_date.day if "<slug>" in urlconf: kwargs["slug"] = self.safe_translation_getter( "slug", language_code=lang, any_language=True) # NOQA if "<category>" in urlconf: kwargs["category"] = category.safe_translation_getter( "slug", language_code=lang, any_language=True) # NOQA return reverse("%s:post-detail" % self.app_config.namespace, kwargs=kwargs) def get_title(self): title = self.safe_translation_getter("meta_title", any_language=True) if not title: title = self.safe_translation_getter("title", any_language=True) return title.strip() def get_keywords(self): """ Returns the list of keywords (as python list) :return: list """ return self.safe_translation_getter("meta_keywords", default="").strip().split(",") def get_description(self): description = self.safe_translation_getter("meta_description", any_language=True) if not description: description = self.safe_translation_getter("abstract", any_language=True) return escape(strip_tags(description)).strip() def get_image_full_url(self): if self.main_image: return self.build_absolute_uri(self.main_image.url) return "" def get_image_width(self): if self.main_image: return self.main_image.width def get_image_height(self): if self.main_image: return self.main_image.height def get_tags(self): """ Returns the list of object tags as comma separated list """ taglist = [tag.name for tag in self.tags.all()] return ",".join(taglist) def get_author(self): """ Return the author (user) objects """ return self.author def _set_default_author(self, current_user): if not self.author_id and self.app_config.set_author: if get_setting("AUTHOR_DEFAULT") is True: user = current_user else: user = get_user_model().objects.get( username=get_setting("AUTHOR_DEFAULT")) self.author = user def thumbnail_options(self): if self.main_image_thumbnail_id: return self.main_image_thumbnail.as_dict else: return get_setting("IMAGE_THUMBNAIL_SIZE") def full_image_options(self): if self.main_image_full_id: return self.main_image_full.as_dict else: return get_setting("IMAGE_FULL_SIZE") @property def is_published(self): """ Checks wether the blog post is *really* published by checking publishing dates too """ return (self.safe_translation_getter("is_publish") and (self.date_published and self.date_published <= timezone.now()) and (self.date_published_end is None or self.date_published_end > timezone.now())) def should_knock(self, signal_type, created=False): """ Returns whether to emit knocks according to the post state """ new = self.app_config.send_knock_create and self.is_published and self.date_published == self.date_modified updated = self.app_config.send_knock_update and self.is_published return (new or updated) and signal_type in ("post_save", "post_delete") def get_cache_key(self, language, prefix): return "djangocms-blog:{2}:{0}:{1}".format(language, self.guid, prefix) @property def liveblog_group(self): return "liveblog-{apphook}-{lang}-{post}".format( lang=self.get_current_language(), apphook=self.app_config.namespace, post=self.safe_translation_getter("slug", any_language=True), )
class Terms(ModelMeta, TranslatableModel): """ Terms Agreement Model """ author = models.ForeignKey( dj_settings.AUTH_USER_MODEL, verbose_name=_(u'author'), null=True, blank=True, related_name='app_terms_author', ) date_created = models.DateTimeField(_(u'created'), auto_now_add=True) date_modified = models.DateTimeField(_(u'last modified'), auto_now=True) date_published = models.DateTimeField(_(u'published Since'), default=timezone.now) date_published_end = models.DateTimeField(_(u'published Until'), null=True, blank=True) publish = models.BooleanField(_(u'publish'), default=False) categories = models.ManyToManyField( 'app.AppCategory', verbose_name=_(u'category'), related_name='app_terms_categories', ) main_image = FilerImageField(verbose_name=_(u'main image'), blank=True, null=True, on_delete=models.SET_NULL, related_name='app_terms_image') main_image_thumbnail = models.ForeignKey( 'cmsplugin_filer_image.ThumbnailOption', verbose_name=_(u'main image thumbnail'), related_name='app_terms_thumbnail', on_delete=models.SET_NULL, blank=True, null=True) main_image_full = models.ForeignKey( 'cmsplugin_filer_image.ThumbnailOption', verbose_name=_(u'main image full'), related_name='app_terms_full', on_delete=models.SET_NULL, blank=True, null=True) enable_comments = models.BooleanField( verbose_name=_(u'enable comments on terms agreement'), default=get_setting('ENABLE_COMMENTS')) sites = models.ManyToManyField( 'sites.Site', verbose_name=_(u'Site(s)'), blank=True, null=True, help_text=_(u'Select sites in which to show the terms agreement ' u'If none is set it will be ' u'visible in all the configured sites.')) translations = TranslatedFields( title=models.CharField(_(u'title'), max_length=255), slug=models.SlugField(_(u'slug'), blank=True, db_index=True), abstract=HTMLField(_(u'abstract'), blank=True, default=''), meta_description=models.TextField( verbose_name=_(u'terms meta description'), blank=True, default=''), meta_keywords=models.TextField(verbose_name=_(u'terms meta keywords'), blank=True, default=''), meta_title=models.CharField( verbose_name=_(u'terms meta title'), help_text=_(u'used in title tag and social sharing'), max_length=255, blank=True, default=''), terms_text=HTMLField(_(u'text'), default='', blank=True), meta={'unique_together': [ ( 'slug', 'language_code', ), ]}, ) content = PlaceholderField('terms_content', related_name='app_terms_content') objects = GenericDateTaggedManager() tags = TaggableManager(blank=True, related_name='app_tags') _metadata = { 'title': 'get_title', 'description': 'get_description', 'og_description': 'get_description', 'twitter_description': 'get_description', 'gplus_description': 'get_description', 'keywords': 'get_keywords', 'locale': None, #'image': 'get_image_full_url', 'object_type': get_setting('TYPE'), 'og_type': get_setting('FB_TYPE'), 'og_app_id': get_setting('FB_APPID'), 'og_profile_id': get_setting('FB_PROFILE_ID'), 'og_publisher': get_setting('FB_PUBLISHER'), 'og_author_url': get_setting('FB_AUTHOR_URL'), 'twitter_type': get_setting('TWITTER_TYPE'), 'twitter_site': get_setting('TWITTER_SITE'), 'twitter_author': get_setting('TWITTER_AUTHOR'), 'gplus_type': get_setting('GPLUS_TYPE'), 'gplus_author': get_setting('GPLUS_AUTHOR'), 'published_time': 'date_published', 'modified_time': 'date_modified', 'expiration_time': 'date_published_end', 'tag': 'get_tags', 'url': 'get_absolute_url', } class Meta: verbose_name = _('app terms') verbose_name_plural = _('app terms agreements') ordering = ('-date_published', '-date_created') get_latest_by = 'date_published' def __str__(self): return self.safe_translation_getter('title') def get_absolute_url(self): #import pdb; pdb.set_trace() kwargs = { 'year': self.date_published.year, 'month': '%02d' % self.date_published.month, 'day': '%02d' % self.date_published.day, 'article_slug': self.safe_translation_getter('slug', language_code=get_language(), any_language=True) } return reverse('app:terms-detail', kwargs=kwargs) def save(self, *args, **kwargs): super(Terms, self).save(*args, **kwargs) main_lang = self.get_current_language() for lang in self.get_available_languages(): self.set_current_language(lang) if not self.slug and self.title: self.slug = slugify(self.title) self.set_current_language(main_lang) self.save_translations() def get_title(self): title = self.safe_translation_getter('meta_title', any_language=True) if not title: title = self.safe_translation_getter('title', any_language=True) return title.strip() def get_keywords(self): return self.safe_translation_getter('meta_keywords').strip().split(',') def get_description(self): description = self.safe_translation_getter('meta_description', any_language=True) if not description: description = self.safe_translation_getter('abstract', any_language=True) return escape(strip_tags(description)).strip() def get_image_full_url(self): if self.main_image: return self.make_full_url(self.main_image.url) return '' def get_tags(self): taglist = [tag.name for tag in self.tags.all()] return ','.join(taglist) def get_author(self): return self.author def thumbnail_options(self): if self.main_image_thumbnail_id: return self.main_image_thumbnail.as_dict else: return get_setting('IMAGE_THUMBNAIL_SIZE') def full_image_options(self): if self.main_image_full_id: return self.main_image_full.as_dict else: return get_setting('IMAGE_FULL_SIZE') def get_full_url(self): return self.make_full_url(self.get_absolute_url())
class News(models.Model): """ News """ author = models.ForeignKey(AUTH_USER_MODEL, verbose_name=_('author'), null=True, blank=True, related_name='news_author') category = models.ForeignKey("NewsCategory", verbose_name=_('category'), related_name="news_category", null=True, blank=True, default=None) meta_description = models.TextField( verbose_name=_('news meta description'), blank=True, default='') meta_keywords = models.TextField(verbose_name=_('news meta keywords'), blank=True, default='') meta_title = models.CharField( verbose_name=_('news meta title'), help_text=_('used in title tag and social sharing'), max_length=255, blank=True, default='') title = models.CharField(_('Title'), max_length=255) slug = AutoSlugField(_('Slug'), max_length=128, unique=True, editable=True, populate_from='title', help_text=_('A slug is a short name which uniquely' ' identifies the news item')) description = HTMLField(_('Description'), blank=True, configuration='CKEDITOR_SETTINGS_NEWS') content = PlaceholderField('news_content', related_name='news_content') publish = models.BooleanField(_('Published'), default=False) date_created = models.DateTimeField(_('created'), auto_now_add=True) date_modified = models.DateTimeField(_('last modified'), auto_now=True) date_published = models.DateTimeField(_('published since'), default=timezone.now) date_published_end = models.DateTimeField(_('published until'), null=True, blank=True) enable_comments = models.BooleanField( verbose_name=_('enable comments on post'), default=ENABLE_COMMENTS) images = models.ManyToManyField( 'filer.Image', through='NewsImages', verbose_name=_("News images"), ) # Oscar links linked_products = models.ManyToManyField( 'catalogue.Product', blank=True, verbose_name=_("Linked products"), help_text=_( "These are products that can be shown with news post " "or news post can be shown on the specific product's page.")) linked_categories = models.ManyToManyField( 'catalogue.Category', blank=True, verbose_name=_("Linked product's categories"), help_text=_("Show news for that categories " "or display news on the category page")) linked_classes = models.ManyToManyField( 'catalogue.ProductClass', blank=True, verbose_name=_("Linked product's classes"), help_text=_("Show news for that classes " "or display news on the specific class product's pages")) sites = models.ManyToManyField( 'sites.Site', verbose_name=_('Site(s)'), blank=True, help_text=_('Select sites in which to show the post. ' 'If none is set it will be ' 'visible in all the configured sites.')) tags = TaggableManager(blank=True, related_name='news_tags') objects = NewsManager() published = PublishedNewsManager() class Meta: app_label = 'oscar_news' verbose_name = _('News') verbose_name_plural = _('News') ordering = ('-date_published', ) def __unicode__(self): return self.title @property def is_published(self): """ Checks whether the news entry is *really* published by checking publishing dates too """ return (self.publish and (self.date_published and self.date_published <= timezone.now()) and (self.date_published_end is None or self.date_published_end > timezone.now())) def _set_default_author(self, current_user): if not self.author_id: if AUTHOR_DEFAULT is True: user = current_user else: user = get_user_model().objects.get(username=AUTHOR_DEFAULT) self.author = user def get_absolute_url(self): """ method below inherited and slightly customized """ cache_key = 'NEWS_ENTRY_URL_%s' % self.pk url = cache.get(cache_key) if not url: # temporarily use link to news detail url = reverse('oscar_news:entry-detail', kwargs={'slug': self.slug}) cache.set(cache_key, url) return url def get_tags(self, queryset=None): """ :return: the list of object's tags annotated with counters. Tags are limited by published news. """ queryset = queryset or News.published.get_queryset() return get_tag_cloud(self.__class__, queryset, set(self.tags.all())) def get_all_tags(self): """ :return: List of all object's tags including unpublished """ return self.get_tags(News.objects.all()) def _get_next_or_previous_published(self, is_next): if not self.pk: raise ValueError( "get_next/get_previous cannot be used on unsaved objects.") op = 'gt' if is_next else 'lt' order = '' if is_next else '-' field = 'date_published' param = force_text(getattr(self, field)) q = Q(**{'%s__%s' % (field, op): param}) q = q | Q(**{field: param, 'pk__%s' % op: self.pk}) qs = self.__class__.published.using(self._state.db).filter(q).order_by( '%s%s' % (order, field), '%spk' % order) try: return qs[0] except IndexError: raise self.DoesNotExist("%s matching query does not exist." % self.__class__._meta.object_name) def get_next_published(self): return self._get_next_or_previous_published(is_next=True) def get_previous_published(self): return self._get_next_or_previous_published(is_next=False)
class JobListing(models.Model) : JOB_TYPE_CHOICES = ( ('fulltime','Full Time'), ('contract','Contract'), ('intern','Intern'), ('freelance','Freelance'), ('parttime','Part Time') ) EXP_CHOICES=[(int(item),int(item)) for item in range(1,20)] JOB_CTC_CHOICE=[(item,item) for item in range(1,20)] company = models.ForeignKey(Company,null=True,help_text="<strong>Select Company from dropdown") job_title = models.ForeignKey(Designation,null=True,blank=True) slug = AutoSlugField( populate_from="job_title",unique=True) job_type = models.CharField(max_length = 10, blank = True, null = True, choices = JOB_TYPE_CHOICES, help_text = '<strong>Select Type of job </strong>') job_desc = models.TextField() job_min_ctc = models.IntegerField(choices=JOB_CTC_CHOICE,null = True) job_max_ctc = models.IntegerField(choices=JOB_CTC_CHOICE,null = True) job_min_exp = models.IntegerField(choices=EXP_CHOICES) job_max_exp = models.IntegerField(choices=EXP_CHOICES) job_location = models.ForeignKey(City,blank=True,null=True) #current_designation = job_skills = TaggableManager() #relavant_skill = models.ForeignKey(SkillsRequired,blank=True,null=True) pub_date = models.DateTimeField(auto_now_add = True,blank=True,null=True) last_updated_date = models.DateTimeField(auto_now=True,blank=True,null=True) job_no_of_applications = models.IntegerField(default=0,blank=True) responsibility = models.TextField(null=True,blank=True) qualification = models.TextField(null=True,blank=True) ##interested_candidates=property(interested_candidate) def PreferredCandidates(self): job=JobListing.objects.get(slug=self.slug) skill_list=[] for job_skill in job.job_skills.all(): skill=str(job_skill).replace(' ','') skill_list.append(skill) for s in skill_list: s.lower() jobseekers=JobSeeker.objects.filter(Q(skills__name__in=skill_list)).distinct() print jobseekers.count() print '$$$$$$$$$$$$$$$$$$$$$$$$$$$' return jobseekers.count() def interested_candidates_count(self): return self.jobapplications_set.filter(action_by_recruiter="interested").distinct().count() def shortlisted_candidates_count(self): return self.jobapplications_set.filter(action_by_team_leader="shortlisted").count() def final_shortlisted_candidates_count(self): return self.jobapplications_set.filter(mail_sent_to_shortlisted=True).count() def final_shortlisted_candidates(self): return self.shortlistedcandidates_set.all() preferred_candidates=property(PreferredCandidates) interested_candidates=property(interested_candidates_count) shortlisted_candidates=property(shortlisted_candidates_count) final_shortlisted_candidates=property(final_shortlisted_candidates_count) final_shortlisted=property(final_shortlisted_candidates) def __str__(self): return "%s " %(self.job_title) class Meta : ordering = ['-job_min_ctc'] def get_absolute_url(self): return reverse('company:job_detail',kwargs={ "company_slug": self.company.slug, "job_slug": self.slug}) def get_time_diff(self): return (timezone.now() - self.pub_date).seconds def get_content_as_markdown(self): return markdown.markdown(self.job_desc, safe_mode='escape')
class Proposal(TimeStampedModel): audience_level = models.CharField( verbose_name=_("Nivel de la audiencia"), choices=PROPOSAL_LEVELS, null=True, default=BASIC_LEVEL, max_length=32, ) language = models.CharField(verbose_name=_("Idioma"), max_length=2, choices=PROPOSAL_LANGUAGES, default="es") duration = models.PositiveIntegerField( verbose_name=_("Duración"), choices=PROPOSAL_DURATIONS, default=30, null=True, blank=True, ) tags = TaggableManager( verbose_name=_("Etiquetas"), help_text=_("Lista de etiquetas separadas por comas."), blank=True, ) is_beginners_friendly = models.BooleanField( verbose_name=_("¿Es apta para principiantes?"), default=False) kind = models.ForeignKey( "proposals.ProposalKind", verbose_name=_("Tipo de propuesta"), on_delete=models.CASCADE, ) title = models.CharField(max_length=100, verbose_name=_("Título")) description = models.TextField( _("Breve descripción"), max_length=500, help_text=_( "Si tu propuesta se acepta esto se hará público, y se incluirá en el programa. " "Debería ser un párrafo, con un máximo de 500 caracteres."), ) abstract = MarkupField( _("Resumen detallado"), blank=True, default="", default_markup_type="markdown", help_text= _("Resumen detallado. Se hará pública si la propuesta se acepta. Edita " "usando <a href='http://daringfireball.net/projects/markdown/basics' " "target='_blank'>Markdown</a>."), ) additional_notes = MarkupField( _("Notas adicionales"), blank=True, default="", default_markup_type="markdown", help_text= _("Cualquier cosa que te gustaría hacer saber a los revisores para que la tengan en " "cuenta al ahora de hacer la selección. Esto no se hará público. Edita usando " "<a href='http://daringfireball.net/projects/markdown/basics' " "target='_blank'>Markdown</a>."), ) speakers = models.ManyToManyField("speakers.Speaker", related_name="proposals", blank=False) cancelled = models.BooleanField(default=False) notified = models.BooleanField(default=False) accepted = models.NullBooleanField(verbose_name=_("Aceptada"), default=None) accepted_notified = models.BooleanField( verbose_name=_("Notificación de aceptación enviada"), default=False) code = models.CharField(max_length=64, null=True, blank=True) def __str__(self): return self.title @property def translated_abstract(self): return get_translated_markdown_field(self, "abstract") @property def translated_additional_notes(self): return get_translated_markdown_field(self, "additional_notes") @property def avg(self): data = [ review.score for review in self.reviews.filter(finished=True) if review.score is not None ] if data: return sum(data) / len(data) return None @property def completed_reviews(self): return self.reviews.filter(finished=True).count() @property def assigned_reviews(self): return self.reviews.count() @property def tag_list(self): return ", ".join(tag.name for tag in self.tags.all()) @property def speakers_list(self): return ", ".join([ "%s <%s>" % (speaker.name, speaker.email) for speaker in self.speakers.all() ]) @property def renormalization_o0(self): """Renormalization with order 0. Average value of 0""" score = [] for review in self.reviews.all(): reviewer = Reviewer.objects.get(user=review.user) mean = reviewer.mean() if reviewer.num_reviews() <= 1: continue score.append((review.score or 0) - mean) if score: return np.mean(score) return None @property def renormalization_o1(self): """Renormalization with order 1. Expand the value to get the same standard deviation for everyone""" score = [] for review in self.reviews.all(): reviewer = Reviewer.objects.get(user=review.user) std = reviewer.std() if reviewer.num_reviews() <= 1 or std < 0.75: continue score.append((review.score or 0) - std) if score: return np.mean(score) return None def notification_email_context(self, speaker): site = Site.objects.get_current() return { "title": self.title, "speaker": speaker, "kind": self.kind.name, "code": self.code, "site": site, } def notify(self): """Sends an email to the creator of the proposal with a confirmation email. The emails has a link to edit the proposal. """ if not self.code: self.code = random_string(64) for speaker in self.speakers.all(): context = self.notification_email_context(speaker=speaker) send_email( context=context, template="emails/proposals/confirmation.html", subject=_("[%s] Confirmación de propuesta de charla") % settings.CONFERENCE_TITLE, to=speaker.email, from_email=settings.CONTACT_EMAIL, ) self.notified = True self.save() def notify_acceptance(self): """Sends an email to the creator of the proposal with an email with the resolution of the acceptance or not of his proposal. """ for speaker in self.speakers.all(): context = self.notification_email_context(speaker=speaker) if self.accepted is None: return template = ("emails/proposals/accepted.html" if self.accepted else "emails/proposals/rejected.html") send_email( context=context, template=template, subject=_("[%s] Notificación de propuesta de charla") % settings.CONFERENCE_TITLE, to=self.speaker.email, from_email=settings.CONTACT_EMAIL, ) self.accepted_notified = True self.save()
class Post(ModelMeta, TranslatableModel): """ Blog post """ author = models.ForeignKey(dj_settings.AUTH_USER_MODEL, verbose_name=_('Author'), null=True, blank=True, related_name='djangocms_blog_post_author') date_created = models.DateTimeField(auto_now_add=True) date_modified = models.DateTimeField(auto_now=True) date_published = models.DateTimeField(_('Published Since'), default=timezone.now) date_published_end = models.DateTimeField(_('Published Until'), null=True, blank=True) publish = models.BooleanField(_('Publish'), default=False) categories = models.ManyToManyField(BlogCategory, verbose_name=_('category'), related_name='blog_posts',) main_image = FilerImageField(verbose_name=_('Main image'), blank=True, null=True, related_name='djangocms_blog_post_image') main_image_thumbnail = models.ForeignKey(ThumbnailOption, verbose_name=_('Main image thumbnail'), related_name='djangocms_blog_post_thumbnail', blank=True, null=True) main_image_full = models.ForeignKey(ThumbnailOption, verbose_name=_('Main image full'), related_name='djangocms_blog_post_full', blank=True, null=True) enable_comments = models.BooleanField( verbose_name=_(u'Enable comments on post'), default=settings.BLOG_ENABLE_COMMENTS ) translations = TranslatedFields( title=models.CharField(_('Title'), max_length=255), slug=models.SlugField(_('slug'), blank=True, db_index=True), abstract=HTMLField(_('Abstract')), meta_description=models.TextField(verbose_name=_(u'Post meta description'), blank=True, default=''), meta_keywords=models.TextField(verbose_name=_(u'Post meta keywords'), blank=True, default=''), meta_title=models.CharField(verbose_name=_(u'Post meta title'), help_text=_(u'used in title tag and social sharing'), max_length=255, blank=True, default=''), post_text=HTMLField(_('Text'), default='', blank=True), meta={'unique_together': (('language_code', 'slug'),)} ) content = PlaceholderField('post_content') objects = GenericDateTaggedManager() tags = TaggableManager(blank=True, related_name='djangocms_blog_tags') _metadata = { 'title': 'get_title', 'description': 'get_description', 'og_description': 'get_description', 'twitter_description': 'get_description', 'gplus_description': 'get_description', 'keywords': 'get_keywords', 'locale': None, 'image': 'get_image_full_url', 'object_type': settings.BLOG_TYPE, 'og_type': settings.BLOG_FB_TYPE, 'og_app_id': settings.BLOG_FB_APPID, 'og_profile_id': settings.BLOG_FB_PROFILE_ID, 'og_publisher': settings.BLOG_FB_PUBLISHER, 'og_author_url': settings.BLOG_FB_AUTHOR_URL, 'twitter_type': settings.BLOG_TWITTER_TYPE, 'twitter_site': settings.BLOG_TWITTER_SITE, 'twitter_author': settings.BLOG_TWITTER_AUTHOR, 'gplus_type': settings.BLOG_GPLUS_TYPE, 'gplus_author': settings.BLOG_GPLUS_AUTHOR, 'published_time': 'date_published', 'modified_time': 'date_modified', 'expiration_time': 'date_published_end', 'tag': 'get_tags', 'url': 'get_absolute_url', } def get_title(self): title = self.safe_translation_getter('meta_title', any_language=True) if not title: title = self.safe_translation_getter('title', any_language=True) return title.strip() def get_keywords(self): return self.safe_translation_getter('meta_keywords').strip().split(',') def get_description(self): description = self.safe_translation_getter('meta_description', any_language=True) if not description: description = self.safe_translation_getter('abstract', any_language=True) return description.strip() def get_image_full_url(self): if self.main_image: return self.make_full_url(self.main_image.url) return '' def get_tags(self): taglist = [tag.name for tag in self.tags.all()] return ','.join(taglist) def get_author(self): return self.author class Meta: verbose_name = _('blog article') verbose_name_plural = _('blog articles') ordering = ('-date_published', '-date_created') get_latest_by = 'date_published' def __unicode__(self): return self.safe_translation_getter('title') def save(self, *args, **kwargs): super(Post, self).save(*args, **kwargs) for lang in self.get_available_languages(): self.set_current_language(lang) if not self.slug and self.title: self.slug = slugify(self.title) self.save_translations() def get_absolute_url(self): kwargs = {'year': self.date_published.year, 'month': self.date_published.month, 'day': self.date_published.day, 'slug': self.safe_translation_getter('slug', any_language=True)} return reverse('djangocms_blog:post-detail', kwargs=kwargs) def thumbnail_options(self): if self.main_image_thumbnail_id: return self.main_image_thumbnail.as_dict else: return settings.BLOG_IMAGE_THUMBNAIL_SIZE def full_image_options(self): if self.main_image_full_id: return self.main_image_full.as_dict else: return settings.BLOG_IMAGE_FULL_SIZE def get_full_url(self): return self.make_full_url(self.get_absolute_url())
class Post(ModelMeta, TranslatableModel): """ Blog post """ author = models.ForeignKey(dj_settings.AUTH_USER_MODEL, verbose_name=_('author'), null=True, blank=True, related_name='djangocms_blog_post_author') date_created = models.DateTimeField(_('created'), auto_now_add=True) date_modified = models.DateTimeField(_('last modified'), auto_now=True) date_published = models.DateTimeField(_('published since'), default=timezone.now) date_published_end = models.DateTimeField(_('published until'), null=True, blank=True) publish = models.BooleanField(_('publish'), default=False) categories = models.ManyToManyField( 'djangocms_blog.BlogCategory', verbose_name=_('category'), related_name='blog_posts', ) main_image = FilerImageField(verbose_name=_('main image'), blank=True, null=True, on_delete=models.SET_NULL, related_name='djangocms_blog_post_image') main_image_thumbnail = models.ForeignKey( 'cmsplugin_filer_image.ThumbnailOption', verbose_name=_('main image thumbnail'), related_name='djangocms_blog_post_thumbnail', on_delete=models.SET_NULL, blank=True, null=True) main_image_full = models.ForeignKey( 'cmsplugin_filer_image.ThumbnailOption', verbose_name=_('main image full'), related_name='djangocms_blog_post_full', on_delete=models.SET_NULL, blank=True, null=True) enable_comments = models.BooleanField( verbose_name=_('enable comments on post'), default=get_setting('ENABLE_COMMENTS')) sites = models.ManyToManyField( 'sites.Site', verbose_name=_('Site(s)'), blank=True, help_text=_('Select sites in which to show the post. ' 'If none is set it will be ' 'visible in all the configured sites.')) app_config = AppHookConfigField(BlogConfig, null=True, verbose_name=_('app. config')) translations = TranslatedFields( title=models.CharField(_('title'), max_length=255), slug=models.SlugField(_('slug'), blank=True, db_index=True), abstract=HTMLField(_('abstract'), blank=True, default=''), meta_description=models.TextField( verbose_name=_('post meta description'), blank=True, default=''), meta_keywords=models.TextField(verbose_name=_('post meta keywords'), blank=True, default=''), meta_title=models.CharField( verbose_name=_('post meta title'), help_text=_('used in title tag and social sharing'), max_length=255, blank=True, default=''), post_text=HTMLField(_('text'), default='', blank=True), meta={'unique_together': (('language_code', 'slug'), )}) content = PlaceholderField('post_content', related_name='post_content') objects = GenericDateTaggedManager() tags = TaggableManager(blank=True, related_name='djangocms_blog_tags') _metadata = { 'title': 'get_title', 'description': 'get_description', 'keywords': 'get_keywords', 'og_description': 'get_description', 'twitter_description': 'get_description', 'gplus_description': 'get_description', 'locale': 'get_locale', 'image': 'get_image_full_url', 'object_type': 'get_meta_attribute', 'og_type': 'get_meta_attribute', 'og_app_id': 'get_meta_attribute', 'og_profile_id': 'get_meta_attribute', 'og_publisher': 'get_meta_attribute', 'og_author_url': 'get_meta_attribute', 'og_author': 'get_meta_attribute', 'twitter_type': 'get_meta_attribute', 'twitter_site': 'get_meta_attribute', 'twitter_author': 'get_meta_attribute', 'gplus_type': 'get_meta_attribute', 'gplus_author': 'get_meta_attribute', 'published_time': 'date_published', 'modified_time': 'date_modified', 'expiration_time': 'date_published_end', 'tag': 'get_tags', 'url': 'get_absolute_url', } class Meta: verbose_name = _('blog article') verbose_name_plural = _('blog articles') ordering = ('-date_published', '-date_created') get_latest_by = 'date_published' def __str__(self): return self.safe_translation_getter('title') def get_absolute_url(self, lang=None): if not lang: lang = get_language() category = self.categories.first() kwargs = {} urlconf = get_setting('PERMALINK_URLS')[self.app_config.url_patterns] if '<year>' in urlconf: kwargs['year'] = self.date_published.year if '<month>' in urlconf: kwargs['month'] = '%02d' % self.date_published.month if '<day>' in urlconf: kwargs['day'] = '%02d' % self.date_published.day if '<slug>' in urlconf: kwargs['slug'] = self.safe_translation_getter( 'slug', language_code=lang, any_language=True) # NOQA if '<category>' in urlconf: kwargs['category'] = category.safe_translation_getter( 'slug', language_code=lang, any_language=True) # NOQA return reverse('%s:post-detail' % self.app_config.namespace, kwargs=kwargs) def get_meta_attribute(self, param): """ Retrieves django-meta attributes from apphook config instance :param param: django-meta attribute passed as key """ attr = None value = getattr(self.app_config, param) if value: attr = getattr(self, value, None) if attr is not None: if callable(attr): try: data = attr(param) except TypeError: data = attr() else: data = attr else: data = value return data def save_translation(self, translation, *args, **kwargs): if not translation.slug and translation.title: translation.slug = slugify(translation.title) super(Post, self).save_translation(translation, *args, **kwargs) def get_title(self): title = self.safe_translation_getter('meta_title', any_language=True) if not title: title = self.safe_translation_getter('title', any_language=True) return title.strip() def get_keywords(self): return self.safe_translation_getter('meta_keywords').strip().split(',') def get_locale(self): return self.get_current_language() def get_description(self): description = self.safe_translation_getter('meta_description', any_language=True) if not description: description = self.safe_translation_getter('abstract', any_language=True) return escape(strip_tags(description)).strip() def get_image_full_url(self): if self.main_image: return self.make_full_url(self.main_image.url) return '' def get_tags(self): taglist = [tag.name for tag in self.tags.all()] return ','.join(taglist) def get_author(self): return self.author def thumbnail_options(self): if self.main_image_thumbnail_id: return self.main_image_thumbnail.as_dict else: return get_setting('IMAGE_THUMBNAIL_SIZE') def full_image_options(self): if self.main_image_full_id: return self.main_image_full.as_dict else: return get_setting('IMAGE_FULL_SIZE') def get_full_url(self): return self.make_full_url(self.get_absolute_url())
class Note(models.Model): text = models.TextField() post = models.ForeignKey(Post, on_delete=models.CASCADE) tags = TaggableManager(blank=True)
class Post(KnockerModel, BlogMetaMixin, TranslatableModel): """ Blog post """ author = models.ForeignKey(dj_settings.AUTH_USER_MODEL, verbose_name=_('author'), null=True, blank=True, related_name='djangocms_blog_post_author', on_delete=models.PROTECT) date_created = models.DateTimeField(_('created'), auto_now_add=True) date_modified = models.DateTimeField(_('last modified'), auto_now=True) date_published = models.DateTimeField(_('published since'), null=True, blank=True) date_published_end = models.DateTimeField(_('published until'), null=True, blank=True) date_featured = models.DateTimeField(_('featured date'), null=True, blank=True) publish = models.BooleanField(_('publish'), default=False) categories = models.ManyToManyField('djangocms_blog.BlogCategory', verbose_name=_('category'), related_name='blog_posts', blank=True) main_image = FilerImageField(verbose_name=_('main image'), blank=True, null=True, on_delete=models.SET_NULL, related_name='djangocms_blog_post_image') main_image_thumbnail = models.ForeignKey( thumbnail_model, verbose_name=_('main image thumbnail'), related_name='djangocms_blog_post_thumbnail', on_delete=models.SET_NULL, blank=True, null=True) main_image_full = models.ForeignKey( thumbnail_model, verbose_name=_('main image full'), related_name='djangocms_blog_post_full', on_delete=models.SET_NULL, blank=True, null=True) enable_comments = models.BooleanField( verbose_name=_('enable comments on post'), default=get_setting('ENABLE_COMMENTS')) sites = models.ManyToManyField( 'sites.Site', verbose_name=_('Site(s)'), blank=True, help_text=_('Select sites in which to show the post. ' 'If none is set it will be ' 'visible in all the configured sites.')) app_config = AppHookConfigField(BlogConfig, null=True, verbose_name=_('app.config')) translations = TranslatedFields( title=models.CharField(_('title'), max_length=752), slug=models.SlugField(_('slug'), max_length=752, blank=True, db_index=True, allow_unicode=True), subtitle=models.CharField(verbose_name=_('subtitle'), max_length=767, blank=True, default=''), abstract=HTMLField(_('abstract'), blank=True, default='', configuration='BLOG_ABSTRACT_CKEDITOR'), meta_description=models.TextField( verbose_name=_('post meta description'), blank=True, default=''), meta_keywords=models.TextField(verbose_name=_('post meta keywords'), blank=True, default=''), meta_title=models.CharField( verbose_name=_('post meta title'), help_text=_('used in title tag and social sharing'), max_length=2000, blank=True, default=''), post_text=HTMLField(_('text'), default='', blank=True, configuration='BLOG_POST_TEXT_CKEDITOR'), meta={'unique_together': (('language_code', 'slug'), )}) media = PlaceholderField('media', related_name='media') content = PlaceholderField('post_content', related_name='post_content') liveblog = PlaceholderField('live_blog', related_name='live_blog') enable_liveblog = models.BooleanField( verbose_name=_('enable liveblog on post'), default=False) objects = GenericDateTaggedManager() tags = TaggableManager(blank=True, related_name='djangocms_blog_tags') related = SortedManyToManyField('self', verbose_name=_('Related Posts'), blank=True, symmetrical=False) amount = models.CharField(max_length=200, default='R50', choices=donations_amount) goal = models.CharField(max_length=200, default='R30 000', choices=donations_goal) _metadata = { 'title': 'get_title', 'description': 'get_description', 'keywords': 'get_keywords', 'og_description': 'get_description', 'twitter_description': 'get_description', 'gplus_description': 'get_description', 'locale': 'get_locale', 'image': 'get_image_full_url', 'image_width': 'get_image_width', 'image_height': 'get_image_height', 'object_type': 'get_meta_attribute', 'og_type': 'get_meta_attribute', 'og_app_id': 'get_meta_attribute', 'og_profile_id': 'get_meta_attribute', 'og_publisher': 'get_meta_attribute', 'og_author_url': 'get_meta_attribute', 'og_author': 'get_meta_attribute', 'twitter_type': 'get_meta_attribute', 'twitter_site': 'get_meta_attribute', 'twitter_author': 'get_meta_attribute', 'gplus_type': 'get_meta_attribute', 'gplus_author': 'get_meta_attribute', 'published_time': 'date_published', 'modified_time': 'date_modified', 'expiration_time': 'date_published_end', 'tag': 'get_tags', 'url': 'get_absolute_url', } class Meta: verbose_name = _('blog article') verbose_name_plural = _('blog articles') ordering = ('-date_published', '-date_created') get_latest_by = 'date_published' def __str__(self): default = ugettext('Post (no translation)') return self.safe_translation_getter('title', any_language=True, default=default) @property def guid(self, language=None): if not language: language = self.get_current_language() base_string = '-{0}-{2}-{1}-'.format( language, self.app_config.namespace, self.safe_translation_getter('slug', language_code=language, any_language=True)) return hashlib.sha256(force_bytes(base_string)).hexdigest() @property def date(self): if self.date_featured: return self.date_featured return self.date_published def save(self, *args, **kwargs): """ Handle some auto configuration during save """ if self.publish and self.date_published is None: self.date_published = timezone.now() if not self.slug and self.title: self.slug = slugify(self.title) super(Post, self).save(*args, **kwargs) def save_translation(self, translation, *args, **kwargs): """ Handle some auto configuration during save """ if not translation.slug and translation.title: translation.slug = slugify(translation.title) super(Post, self).save_translation(translation, *args, **kwargs) def get_absolute_url(self, lang=None): if not lang or lang not in self.get_available_languages(): lang = get_language() if not lang or lang not in self.get_available_languages(): lang = self.get_current_language() with switch_language(self, lang): category = self.categories.first() kwargs = {} if self.date_published: current_date = self.date_published else: current_date = self.date_created urlconf = get_setting('PERMALINK_URLS')[ self.app_config.url_patterns] if '<year>' in urlconf: kwargs['year'] = current_date.year if '<month>' in urlconf: kwargs['month'] = '%02d' % current_date.month if '<day>' in urlconf: kwargs['day'] = '%02d' % current_date.day if '<slug>' in urlconf: kwargs['slug'] = self.safe_translation_getter( 'slug', language_code=lang, any_language=True) # NOQA if '<category>' in urlconf: kwargs['category'] = category.safe_translation_getter( 'slug', language_code=lang, any_language=True) # NOQA return reverse('%s:post-detail' % self.app_config.namespace, kwargs=kwargs) def get_title(self): title = self.safe_translation_getter('meta_title', any_language=True) if not title: title = self.safe_translation_getter('title', any_language=True) return title.strip() def get_keywords(self): """ Returns the list of keywords (as python list) :return: list """ return self.safe_translation_getter('meta_keywords', default='').strip().split(',') def get_description(self): description = self.safe_translation_getter('meta_description', any_language=True) if not description: description = self.safe_translation_getter('abstract', any_language=True) return escape(strip_tags(description)).strip() def get_image_full_url(self): if self.main_image: return self.build_absolute_uri(self.main_image.url) return '' def get_image_width(self): if self.main_image: return self.main_image.width def get_image_height(self): if self.main_image: return self.main_image.height def get_tags(self): """ Returns the list of object tags as comma separated list """ taglist = [tag.name for tag in self.tags.all()] return ','.join(taglist) def get_author(self): """ Return the author (user) objects """ return self.author def _set_default_author(self, current_user): if not self.author_id and self.app_config.set_author: if get_setting('AUTHOR_DEFAULT') is True: user = current_user else: user = get_user_model().objects.get( username=get_setting('AUTHOR_DEFAULT')) self.author = user def thumbnail_options(self): if self.main_image_thumbnail_id: return self.main_image_thumbnail.as_dict else: return get_setting('IMAGE_THUMBNAIL_SIZE') def full_image_options(self): if self.main_image_full_id: return self.main_image_full.as_dict else: return get_setting('IMAGE_FULL_SIZE') @property def is_published(self): """ Checks wether the blog post is *really* published by checking publishing dates too """ return (self.publish and (self.date_published and self.date_published <= timezone.now()) and (self.date_published_end is None or self.date_published_end > timezone.now())) def should_knock(self, signal_type, created=False): """ Returns whether to emit knocks according to the post state """ new = (self.app_config.send_knock_create and self.is_published and self.date_published == self.date_modified) updated = self.app_config.send_knock_update and self.is_published return (new or updated) and signal_type in ('post_save', 'post_delete') def get_cache_key(self, language, prefix): return 'djangocms-blog:{2}:{0}:{1}'.format(language, self.guid, prefix) @property def liveblog_group(self): return 'liveblog-{apphook}-{lang}-{post}'.format( lang=self.get_current_language(), apphook=self.app_config.namespace, post=self.safe_translation_getter('slug', any_language=True)) def get_gallery_image(self): """ Returns the best gallery image """ from api.models import Gallery if self.id: gallery = Gallery.objects.filter(blog_post=self.id) if gallery: self.main_image = gallery[0].image self.save() return gallery[0].image return False
class Asset(models.Model): class Meta: verbose_name = _("asset") verbose_name_plural = _("assets") author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name=_("author")) application = models.ForeignKey('Application', on_delete=models.CASCADE, verbose_name=_("application")) component = models.ForeignKey('Component', on_delete=models.CASCADE, null=True, verbose_name=_("component")) license = models.ForeignKey('License', on_delete=models.SET_NULL, null=True, blank=False, verbose_name=_("license")) original_author = models.CharField(max_length=255, null=True, blank=True, verbose_name=_("original author")) creation_date = models.DateTimeField(null=True, blank=True, verbose_name=_("Originally created")) title = models.CharField(max_length=255, verbose_name=_("title")) notes = models.TextField(null=True, verbose_name=_("description")) image = models.ImageField(upload_to=get_thumbnail_path, verbose_name=_("thumbnail"), null=True, blank=True) big_image = models.ImageField(upload_to=get_big_image_path, verbose_name=_("larger image"), null=True, blank=True) data = models.FileField(upload_to=get_data_path, verbose_name=_("data file")) url = models.URLField(null=True, blank=True, verbose_name=_("URL")) pub_date = models.DateTimeField(verbose_name=_("date published")) version = VersionField(null=True, blank=True, number_bits=[8,8,8,8], verbose_name=_("asset version")) app_version_min = VersionField(verbose_name=_("Minimum compatible application version"), null=True, blank=True, number_bits=[8,8,8,8]) app_version_max = VersionField(verbose_name=_("Maximum compatible application version"), null=True, blank=True, number_bits=[8,8,8,8]) tags = TaggableManager(blank=True, verbose_name=_("tags")) num_votes = models.PositiveIntegerField(default=0) votes = VotableManager(extra_field='num_votes') def clean(self): if self.component and self.data and not self.component.is_filename_allowed(self.data.name): raise ValidationError(_("It is not allowed to upload files of this type for this component")) if self.component and not self.component.big_image_allowed: if self.big_image: raise ValidationError(_("It is not allowed to upload big images for this component")) if self.component and self.component.thumbnail_mandatory: if not self.image and not (self.component and self.component.thumbnailer_name): raise ValidationError(_("You should upload thumbnail file")) super(Asset, self).clean() def save(self, *args, **kwargs): if self.data and not self.image and self.component: thumbnailer = self.component.thumbnailer() auto_thumbnail = None if thumbnailer: auto_thumbnail = thumbnailer.make_thumbnail(self.data) elif self.big_image: auto_thumbnail = thumbnail_from_big_image(self.big_image, size=self.component.max_thumbnail_size) if auto_thumbnail: # pass save=False because otherwise it would call save() recursively self.image.save("auto_thumbnail.png", auto_thumbnail, save=False) super(Asset,self).save(*args, **kwargs) def get_tags(self): return ", ".join([tag.name for tag in self.tags.all()]) def get_app_versions(self): if not self.app_version_min and not self.app_version_max: return pgettext_lazy("application version", "any") if self.app_version_min and not self.app_version_max: return pgettext_lazy("application version", ">= {}").format(self.app_version_min) if not self.app_version_min and self.app_version_max: return pgettext_lazy("application version", "<= {}").format(self.app_version_max) return pgettext_lazy("application version", ">= {0} and <= {1}").format(self.app_version_min, self.app_version_max) def get_filename(self): return basename(self.data.name) def get_comments_count(self): ct = ContentType.objects.get_for_model(Asset) return Comment.objects.filter(content_type=ct, object_pk=self.pk).count() def __str__(self): result = "" if self.application: result += str(self.application) + " " if self.component: result += self.component.title + " " result += self.title return result.encode('utf-8') def __unicode__(self): result = "" if self.application: result += str(self.application) + " " if self.component: result += self.component.title + " " result += self.title return result
class Post(models.Model): title = models.CharField(max_length=60) tags = TaggableManager() def __unicode__(self): return self.title
class Entry(Publishable): """An entry in a 'blog' or whatever you want to call it.""" title = models.CharField(max_length=100) subtitle = models.CharField(max_length=100, blank=True) slug = models.SlugField(max_length=110, allow_unicode=True, unique=True) author = models.CharField('Author(s)', blank=True, max_length=100) content = MarkdownField(blank=True) content_rendered = models.TextField(blank=True, editable=False) description = MarkdownField( 'Summary/Description', blank=True, help_text='Short text to be used where post might be promoted/referenced. Limited to 400 characters.' ) description_rendered = models.TextField(blank=True, editable=False) share_text = models.CharField(blank=True, max_length=140) featured_image = FilerImageField(blank=True, null=True) is_sponsored = models.BooleanField(default=False) sponsored_logo = FilerImageField(blank=True, null=True, related_name='sponsored_article') publication_date = models.DateTimeField( blank=True, null=True, help_text="""<p>Publication date will be set to the current time automatically, when <em>published</em> is selected. <p>You may set a date/time manually, but <strong>you must select <em>published</em> for the post to appear!</strong> """ ) categories = models.ManyToManyField( Category, blank=True, related_name='entries', ) tags = TaggableManager(blank=True) related_entries = models.ManyToManyField('self', blank=True) class Meta: ordering = ("-publication_date", "-created_at") get_latest_by = "publication_date" verbose_name = "entry" verbose_name_plural = "entries" def __str__(self): return self.title def save(self, *args, **kwargs): if self.published and not self.publication_date: self.publication_date = timezone.now() self.content_rendered = render_markdown(self.content) self.description_rendered = render_markdown(self.description) super(Entry, self).save(*args, **kwargs) def get_absolute_url(self): return reverse( 'writings:entry-detail', kwargs={ 'slug': self.slug, } ) def is_visible(self): return self.published and self.publication_date <= timezone.now() def get_next_published_entry(self): if not self.publication_date: return None # If no publication date query = Q(publication_date__gt=self.publication_date) query |= Q(publication_date=self.publication_date, pk__gt=self.pk) qs = self.__class__.objects.published().filter(query).order_by('publication_date', 'pk') try: return qs[0] except IndexError: return None def get_previous_published_entry(self): if not self.publication_date: return None # If no publication date query = Q(publication_date__lt=self.publication_date) query |= Q(publication_date=self.publication_date, pk__lt=self.pk) qs = self.__class__.objects.published().filter(query).order_by('-publication_date', '-pk') try: return qs[0] except IndexError: return None