From: Guillaume Pellerin Date: Wed, 4 Jan 2017 17:35:32 +0000 (+0100) Subject: Add ProjectBlogPage and related views with login required content X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=d419e344ee34c72cb0acfb36d869d8604be9faa1;p=mezzo.git Add ProjectBlogPage and related views with login required content --- diff --git a/app/organization/core/models.py b/app/organization/core/models.py index 529849d6..05085f78 100644 --- a/app/organization/core/models.py +++ b/app/organization/core/models.py @@ -96,7 +96,7 @@ class CustomCategory(Named): return self.name -class Block(RichText, Titled, Orderable): +class Block(Titled, RichText, Orderable): with_separator = models.BooleanField(default=False) background_color = models.CharField(_('background color'), max_length=32, choices=COLOR_CHOICES, blank=True) diff --git a/app/organization/projects/admin.py b/app/organization/projects/admin.py index 11ad0ba2..63140ead 100644 --- a/app/organization/projects/admin.py +++ b/app/organization/projects/admin.py @@ -76,6 +76,11 @@ class ProjectDemoAdmin(BaseTranslationModelAdmin): filter_horizontal = ['authors'] +class ProjectBlogPageInline(StackedDynamicInlineAdmin): + + model = ProjectBlogPage + + class ProjectAdmin(admin.ModelAdmin): model = Project @@ -107,7 +112,8 @@ class ProjectAdminDisplayable(DisplayableAdmin): ProjectLinkInline, ProjectFileInline, ProjectRelatedTitleAdmin, - DynamicContentProjectInline] + DynamicContentProjectInline, + ProjectBlogPageInline,] filter_horizontal = ['teams', 'organizations'] list_filter = ['type', 'program', 'program_type', null_filter('external_id')] list_display = ['title', 'external_id', 'date_from', 'date_to', 'status', 'admin_link'] diff --git a/app/organization/projects/migrations/0037_projectblogpage.py b/app/organization/projects/migrations/0037_projectblogpage.py new file mode 100644 index 00000000..94585109 --- /dev/null +++ b/app/organization/projects/migrations/0037_projectblogpage.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.11 on 2017-01-04 16:33 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import mezzanine.core.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('sites', '0002_alter_domain_unique'), + ('organization-projects', '0036_auto_20170103_1227'), + ] + + operations = [ + migrations.CreateModel( + name='ProjectBlogPage', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('keywords_string', models.CharField(blank=True, editable=False, max_length=500)), + ('title', models.CharField(max_length=500, verbose_name='Title')), + ('title_fr', models.CharField(max_length=500, null=True, verbose_name='Title')), + ('title_en', models.CharField(max_length=500, null=True, verbose_name='Title')), + ('slug', models.CharField(blank=True, help_text='Leave blank to have the URL auto-generated from the title.', max_length=2000, null=True, verbose_name='URL')), + ('_meta_title', models.CharField(blank=True, help_text='Optional title to be used in the HTML title tag. If left blank, the main title field will be used.', max_length=500, null=True, verbose_name='Title')), + ('description', models.TextField(blank=True, verbose_name='Description')), + ('description_fr', models.TextField(blank=True, null=True, verbose_name='Description')), + ('description_en', models.TextField(blank=True, null=True, verbose_name='Description')), + ('gen_description', models.BooleanField(default=True, help_text='If checked, the description will be automatically generated from content. Uncheck if you want to manually set a custom description.', verbose_name='Generate description')), + ('created', models.DateTimeField(editable=False, null=True)), + ('updated', models.DateTimeField(editable=False, null=True)), + ('status', models.IntegerField(choices=[(1, 'Draft'), (2, 'Published')], default=2, help_text='With Draft chosen, will only be shown for admin users on the site.', verbose_name='Status')), + ('publish_date', models.DateTimeField(blank=True, db_index=True, help_text="With Published chosen, won't be shown until this time", null=True, verbose_name='Published from')), + ('expiry_date', models.DateTimeField(blank=True, help_text="With Published chosen, won't be shown after this time", null=True, verbose_name='Expires on')), + ('short_url', models.URLField(blank=True, null=True)), + ('in_sitemap', models.BooleanField(default=True, verbose_name='Show in sitemap')), + ('content', mezzanine.core.fields.RichTextField(verbose_name='Content')), + ('content_fr', mezzanine.core.fields.RichTextField(null=True, verbose_name='Content')), + ('content_en', mezzanine.core.fields.RichTextField(null=True, verbose_name='Content')), + ('project', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='blog_pages', to='organization-projects.Project', verbose_name='project')), + ('site', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')), + ], + options={ + 'verbose_name_plural': 'Project blog pages', + 'verbose_name': 'Project blog page', + }, + ), + ] diff --git a/app/organization/projects/migrations/0038_projectblogpage_login_required_content.py b/app/organization/projects/migrations/0038_projectblogpage_login_required_content.py new file mode 100644 index 00000000..340454b1 --- /dev/null +++ b/app/organization/projects/migrations/0038_projectblogpage_login_required_content.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.11 on 2017-01-04 17:00 +from __future__ import unicode_literals + +from django.db import migrations +import mezzanine.core.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('organization-projects', '0037_projectblogpage'), + ] + + operations = [ + migrations.AddField( + model_name='projectblogpage', + name='login_required_content', + field=mezzanine.core.fields.RichTextField(null=True, verbose_name='Login required content'), + ), + ] diff --git a/app/organization/projects/migrations/0039_auto_20170104_1820.py b/app/organization/projects/migrations/0039_auto_20170104_1820.py new file mode 100644 index 00000000..32d2fdd0 --- /dev/null +++ b/app/organization/projects/migrations/0039_auto_20170104_1820.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.11 on 2017-01-04 17:20 +from __future__ import unicode_literals + +from django.db import migrations +import mezzanine.core.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('organization-projects', '0038_projectblogpage_login_required_content'), + ] + + operations = [ + migrations.AddField( + model_name='projectblogpage', + name='login_required_content_en', + field=mezzanine.core.fields.RichTextField(null=True, verbose_name='Login required content'), + ), + migrations.AddField( + model_name='projectblogpage', + name='login_required_content_fr', + field=mezzanine.core.fields.RichTextField(null=True, verbose_name='Login required content'), + ), + ] diff --git a/app/organization/projects/models.py b/app/organization/projects/models.py index d5c85d67..25252dd6 100644 --- a/app/organization/projects/models.py +++ b/app/organization/projects/models.py @@ -255,3 +255,16 @@ class DynamicContentProject(DynamicContent, Orderable): class Meta: verbose_name = 'Dynamic Content Project' + + +class ProjectBlogPage(Displayable, RichText): + + project = models.ForeignKey(Project, verbose_name=_('project'), related_name='blog_pages', blank=True, null=True, on_delete=models.SET_NULL) + login_required_content = RichTextField(_("Login required content"), null=True) + + class Meta: + verbose_name = 'Project blog page' + verbose_name_plural = 'Project blog pages' + + def get_absolute_url(self): + return reverse("organization-project-blogpage-detail", kwargs={"slug": self.slug}) diff --git a/app/organization/projects/translation.py b/app/organization/projects/translation.py index 3ce5a108..e292ad11 100644 --- a/app/organization/projects/translation.py +++ b/app/organization/projects/translation.py @@ -54,6 +54,12 @@ class ProjectBlockTranslationOptions(TranslationOptions): fields = ('title', 'description', 'content') +@register(ProjectBlogPage) +class ProjectBlogPageTranslationOptions(TranslationOptions): + + fields = ('title', 'description', 'content', 'login_required_content') + + @register(ProjectLink) class ProjectLinkTranslationOptions(TranslationOptions): diff --git a/app/organization/projects/urls.py b/app/organization/projects/urls.py index 4492975a..63fbca1f 100644 --- a/app/organization/projects/urls.py +++ b/app/organization/projects/urls.py @@ -34,4 +34,5 @@ urlpatterns = [ url("^project/detail/(?P.*)/$", ProjectDetailView.as_view(), name='organization-project-detail'), url("^dynamic-content-project/$", permission_required('project.can_edit')(DynamicContentProjectView.as_view()), name='dynamic-content-project'), url("^project/demo/(?P.*)/$", ProjectDemoDetailView.as_view(), name='organization-project-demo-detail'), + url("^project/blog/(?P.*)/$", ProjectBlogPageView.as_view(), name='organization-project-blogpage-detail'), ] diff --git a/app/organization/projects/views.py b/app/organization/projects/views.py index cdb02a88..3d598284 100644 --- a/app/organization/projects/views.py +++ b/app/organization/projects/views.py @@ -20,6 +20,7 @@ # along with this program. If not, see . from django.shortcuts import render +from django.views.generic.detail import SingleObjectMixin from dal import autocomplete from dal_select2_queryset_sequence.views import Select2QuerySetSequenceView from mezzanine_agenda.models import Event @@ -30,9 +31,16 @@ from organization.magazine.views import Article from organization.pages.models import CustomPage -class ProjectMixin(object): +class ProjectMixin(SingleObjectMixin): + + def get_context_data(self, **kwargs): + context = super(ProjectMixin, self).get_context_data(**kwargs) + self.object = self.get_object() + if not isinstance(self.object, Project): + self.project = self.object.project + else: + self.project = self.object - def get_context_data_mixin(self, context): department = None if self.project.lead_team: @@ -57,14 +65,6 @@ class ProjectDetailView(SlugMixin, ProjectMixin, DetailView): model = Project template_name='projects/project_detail.html' - context_object_name = 'project' - - def get_context_data(self, **kwargs): - context = super(ProjectDetailView, self).get_context_data(**kwargs) - self.project = self.get_object() - self.get_context_data_mixin(context) - context['next'] = reverse_lazy('organization-project-detail', kwargs={'slug': self.project.slug}) - return context class DynamicContentProjectView(Select2QuerySetSequenceView): @@ -100,11 +100,9 @@ class ProjectDemoDetailView(SlugMixin, ProjectMixin, DetailView): model = ProjectDemo template_name='projects/project_demo_detail.html' - context_object_name = 'demo' - def get_context_data(self, **kwargs): - context = super(ProjectDemoDetailView, self).get_context_data(**kwargs) - demo = self.get_object() - project = demo.project - self.get_context_data_mixin(context) - return context + +class ProjectBlogPageView(SlugMixin, ProjectMixin, DetailView): + + model = ProjectBlogPage + template_name='projects/project_blogpage_detail.html' diff --git a/app/templates/pages/page.html b/app/templates/pages/page.html index 17e38986..5ef745fb 100644 --- a/app/templates/pages/page.html +++ b/app/templates/pages/page.html @@ -112,6 +112,9 @@ {% block page_demo %} {% endblock %} + {% block page_blog %} + {% endblock %} + {% block page_sub_content %} {% with object.blocks.all as blocks %} {% include "core/inc/block.html" %} diff --git a/app/templates/projects/inc/project_block.html b/app/templates/projects/inc/project_block.html index 162e5774..f428754d 100644 --- a/app/templates/projects/inc/project_block.html +++ b/app/templates/projects/inc/project_block.html @@ -23,7 +23,7 @@ {% if block.login_required and not user.is_authenticated %}
{% trans "Please login to get links to the data" %}

- {% trans "Login" %} + {% trans "Login" %}
{% else %} {% if block.content %} diff --git a/app/templates/projects/project_blogpage_detail.html b/app/templates/projects/project_blogpage_detail.html new file mode 100644 index 00000000..a95857fc --- /dev/null +++ b/app/templates/projects/project_blogpage_detail.html @@ -0,0 +1,58 @@ +{% extends "pages/page.html" %} +{% load i18n mezzanine_tags keyword_tags pages_tags organization_tags %} + +{% block meta_title %}{% trans "Demo" %}{% endblock %} + +{% block meta_description %} + {% metablock %} + {{ object.description }} + {% endmetablock %} +{% endblock %} + +{% block page_class %} + projectblogpage +{% endblock %} + +{% block breadcrumb_menu %} + {{ block.super }} + + +{% endblock %} + +{% block page_title %} + {% editable project.title %} +

{{ object.title }}

+ {% endeditable %} + + {% if object.description %} + {% editable object.description %} +
+ {{ object.description }} +
+ {% endeditable %} + {% endif %} +{% endblock %} + +{% block page_sidebar %} +{% endblock %} + +{% block page_slider %} +{% endblock %} + +{% block page_content %} + {% if project.content %} + {% editable project.content %} + {{ object.content|richtext_filters|safe }} + {% endeditable %} + {% endif %} + {% if object.login_required_content and not user.is_authenticated %} +
+ {% trans "Please login to get more data." %}

+ {% trans "Login" %} +
+ {% else %} + {% editable block.content %} + {{ object.login_required_content|richtext_filters|safe }} + {% endeditable %} + {% endif %} +{% endblock %} diff --git a/app/templates/projects/project_detail.html b/app/templates/projects/project_detail.html index 267db9dc..72674f68 100644 --- a/app/templates/projects/project_detail.html +++ b/app/templates/projects/project_detail.html @@ -1,10 +1,10 @@ {% extends "pages/page.html" %} {% load mezzanine_tags keyword_tags i18n organization_tags pages_tags %} -{% block meta_title %}{{ project.meta_title }}{% endblock %} +{% block meta_title %}{{ object.meta_title }}{% endblock %} {% block meta_keywords %}{% metablock %} -{% keywords_for project as keywords %} +{% keywords_for object as keywords %} {% for keyword in keywords %} {% if not forloop.first %}, {% endif %} {{ keyword }} @@ -12,7 +12,7 @@ {% endmetablock %}{% endblock %} {% block page_class %} - project + object {% endblock %} {% block body_class %} @@ -21,7 +21,7 @@ {% block breadcrumb_menu %} {{ block.super }} - + {% endblock %} {% block page_tags %} @@ -41,8 +41,8 @@ {% block page_title %} - {% editable project.title %} -

{{ project.title }}

+ {% editable object.title %} +

{{ object.title }}

{% endeditable %} {% with page.get_ascendants|last as top_level_parent %} @@ -51,10 +51,10 @@ {% endif %} {% endwith %} - {% if project.description %} - {% editable project.description %} + {% if object.description %} + {% editable object.description %}
- {{ project.description }} + {{ object.description }}
{% endeditable %} {% endif %} @@ -62,9 +62,9 @@ {% endblock %} {% block page_content %} - {% if project.content %} - {% editable project.content %} - {{ project.content|richtext_filters|safe }} + {% if object.content %} + {% editable object.content %} + {{ object.content|richtext_filters|safe }} {% endeditable %} {% endif %} {% endblock %} @@ -78,7 +78,7 @@ {{ page.title }}