From cb1de02514af3a0f61ffcb05b1133a999a20b430 Mon Sep 17 00:00:00 2001 From: Guillaume Pellerin Date: Fri, 3 Mar 2017 18:22:29 +0100 Subject: [PATCH] add Project ICT data and related content, first version of ICT Project form, take host organization from current site --- app/bin/app.sh | 2 +- app/local_settings.py | 1 + app/organization/core/context_processors.py | 11 +- app/organization/core/models.py | 32 +- app/organization/core/views.py | 2 + app/organization/network/admin.py | 1 + .../migrations/0089_auto_20170303_1637.py | 36 ++ app/organization/network/models.py | 2 +- app/organization/projects/admin.py | 74 ++-- app/organization/projects/forms.py | 38 +- .../migrations/0044_auto_20170303_1557.py | 261 +++++++++++++ .../migrations/0045_auto_20170303_1605.py | 50 +++ .../migrations/0046_auto_20170303_1631.py | 20 + .../0047_remove_projectictdata_contact.py | 19 + app/organization/projects/models.py | 98 +++-- app/organization/projects/translation.py | 47 +++ app/organization/projects/urls.py | 3 + app/organization/projects/views.py | 27 ++ .../projects/project_call_detail.html | 351 ++++++++++++++++++ .../projects/project_ict_create.html | 50 +++ app/themes/starts_eu/templates/base.html | 2 +- .../starts_eu/pages/menus/header.html | 2 +- .../projects/project_ict_create.html | 50 +++ .../vertigo_starts_eu/pages/menus/header.html | 2 +- requirements.txt | 1 + var | 2 +- 26 files changed, 1113 insertions(+), 71 deletions(-) create mode 100644 app/organization/network/migrations/0089_auto_20170303_1637.py create mode 100644 app/organization/projects/migrations/0044_auto_20170303_1557.py create mode 100644 app/organization/projects/migrations/0045_auto_20170303_1605.py create mode 100644 app/organization/projects/migrations/0046_auto_20170303_1631.py create mode 100644 app/organization/projects/migrations/0047_remove_projectictdata_contact.py create mode 100644 app/themes/base/templates/projects/project_call_detail.html create mode 100644 app/themes/base/templates/projects/project_ict_create.html create mode 100644 app/themes/vertigo_starts_eu/templates/projects/project_ict_create.html diff --git a/app/bin/app.sh b/app/bin/app.sh index 5d9fcf0d..475bba6d 100755 --- a/app/bin/app.sh +++ b/app/bin/app.sh @@ -19,7 +19,7 @@ gid='www-data' # patterns='*.js;*.css;*.jpg;*.jpeg;*.gif;*.png;*.svg;*.ttf;*.eot;*.woff;*.woff2' # Staging -pip install pandas xlwt +# pip install pandas xlwt # pip install -U https://forge.ircam.fr/p/django-eve/source/download/dev/ # pip install https://forge.ircam.fr/p/django-prestashop/source/download/master/ --src /srv/lib # pip install -U https://github.com/stephenmcd/grappelli-safe/archive/dynamic_stacked.zip diff --git a/app/local_settings.py b/app/local_settings.py index ffee9f54..4d77d167 100644 --- a/app/local_settings.py +++ b/app/local_settings.py @@ -124,6 +124,7 @@ ADMIN_MENU_ORDER = ( 'organization-network.PersonActivityTimeSheet' )), (_('Projects'), ('organization-projects.Project', + 'organization-projects.ProjectCall', 'organization-projects.ProjectProgram', 'organization-projects.ProjectProgramType', 'organization-projects.ProjectTopic', diff --git a/app/organization/core/context_processors.py b/app/organization/core/context_processors.py index e0cdabed..162cf467 100644 --- a/app/organization/core/context_processors.py +++ b/app/organization/core/context_processors.py @@ -24,6 +24,7 @@ from datetime import datetime, date from organization.pages.models import Page from organization.network.models import Organization, OrganizationLinkedInline from mezzanine.utils.sites import current_site_id +from django.contrib.sites.models import Site def settings(request): @@ -39,7 +40,15 @@ def settings(request): newsletter_subscribing_url = newsletter_page.first().get_absolute_url() # HOST ORGANIZATIONS - host_org = Organization.objects.filter(is_host=True).first() + try: + site = Site.objects.get(id=current_site_id()) + host_org = Organization.objects.get(site=site) + except: + try: + host_org = Organization.objects.filter(is_host=True).first() + except: + host_org = Organization.objects.first() + organization_lists = [] for orga_linked_block in host_org.organization_linked_block.all(): diff --git a/app/organization/core/models.py b/app/organization/core/models.py index cd227ae3..c4764827 100644 --- a/app/organization/core/models.py +++ b/app/organization/core/models.py @@ -47,11 +47,10 @@ class Description(models.Model): abstract = True -class Named(models.Model): - """Abstract model providing a name field""" +class NamedOnly(models.Model): + """Abstract model providing a name field only""" name = models.CharField(_('name'), max_length=512) - description = models.TextField(_('description'), blank=True) class Meta: abstract = True @@ -65,6 +64,16 @@ class Named(models.Model): return slugify(self.__unicode__()) +class Named(NamedOnly): + """Abstract model providing a name field and a description""" + + description = models.TextField(_('description'), blank=True) + + class Meta: + abstract = True + ordering = ['name',] + + class Titled(models.Model): """Abstract model providing a title field""" @@ -124,6 +133,23 @@ class Image(Titled, Orderable): return value +class SimpleImage(Titled, Orderable): + + file = models.FileField(_("Image"), max_length=1024, upload_to="images") + credits = models.CharField(_('credits'), max_length=256, blank=True, null=True) + + class Meta: + abstract = True + + def __str__(self): + value = self.description + if not value: + value = self.file.name + if not value: + value = "" + return value + + class File(Titled, Orderable): file = FileField(_("document"), max_length=1024, upload_to="Documents/%Y/%m/%d/") diff --git a/app/organization/core/views.py b/app/organization/core/views.py index bb386a77..a1f45aca 100644 --- a/app/organization/core/views.py +++ b/app/organization/core/views.py @@ -37,6 +37,8 @@ from organization.media.models import Playlist from mezzanine_agenda.models import Event from organization.pages.models import CustomPage from organization.projects.models import Project +from extra_views import CreateWithInlinesView, UpdateWithInlinesView, InlineFormSet + class SlugMixin(object): diff --git a/app/organization/network/admin.py b/app/organization/network/admin.py index e0721784..a21de84f 100644 --- a/app/organization/network/admin.py +++ b/app/organization/network/admin.py @@ -35,6 +35,7 @@ from organization.pages.admin import PageImageInline, PageBlockInline, PagePlayl from organization.shop.models import PageProductList from organization.network.utils import TimesheetXLS, set_timesheets_validation_date + class OrganizationAdminInline(StackedDynamicInlineAdmin): model = OrganizationLinkedInline diff --git a/app/organization/network/migrations/0089_auto_20170303_1637.py b/app/organization/network/migrations/0089_auto_20170303_1637.py new file mode 100644 index 00000000..dfcdf77c --- /dev/null +++ b/app/organization/network/migrations/0089_auto_20170303_1637.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.11 on 2017-03-03 15:37 +from __future__ import unicode_literals + +from django.db import migrations, models +import django_countries.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('organization-network', '0088_organization_site'), + ] + + operations = [ + migrations.AddField( + model_name='person', + name='address', + field=models.TextField(blank=True, verbose_name='address'), + ), + migrations.AddField( + model_name='person', + name='city', + field=models.CharField(blank=True, max_length=255, null=True, verbose_name='city'), + ), + migrations.AddField( + model_name='person', + name='country', + field=django_countries.fields.CountryField(blank=True, max_length=2, null=True, verbose_name='country'), + ), + migrations.AddField( + model_name='person', + name='postal_code', + field=models.CharField(blank=True, max_length=16, null=True, verbose_name='postal code'), + ), + ] diff --git a/app/organization/network/models.py b/app/organization/network/models.py index 22d0eb3f..27872ae9 100644 --- a/app/organization/network/models.py +++ b/app/organization/network/models.py @@ -302,7 +302,7 @@ class TeamLink(Link): team = models.ForeignKey(Team, verbose_name=_('team'), related_name='links', blank=True, null=True, on_delete=models.SET_NULL) -class Person(Displayable, AdminThumbMixin): +class Person(Displayable, AdminThumbMixin, Address): """(Person description)""" user = models.OneToOneField(User, verbose_name=_('user'), blank=True, null=True, on_delete=models.SET_NULL) diff --git a/app/organization/projects/admin.py b/app/organization/projects/admin.py index ee3fcb5a..e375b011 100644 --- a/app/organization/projects/admin.py +++ b/app/organization/projects/admin.py @@ -81,14 +81,24 @@ class ProjectBlogPageInline(StackedDynamicInlineAdmin): model = ProjectBlogPage +class ProjectSimpleImageInline(StackedDynamicInlineAdmin): + + model = ProjectSimpleImage + + +class ProjectContactInline(StackedDynamicInlineAdmin): + + model = ProjectContact + + class ProjectAdmin(admin.ModelAdmin): model = Project -class ICTProjectAdmin(admin.ModelAdmin): +class ProjectICTDataInline(StackedDynamicInlineAdmin): - model = ICTProject + model = ProjectICTData class ProjectRelatedTitleAdmin(TranslationTabularInline): @@ -111,36 +121,23 @@ class ProjectAdminDisplayable(DisplayableAdmin): fieldsets = deepcopy(ProjectAdmin.fieldsets) inlines = [ ProjectBlockInline, + ProjectContactInline, + ProjectSimpleImageInline, ProjectImageInline, + ProjectICTDataInline, ProjectWorkPackageInline, ProjectPlaylistInline, ProjectLinkInline, ProjectFileInline, ProjectRelatedTitleAdmin, DynamicContentProjectInline, - ProjectBlogPageInline,] + 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'] -class ICTProjectAdminDisplayable(DisplayableAdmin): - - fieldsets = deepcopy(ICTProjectAdmin.fieldsets) - inlines = [ ProjectBlockInline, - ProjectImageInline, - ProjectWorkPackageInline, - ProjectPlaylistInline, - ProjectLinkInline, - ProjectFileInline, - ProjectRelatedTitleAdmin, - DynamicContentProjectInline, - ProjectBlogPageInline,] - filter_horizontal = ['contact'] - list_filter = ['validation_status', null_filter('external_id')] - list_display = ['title', 'external_id', 'date_from', 'date_to', 'status', 'admin_link'] - - class ProjectTopicAdmin(BaseTranslationModelAdmin): model = ProjectTopic @@ -168,9 +165,40 @@ class ProjectWorkPackageAdmin(BaseTranslationModelAdmin): list_filter = ['project', 'date_from', 'date_to', 'lead_organization' ] -class ICTProjectAdmin(admin.ModelAdmin): +class ProjectCallAdmin(admin.ModelAdmin): + + model = ProjectCall + + +class ProjectCallBlockInline(StackedDynamicInlineAdmin): + + model = ProjectCallBlock + + +class ProjectCallLinkInline(StackedDynamicInlineAdmin): + + model = ProjectCallLink + + +class ProjectCallImageInline(StackedDynamicInlineAdmin): + + model = ProjectCallImage + + +class ProjectCallFileInline(StackedDynamicInlineAdmin): + + model = ProjectCallFile + + +class ProjectCallAdminDisplayable(DisplayableAdmin): - model = ICTProject + fieldsets = deepcopy(ProjectCallAdmin.fieldsets) + inlines = [ ProjectCallBlockInline, + ProjectCallImageInline, + ProjectCallLinkInline, + ProjectCallFileInline, + ] + list_display = ['title', 'date_from', 'date_to', 'status', 'admin_link'] admin.site.register(Project, ProjectAdminDisplayable) @@ -182,4 +210,4 @@ admin.site.register(ProjectDemo, ProjectDemoAdmin) admin.site.register(Repository) admin.site.register(RepositorySystem) admin.site.register(ProjectWorkPackage, ProjectWorkPackageAdmin) -admin.site.register(ICTProject, ICTProjectAdmin) +admin.site.register(ProjectCall, ProjectCallAdminDisplayable) diff --git a/app/organization/projects/forms.py b/app/organization/projects/forms.py index 640d67ed..e12c9ad7 100644 --- a/app/organization/projects/forms.py +++ b/app/organization/projects/forms.py @@ -32,7 +32,8 @@ from organization.magazine.models import Article, Topic, Brief from organization.pages.models import CustomPage from organization.agenda.models import Event, DynamicContentEvent from organization.media.models import Playlist -from organization.projects.models import DynamicContentProject +from organization.projects.models import * +from extra_views import InlineFormSet class DynamicContentProjectForm(autocomplete.FutureModelForm): @@ -50,3 +51,38 @@ class DynamicContentProjectForm(autocomplete.FutureModelForm): class Meta: model = DynamicContentProject fields = ('content_object',) + + +class ProjectForm(ModelForm): + + class Meta: + model = Project + fields = ('title', 'description', 'keywords', 'website') + + +class ProjectICTForm(ModelForm): + + class Meta: + model = Project + exclude = ('external_id', '_meta_title') + + +class ProjectICTDataInline(InlineFormSet): + + max_num = 1 + model = ProjectICTData + exclude = ('validation_status', ) + + +class ProjectSimpleImageInline(InlineFormSet): + + max_num = 3 + model = ProjectSimpleImage + fields = ('file', 'credits') + + +class ProjectContactInline(InlineFormSet): + + max_num = 1 + model = ProjectContact + fields = ('gender', 'person_title', 'first_name', 'last_name', 'address', 'email', 'telephone', 'bio', 'address', 'postal_code', 'city', 'country') diff --git a/app/organization/projects/migrations/0044_auto_20170303_1557.py b/app/organization/projects/migrations/0044_auto_20170303_1557.py new file mode 100644 index 00000000..992ab8ac --- /dev/null +++ b/app/organization/projects/migrations/0044_auto_20170303_1557.py @@ -0,0 +1,261 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.11 on 2017-03-03 14:57 +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 = [ + ('organization-network', '0088_organization_site'), + ('sites', '0002_alter_domain_unique'), + ('organization-core', '0005_linktype_fa_option'), + ('organization-projects', '0043_auto_20170214_1643'), + ] + + operations = [ + migrations.CreateModel( + name='ProjectCallBlock', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('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')), + ('_order', mezzanine.core.fields.OrderField(null=True, verbose_name='Order')), + ('title', models.CharField(max_length=1024, verbose_name='title')), + ('title_fr', models.CharField(max_length=1024, null=True, verbose_name='title')), + ('title_en', models.CharField(max_length=1024, 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')), + ('with_separator', models.BooleanField(default=False)), + ('background_color', models.CharField(blank=True, choices=[('black', 'black'), ('yellow', 'yellow'), ('red', 'red'), ('white', 'white')], max_length=32, verbose_name='background color')), + ('login_required', models.BooleanField(default=False, verbose_name='login required')), + ], + options={ + 'ordering': ('_order',), + }, + ), + migrations.CreateModel( + name='ProjectCallFile', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('_order', mezzanine.core.fields.OrderField(null=True, verbose_name='Order')), + ('title', models.CharField(max_length=1024, verbose_name='title')), + ('description', models.TextField(blank=True, verbose_name='description')), + ('file', mezzanine.core.fields.FileField(max_length=1024, verbose_name='document')), + ], + options={ + 'ordering': ('_order',), + }, + ), + migrations.CreateModel( + name='ProjectCallImage', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('_order', mezzanine.core.fields.OrderField(null=True, verbose_name='Order')), + ('title', models.CharField(max_length=1024, verbose_name='title')), + ('description', models.TextField(blank=True, verbose_name='description')), + ('file', mezzanine.core.fields.FileField(max_length=1024, verbose_name='Image')), + ('credits', models.CharField(blank=True, max_length=256, null=True, verbose_name='credits')), + ('type', models.CharField(choices=[('logo', 'logo'), ('logo_white', 'logo white'), ('logo_black', 'logo black'), ('logo_header', 'logo header'), ('logo_footer', 'logo footer'), ('slider', 'slider'), ('card', 'card'), ('page_slider', 'page - slider'), ('page_featured', 'page - featured')], max_length=64, verbose_name='type')), + ], + options={ + 'ordering': ('_order',), + }, + ), + migrations.CreateModel( + name='ProjectCallLink', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('url', models.URLField(blank=True, max_length=512, verbose_name='URL')), + ('title', models.CharField(blank=True, max_length=1024, null=True, verbose_name='title')), + ('title_fr', models.CharField(blank=True, max_length=1024, null=True, verbose_name='title')), + ('title_en', models.CharField(blank=True, max_length=1024, null=True, verbose_name='title')), + ], + options={ + 'verbose_name_plural': 'links', + 'abstract': False, + 'verbose_name': 'link', + }, + ), + migrations.CreateModel( + name='ProjectICTData', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('affiliation', models.CharField(max_length=512, verbose_name='affiliation')), + ('short_description', models.CharField(help_text='Very short description of challenge / technology (110 characters max)', max_length=110, verbose_name='short description')), + ('technology_description', models.TextField(help_text='Description of the project technology to be made available to artists + challenges it produces (100-200 words) ', verbose_name='technology description')), + ('challenges_description', models.TextField(help_text='Description of the challenges faced by the ICT-Project (100-150 words).', verbose_name='challenges description')), + ('objectives_description', models.TextField(help_text='What the project is looking to gain from the collaboration and what kind of artist would be suitable (100 – 150 words)', verbose_name='challenges description')), + ('resources_description', models.TextField(help_text='Resources available to the artist (50 – 100 words) -- e.g. office facility, studio facility, technical equipment, internet connection, laboratory, and periods of availability for artistic production, staff possibly allocated to the project, available budget for travel, consumables and equipments, etc.).', verbose_name='resources description')), + ('letter', models.TextField(verbose_name='letter of commitment')), + ('validation_status', models.IntegerField(choices=[(0, 'pending'), (1, 'accepted'), (2, 'rejected'), (3, 'in process')], verbose_name='validation status')), + ('contact', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ict_projects_contact_person', to='organization-network.Person', verbose_name='Contact Person')), + ], + options={ + 'verbose_name_plural': 'Project ICT data', + 'verbose_name': 'Project ICT data', + }, + ), + migrations.AlterModelOptions( + name='projectcall', + options={'ordering': ['title', 'name'], 'verbose_name': 'project call', 'verbose_name_plural': 'project calls'}, + ), + migrations.AddField( + model_name='projectcall', + name='_meta_title', + field=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'), + ), + migrations.AddField( + model_name='projectcall', + name='content', + field=mezzanine.core.fields.RichTextField(default='', verbose_name='Content'), + preserve_default=False, + ), + migrations.AddField( + model_name='projectcall', + name='content_en', + field=mezzanine.core.fields.RichTextField(null=True, verbose_name='Content'), + ), + migrations.AddField( + model_name='projectcall', + name='content_fr', + field=mezzanine.core.fields.RichTextField(null=True, verbose_name='Content'), + ), + migrations.AddField( + model_name='projectcall', + name='created', + field=models.DateTimeField(editable=False, null=True), + ), + migrations.AddField( + model_name='projectcall', + name='date_from', + field=models.DateField(blank=True, null=True, verbose_name='begin date'), + ), + migrations.AddField( + model_name='projectcall', + name='date_to', + field=models.DateField(blank=True, null=True, verbose_name='end date'), + ), + migrations.AddField( + model_name='projectcall', + name='description_en', + field=models.TextField(blank=True, null=True, verbose_name='Description'), + ), + migrations.AddField( + model_name='projectcall', + name='description_fr', + field=models.TextField(blank=True, null=True, verbose_name='Description'), + ), + migrations.AddField( + model_name='projectcall', + name='expiry_date', + field=models.DateTimeField(blank=True, help_text="With Published chosen, won't be shown after this time", null=True, verbose_name='Expires on'), + ), + migrations.AddField( + model_name='projectcall', + name='gen_description', + field=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'), + ), + migrations.AddField( + model_name='projectcall', + name='in_sitemap', + field=models.BooleanField(default=True, verbose_name='Show in sitemap'), + ), + migrations.AddField( + model_name='projectcall', + name='keywords_string', + field=models.CharField(blank=True, editable=False, max_length=500), + ), + migrations.AddField( + model_name='projectcall', + name='publish_date', + field=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'), + ), + migrations.AddField( + model_name='projectcall', + name='short_url', + field=models.URLField(blank=True, null=True), + ), + migrations.AddField( + model_name='projectcall', + name='site', + field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site'), + preserve_default=False, + ), + migrations.AddField( + model_name='projectcall', + name='slug', + field=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'), + ), + migrations.AddField( + model_name='projectcall', + name='status', + field=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'), + ), + migrations.AddField( + model_name='projectcall', + name='title', + field=models.CharField(default='', max_length=500, verbose_name='Title'), + preserve_default=False, + ), + migrations.AddField( + model_name='projectcall', + name='title_en', + field=models.CharField(max_length=500, null=True, verbose_name='Title'), + ), + migrations.AddField( + model_name='projectcall', + name='title_fr', + field=models.CharField(max_length=500, null=True, verbose_name='Title'), + ), + migrations.AddField( + model_name='projectcall', + name='updated', + field=models.DateTimeField(editable=False, null=True), + ), + migrations.AlterField( + model_name='project', + name='type', + field=models.CharField(choices=[('internal', 'internal'), ('external', 'external'), ('ICT', 'ICT')], max_length=128, verbose_name='type'), + ), + migrations.AlterField( + model_name='projectcall', + name='description', + field=models.TextField(blank=True, verbose_name='Description'), + ), + migrations.AddField( + model_name='projectictdata', + name='project', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ict_data', to='organization-projects.Project', verbose_name='project'), + ), + migrations.AddField( + model_name='projectcalllink', + name='call', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='links', to='organization-projects.ProjectCall', verbose_name='project call link'), + ), + migrations.AddField( + model_name='projectcalllink', + name='link_type', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='organization-core.LinkType', verbose_name='link type'), + ), + migrations.AddField( + model_name='projectcallimage', + name='call', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='images', to='organization-projects.ProjectCall', verbose_name='project call image'), + ), + migrations.AddField( + model_name='projectcallfile', + name='call', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='files', to='organization-projects.ProjectCall', verbose_name='project call file'), + ), + migrations.AddField( + model_name='projectcallblock', + name='call', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='blocks', to='organization-projects.ProjectCall', verbose_name='project call blocks'), + ), + ] diff --git a/app/organization/projects/migrations/0045_auto_20170303_1605.py b/app/organization/projects/migrations/0045_auto_20170303_1605.py new file mode 100644 index 00000000..64affdd6 --- /dev/null +++ b/app/organization/projects/migrations/0045_auto_20170303_1605.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.11 on 2017-03-03 15:05 +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 = [ + ('organization-network', '0088_organization_site'), + ('organization-projects', '0044_auto_20170303_1557'), + ] + + operations = [ + migrations.CreateModel( + name='ProjectContact', + fields=[ + ('person_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='organization-network.Person')), + ('project', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='contacts', to='organization-projects.Project', verbose_name='project')), + ], + options={ + 'verbose_name': 'Project contact', + 'verbose_name_plural': 'Project contacts', + }, + bases=('organization-network.person',), + ), + migrations.CreateModel( + name='ProjectSimpleImage', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('_order', mezzanine.core.fields.OrderField(null=True, verbose_name='Order')), + ('title', models.CharField(max_length=1024, verbose_name='title')), + ('description', models.TextField(blank=True, verbose_name='description')), + ('file', mezzanine.core.fields.FileField(max_length=1024, verbose_name='Image')), + ('credits', models.CharField(blank=True, max_length=256, null=True, verbose_name='credits')), + ('project', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='simple_images', to='organization-projects.Project', verbose_name='project')), + ], + options={ + 'ordering': ('_order',), + }, + ), + migrations.AlterField( + model_name='projectictdata', + name='objectives_description', + field=models.TextField(help_text='What the project is looking to gain from the collaboration and what kind of artist would be suitable (100 – 150 words)', verbose_name='objectives description'), + ), + ] diff --git a/app/organization/projects/migrations/0046_auto_20170303_1631.py b/app/organization/projects/migrations/0046_auto_20170303_1631.py new file mode 100644 index 00000000..51ce2aa5 --- /dev/null +++ b/app/organization/projects/migrations/0046_auto_20170303_1631.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.11 on 2017-03-03 15:31 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('organization-projects', '0045_auto_20170303_1605'), + ] + + operations = [ + migrations.AlterField( + model_name='projectsimpleimage', + name='file', + field=models.FileField(max_length=1024, upload_to='images', verbose_name='Image'), + ), + ] diff --git a/app/organization/projects/migrations/0047_remove_projectictdata_contact.py b/app/organization/projects/migrations/0047_remove_projectictdata_contact.py new file mode 100644 index 00000000..22091b6f --- /dev/null +++ b/app/organization/projects/migrations/0047_remove_projectictdata_contact.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.11 on 2017-03-03 16:38 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('organization-projects', '0046_auto_20170303_1631'), + ] + + operations = [ + migrations.RemoveField( + model_name='projectictdata', + name='contact', + ), + ] diff --git a/app/organization/projects/models.py b/app/organization/projects/models.py index 28c1820f..18ef493d 100644 --- a/app/organization/projects/models.py +++ b/app/organization/projects/models.py @@ -37,9 +37,10 @@ from organization.network.models import * PROJECT_TYPE_CHOICES = [ ('internal', _('internal')), ('external', _('external')), + ('ICT', _('ICT')), ] -ACCESS_CHOICES = [ +REPOSITORY_ACCESS_CHOICES = [ ('public', _('public')), ('shared', _('shared')), ('private', _('private')), @@ -52,6 +53,7 @@ PROJECT_STATUS_CHOICES = ( (3, _('in process')) ) + class Project(Displayable, Period, RichText): """(Project description)""" @@ -124,14 +126,6 @@ class ProjectProgramType(Named): ordering = ['name',] -class ProjectCall(Named): - - class Meta: - verbose_name = _('project call') - verbose_name_plural = _("project calls") - ordering = ['name',] - - class ProjectWorkPackage(Titled, Period): project = models.ForeignKey(Project, verbose_name=_('project'), related_name='work_packages') @@ -159,6 +153,11 @@ class ProjectImage(Image): project = models.ForeignKey(Project, verbose_name=_('project'), related_name='images', blank=True, null=True, on_delete=models.SET_NULL) +class ProjectSimpleImage(SimpleImage): + + project = models.ForeignKey(Project, verbose_name=_('project'), related_name='simple_images', blank=True, null=True, on_delete=models.SET_NULL) + + class ProjectFile(File): project = models.ForeignKey(Project, verbose_name=_('project'), related_name='files', blank=True, null=True, on_delete=models.SET_NULL) @@ -178,6 +177,40 @@ class ProjectTopicPage(Page, SubTitled): verbose_name_plural = _("project topic pages") +class ProjectCall(Displayable, Period, RichText, NamedOnly): + + class Meta: + verbose_name = _('project call') + verbose_name_plural = _("project calls") + ordering = ['title', 'name',] + + def __str__(self): + return self.title + + def get_absolute_url(self): + return reverse("organization-call-detail", kwargs={"slug": self.slug}) + + +class ProjectCallBlock(Block): + + call = models.ForeignKey(ProjectCall, verbose_name=_('project call blocks'), related_name='blocks', blank=True, null=True, on_delete=models.SET_NULL) + + +class ProjectCallImage(Image): + + call = models.ForeignKey(ProjectCall, verbose_name=_('project call image'), related_name='images', blank=True, null=True, on_delete=models.SET_NULL) + + +class ProjectCallFile(File): + + call = models.ForeignKey(ProjectCall, verbose_name=_('project call file'), related_name='files', blank=True, null=True, on_delete=models.SET_NULL) + + +class ProjectCallLink(Link): + + call = models.ForeignKey(ProjectCall, verbose_name=_('project call link'), related_name='links', blank=True, null=True, on_delete=models.SET_NULL) + + class ProjectDemo(Displayable, RichText, URL): project = models.ForeignKey('Project', verbose_name=_('project'), related_name='demos', blank=True, null=True, on_delete=models.SET_NULL) @@ -212,7 +245,7 @@ class ProjectDemo(Displayable, RichText, URL): class Repository(Named): system = models.ForeignKey('RepositorySystem', verbose_name=_('system'), related_name='repositories') - access = models.CharField(_('access'), max_length=64, choices=ACCESS_CHOICES, default='private') + access = models.CharField(_('access'), max_length=64, choices=REPOSITORY_ACCESS_CHOICES, default='private') branch = models.CharField(_('branch'), max_length=32, default='master') url = models.CharField(_('URL'), max_length=256, help_text='http(s) or ssh') @@ -287,40 +320,31 @@ class ProjectBlogPage(Displayable, RichText): return reverse("organization-project-blogpage-detail", kwargs={"slug": self.slug}) -class ICTProject(Displayable, Period, RichText): +class ProjectICTData(models.Model): + + project = models.ForeignKey(Project, verbose_name=_('project'), related_name='ict_data', blank=True, null=True, on_delete=models.SET_NULL) # Public - # Already in Displayable #name = models.CharField(_('name'), blank=True, max_length=512) - # Already in Displayable #website = models.URLField(_('website'), max_length=512, blank=True) - affiliation = models.CharField(_('affiliation'), blank=True, max_length=512) - short_description = models.TextField(_('short description'), blank=True, max_length=128) - # Already in Displayable #project_description = models.TextField(_('project description'), blank=True, max_length=128) - technology_description = models.TextField(_('technology description'), blank=True, max_length=256) - challenges_description = models.TextField(_('challenges description'), blank=True, max_length=256) - objectives_description = models.TextField(_('challenges description'), blank=True, max_length=256) - resources_description = models.TextField(_('resources description'), blank=True, max_length=256) - # Defined as objectives_description # What the project is looking to gain from the collaboration and what kind of artist would be suitable (100 – 150 words) - # Defined as resources_description # Resources available to the artist (50 – 100 words) -- e.g. office facility, studio facility, technical equipment, internet connection, laboratory, and periods of availability for artistic production, staff possibly allocated to the project, available budget for travel, consumables and equipments, etc.). - # Already in Displayable # 5 key words to describe project and challenge - #TODO: Inherit from ProjectImage or in inlines? # 3 key images for inspiring the artists + any video content available - # Already in Period # Possible period of implementation -- (must be part of the project implementation workplan) + affiliation = models.CharField(_('affiliation'), max_length=512) + short_description = models.CharField(_('short description'), max_length=110, help_text="Very short description of challenge / technology (110 characters max)") + technology_description = models.TextField(_('technology description'), help_text="Description of the project technology to be made available to artists + challenges it produces (100-200 words) ") + challenges_description = models.TextField(_('challenges description'), help_text="Description of the challenges faced by the ICT-Project (100-150 words).") + objectives_description = models.TextField(_('objectives description'), help_text="What the project is looking to gain from the collaboration and what kind of artist would be suitable (100 – 150 words)") + resources_description = models.TextField(_('resources description'), help_text="Resources available to the artist (50 – 100 words) -- e.g. office facility, studio facility, technical equipment, internet connection, laboratory, and periods of availability for artistic production, staff possibly allocated to the project, available budget for travel, consumables and equipments, etc.).") # Private - contact = models.ManyToManyField('organization-network.Person', verbose_name=_('Contact Person'), related_name='ict_projects_contact_person', blank=True) - letter = models.TextField(_('letter of commitment'), blank=True, max_length=1024) - external_id = models.CharField(_('external ID'), blank=True, null=True, max_length=128) + letter = models.TextField(_('letter of commitment')) validation_status = models.IntegerField(_('validation status'), choices=PROJECT_STATUS_CHOICES) class Meta: - verbose_name = _('ICT project') - verbose_name_plural = _('ICT projects') - ordering = ['-date_from', '-date_to'] + verbose_name = 'Project ICT data' + verbose_name_plural = 'Project ICT data' - def __str__(self): - return self.title - def get_absolute_url(self): - return reverse("ict-project-detail", kwargs={"slug": self.slug}) +class ProjectContact(Person): - def project_status(self): - return self.validation_status + project = models.ForeignKey(Project, verbose_name=_('project'), related_name='contacts', blank=True, null=True, on_delete=models.SET_NULL) + + class Meta: + verbose_name = 'Project contact' + verbose_name_plural = 'Project contacts' diff --git a/app/organization/projects/translation.py b/app/organization/projects/translation.py index e292ad11..8dff852b 100644 --- a/app/organization/projects/translation.py +++ b/app/organization/projects/translation.py @@ -42,6 +42,12 @@ class ProjectImageTranslationOptions(TranslationOptions): pass +@register(ProjectSimpleImage) +class ProjectSimpleImageTranslationOptions(TranslationOptions): + + pass + + @register(ProjectFile) class ProjectFileTranslationOptions(TranslationOptions): @@ -112,3 +118,44 @@ class ProjectRelatedTitleTranslationOptions(TranslationOptions): class DynamicContentProjectTranslationOptions(TranslationOptions): fields = () + + +@register(ProjectICTData) +class ProjectICTDataTranslationOptions(TranslationOptions): + + pass + + +@register(ProjectCall) +class ProjectCallTranslationOptions(TranslationOptions): + + fields = ('title', 'description', 'content') + + +@register(ProjectCallBlock) +class ProjectCallBlockTranslationOptions(TranslationOptions): + + fields = ('title', 'description', 'content') + + +@register(ProjectCallImage) +class ProjectCallImageTranslationOptions(TranslationOptions): + + pass + + +@register(ProjectCallLink) +class ProjectCallLinkTranslationOptions(TranslationOptions): + + fields = ('title',) + + +@register(ProjectCallFile) +class ProjectCallFileTranslationOptions(TranslationOptions): + + pass + +@register(ProjectContact) +class ProjectContactTranslationOptions(TranslationOptions): + + pass diff --git a/app/organization/projects/urls.py b/app/organization/projects/urls.py index 63fbca1f..1d7b18d1 100644 --- a/app/organization/projects/urls.py +++ b/app/organization/projects/urls.py @@ -35,4 +35,7 @@ urlpatterns = [ 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'), + url("^project/ict/create/$", ProjectICTCreateView.as_view(), name='organization-project-create'), + url("^call/detail/(?P.*)/$", ProjectCallDetailView.as_view(), name='organization-call-detail'), + url("^call/list/$", ProjectCallListView.as_view(), name='organization-call-list'), ] diff --git a/app/organization/projects/views.py b/app/organization/projects/views.py index 3d598284..8cc162b6 100644 --- a/app/organization/projects/views.py +++ b/app/organization/projects/views.py @@ -26,6 +26,7 @@ from dal_select2_queryset_sequence.views import Select2QuerySetSequenceView from mezzanine_agenda.models import Event from mezzanine.conf import settings from organization.projects.models import * +from organization.projects.forms import * from organization.core.views import * from organization.magazine.views import Article from organization.pages.models import CustomPage @@ -106,3 +107,29 @@ class ProjectBlogPageView(SlugMixin, ProjectMixin, DetailView): model = ProjectBlogPage template_name='projects/project_blogpage_detail.html' + + +class ProjectICTDetailView(SlugMixin,DetailView): + + model = Project + template_name='projects/project_ict_detail.html' + + +class ProjectICTCreateView(CreateWithInlinesView): + + model = Project + form_class = ProjectForm + template_name='projects/project_ict_create.html' + inlines = [ProjectICTDataInline, ProjectSimpleImageInline, ProjectContactInline,] + + +class ProjectCallDetailView(SlugMixin, DetailView): + + model = ProjectCall + template_name='projects/project_call_detail.html' + + +class ProjectCallListView(SlugMixin, ListView): + + model = ProjectCall + template_name='projects/project_call_list.html' diff --git a/app/themes/base/templates/projects/project_call_detail.html b/app/themes/base/templates/projects/project_call_detail.html new file mode 100644 index 00000000..e426951c --- /dev/null +++ b/app/themes/base/templates/projects/project_call_detail.html @@ -0,0 +1,351 @@ +{% extends "pages/page.html" %} +{% load mezzanine_tags keyword_tags i18n organization_tags pages_tags %} + +{% block meta_title %}{{ object.meta_title }}{% endblock %} + +{% block meta_keywords %}{% metablock %} +{% keywords_for object as keywords %} +{% for keyword in keywords %} + {% if not forloop.first %}, {% endif %} + {{ keyword }} +{% endfor %} +{% endmetablock %}{% endblock %} + +{% block page_class %} + object +{% endblock %} + +{% block body_class %} + pattern pattern-bg {{ department.pages.all.0.weaving_css_class }} +{% endblock %} + +{% block breadcrumb_menu %} + {{ block.super }} + +{% endblock %} + +{% block page_tags %} + + {% comment %} + {% if department %} +
+ {{ department.pages.all.0.title }} +
+ {% endif %} +
+ {% trans 'Project' %} +
+ {% endcomment %} + +{% endblock %} + +{% block page_title %} + + {% editable object.title %} +

