class AboutPage(RoutablePageMixin, Page): body = MarkdownField(null=True, blank=True) content_panels = Page.content_panels + [ MarkdownPanel('body', classname="full"), ] def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) context["posts"] = IndexDetailPage.objects.live().public() json_list = list(context["posts"].values( 'slug', 'title', 'author_founder', 'rownum', 'pub_date', 'end_date', 'about', 'location', 'external_link', 'external_link_two', 'images_list', 'page_ptr_id')) context['json_dict'] = json.dumps(json_list) context["image_entries"] = [] for index in context["posts"]: for c in index.images_list.all(): context["image_entries"].append({ "slug": index.slug, "img_name": str(c) }) context['json_img_dict'] = json.dumps(list(context["image_entries"])) return context @route(r'^submit/$', name="submit_page") def submit_page(self, request): return TemplateResponse(request, 'about/about_submit_page.html')
class ContactFormSuccessPage(Page): body_text = MarkdownField() content_panels = [ FieldPanel('title'), FieldPanel('body_text'), ]
class PortfolioPageJobCareer(GraphQLEnabledModel, Orderable): portfolio = ParentalKey(PortfolioPage, on_delete=models.CASCADE, related_name='job_career', verbose_name=u'職務経歴') title = models.CharField(verbose_name=u'タイトル', max_length=50) start_date = models.DateField(u'開始日', auto_now=False, auto_now_add=False) end_date = models.DateField(u'終了日', auto_now=False, auto_now_add=False, blank=True, null=True) job_role = models.CharField(u'役割', max_length=50, blank=True, null=True) description = MarkdownField(verbose_name=u'説明', blank=True, null=True) panels = [ FieldPanel('title'), FieldPanel('start_date'), FieldPanel('end_date'), FieldPanel('job_role'), MarkdownPanel('description') ] graphql_fields = [ GraphQLField('title'), GraphQLField('start_date'), GraphQLField('end_date'), GraphQLField('job_role'), GraphQLField('description'), ]
class ContactUserEmail(BaseSetting): title = CharField( max_length=255, default="Invest in GREAT Britain", ) heading = CharField(max_length=255, default="Invest in GREAT Britain Contact Confirmation") body_text = MarkdownField(default=dedent(""" Thank you for contacting the Department for International Trade about your investment plans. We have received the information you sent through the Invest in Great Britain website and will aim to follow up with you in the next 7 days. Your enquiry may be forwarded to a local post for follow up. The Department for International Trade provides free and impartial advice to companies around the world interested in doing business in the UK. We look forward to welcoming you as one of the many companies to enjoy success in the UK. Find our Terms and Conditions [here](http://https://invest.great.gov.uk/int/terms-and-conditions/). See below for your submitted form:""")) # noqa body_text_continued = MarkdownField(default=dedent(""" Many Thanks DIT""" # noqa )) footer = MarkdownField(default=dedent(""" Department for International Trade (DIT) is the Government Department that helps UK‑based companies succeed in the global economy. We also help overseas companies bring their high-quality investment to the UK’s dynamic economy, acknowledged as Europe’s best place in which to succeed in global business. [invest.great.gov.uk](http://https://invest.great.gov.uk)""") ) # noqa panels = [ FieldPanel('title'), FieldPanel('heading'), FieldPanel('body_text'), FieldPanel('body_text_continued'), FieldPanel('footer'), ]
class StaticContent(models.Model): text = MarkdownField() panels = [ MarkdownPanel('text'), ] def __str__(self): return self.text
class InfoPage(Page): """ Markdown page - used for terms and conditions and privacy policy """ content = MarkdownField() content_panels = Page.content_panels + [ FieldPanel('content'), ]
class PostPage(Page): body = MarkdownField() date = models.DateTimeField(verbose_name="Post date", default=datetime.datetime.today) excerpt = MarkdownField( verbose_name='excerpt', blank=True, ) header_image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', ) categories = ParentalManyToManyField('blog.BlogCategory', blank=True) tags = ClusterTaggableManager(through='blog.BlogPageTag', blank=True) content_panels = Page.content_panels + [ ImageChooserPanel('header_image'), MarkdownPanel("body"), MarkdownPanel("excerpt"), FieldPanel('categories', widget=forms.CheckboxSelectMultiple), FieldPanel('tags'), ] settings_panels = Page.settings_panels + [ FieldPanel('date'), ] @property def blog_page(self): return self.get_parent().specific def get_context(self, request, *args, **kwargs): context = super(PostPage, self).get_context(request, *args, **kwargs) context['blog_page'] = self.blog_page context['post'] = self return context
class ContactAgentEmail(BaseSetting): title = CharField( max_length=255, default="Invest in GREAT Britain", ) heading = CharField(max_length=255, default="Invest in GREAT Britain Contact Confirmation") body_text = MarkdownField(default=dedent(""" This is confirmation of an Invest in Great Britain lead via the contact us form on the website. See below for the user submitted form:""") # noqa ) body_text_continued = MarkdownField(default=dedent(""" Many Thanks DIT""") # noqa ) footer = MarkdownField(default=dedent(""" Department for International Trade (DIT) is the Government Department that helps UK‑based companies succeed in the global economy. We also help overseas companies bring their high-quality investment to the UK’s dynamic economy, acknowledged as Europe’s best place in which to succeed in global business. [invest.great.gov.uk](http://https://invest.great.gov.uk)""" ) # noqa ) panels = [ FieldPanel('title'), FieldPanel('heading'), FieldPanel('body_text'), FieldPanel('body_text_continued'), FieldPanel('footer'), ]
class SitePolicyPage(GraphQLEnabledModel, Page): body = MarkdownField(verbose_name=u'本文', blank=True) content_panels = Page.content_panels + [ MarkdownPanel("body", classname="full"), ] promote_panels = [ MultiFieldPanel(Page.promote_panels, "Common page configuration"), ] graphql_fields = [ GraphQLField('body'), ]
class CharacterPage(GraphQLEnabledModel, Page): """A page of character list.""" nickname = models.CharField(u"称号", max_length=15, null=True) name = models.CharField(u"名前", max_length=35, null=True) character_id = models.CharField(u"キャラクターID", max_length=6, null=True) image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', verbose_name=u'画像', ) description = models.CharField(u'概要', max_length=255, null=True) introduction = MarkdownField(verbose_name=u"説明", null=True) game_name = models.CharField(u"登録されているゲーム", max_length=20, null=True) character_page_url = models.CharField(u"キャラクターのページ", max_length=255, null=True) content_panels = Page.content_panels + [ FieldPanel('nickname'), FieldPanel('name'), FieldPanel('character_id'), ImageChooserPanel('image'), FieldPanel('description'), MarkdownPanel('introduction'), FieldPanel('game_name'), FieldPanel('character_page_url'), ] promote_panels = [ MultiFieldPanel(Page.promote_panels, "Common page configuration"), ] graphql_fields = [ GraphQLField("nickname"), GraphQLField("name"), GraphQLField("character_id"), GraphQLField("image"), GraphQLField("description"), GraphQLField("introduction"), GraphQLField("game_name"), GraphQLField("character_page_url"), ] def clean(self): super().clean() new_title = '%s(%s)' % (self.name, self.character_id) new_slug = '%s' % self.character_id self.title = new_title self.slug = slugify(new_slug)
class PuzzlePostPage(Page): date = models.DateField('Post date') body = MarkdownField(blank=True) answer = MarkdownField(blank=True) def main_image(self): gallery_item = self.gallery_images.first() if gallery_item: return gallery_item.image else: return None search_fields = Page.search_fields + [ index.SearchField('body'), index.SearchField('answer'), ] content_panels = Page.content_panels + [ FieldPanel('date'), MarkdownPanel('body'), MarkdownPanel('answer'), InlinePanel('gallery_images', label='Gallery images'), ]
class Branding(BaseSetting): logo = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') favicon = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') language_choice_icon = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') footer_logo = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') footer_secondary_nav = StreamField([ ('internal_link', PageChooserBlock()), ('external_link', ExternalLinkBlock()), ], blank=True) footer_copyright = models.CharField(max_length=255) is_beta = models.BooleanField(default=True) beta_bar_text = MarkdownField( default="This is a new service - your feedback will help improve it.") skip_to_main_text = models.CharField(default="Skip to main content", max_length=40) panels = [ ImageChooserPanel('logo'), ImageChooserPanel('favicon'), ImageChooserPanel('language_choice_icon'), ImageChooserPanel('footer_logo'), StreamFieldPanel('footer_secondary_nav'), FieldPanel('footer_copyright'), FieldPanel('is_beta'), FieldPanel('beta_bar_text'), ]
class BookIndexPage(GraphQLEnabledModel, Page): intro = MarkdownField(null=True) def child_pages(self): return BookPage.objects.live().child_of(self) content_panels = Page.content_panels + [ MarkdownPanel('intro', classname='full') ] graphql_fields = [ GraphQLField('intro'), ] subpage_types = ['BookPage']
class BlogIndexPage(MetadataPageMixin, Page): sub_title = models.CharField(max_length=600, blank=True) body = MarkdownField(blank=True) image = models.ForeignKey('wagtailimages.Image', blank=True, null=True, on_delete=models.PROTECT, related_name='blog_index_image') content_panels = Page.content_panels + [ FieldPanel("sub_title", classname="blog index title"), MarkdownPanel("body"), FieldPanel('image', classname="blog index image"), ] search_fields = Page.search_fields + [ index.SearchField('sub_title'), index.SearchField('body'), ]
class ArticlePage(GraphQLEnabledModel, Page): """Article Pages""" date = models.DateTimeField(u"投稿日") tags = ClusterTaggableManager(verbose_name=u'タグ', through=ArticlePageTag, blank=True) body = MarkdownField(verbose_name=u'本文', blank=True) feed_image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', verbose_name=u'画像', ) author = models.ForeignKey( 'author.AuthorPage', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', verbose_name=u'著者', ) content_panels = Page.content_panels + [ FieldPanel('date'), FieldPanel('tags'), MarkdownPanel("body", classname="full"), ImageChooserPanel('feed_image'), PageChooserPanel('author', 'author.AuthorPage'), InlinePanel('related_links', label=u'関連リンク'), ] promote_panels = [ MultiFieldPanel(Page.promote_panels, "Common page configuration"), ] graphql_fields = [ GraphQLField('author'), GraphQLField('date'), GraphQLField('tags'), GraphQLField('slug'), GraphQLField('body'), GraphQLField('feed_image'), GraphQLField('related_links') ]
class EntryAbstract(models.Model): body = MarkdownField(blank=True) verbose_name = _('body') tags = ClusterTaggableManager(through='puput.TagEntryPage', blank=True) date = models.DateTimeField(verbose_name=_("Post date"), default=datetime.datetime.today) header_image = models.ForeignKey(get_image_model_path(), verbose_name=_('Header image'), null=True, blank=True, on_delete=models.SET_NULL, related_name='+') categories = models.ManyToManyField('puput.Category', through='puput.CategoryEntryPage', blank=True) excerpt = RichTextField( verbose_name=_('excerpt'), blank=True, help_text=_( "Entry excerpt to be displayed on entries list. " "If this field is not filled, a truncate version of body text will be used." )) num_comments = models.IntegerField(default=0, editable=False) content_panels = [ MultiFieldPanel([ FieldPanel('title', classname="title"), ImageChooserPanel('header_image'), FieldPanel('body', classname="full"), FieldPanel('excerpt', classname="full"), ], heading=_("Content")), MultiFieldPanel([ FieldPanel('tags'), InlinePanel('entry_categories', label=_("Categories")), InlinePanel('related_entrypage_from', label=_("Related Entries"), panels=[PageChooserPanel('entrypage_to')]), ], heading=_("Metadata")), ] class Meta: abstract = True
class HomePage(Page): home_title = models.CharField(max_length=600, blank=True) body = MarkdownField(blank=True) image = models.ForeignKey('wagtailimages.Image', blank=True, null=True, on_delete=models.PROTECT, related_name='home_image') content_panels = Page.content_panels + [ FieldPanel("home_title", classname="Home title"), MarkdownPanel("body"), FieldPanel('image', classname="Home image"), ] search_fields = Page.search_fields + [ index.SearchField('title'), index.SearchField('body'), ]
class BaseCompany(TimeStampedModel): name = models.CharField(max_length=200, unique=True) location = models.ForeignKey('crm.City', on_delete=models.CASCADE) channel = models.ForeignKey('Channel', on_delete=models.SET_NULL, help_text="Lead channel this company came from", null=True, blank=True) url = models.URLField(blank=True, null=True) notes = MarkdownField(default="", blank=True) def __str__(self): return self.name class Meta: abstract = True verbose_name_plural = 'clients' verbose_name = 'client'
class BlogPage(MetadataPageMixin, Page): sub_title = models.CharField(max_length=600, blank=True) body = MarkdownField(blank=True) image = models.ForeignKey('wagtailimages.Image', blank=True, null=True, on_delete=models.PROTECT, related_name='blog_image') content_panels = Page.content_panels + [ FieldPanel("sub_title", classname="blog title"), MarkdownPanel("body"), FieldPanel('image', classname="blog image"), ] search_fields = Page.search_fields + [ index.SearchField('sub_title'), index.SearchField('body'), ] def get_context(self, request): context = super(BlogPage, self).get_context(request) context['recommended'] = BlogPage.objects.live().exclude(id=self.id).order_by('?')[:5] context['surah'] = Chapter.objects.order_by('?')[:10] return context
class BookPage(GraphQLEnabledModel, Page): price = models.IntegerField() published_date = models.DateField() published_event = models.CharField(max_length=50) description = MarkdownField(verbose_name=u'説明') booth_url = models.URLField(max_length=255, null=True) bookwalker_url = models.URLField(max_length=255, null=True) image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', ) content_panels = Page.content_panels + [ FieldPanel('price'), FieldPanel('published_date'), FieldPanel('published_event'), MarkdownPanel('description'), FieldPanel('booth_url'), FieldPanel('bookwalker_url'), ImageChooserPanel('image'), ] promote_panels = [ MultiFieldPanel(Page.promote_panels, "Common page configuration"), ] graphql_fields = [ GraphQLField('price'), GraphQLField('published_date'), GraphQLField('published_event'), GraphQLField('description'), GraphQLField('booth_url'), GraphQLField('bookwalker_url'), GraphQLField('image'), GraphQLField('slug') ]
class Project(ProjectStateMixin, TimeStampedModel): company = models.ForeignKey('ClientCompany', on_delete=models.SET_NULL, null=True, blank=True, related_name='projects') manager = models.ForeignKey('Employee', on_delete=models.SET_NULL, null=True, blank=True, related_name='projects') location = models.ForeignKey('crm.City', related_name='projects', on_delete=models.CASCADE) original_description = RichTextField() original_url = models.URLField(null=True, blank=True) notes = MarkdownField(null=True, blank=True) daily_rate = models.DecimalField( decimal_places=2, max_digits=6, null=True, blank=True ) start_date = models.DateField(null=True, blank=True) end_date = models.DateField(null=True, blank=True) project_page = models.ForeignKey('home.ProjectPage', on_delete=models.SET_NULL, null=True, blank=True) messages = models.ManyToManyField('django_mailbox.Message', through='ProjectMessage', related_name="projects", editable=False) @property def recruiter(self): return self.manager.company if self.manager else None @property def duration(self): try: return math.ceil((self.end_date - self.start_date).days / 30) except TypeError: pass def get_duration_display(self): return f"{self.duration} months" def get_original_description_display(self): return SafeText(self.original_description) def get_notes_display(self): return SafeText(render_markdown(self.notes)) def get_project_page_display(self): if not self.project_page: return url = reverse("wagtailadmin_pages:edit", args=(self.project_page.pk,)) return SafeText( f"<a href='{url}'>{self.project_page}</a>" ) @property def budget(self): if not self.start_date or not self.end_date: return working_days = len(get_working_days(self.start_date, self.end_date)) if not self.daily_rate: return return self.daily_rate * working_days @property def vat(self): if not self.budget: return return self.budget * settings.VAT_RATE @property def invoice_amount(self): if not self.vat: return return self.budget + self.vat @property def income_tax(self): if not self.budget: return return self.budget * settings.INCOME_TAX_RATE @property def nett_income(self): if not self.budget or not self.income_tax: return return self.budget - self.income_tax @property def working_days(self): if not self.start_date or not self.end_date: return return len(get_working_days(self.start_date, self.end_date)) def get_budget_display(self): return f"{self.budget} €" if self.budget else None def get_vat_display(self): return f"{self.vat:.2f} €" if self.vat else None def get_invoice_amount_display(self): return f"{self.invoice_amount:.2f} €" if self.invoice_amount else None def get_income_tax_display(self): return f"{self.income_tax:.2f} €" if self.income_tax else None def get_nett_income_display(self): return f"{self.nett_income:.2f} €" if self.nett_income else None def clean(self): if self.start_date and self.end_date and self.start_date >= self.end_date: raise ValidationError( { "start_date": "End date can't be earlier than start date", "end_date": "End date can't be earlier than start date", } ) def save(self, *args, **kwargs): if not self.daily_rate and self.recruiter: self.daily_rate = self.recruiter.default_daily_rate super().save(*args, **kwargs) def __str__(self): return str(self.company or self.recruiter) class Meta: verbose_name_plural = "projects"
class AuthorPage(GraphQLEnabledModel, Page): profile = MarkdownField(verbose_name=u'プロフィール') nickname = models.CharField(verbose_name=u'ニックネーム', max_length=25, null=True, blank=True) first_name = models.CharField(verbose_name=u'名', max_length=10, null=True, blank=True) middle_name = models.CharField(verbose_name=u'ミドルネーム', max_length=10, null=True, blank=True) family_name = models.CharField(verbose_name=u'姓', max_length=10, null=True, blank=True) name = models.CharField(verbose_name=u'表示名', max_length=80, null=True, blank=True) is_surname_first = models.BooleanField(verbose_name=u'姓が先の表記', null=True, blank=True) use_nickname = models.BooleanField(verbose_name=u'ニックネームの使用', null=True, blank=True) portrait = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', verbose_name=u'画像', ) interest = ClusterTaggableManager(verbose_name=u'興味を持っていること', through=AuthorPageInterest, blank=True) content_panels = Page.content_panels + [ MarkdownPanel('profile'), ImageChooserPanel('portrait'), FieldPanel('interest'), FieldPanel('nickname'), FieldPanel('first_name'), FieldPanel('middle_name'), FieldPanel('family_name'), FieldPanel('name'), FieldPanel('is_surname_first'), FieldPanel('use_nickname'), InlinePanel('portfolio_links', label=u'ポートフォリオ'), InlinePanel('amazon_wish_list_links', label=u'Amazonのほしいものリスト'), InlinePanel('sns_links', label=u'SNSなどのリンク'), ] promote_panels = [ MultiFieldPanel(Page.promote_panels, "Common page configuration"), ] graphql_fields = [ GraphQLField('name'), GraphQLField('profile'), GraphQLField('portrait'), GraphQLField('interest'), GraphQLField('portfolio_links'), GraphQLField('amazon_wish_list_links'), GraphQLField('sns_links'), ] def clean(self): """Rename title when posted.""" if self.nickname is not None and self.use_nickname is True: self.name = self.nickname elif self.is_surname_first is True: if self.middle_name is None: self.name = self.family_name + u' ' + self.first_name else: self.name = (self.family_name + u' ' + self.middle_name + u' ' + self.first_name) else: if self.middle_name is None: self.name = self.first_name + u' ' + self.family_name else: self.name = (self.first_name + u' ' + self.middle_name + u' ' + self.family_name) self.title = '%s のプロフィール' % self.name
class TestPage(Page): body = MarkdownField(blank=True) content_panels = Page.content_panels + [FieldPanel("body")]
class Action(models.Model): name = models.CharField(max_length=255, db_index=True) when = models.DateTimeField(db_index=True) description = MarkdownField(default="", blank=True, help_text="Markdown formatted") slug = models.SlugField(unique=True, help_text="Short form of the title, for URLs") public = models.BooleanField( default=True, blank=True, help_text="Whether this action should be listed publicly", ) location = models.TextField( default="", blank=True, help_text="Event location will be converted to a google maps link, unless you format it as a Markdown link -- [link text](http://example.com)", ) virtual = models.BooleanField( default=False, help_text="Check this if the event is online (virtual zoom or other video conferencing)", ) available_roles = models.CharField( default="", blank=True, max_length=255, help_text="List of comma-separated strings", ) # Will need to figure out how to migrate this over. photos = models.ManyToManyField(Photo, blank=True) image = models.ForeignKey( "vaquita.CustomImage", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) modified = models.DateTimeField(auto_now=True) show_commitment = models.BooleanField( blank=True, default=False, help_text="Whether to show the conditional commitment fields", ) max_participants = models.IntegerField( blank=True, default=0, help_text="Maximun number of people allowed to register" ) accessibility = models.TextField( default="", help_text="Indicate what the accessibility accomodations are for this location.", ) contact_email = models.TextField( default="", null=True, help_text="Contact info of event organizer." ) tags = TaggableManager( blank=True, help_text="Attendees will automatically be tagged with these tags" ) objects = ActionManager() panels = [ MultiFieldPanel( [ FieldPanel("name", widget=forms.TextInput(attrs={"id": "id_title"})), FieldPanel("when"), FieldPanel("virtual"), FieldPanel("location"), FieldPanel("slug"), ] ), FieldPanel("contact_email"), MarkdownPanel("description", widget=ZOrderMarkdownTextarea), ImageChooserPanel("image"), FieldPanel("tags"), FieldRowPanel( [ FieldPanel("public"), FieldPanel("max_participants"), FieldPanel("show_commitment"), ] ), FieldPanel("accessibility"), ] @property def available_role_choices(self): for role in self.available_roles.split(","): role = role.strip() if role: yield role def is_full(self): return ( self.max_participants and self.attendee_set.count() >= self.max_participants ) def get_absolute_url(self): return reverse("extinctionr.actions:action", kwargs={"slug": self.slug}) @property def full_url(self): return f"{base_url()}{self.get_absolute_url()}" def signup(self, email, role, name="", notes="", promised=None, commit=0): if not isinstance(role, ActionRole): role = ActionRole.objects.get_or_create(name=role or "")[0] user = get_contact(email, name=name) atten, created = Attendee.objects.get_or_create( action=self, contact=user, role=role ) if not created: if notes: atten.notes = notes else: atten.notes = notes atten.mutual_commitment = commit if promised: atten.promised = now() atten.save() return atten @property def html_title(self): return mark_safe(self.name.replace("\n", "<br>").replace("\\n", "<br>")) @property def text_title(self): return self.name.replace("\\n", " ") def __str__(self): return f"{self.name} on {self.when.strftime('%b %e, %Y @ %H:%M')}" def save(self, *args, **kwargs): ret = super().save(*args, **kwargs) for role in self.available_role_choices: ActionRole.objects.get_or_create(name=role) return ret @property def location_link(self): if self.location.startswith("["): link = markdown(self.location) else: if self.virtual: link_text = "Online Meeting" else: link_text = self.location # See if the text is already a valid url. url_validator = URLValidator(schemes=["http", "https"]) try: url_validator(self.location) link = f"<a href={self.location}>{link_text}</a>" except ValidationError: if self.virtual: link = "/" # validation should have seen to this. else: link = '<a href="https://maps.google.com/?q={}">{}</a>'.format( quote(self.location), linebreaks(self.location) ) pass return mark_safe(link) @property def card_thumbnail_url(self): if self.photos: photo = self.photos.first() if photo: return photo.photo.url return None
class BaseResumePage(MetadataMixin, Page): page_ptr = models.OneToOneField(Page, parent_link=True, related_name="+", on_delete=models.CASCADE) is_creatable = False font = models.CharField(max_length=100, null=True, blank=True) background_color = models.CharField(max_length=100, null=True, blank=True) full_name = models.CharField(max_length=100, null=True, blank=True) role = models.CharField(max_length=100, null=True, blank=True) about = MarkdownField(max_length=2500, null=True, blank=True) photo = models.ForeignKey(Image, null=True, blank=True, on_delete=models.SET_NULL, related_name="+") social_links = fields.StreamField( [ ( "social_link", blocks.StructBlock( [ ("text", blocks.TextBlock()), ("url", blocks.URLBlock()), ("logo", ImageChooserBlock()), ], icon="group", ), ), ], null=True, blank=True, ) resume = fields.StreamField( [ ("work_experience", WorkExperienceBlock()), ("contributions", ContributionsBlock()), ("writing", WritingsBlock()), ("education", EducationBlock()), ], null=True, blank=True, ) content_panels = Page.content_panels + [ MultiFieldPanel( [ FieldPanel("font"), FieldPanel("background_color"), ], heading="Customization", ), MultiFieldPanel( [ FieldPanel("full_name"), FieldPanel("role"), MarkdownPanel("about"), ImageChooserPanel("photo"), StreamFieldPanel("social_links"), ], heading="Personal details", ), StreamFieldPanel("resume"), ] def get_template(self, request): return "wagtail_resume/resume_page.html" def get_meta_title(self): return self.full_name def get_meta_description(self): return f"{self.full_name} - {self.role}" def get_meta_image(self): return self.photo def get_meta_url(self): return self.get_full_url def get_meta_twitter_card_type(self): return self.photo
def test_markdown_field(self): field = MarkdownField() self.assertEqual(type(field.formfield().widget), MarkdownTextarea)
class BlogPage(Page): """ This is the core of the Blog app. BlogPage are individual articles """ subtitle = models.CharField(blank=True, max_length=255) body = MarkdownField(blank=True) extended_body = StreamField([ ('content', MarkdownBlock(template='blog/markdown_block.html')), ('newsletter', NewsletterSubscribe()), ('book', BookInline()), ], null=True) image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', help_text='Header Image, used also for social sharing') image_data = RichTextField( blank=True, null=True, help_text= 'Information about the header image, to appear after the article') tags = ClusterTaggableManager(through=BlogPageTag, blank=True) date_published = models.DateField("Date article published", blank=True, null=True) allow_comments = models.BooleanField(default=True) content_panels = Page.content_panels + [ FieldPanel('subtitle'), StreamFieldPanel('extended_body'), MarkdownPanel('body'), ImageChooserPanel('image'), FieldPanel('image_data'), FieldPanel('date_published'), InlinePanel('blog_person_relationship', label="Author(s)", panels=None, min_num=1), FieldPanel('tags'), ] promote_panels = Page.promote_panels + [ FieldPanel('allow_comments'), ] search_fields = Page.search_fields + [ index.SearchField('body'), ] def authors(self): """ Returns the BlogPage's related People. Again note that we are using the ParentalKey's related_name from the BlogPeopleRelationship model to access these objects. This allows us to access the People objects with a loop on the template. If we tried to access the blog_person_ relationship directly we'd print `blog.BlogPeopleRelationship.None` """ authors = [n.people for n in self.blog_person_relationship.all()] return authors @property def first_author(self): return self.authors()[-1] @property def get_tags(self): """ Similar to the authors function above we're returning all the tags that are related to the blog post into a list we can access on the template. We're additionally adding a URL to access BlogPage objects with that tag """ tags = self.tags.all() for tag in tags: tag.url = '/' + '/'.join( s.strip('/') for s in [self.get_parent().url, 'tags', tag.slug]) return tags # Specifies parent to BlogPage as being BlogIndexPages parent_page_types = ['BlogIndexPage'] # Specifies what content types can exist as children of BlogPage. # Empty list means that no child content types are allowed. subpage_types = [] def get_absolute_url(self): return self.specific.url def get_context(self, request): context = super(BlogPage, self).get_context(request) context['latest_articles'] = BlogPage.objects.live().order_by( '-date_published')[:5] context['intro_class'] = 'blog article' return context @property def introduction(self): html = render_markdown(self.body) soup = BeautifulSoup(html, "html.parser") try: introduction = soup.find('p').text return introduction except AttributeError: return None class Meta: ordering = ['-date_published']
class IndexDetailPage(Page): about = MarkdownField(null=True, blank=True) sourceforabouttext = models.CharField("Source for about text", max_length=255, null=True, blank=True) categories = ParentalManyToManyField("index.IndexCategory", blank=True) pub_date = models.PositiveSmallIntegerField("Date Published / Created", null=True, blank=True) end_date = models.PositiveSmallIntegerField("End Date", null=True, blank=True) author_founder = models.CharField("Author/Founder", max_length=500, null=True, blank=True) contributed_by = models.CharField("Contributed By", max_length=500, null=True, blank=True) external_link = models.URLField(null=True, blank=True) external_link_two = models.URLField(null=True, blank=True) autoincrement_num = models.PositiveSmallIntegerField(null=True, blank=True) rownum = models.PositiveSmallIntegerField(null=True, blank=True) location = models.CharField("location", max_length=255, null=True, blank=True) # slug = models.SlugField(verbose_name=_('slug'), allow_unicode=True, max_length=255) search_fields = Page.search_fields + [ index.SearchField('title'), index.SearchField('author_founder'), index.SearchField('about'), index.SearchField('contributed_by'), index.SearchField('location'), index.SearchField('pub_date'), index.SearchField('end_date'), ] content_panels = Page.content_panels + [ MarkdownPanel('about', classname="full"), MultiFieldPanel([ FieldRowPanel([ FieldPanel('pub_date'), FieldPanel('end_date'), ]), FieldRowPanel([ FieldPanel('author_founder'), FieldPanel('location'), ]), FieldRowPanel([ FieldPanel('external_link'), FieldPanel('external_link_two'), ]), FieldRowPanel([ FieldPanel('contributed_by'), ]), ], 'Details'), MultiFieldPanel( [ InlinePanel('images_list', label='Image'), ], heading="Image(s)", ), MultiFieldPanel( [FieldPanel("categories", widget=forms.CheckboxSelectMultiple)], heading="Categories"), MultiFieldPanel( [ InlinePanel('collections_list', label='Curator'), ], heading="Curator(s)", ), ] promote_panels = [] class Meta: # noqa verbose_name = "Index Detail Page" verbose_name_plural = "Index Detail Pages"