示例#1
0
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'),
    ]
示例#2
0
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')
示例#3
0
class StaticContent(models.Model):
    text = MarkdownField()

    panels = [
        MarkdownPanel('text'),
    ]

    def __str__(self):
        return self.text
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
示例#5
0
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'),
    ]
示例#6
0
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'),
    ]
示例#7
0
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)
示例#8
0
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']
示例#9
0
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'),
    ]
示例#10
0
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')
    ]
示例#11
0
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'),
    ]
示例#12
0
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
示例#13
0
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')
    ]
示例#14
0
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
示例#15
0
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"
示例#16
0
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']
示例#17
0
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
示例#18
0
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