{{ object.title }}

+ {% endeditable %} + + {% with page.get_ascendants|last as top_level_parent %} + {% if linked_organization_content and research_slug == top_level_parent.slug %} + {% include 'pages/page/includes/linked_organization_content.html' %} + {% endif %} + {% endwith %} + + {% if object.description %} + {% editable object.description %} +
+ {{ object.description }} +
+ {% endeditable %} + {% endif %} + +{% endblock %} + +{% block page_content %} + {% if object.content %} + {% editable object.content %} + {{ object.content|richtext_filters|safe }} + {% endeditable %} + {% endif %} +{% endblock %} + +{% block page_sidebar %} + +{% endblock %} + +{% block page_link %} + {% with object.links.all as links %} + {% if links %} + {% include 'core/inc/link.html' %} + {% endif %} + {% endwith %} +{% endblock %} + +{% block page_audio %} + {% with object as object %} + {{ block.super }} + {% endwith %} +{% endblock %} + +{% block page_slider %} + {% with object as object %} + {{ block.super }} + {% endwith %} +{% endblock %} + +{% block page_video %} + {% with object as object %} + {{ block.super }} + {% endwith %} +{% endblock %} + +{% block page_sub_content %} + + {% if object.type == 'external' %} +
+ +
+
+
+
+
+
+
+

