class GridSection(Orderable): page = models.ForeignKey("GridPage", related_name="gridsection") title = models.CharField(_("Section Title"), max_length=100) icon = models.CharField(_("Section Icon"), max_length=100) textfield = RichTextField(_("Content"), blank=True)
class Lesson(Page, RichText): overview = RichTextField('Lesson Overview') duration = models.CharField('Duration', help_text='Duration of lesson', max_length=255, blank=True, null=True) week = models.IntegerField( 'Week', help_text= 'Week within the unit (only use for first lesson of the week)', blank=True, null=True) pacing_weight = models.DecimalField( 'Pacing Weight', help_text='Higher numbers take up more space pacing calendar', default=1, max_digits=4, decimal_places=1, blank=True, null=True) unplugged = models.BooleanField(default=False) resources = SortedManyToManyField(Resource, blank=True) prep = RichTextField('Preparation', help_text='ToDos for the teacher to prep this lesson', blank=True, null=True) questions = RichTextField( 'Support Details', help_text='Open questions or comments about this lesson', blank=True, null=True) cs_content = RichTextField( 'Purpose', help_text='Purpose of this lesson in progression and CS in general', blank=True, null=True) ancestor = models.ForeignKey('self', blank=True, null=True) standards = models.ManyToManyField(Standard, blank=True) anchor_standards = models.ManyToManyField( Standard, help_text='1 - 3 key standards this lesson focuses on', related_name="anchors", blank=True) vocab = models.ManyToManyField(Vocab, blank=True) blocks = models.ManyToManyField(Block, blank=True) comments = CommentsField() unit = models.ForeignKey(curricula.models.Unit, blank=True, null=True) curriculum = models.ForeignKey(curricula.models.Curriculum, blank=True, null=True) number = models.IntegerField('Number', blank=True, null=True) image = models.ImageField('Image', blank=True, null=True) stage = JSONField('Code Studio stage', blank=True, null=True) _old_slug = models.CharField('old_slug', max_length=2000, blank=True, null=True) class Meta: ordering = ["number"] def __unicode__(self): return self.title def __deepcopy(self): lesson_copy = self lesson_copy.pk = None # deepcopy page, activities, prereqs, and objectives lesson_copy.save() return lesson_copy def can_move(self, request, new_parent): parent_type = getattr(new_parent, 'content_model', None) if not (parent_type == 'lesson' or parent_type == 'chapter' or parent_type == 'unit'): print "no unit here" msg = 'Lesson cannot live under a %s' % parent_type raise PageMoveException(msg) def get_absolute_url(self): # Check if this is the child of a lesson, and therefore optional if hasattr(self.parent, 'lesson'): return "%soptional/%s/" % (self.parent.lesson.get_absolute_url(), str(self.number)) try: return "%s%s/" % (self.unit.get_absolute_url(), str(self.number)) except AttributeError: return "%s%s/" % (self.get_unit().get_absolute_url(), str(self.number)) def get_overview_url(self): return '%soverview/' % self.get_absolute_url() def get_unit(self): parent = self.parent while not parent.content_model == 'unit': parent = parent.parent if parent is None: return None return parent.unit def get_number(self): order = 1 if self.parent.content_model == 'chapter': chapter = self.parent.chapter while chapter is not None: try: chapter = chapter.get_previous_by_order() if hasattr(chapter, "chapter"): chapter = chapter.chapter order += chapter.lessons.count() except AttributeError as e: chapter = None if self._order is not None: try: order += int(self._order) except Exception as e: print(e) return order def get_curriculum(self): return self.get_unit().curriculum def get_levels(self): if self.stage: raw_levels = self.stage.get('levels') levels = [] # To store levels organized by logical chunk counter = 0 last_type = raw_levels[0].get('named_level') last_progression = raw_levels[0].get('progression') levels.insert(counter, { 'named': last_type, 'progression': last_progression, 'levels': [] }) for level in raw_levels: current_type = level.get('named_level') current_progression = level.get('progression') if last_type != current_type or last_progression != current_progression: last_type = current_type last_progression = current_progression counter += 1 levels.insert( counter, { 'named': last_type, 'progression': last_progression, 'levels': [] }) levels[counter]['levels'].append(level) return levels else: return def get_levels_from_levelbuilder(self): try: url = "https://levelbuilder-studio.code.org/s/%s/stage/%d/summary_for_lesson_plans" % ( self.unit.stage_name, self.number) response = urllib2.urlopen(url) data = json.loads(response.read()) self.stage = data self.save() except Exception: logger.warning("Couldn't get stage details for %s" % self) # Return publishable urls for JackFrost def jackfrost_urls(self): urls = [self.get_absolute_url(), self.get_overview_url()] return urls def jackfrost_can_build(self): try: can_build = settings.ENABLE_PUBLISH and self.status == 2 and not self.login_required and \ not self.unit.login_required and not self.curriculum.login_required except: can_build = False return can_build def publish(self, children=False): if self.jackfrost_can_build(): for url in self.jackfrost_urls(): try: read, written = build_single(url) slack_message( 'slack/message.slack', { 'message': 'published %s %s' % (self.content_model, self.title), 'color': '#00adbc' }) yield json.dumps(written) yield '\n' except Exception, e: yield json.dumps(e.message) yield '\n' logger.exception('Failed to publish %s' % url) else:
class AddFieldsToProducts(Orderable): product = models.ForeignKey(Product, related_name="supplementary") short_desco = RichTextField(blank=True)
class IndividualBeautyAndStylePage(Page): image = models.ImageField(upload_to="beauty_images") article = RichTextField(_("Article"), default="") date_added = models.DateField(auto_now_add=True)
class Actividades(Page, RichText, GenericContent): # fechas y horas del evento (inicio y fin) start_date = models.DateField() finish_date = models.DateField() destacado = models.BooleanField(_("Es una actividad destacada"), default=False) url = models.TextField(max_length=500, default="", blank=True) descripcion = RichTextField() # para los participantes limite_participantes = models.BooleanField(_("limit participants"), default=False) limit = models.IntegerField(blank=True, null=True) # localizacion lugar = models.TextField(max_length=500, blank=True) # creditos de libre eleccion creditos_rac = models.BooleanField(_("Se conceden RAC"), default=False) n_rac = models.IntegerField(blank=True, null=True) adminlist = models.TextField(max_length=500, blank=True) owner = models.ForeignKey(User, on_delete=models.CASCADE) # inscripciones al evento permitir_inscriptions = models.BooleanField(_("Permitir inscripciones"), default=False) fecha_inscripcion_inicio = models.DateField(blank=True, null=True) fecha_inscripcion_final = models.DateField(blank=True, null=True) lista_espera = models.BooleanField(_("Permitir lista de espera"), default=False) enviar_notificaciones = models.BooleanField(_("Enviar notificaciones"), default=True) email_organizador = models.EmailField(_("Email to receive notifications"), null=True, blank=True) attached_file = models.FileField(_("Attach an file"), upload_to=user_directory_actividades, null=True, blank=True) incluir_miniactividades = models.BooleanField(_("Incluir MiniActividades"), default=True) def has_permissions(self, user): """ Esta funcion comprueba si un usuario tiene permisos sobre el seminario o no :param user: usuario :return: boleano resultado de la comprobacion de si el user tiene permisos sobre el seminario o no """ if user.is_superuser or (user == self.owner) or (user.email in self.adminlist): return True return False def delete(self, *args, **kwargs): # construimos el path del seminario para borrar el posible fichero folder = os.path.join(settings.MEDIA_ROOT, "actividad") folder_event = os.path.join(folder, str(self.id)) try: shutil.rmtree(folder_event) except: pass super(Actividades, self).delete(*args, **kwargs) class Meta: verbose_name = _("Actividades") verbose_name_plural = _("Lista de Actividades") ordering = ("-start_date", )
class UpcomingEvent(models.Model): page = models.ForeignKey("UpcomingEventsPage") image = RichTextField(_("Image for Upcoming Event ")) text = RichTextField(_("Text for Upcoming Event"))
class HomePage(Page): youtube_url = RichTextField(_("Youtube URL")) beauty_tips_image = RichTextField(_("Beauty Tips image")) goals_image = RichTextField(_("Reach Your Goals image")) amanda_image = RichTextField(_("Photos of Amanda image")) upcoming_events = RichTextField(_("Upcoming Events Block"))
class Project(Displayable, Ownable, AdminThumbMixin): """ A project submission """ featured_photo = models.ImageField('Cover Photo', upload_to='images/project_featured_photos', blank=True, null=True, help_text='Upload an image for the home page. Suggested ' \ 'dimensions are 1252x626px and max 5MB filesize.' ) featured_video = models.URLField(blank=True, default='', help_text='Youtube Video URL') featured_video_thumbnail = models.ImageField( upload_to='images/project_featured_video_thumbnails', blank=True, null=True, editable=False) tldr = RichTextField('Description', help_text='A description of your project as a whole.') categories = models.ManyToManyField(BlogCategory, related_name='projects') score = models.IntegerField(default=0) created_datetime = models.DateTimeField('Created') modified_datetime = models.DateTimeField('Modified') admin_thumb_field = 'featured_photo' def save(self, *args, **kwargs): # Set project as draft by default if not self.id: self.status = CONTENT_STATUS_DRAFT # Set created and modified datetimes if not provided. if not self.id: self.created_datetime = now() self.modified_datetime = now() super(Project, self).save(*args, **kwargs) def is_published(self, request=None): """ Returns True/False if the Project is published for the user in the given request. Staff users can see any projects while regular users can see any of their own projects If no request is given, or the user is not staff and viewing another user's project, returns True if publish_date <= now() and status == CONTENT_STATUS_PUBLISHED otherwise False. """ if request is not None: if request.user.is_staff or request.user == self.user: return True return (self.publish_date <= now() and self.status == CONTENT_STATUS_PUBLISHED) @property def video_id(self): """Extract Video ID.""" if self.featured_video: return get_youtube_video_id(self.featured_video) @property def embed_url(self): """HTML5 embed url.""" if self.video_id: return 'http://www.youtube.com/embed/%s?wmode=transparent' % self.video_id return None @models.permalink def get_absolute_url(self): return ('project-detail', [self.slug]) def __unicode__(self): return unicode(self.title)
class ActionGroup(PageLike, Ownable): parent = None # To make it compatible with the side_menu template children = DummyEmptyResultSet( ) # To make it compatible with the side_menu template category = ForeignKey(Category, related_name='action_groups') announcements = RichTextField( null=True, blank=True, verbose_name='Announcements', help_text= 'Use this section to let people know about any upcoming events, volunteer opportunities, new initiatives - or just anything you want to draw attention to.' ) meetings = RichTextField( null=True, blank=True, verbose_name='Meetings', help_text= 'Let people know when & where you meet if you have regular meeting times. Don\'t forget you can book the SFPIRG lounge or meeting room to host your meetings.' ) contact_name = models.CharField('Main Contact Person', null=True, blank=True, max_length=255) contact_email = models.EmailField(null=True, blank=True, max_length=255, verbose_name='Contact Email') contact_phone = models.CharField(null=True, blank=True, max_length=255, verbose_name='Contact Telephone') group_email = models.EmailField(null=True, blank=True, max_length=255, verbose_name='Group Email') goals = RichTextField('Main Goal(s)', null=True, blank=True) timeline = RichTextField( 'Plans and Timeline', null=True, blank=True, help_text= 'Specific Plans and timeline for the semester (please be as concrete as possible)' ) oneliner = RichTextField('One-liner for SFPIRG promotional materials', null=True, blank=True) twoliner = RichTextField('One paragraph for SFPIRG website', null=True, blank=True) potential_members = RichTextField( 'Potential members of your group', null=True, blank=True, help_text= 'Please include the members of your potential Action Group: (NAME, PHONE, EMAIL)' ) links = RichTextField( null=True, blank=True, verbose_name='Links', help_text= 'Either to your website, or anywhere else you want to direct people to' ) facebook_url = models.URLField(null=True, blank=True, max_length=255) twitter = models.CharField(null=True, blank=True, max_length=255) google_plus_url = models.URLField(null=True, blank=True, max_length=255) mailing_list_url = models.URLField( null=True, blank=True, max_length=255, verbose_name='Link to Mailing List', help_text= 'You can create a free html email newsletter using mailchimp (www.mailchimp.com). Then people can automatically subscribe to your news. If you already have one, put in your Mailchimp List page address here. Visit mailchimp.com to get it quick' ) is_approved = models.BooleanField(default=False) in_menus = MenusField("Show in menus", blank=True, null=True) @property def richtextpage(self): return self def in_menu_template(self, template_name): if self.in_menus is not None: for i, _l, t in settings.PAGE_MENU_TEMPLATES: if not unicode(i) in self.in_menus and t == template_name: return False return True @models.permalink def get_absolute_url(self): return ('action-group', (), {'slug': self.slug}) def twitter_url(self): if not self.twitter: return '' if self.twitter.startswith('http://') or self.twitter.startswith( 'https://'): return self.twitter if self.twitter.startswith('@'): return 'http://twitter.com/%s' % self.twitter[1:] return 'http://twitter.com/%s' % self.twitter def save(self, *args, **kwargs): if self.is_approved: self.status = CONTENT_STATUS_PUBLISHED else: self.status = CONTENT_STATUS_DRAFT return super(ActionGroup, self).save(*args, **kwargs)
class Project(Page): image = models.ImageField(upload_to='projects', blank=True) content = RichTextField(_("Content"), null=True, blank=True) external_url = models.URLField("External URL", null=True, blank=True) search_fields = ("content",)
class Petition(models.Model): title = models.CharField( max_length=100, help_text="Identify this component for other editors", ) header = models.CharField( max_length=500, help_text="Signup heading that will display on page", blank=True) description = RichTextField("description", help_text="Body of signup component") newsletter = models.CharField( max_length=100, help_text="The (pre-existing) SalesForce newsletter to sign up for", default="mozilla-foundation") google_forms_url = models.URLField( help_text="Google form to post petition data to", max_length=2048, null=True) checkbox_1 = models.CharField( max_length=1024, help_text="label for the first checkbox option (may contain HTML)", blank=True) checkbox_2 = models.CharField( max_length=1024, help_text="label for the second checkbox option (may contain HTML)", blank=True) checkbox_1_form_field = models.CharField( max_length=1024, help_text="Google form field name for Checkbox 1", verbose_name="First checkbox Google Form field", blank=True) checkbox_2_form_field = models.CharField( max_length=1024, help_text="Google form field name for Checkbox 1", verbose_name="Second checkbox Google Form field", blank=True) given_name_form_field = models.CharField( max_length=1024, help_text="Google form field name for Given Name(s)", verbose_name="Given Name(s) Google Form field", ) surname_form_field = models.CharField( max_length=1024, help_text="Google form field name for Surname", verbose_name="Surname Google Form field", ) email_form_field = models.CharField( max_length=1024, help_text="Google form field name for Email", verbose_name="Email Google Form field", ) newsletter_signup_form_field = models.CharField( max_length=1024, help_text="Google form field name for Mozilla Newsletter checkbox", verbose_name="Mozilla Newsletter signup checkbox Google Form field", ) share_link = models.URLField( max_length=1024, help_text="Link that will be put in share button", blank=True) share_link_text = models.CharField( max_length=20, help_text="Text content of the share button", default="Share this", blank=True) thank_you = models.CharField( max_length=140, help_text="Message to show after thanking people for signing", default="Thank you for signing too!", ) def __str__(self): return str(self.title) class Meta: verbose_name_plural = 'petition widgets' verbose_name = 'petition widget'
class Project(Displayable, AdminThumbMixin, ExcerptMixin): '''A CDH sponsored project''' short_description = models.CharField( max_length=255, blank=True, help_text='Brief tagline for display on project card in browse view') long_description = RichTextField() highlight = models.BooleanField( default=False, help_text='Include in randomized project display on the home page.') cdh_built = models.BooleanField( 'CDH Built', default=False, help_text='Project built by CDH Development & Design team.') members = models.ManyToManyField(Person, through='Membership') resources = models.ManyToManyField(ResourceType, through='ProjectResource') tags = TaggableManager(blank=True) # TODO: include help text to indicate images are optional, where they # are used (size?); add language about putting large images in the # body of the project description, when we have styles for that. image = FileField(verbose_name="Image", upload_to=upload_to("projects.image", "projects"), format="Image", max_length=255, null=True, blank=True) thumb = FileField(verbose_name="Thumbnail", upload_to=upload_to("projects.image", "projects/thumbnails"), format="Image", max_length=255, null=True, blank=True) attachments = models.ManyToManyField(Attachment, blank=True) # custom manager and queryset objects = ProjectQuerySet.as_manager() admin_thumb_field = "thumb" class Meta: # sort by project title for now ordering = ['title'] def __str__(self): return self.title def get_absolute_url(self): return reverse('project:detail', kwargs={'slug': self.slug}) @property def website_url(self): '''website url, if set''' website = self.projectresource_set \ .filter(resource_type__name='Website').first() if website: return website.url def latest_grant(self): '''Most recent :class:`Grant`''' if self.grant_set.count(): return self.grant_set.order_by('-start_date').first() def current_memberships(self): ''':class:`MembershipQueryset` of current members sorted by role''' # uses memberships rather than members so that we can retain role # information attached to the membership return self.membership_set.filter( Q(grant=self.latest_grant()) | Q(status_override='current')) \ .exclude(status_override='past') \ def alums(self): ''':class:`PersonQueryset` of past members sorted by last name''' # uses people rather than memberships so that we can use distinct() # to ensure people aren't counted multiple times for each grant # and because we don't care about role (always 'alum') return self.members \ .distinct() \ .exclude(Q(membership__grant=self.latest_grant()) & ~Q(membership__status_override='past')) \ .exclude(membership__status_override='current') \ .order_by('last_name')
class Event(Displayable, RichText, AdminThumbMixin): """ Evento """ EVENT_IMAGE_PATH = os.path.join('eventos','evento') event_title_menu = models.CharField(verbose_name=_(u"Título do Evento para o Menu"), max_length=255, blank=False, null=False, help_text=_(u"Título que vai no link à esquerda no Menu do Topo. Máximo 255 caracteres. Ex: Congresso")) event_description_short = models.CharField(verbose_name=_(u"Descrição curta"), max_length=255, blank=False, null=False, help_text=_(u"Descrição curta para Buscadores e Redes sociais. Ex: Congresso Escoteiro Regional 2015")) # event_url = models.SlugField(verbose_name=_(u"Nome da URL do Evento"), unique=True, max_length=255, blank=False, # null=False, help_text=_(u"Nome do link, ex: congresso-2015")) # Cabecalho event_logo = FileField(verbose_name=_(u"Cabeçalho Logo"), upload_to=EVENT_IMAGE_PATH, format="Image", max_length=255, null=True, blank=True) #event_title = RichTextField(verbose_name=_(u"Cabeçalho Título"), blank=True, config_name='description') event_title = RichTextField(verbose_name=_(u"Cabeçalho Título"), blank=True, default='', help_text=_("This field can contain HTML and should contain a few paragraphs describing the background of the person."),) event_image_background = FileField(verbose_name=_(u"Cabeçalho Imagem de Fundo"), upload_to=EVENT_IMAGE_PATH, max_length=200, blank=True, null=True, help_text=_(u"Para não distorcer, envie uma imagem com resolução máxima de 2362x591px.")) event_social_image = FileField(verbose_name=_(u"Imagem para Redes Sociais"), upload_to=EVENT_IMAGE_PATH, max_length=200, blank=True, null=True, help_text=_(u"Imagem para exibir em links de Redes Sociais, como Facebook. Para imagem retangular envie em 600x315, para imagem quadrada envie em 200x200. Ou formatos maiores sempre mantendo a proporção.")) code = models.TextField(verbose_name=_(u"Códigos"), blank=True, null=True, help_text=_(u"Insira aqui códigos HTML, CSS ou JS.")) # event_blocks = models.ManyToManyField("EventBlock", verbose_name=_(u"Equipes"), blank=True, # related_name="people", ) #through="PeoplePersonCategory" # programations = models.ManyToManyField("EventProgramation", verbose_name=_(u"Programação"), blank=True, # related_name="programations", ) #through="PeoplePersonCategory" class Meta: ordering = ["status", 'pk'] db_table = "event_homepage" verbose_name = _(u"Evento") verbose_name_plural = _(u"Eventos") def __unicode__(self): """ text = strip_tags(self.event_title) if len(text) > 50: text = "%s..." % text[0:50] else: text = "%s" % text return mark_safe(text) """ return unicode(self.title) def get_text(valor): return mark_safe(strip_tags(valor)) def get_absolute_url(self): """ URL absoluta do Evento """ return reverse('events:event-homepage', args=(self.slug,)) def get_absolute_url_with_host(self): """ URL para montar a pre-visualizacao do Evento, para quando ainda estivar com STATUS=DRAFT """ return current_request().build_absolute_uri(self.get_absolute_url()) def get_url_preview(self): return reverse('events:event-preview', args=(self.slug,)) def get_link_preview(self): return '<a href="%s" target="_blank">%s</a>' % ( reverse('events:event-preview', args=(self.slug,)), unicode(_(u"Pré-visualizar"))) def duplicate_save(self): obj_new = deepcopy(self) obj_new.id = None obj_new.title += "Cópia de %s" % (obj_new.title) obj_new.homepage_active = INACTIVE obj_new.save() return obj_new def get_event_logo(self): """ retorna o caminho do logo do evento para montar a URL """ if self.event_logo: return "%s/%s" % (settings.MEDIA_URL, self.event_logo) else: return False def get_event_image_background(self): if self.event_image_background: return "%s/%s" % (settings.MEDIA_URL, self.event_image_background) else: return os.path.join(settings.STATIC_URL, 'events', 'img', 'header.jpg') def get_event_social_image(self): """ retorna o caminho do logo do evento para montar a URL """ if self.event_logo: return "%s/%s" % (settings.MEDIA_URL, self.event_social_image) else: return '' def get_all_blocks_published(self): """ Busca todos os Blocos de Eventos com Status == Publicados :return: lista de EventBlock """ return self.eventblock_set.filter(status=CONTENT_STATUS_PUBLISHED).order_by('_order') def get_all_programations_published(self): """ Busca todas as Programações de Eventos com Status == Publicados :return: lista de EventProgramation """ return self.eventprogramation_set.filter(status=CONTENT_STATUS_PUBLISHED, programation__status=CONTENT_STATUS_PUBLISHED).order_by('_order') def get_all_programations_published_by_date_time(self): """ Busca todas as Programações de Eventos com Status == Publicados :return: lista de EventProgramation """ # event_programations = self.eventprogramation_set.filter(status=CONTENT_STATUS_PUBLISHED, # programation__status=CONTENT_STATUS_PUBLISHED).order_by('event__eventprogramation__programation__date_time') programations = Programation.objects.filter(eventprogramation__event=self.id, eventprogramation__status=CONTENT_STATUS_PUBLISHED, status=CONTENT_STATUS_PUBLISHED).order_by('date_time', '-eventprogramation___order') list_programations = {} list_dates = [] for programation in programations: #programation = event_programation.programation date_time = programation.date_time.strftime("%d/%m/%Y") if not list_programations.has_key(date_time): list_programations[date_time] = [] list_dates.append(date_time) list_programations[date_time].append(programation) context = { 'list_programations': list_programations, 'list_dates': list_dates } return context def get_code(self): return mark_safe(self.code)
class TinyMCESnippet(models.Model): """Stores small snippets for common content patterns.""" title = models.CharField(max_length=100) description = models.TextField(blank=True) content = RichTextField()
class IndividualWorkoutPage(Page): image = models.ImageField(upload_to="workout_images") article = RichTextField(_("Article for the workout")) date_added = models.DateField(auto_now_add=True,null = True)
class Project(Displayable, AdminThumbMixin): user = ForeignKey(User) liaison = ForeignKey( Liaison, blank=True, null=True, on_delete=models.SET_NULL, help_text='Who can SFPIRG contact with questions about this project?') time_per_week = RichTextField( blank=True, null=True, verbose_name= 'How much time per week can the Contact/Liaison devote to the student?' ) support_method = RichTextField( blank=True, null=True, verbose_name= 'How will the Contact/Liaison provide direction and support to the project?' ) logo = MyImageField( verbose_name="Project Image", upload_to=upload_to("sfpirgapp.project", "uploads/project-images"), format="Image", max_length=255, null=True, blank=True, help_text= 'Please upload an image to represent the project, or your logo. If you do not have one, do not worry, just leave this section blank.' ) admin_thumb_field = "logo" project_type = models.ManyToManyField( ProjectType, help_text='(Please select all that apply)') project_type_other = models.CharField( blank=True, null=True, max_length=255, verbose_name='Other Description', help_text= 'If you checked "other", please briefly describe your project type') project_subject = models.ManyToManyField( ProjectSubject, verbose_name='Project Issues', help_text='(Please select all that apply)') project_subject_other = models.CharField( blank=True, null=True, max_length=255, verbose_name='Other Issues', help_text= 'If you checked "other", please briefly describe your project subject') length = models.CharField( null=True, blank=True, max_length=255, verbose_name='Project Duration', help_text= ('(Please indicate how many months you expect this project to take; ' 'keeping in mind that if your project will take longer than one semester ' 'to complete the pool of students who can undertake it will be limited ' 'to grad students and students who undertake the project independently/not ' 'for course credit. Semesters run from Sept-Dec, Jan-Apr & May-Aug.)' )) description_long = RichTextField( blank=True, null=True, verbose_name='About this Project', help_text= '(What is the central research question you want answered or what project would you like help with? Please provide a detailed description of your project here.)' ) results_plan = RichTextField( blank=True, null=True, verbose_name='Use of Project Results', help_text= '(How do you plan to use the results of this project? For example, do you plan to publish it or will it be kept internal to your organization?)' ) larger_goal = RichTextField( blank=True, null=True, verbose_name='Deliverables', help_text= '(What do you want as specific deliverables for this project? For example, you might want a 10 page research paper on a topic, plus an executive summary, plus a power-point presentation to your organization\'s board of directors.)' ) researcher_qualities = RichTextField( blank=True, null=True, verbose_name='The Student Researcher Must Possess', help_text= '(What skills or attributes do you hope the student researcher will possess?)' ) date_created = models.DateTimeField(auto_now_add=True) date_start = models.DateField('Approval Date', blank=True, null=True) is_submitted = models.BooleanField(default=False) is_approved = models.BooleanField(default=False) is_underway = models.BooleanField(default=False) is_finished = models.BooleanField(default=False) is_completed_successfully = models.BooleanField(default=False) category = ForeignKey(Category, related_name='arx_projects') in_menus = MenusField("Show in menus", blank=True, null=True) admin_notes = models.TextField( blank=True, null=True, help_text='Internal Admin notes, not shown to the front-end users') search_fields = ('title', 'description_long', 'results_plan', 'larger_goal', 'researcher_qualities') def get_description(self): return self.description_long def set_description(self, value): pass description = property(get_description, set_description) @property def richtextpage(self): return self def in_menu_template(self, template_name): if self.in_menus is not None: for i, l, t in settings.PAGE_MENU_TEMPLATES: if not unicode(i) in self.in_menus and t == template_name: return False return True @property def organization_title(self): try: return self.user.profile.organization.title except: return '[None]' @property def featured_image(self): return self.logo @property def content(self): return self.description_long @models.permalink def get_absolute_url(self): return ('arx-project', (), {'slug': self.slug}) @models.permalink def get_apply_url(self): return ('arx-project-apply', (), {'slug': self.slug}) @property def formatted_project_subject(self): subjects = [subj.title for subj in self.project_subject.all()] if subjects == ['Other']: return self.project_subject_other return ', '.join(subjects) def save(self, *args, **kwargs): # Can't save a state that violates consistency if self.is_approved and not self.is_submitted: return if ((self.is_completed_successfully or self.is_finished or self.is_underway) and not (self.is_approved and self.is_submitted)): return if ((self.is_completed_successfully or self.is_finished) and not (self.is_approved and self.is_submitted and self.is_underway)): return if self.is_completed_successfully and not self.is_finished: return if self.is_approved: self.date_start = datetime.datetime.now() return super(Project, self).save(*args, **kwargs)
class Step(models.Model): workout = models.ForeignKey("IndividualWorkoutPage") text = RichTextField() image = models.ImageField(upload_to="step_images")
class Announcement(SiteRelated): """ An announcement to all site visitors. Announcements can be scheduled and/or dismissed by each user when seen. """ title = models.CharField("Title", max_length=255) content = RichTextField("Content") extra_content = RichTextField("Extra Content (optional)", blank=True) image = FileField( "Image", upload_to="announcements/images", format="Image", blank=True ) date_created = models.DateTimeField( "Date created", db_index=True, auto_now_add=True ) date_start = models.DateTimeField("Start date", db_index=True, default=now) date_end = models.DateTimeField("End date", db_index=True, null=True, blank=True) can_dismiss = models.BooleanField( "Dismissable", default=True, help_text="The user can dismiss (close) this announcement", ) button_dismiss_text = models.CharField( "Dismiss text", max_length=100, blank=True, help_text="Text displayed with the dismiss button", ) template = models.CharField(max_length=200) form = models.ForeignKey("forms.Form", blank=True, null=True) video_link = models.URLField("Video URL", blank=True) expire_days = models.PositiveIntegerField( "Announcement frequency", default=365, help_text="Show the announcement again after being dismissed after " "this amount of days", ) appearance_delay = models.PositiveIntegerField( "Appearance delay", default=0, help_text="Delay time for the announcement to appear (milliseconds)", ) objects = AnnouncementManager() class Meta: verbose_name = "Announcement" verbose_name_plural = "Announcements" ordering = ["-date_start"] def __str__(self): return self.title def get_template_display(self): templates = dict(settings.ANNOUNCEMENTS_TEMPLATES) return templates.get(self.template, "") get_template_display.short_description = "Template" def get_email_form(self): if self.form: return FormForForm(self.form, RequestContext(current_request()), None, None) return None def is_active(self): """ Helper method to determine if the announcement is currently active. """ now = timezone.now() if self.date_start < now: if self.date_end is None or self.date_end > now: return True return False is_active.boolean = True def to_html(self): """ HTML representation of this announcement. """ t = loader.get_template(self.template) return t.render({"announcement": self}) def to_json(self): """ JSON representation of this announcement. """ return { "id": self.pk, "title": self.title, "can_dismiss": self.can_dismiss, "html": self.to_html(), }
class IndividualTipsAndAdvicePage(Page): image = models.ImageField(upload_to="tips_images") article = RichTextField(_("Article for tips and advice")) date_added = models.DateField(auto_now_add=True,null = True)
class EventLocation(Slugged): """ A Event Location. """ address = models.TextField() postal_code = models.CharField(_('postal code'), max_length=16) city = models.CharField(_('city'), max_length=255) mappable_location = models.CharField( max_length=128, blank=True, help_text= "This address will be used to calculate latitude and longitude. Leave blank and set Latitude and Longitude to specify the location yourself, or leave all three blank to auto-fill from the Location field." ) lat = models.DecimalField( max_digits=10, decimal_places=7, blank=True, null=True, verbose_name="Latitude", help_text="Calculated automatically if mappable location is set.") lon = models.DecimalField( max_digits=10, decimal_places=7, blank=True, null=True, verbose_name="Longitude", help_text="Calculated automatically if mappable location is set.") room = models.CharField(_('room'), max_length=512, blank=True, null=True) description = RichTextField(_('description'), blank=True) link = models.URLField(max_length=512, blank=True, null=True) external_id = models.IntegerField(_('external_id'), null=True, blank=True) class Meta: verbose_name = _("Event Location") verbose_name_plural = _("Event Locations") ordering = ("title", ) def clean(self): """ Validate set/validate mappable_location, longitude and latitude. """ super(EventLocation, self).clean() if self.lat and not self.lon: raise ValidationError("Longitude required if specifying latitude.") if self.lon and not self.lat: raise ValidationError("Latitude required if specifying longitude.") if not (self.lat and self.lon) and not self.mappable_location: self.mappable_location = self.address.replace("\n", " ").replace( '\r', ' ') + ", " + self.postal_code + " " + self.city if self.mappable_location and not ( self.lat and self.lon): #location should always override lat/long if set g = GoogleMaps(api_key=settings.GOOGLE_API_KEY, domain=settings.EVENT_GOOGLE_MAPS_DOMAIN) try: mappable_location, (lat, lon) = g.geocode(self.mappable_location) except GeocoderQueryError as e: raise ValidationError( "The mappable location you specified could not be found on {service}: \"{error}\" Try changing the mappable location, removing any business names, or leaving mappable location blank and using coordinates from getlatlon.com." .format(service="Google Maps", error=e)) except ValueError as e: raise ValidationError( "The mappable location you specified could not be found on {service}: \"{error}\" Try changing the mappable location, removing any business names, or leaving mappable location blank and using coordinates from getlatlon.com." .format(service="Google Maps", error=e.message)) self.mappable_location = mappable_location self.lat = lat self.lon = lon def save(self): self.clean() super(EventLocation, self).save() def __str__(self): return str(self.title + " - " + self.room) @models.permalink def get_absolute_url(self): return ("event_list_location", (), {"location": self.slug})
class IndividualWeightLossPage(Page): image = models.ImageField(upload_to="weightloss_images") article = RichTextField(_("Article for the weightloss")) date_added = models.DateField(auto_now_add=True, null=True)
class Event(Displayable, SubTitle, Ownable, RichText, AdminThumbMixin): """ An event. """ parent = models.ForeignKey('Event', verbose_name=_('parent'), related_name='children', blank=True, null=True, on_delete=models.SET_NULL) category = models.ForeignKey('EventCategory', verbose_name=_('category'), related_name='events', blank=True, null=True, on_delete=models.SET_NULL) start = models.DateTimeField(_("Start")) end = models.DateTimeField(_("End"), blank=True, null=True) date_text = models.CharField(_('Date text'), max_length=512, blank=True, null=True) location = models.ForeignKey("EventLocation", blank=True, null=True, on_delete=models.SET_NULL) facebook_event = models.BigIntegerField(_('Facebook ID'), blank=True, null=True) shop = models.ForeignKey('EventShop', verbose_name=_('shop'), related_name='events', blank=True, null=True, on_delete=models.SET_NULL) external_id = models.IntegerField(_('External ID'), null=True, blank=True) is_full = models.BooleanField(verbose_name=_("Is Full"), default=False) brochure = FileField(_('brochure'), upload_to='brochures', max_length=1024, blank=True) prices = models.ManyToManyField('EventPrice', verbose_name=_('prices'), related_name='events', blank=True) no_price_comments = RichTextField(_('Price comments'), blank=True, null=True) mentions = models.TextField(_('mentions'), blank=True) allow_comments = models.BooleanField(verbose_name=_("Allow comments"), default=False) comments = CommentsField(verbose_name=_("Comments")) rating = RatingField(verbose_name=_("Rating")) rank = models.IntegerField(verbose_name=_('rank'), blank=True, null=True) admin_thumb_field = "photo" class Meta: verbose_name = _("Event") verbose_name_plural = _("Events") ordering = ( "rank", "start", ) def clean(self): """ Validate end date is after the start date. """ super(Event, self).clean() if self.end and self.start > self.end: raise ValidationError("Start must be sooner than end.") def save(self, *args, **kwargs): super(Event, self).save(*args, **kwargs) # take some values from parent if not self.parent is None: self.title = self.parent.title self.user = self.parent.user self.status = self.parent.status if not self.location: self.location = self.parent.location if not self.description: self.description = self.parent.description self.description_en = self.parent.description_en if not self.category: self.category = self.parent.category if not self.mentions: self.mentions = self.parent.mentions self.mentions_en = self.parent.mentions_en parent_images = self.parent.images.select_related('event').all() for parent_image in parent_images: if not self.images.filter(file=parent_image.file, type=parent_image.type): parent_image.pk = None parent_image.save() parent_image.event = self parent_image.save() if not self.user: self.user = self.parent.user if not self.status: self.status = self.parent.status if not self.content: self.content = self.parent.content self.content_en = self.parent.content_en if not self.departments.all(): parent_departments = self.parent.departments.all() for parent_department in parent_departments: parent_department.pk = None parent_department.save() parent_department.event = self parent_department.save() if not self.links.all(): all_links = self.parent.links.all() for link in all_links: link.pk = None link.save() link.event = self link.save() super(Event, self).save(*args, **kwargs) def update(self, *args, **kwargs): super(Event, self).save(*args, **kwargs) def get_absolute_url(self): """ URLs for events can either be just their slug, or prefixed with a portion of the post's publish date, controlled by the setting ``EVENT_URLS_DATE_FORMAT``, which can contain the value ``year``, ``month``, or ``day``. Each of these maps to the name of the corresponding urlpattern, and if defined, we loop through each of these and build up the kwargs for the correct urlpattern. The order which we loop through them is important, since the order goes from least granualr (just year) to most granular (year/month/day). """ url_name = "event_detail" kwargs = {"slug": self.slug} date_parts = ("year", "month", "day") if settings.EVENT_URLS_DATE_FORMAT in date_parts: url_name = "event_detail_%s" % settings.EVENT_URLS_DATE_FORMAT for date_part in date_parts: date_value = str(getattr(self.publish_date, date_part)) if len(date_value) == 1: date_value = "0%s" % date_value kwargs[date_part] = date_value if date_part == settings.EVENT_URLS_DATE_FORMAT: break return reverse(url_name, kwargs=kwargs) def get_icalendar_event(self): """ Builds an icalendar.event object from event data. """ icalendar_event = IEvent() icalendar_event.add('summary'.encode("utf-8"), self.title) icalendar_event.add( 'url', 'http://{domain}{url}'.format( domain=Site.objects.get(id=current_site_id()).domain, url=self.get_absolute_url(), )) if self.location: icalendar_event.add('location'.encode("utf-8"), self.location.address) icalendar_event.add('dtstamp', self.start) icalendar_event.add('dtstart', self.start) if self.end: icalendar_event.add('dtend', self.end) icalendar_event['uid'.encode("utf-8")] = "event-{id}@{domain}".format( id=self.id, domain=Site.objects.get(id=current_site_id()).domain, ).encode("utf-8") return icalendar_event def _get_next_or_previous_by_start_date(self, is_next, **kwargs): """ Retrieves next or previous object by start date. We implement our own version instead of Django's so we can hook into the published manager and concrete subclasses. """ arg = "start__gt" if is_next else "start__lt" order = "start" if is_next else "-start" lookup = {arg: self.start} concrete_model = base_concrete_model(Displayable, self) try: queryset = concrete_model.objects.published except AttributeError: queryset = concrete_model.objects.all try: return queryset(**kwargs).filter(**lookup).filter( parent__isnull=True).order_by(order)[0] except IndexError: pass def get_next_by_start_date(self, **kwargs): """ Retrieves next object by start date. """ return self._get_next_or_previous_by_start_date(True, **kwargs) def get_previous_by_start_date(self, **kwargs): """ Retrieves previous object by start date. """ return self._get_next_or_previous_by_start_date(False, **kwargs) def date_format(self): if self.periods.all(): return 'D j F' else: return 'l j F'
class IndividualHealthyLivingPage(Page): image = models.ImageField(upload_to="healthyliving_images") article = RichTextField(_("Article"), default="") date_added = models.DateField(auto_now_add=True)
class IndividualMealIdeasPage(Page): image = models.ImageField(upload_to="meal_images") article = RichTextField(_("Article"), default="") date_added = models.DateField(auto_now_add=True)
class Block(Page, RichText): IDE = models.ForeignKey(IDE, blank=True, null=True) syntax = RichTextField(blank=True, null=True) ext_doc = models.URLField('External Documentation', blank=True, null=True, help_text='Link to external documentation') parent_object = models.ForeignKey( "self", related_name='object', blank=True, null=True, help_text='Parent object for property or method') proxy = models.ForeignKey( "self", related_name="proxied", blank=True, null=True, help_text='Existing block to pull documentation from') signature = models.CharField(max_length=255, blank=True, null=True) category = models.ForeignKey(Category, blank=True, null=True) return_value = models.CharField( max_length=255, blank=True, null=True, help_text='Description of return value or alternate functionality') tips = RichTextField(blank=True, null=True, help_text='List of tips for using this block') video = models.ForeignKey('lessons.Resource', blank=True, null=True) # Using FileField instead of ImageField to support SVG blocks. ImageField is raster only :( image = models.FileField(blank=True, null=True, upload_to="blocks/") _old_slug = models.CharField('old_slug', max_length=2000, blank=True, null=True) class Meta: ordering = ["IDE", "category"] def __unicode__(self): return self.block_with_ide @property def block_with_ide(self): return "%s - %s" % (self.IDE, self.title) @property def lessons_introduced(self): return self.lesson_set.filter( unit__login_required=False, curriculum__login_required=False).order_by('curriculum', 'unit', 'number') @property def code(self): if self.syntax: return self.syntax else: return self.title def get_absolute_url(self): return '/%s/%s/' % (self.IDE.slug, self.slug) def get_published_url(self): return '//docs.code.org/%s/%s/' % (self.IDE.slug, self.slug) def jackfrost_urls(self): urls = [ "/documentation%s" % self.get_absolute_url(), "/documentation%sembed/" % self.get_absolute_url() ] return urls def jackfrost_can_build(self): return settings.ENABLE_PUBLISH and self.status == 2 and not self.login_required def publish(self, children=False): if self.jackfrost_can_build(): try: read, written = build_page_for_obj(Block, self) slack_message( 'slack/message.slack', { 'message': 'published %s %s' % (self.content_model, self.title), 'color': '#00adbc' }) yield json.dumps(written) yield '\n' except Exception, e: yield json.dumps(e.message) yield '\n' logger.exception('Failed to publish %s' % self)
class IndividualGuiltyPleasuresPage(Page): image = models.ImageField(upload_to="guiltypleasure_images") article = RichTextField(_("Article"), default="") date_added = models.DateField(auto_now_add=True)
class Question(KnowledgeBase): is_question = True _requesting_user = None title = models.CharField(max_length=255, verbose_name=_('Question'), help_text=_('Enter your question or suggestion.')) body = RichTextField( blank=True, null=True, verbose_name=_('Description'), help_text=_('Please offer details. Markdown enabled.')) status = models.CharField(verbose_name=_('Status'), max_length=32, choices=STATUSES, default='private', db_index=True) locked = models.BooleanField(default=False) categories = models.ManyToManyField('knowledge.Category', blank=True) objects = QuestionManager() class Meta: ordering = ['-added'] verbose_name = _('Question') verbose_name_plural = _('Questions') def __unicode__(self): return self.title @models.permalink def get_absolute_url(self): from django.template.defaultfilters import slugify if settings.SLUG_URLS: return ('knowledge_thread', [self.id, slugify(self.title)]) else: return ('knowledge_thread_no_slug', [self.id]) def inherit(self): pass def internal(self): pass def lock(self, save=True): self.locked = not self.locked if save: self.save() lock.alters_data = True ################### #### RESPONSES #### ################### def get_responses(self, user=None): user = user or self._requesting_user if user: return [ r for r in self.responses.all().select_related('user') if r.can_view(user) ] else: return self.responses.all().select_related('user') def answered(self): """ Returns a boolean indictating whether there any questions. """ return bool(self.get_responses()) def accepted(self): """ Returns a boolean indictating whether there is a accepted answer or not. """ return any([r.accepted for r in self.get_responses()]) def clear_accepted(self): self.get_responses().update(accepted=False) clear_accepted.alters_data = True def accept(self, response=None): """ Given a response, make that the one and only accepted answer. Similar to StackOverflow. """ self.clear_accepted() if response and response.question == self: response.accepted = True response.save() return True else: return False accept.alters_data = True def states(self): """ Handy for checking for mod bar button state. """ return [self.status, 'lock' if self.locked else None] @property def url(self): return self.get_absolute_url()
class ArProgramPage(Page): youtube_url = RichTextField(_("Youtube URL for AR Program")) text = RichTextField(_("Text for AR Program"))
class RichTextModel(models.Model): text_default = RichTextField() text_overridden = RichTextField()
class MemberPage(Page): text = RichTextField(verbose_name='Texto')