{% trans "Project details" %}

+ +
+ {% if object.program %} +
+
+ {% trans "Program" %} +
+
+ {{ object.program }} +
+
+ {% endif %} + + {% if object.program_type %} +
+
+ {% trans "Program type" %} +
+
+ {{ object.program_type }} +
+
+ {% endif %} + +
+
+ {% trans "Beginning" %} +
+
+ {{ object.date_from }} +
+
+ +
+
+ {% trans "End" %} +
+
+ {{ object.date_to }} +
+
+ +
+
+ {% trans "Status" %} +
+
+ {{ object.object_status }} +
+
+ + {% if object.website %} +
+
+ {% trans "Website" %} +
+ +
+ {% endif %} + + + +
+
+
+
+
+

{% trans "Participants" %}

+ +
+ + {% if object.lead_team or object.lead_organization %} +
+ {% if object.lead_team %} +
+ {% trans "Project lead team" %} +
+ + {% elif object.lead_organization %} +
+ {% trans "Project lead organization" %} +
+ + {% endif %} +
+ {% endif %} + +
+
+ {% trans "Partners" %} +
+
+ {% for organization in object.organizations.all %} + {% if organization.url %} + + {% endif %} + {{ organization }}
+ {% if organization.url %} +
+ {% endif %} + {% endfor %} +
+ +
+ {% trans "teams" %} ({{ host_organization }}) +
+
+ {% for team in object.teams.all %} + {% if team.pages.all %} + {{ team.short }}
+ {% endif %} + {% endfor %} +
+
+
+
+
+
+
+
+
+
+
+ {% endif %} + + {% with object.blocks.all as blocks %} + {% include "projects/inc/project_block.html" %} + {% endwith %} +{% endblock %} + +{% block page_demo %} +{% if object.demos.all %} +
+
+
+
+
+
+
    +

    {% trans "Demos" %}

    + {% for demo in object.demos.all %} +
  • {{ demo.title }}
  • + {% endfor %} +
+
+
+
+
+
+{% endif %} +{% endblock %} + +{% block page_blog %} +{% if object.blog_pages.all %} +
+
+
+
+
+
+
    +

    {% trans "Blog Pages" %}

    + {% for blog_page in object.blog_pages.all %} +
  • {{ blog_page.title }}
  • + {% endfor %} +
+
+
+
+
+
+{% endif %} +{% endblock %} + +{% block logo %} + {% if object.organizations.all|length > 0 %} +
+
+
+
+
+
    + {% if object.lead_organization %} + {% with object.lead_organization.images.all|get_type:'logo' as images %} + {% include 'core/inc/logo.html' %} + {% endwith %} + {% endif %} + {% for organization in object.organizations.all %} + {% with organization.images.all|get_type:'logo' as images %} + {% include 'core/inc/logo.html' %} + {% endwith %} + {% endfor %} +
+
+
+
+
+
+ {% endif %} +{% endblock %} + +{% block page_related_content %} + {% with dynamic_content=object.dynamic_content_object.all|filter_content object=object %} + {% include "core/inc/related_content.html" %} + {% endwith %} +{% endblock %} diff --git a/app/themes/base/templates/projects/project_ict_create.html b/app/themes/base/templates/projects/project_ict_create.html new file mode 100644 index 00000000..a5d08a2b --- /dev/null +++ b/app/themes/base/templates/projects/project_ict_create.html @@ -0,0 +1,50 @@ +{% extends "vertigo_starts_eu/pages/page.html" %} +{% load mezzanine_tags keyword_tags i18n organization_tags pages_tags %} + +{% block meta_title %}{% endblock %} + +{% block meta_keywords %}{% endblock %} + +{% block body_class %} + pattern pattern-bg {{ department.pages.all.0.weaving_css_class }} +{% endblock %} + +{% block breadcrumb_menu %} + {{ block.super }} + +{% endblock %} + +{% block page_tags %} +{% endblock %} + +{% block page_title %} + {% editable object.title %} +

{% trans "New project form" %}

+ {% endeditable %} +{% endblock %} + +{% block page_content %} +
+ {% errors_for form %} +
+ {% fields_for form %} + {% for formset in inlines %} + {{ formset.management_form }} + {% for form in formset %} + {% fields_for form %} + {% endfor %} + {% endfor %} +
+ +
+
+
+{% endblock %} + +{% block extra_js %} +{{ block.super }} + +{% endblock %} diff --git a/app/themes/starts_eu/templates/base.html b/app/themes/starts_eu/templates/base.html index 701b6a98..1b61869e 100644 --- a/app/themes/starts_eu/templates/base.html +++ b/app/themes/starts_eu/templates/base.html @@ -56,7 +56,7 @@
diff --git a/app/themes/starts_eu/templates/starts_eu/pages/menus/header.html b/app/themes/starts_eu/templates/starts_eu/pages/menus/header.html index 51447793..0676e819 100644 --- a/app/themes/starts_eu/templates/starts_eu/pages/menus/header.html +++ b/app/themes/starts_eu/templates/starts_eu/pages/menus/header.html @@ -16,7 +16,7 @@ {% with host_organization.images|get_type:"logo_header" as images %} {% if images %} {% with images|first as img %} - + {% endwith %} {% endif %} {% endwith %} diff --git a/app/themes/vertigo_starts_eu/templates/projects/project_ict_create.html b/app/themes/vertigo_starts_eu/templates/projects/project_ict_create.html new file mode 100644 index 00000000..a5d08a2b --- /dev/null +++ b/app/themes/vertigo_starts_eu/templates/projects/project_ict_create.html @@ -0,0 +1,50 @@ +{% extends "vertigo_starts_eu/pages/page.html" %} +{% load mezzanine_tags keyword_tags i18n organization_tags pages_tags %} + +{% block meta_title %}{% endblock %} + +{% block meta_keywords %}{% endblock %} + +{% block body_class %} + pattern pattern-bg {{ department.pages.all.0.weaving_css_class }} +{% endblock %} + +{% block breadcrumb_menu %} + {{ block.super }} + +{% endblock %} + +{% block page_tags %} +{% endblock %} + +{% block page_title %} + {% editable object.title %} +

{% trans "New project form" %}

+ {% endeditable %} +{% endblock %} + +{% block page_content %} +
+ {% errors_for form %} +
+ {% fields_for form %} + {% for formset in inlines %} + {{ formset.management_form }} + {% for form in formset %} + {% fields_for form %} + {% endfor %} + {% endfor %} +
+ +
+
+
+{% endblock %} + +{% block extra_js %} +{{ block.super }} + +{% endblock %} diff --git a/app/themes/vertigo_starts_eu/templates/vertigo_starts_eu/pages/menus/header.html b/app/themes/vertigo_starts_eu/templates/vertigo_starts_eu/pages/menus/header.html index 51447793..0676e819 100644 --- a/app/themes/vertigo_starts_eu/templates/vertigo_starts_eu/pages/menus/header.html +++ b/app/themes/vertigo_starts_eu/templates/vertigo_starts_eu/pages/menus/header.html @@ -16,7 +16,7 @@ {% with host_organization.images|get_type:"logo_header" as images %} {% if images %} {% with images|first as img %} - + {% endwith %} {% endif %} {% endwith %} diff --git a/requirements.txt b/requirements.txt index c8d813fc..24cd6335 100644 --- a/requirements.txt +++ b/requirements.txt @@ -26,3 +26,4 @@ xlwt==1.2.0 DateTimeRange==0.2.8 workalendar==1.0.0 django-instagram==0.2.0a1 +django-extra-views==0.8.0 diff --git a/var b/var index 73490e43..595000c5 160000 --- a/var +++ b/var @@ -1 +1 @@ -Subproject commit 73490e436f57a0dc7a3bb9a9e3d535aa2b443ba9 +Subproject commit 595000c55f1205bced7a836d309be26303da1509 -- 2.39.5