diff --git a/README.md b/README.md index d158974fd..6c9ba025e 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,13 @@ ## Vagrant -* Install [Vagrant](https://wiki.torchbox.com/view/Vagrant) -* ```git clone git@github.com:torchbox/verdant-rca.git``` -* ```cd verdant-rca``` -* ```vagrant up``` -* ```vagrant ssh``` -* ```djrun``` -* Edit your code locally, browse at [localhost:8000](http://localhost:8000/) +- Install [Vagrant](https://wiki.torchbox.com/view/Vagrant) +- `git clone git@github.com:torchbox/verdant-rca.git` +- `cd verdant-rca` +- `vagrant up` +- `vagrant ssh` +- `djrun` +- Edit your code locally, browse at [localhost:8000](http://localhost:8000/) ## Docker @@ -35,12 +35,10 @@ You may encounter a "Invalid input of type: 'CacheKey'" error when running a new `redis==2.10.6` to `django-verdant/requirements.txt` and then running `pip install -r requirements.txt` - # Implementation notes -* MyRCA / student profiles: https://projects.torchbox.com/projects/rca-django-cms-project/notebook/Implementation%20notes%20for%20%22My%20RCA%22%20feature.md -* Course registration: https://projects.torchbox.com/projects/rca-django-cms-project/notebook/Implementation%20notes%20for%20Course%20registration%20(%23788).md - +- MyRCA / student profiles: https://projects.torchbox.com/projects/rca-django-cms-project/notebook/Implementation%20notes%20for%20%22My%20RCA%22%20feature.md +- Course registration: https://projects.torchbox.com/projects/rca-django-cms-project/notebook/Implementation%20notes%20for%20Course%20registration%20(%23788).md # My RCA @@ -57,17 +55,14 @@ Also you will need to add the following user groups (with same ID) - MPhil Students => 5 - PhD Students => 6 - # Front end notes on the main RCA build - ## Original set up and build -It was orignally built to a design provided by an external agency, and some of the terminology e.g. 'modules' and the names of the text styles are based on their original terminology. +It was originally built to a design provided by an external agency, and some of the terminology e.g. 'modules' and the names of the text styles are based on their original terminology. There is no tooling, and the site uses `django-compressor`. - ### CSS This build uses Less. @@ -99,7 +94,7 @@ Note that all templates for template tags sit in a separate `tags` subfolder. There's the usual `blocks` folder for streamfield block templates. ### Carousels + The original carousel used was bxslider, and on some templates there is still functionality to add a hero carousel (with both videos and images) using bxslider. The bxslider javascript is loaded via base.html. RCA are not using this functionality much and it may get removed at a later date. When the homepage 2018 redesign happened, there was a need to use another carousel, slick, in order to use the centre mode functionality. - diff --git a/django-verdant/rca/api/filters.py b/django-verdant/rca/api/filters.py index 08b712c18..e75830389 100644 --- a/django-verdant/rca/api/filters.py +++ b/django-verdant/rca/api/filters.py @@ -41,7 +41,7 @@ def filter_queryset(self, request, queryset, view): date_from = request.query_params.get('event_date_from', None) if date_from: now = datetime.utcnow().date() - queryset = queryset.filter(dates_times__date_from__gte=now) + queryset = queryset.filter(dates_times__date_from__gte=now) | queryset.filter(dates_times__date_to__gte=now) queryset = queryset.order_by('dates_times__date_from') return queryset diff --git a/django-verdant/rca/migrations/0108_add_programme_override_field.py b/django-verdant/rca/migrations/0108_add_programme_override_field.py new file mode 100644 index 000000000..5d0949dc3 --- /dev/null +++ b/django-verdant/rca/migrations/0108_add_programme_override_field.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2020-05-07 14:43 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('rca', '0107_allow_event_blank_body'), + ] + + operations = [ + migrations.AddField( + model_name='newstudentpage', + name='programme_value_override', + field=models.CharField(blank=True, help_text=b'', max_length=255), + ), + ] diff --git a/django-verdant/rca/migrations/0109_merge.py b/django-verdant/rca/migrations/0109_merge.py new file mode 100644 index 000000000..08d10940e --- /dev/null +++ b/django-verdant/rca/migrations/0109_merge.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2020-06-04 10:15 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('rca', '0108_auto_20200604_0924'), + ('rca', '0108_add_programme_override_field'), + ] + + operations = [ + ] diff --git a/django-verdant/rca/migrations/0110_merge.py b/django-verdant/rca/migrations/0110_merge.py new file mode 100644 index 000000000..236706e71 --- /dev/null +++ b/django-verdant/rca/migrations/0110_merge.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2020-07-07 12:15 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('rca', '0109_remove-student-char-limits'), + ('rca', '0109_merge'), + ] + + operations = [ + ] diff --git a/django-verdant/rca/migrations/0111_merge.py b/django-verdant/rca/migrations/0111_merge.py new file mode 100644 index 000000000..6e69f904f --- /dev/null +++ b/django-verdant/rca/migrations/0111_merge.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2020-08-13 10:22 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('rca', '0110_merge'), + ('rca', '0110_remove_ma_specialism_choices_and_last_name_validation'), + ] + + operations = [ + ] diff --git a/django-verdant/rca/migrations/0112_merge.py b/django-verdant/rca/migrations/0112_merge.py new file mode 100644 index 000000000..5f03dc538 --- /dev/null +++ b/django-verdant/rca/migrations/0112_merge.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2020-08-14 09:03 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('rca', '0111_merge'), + ('rca', '0111_reimplement_ma_specialism_choices'), + ] + + operations = [ + ] diff --git a/django-verdant/rca/models.py b/django-verdant/rca/models.py index 2cd44f385..99dc6b0b4 100644 --- a/django-verdant/rca/models.py +++ b/django-verdant/rca/models.py @@ -1,78 +1,77 @@ -from datetime import date import datetime +import hashlib +import json import logging import random - +from datetime import date from itertools import chain +import stripe from captcha.fields import ReCaptchaField -from django.core.exceptions import ValidationError -from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.conf import settings from django.contrib import messages from django.contrib.auth.signals import user_logged_in -from django.db import models -from django.db.models.signals import pre_delete +from django.core.exceptions import ValidationError +from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator from django.core.serializers.json import DjangoJSONEncoder +from django.db import models from django.db.models import Q +from django.db.models.signals import pre_delete from django.dispatch.dispatcher import receiver -from django.http import HttpResponse, HttpResponseRedirect, Http404 -from django.shortcuts import render, redirect +from django.http import Http404, HttpResponse, HttpResponseRedirect +from django.shortcuts import redirect, render +from django.utils import timezone from django.utils.functional import cached_property from django.utils.html import conditional_escape from django.utils.safestring import mark_safe -from django.utils import timezone from django.views.decorators.vary import vary_on_headers +from modelcluster.contrib.taggit import ClusterTaggableManager +from modelcluster.fields import ParentalKey +from modelcluster.models import ClusterableModel +from taggit.models import Tag, TaggedItemBase from wagtail.contrib.settings.models import BaseSetting from wagtail.contrib.settings.registry import register_setting - -from wagtail.wagtailcore.models import Page, Orderable, PageManager +from wagtail.wagtailadmin.edit_handlers import (FieldPanel, InlinePanel, + MultiFieldPanel, ObjectList, + PageChooserPanel, + PublishingPanel, + StreamFieldPanel, + TabbedInterface) +from wagtail.wagtailadmin.utils import send_mail from wagtail.wagtailcore.fields import RichTextField, StreamField +from wagtail.wagtailcore.models import Orderable, Page, PageManager +from wagtail.wagtailcore.query import PageQuerySet from wagtail.wagtailcore.url_routing import RouteResult -from modelcluster.fields import ParentalKey - -from wagtail.wagtailadmin.edit_handlers import ( - FieldPanel, MultiFieldPanel, InlinePanel, ObjectList, PageChooserPanel, - PublishingPanel, TabbedInterface, StreamFieldPanel -) +from wagtail.wagtaildocs.edit_handlers import DocumentChooserPanel from wagtail.wagtailembeds import embeds from wagtail.wagtailembeds.exceptions import EmbedNotFoundException -from wagtail.wagtailembeds.finders.embedly import AccessDeniedEmbedlyException, EmbedlyException +from wagtail.wagtailembeds.finders.embedly import ( + AccessDeniedEmbedlyException, EmbedlyException) +from wagtail.wagtailforms.models import AbstractFormField, FormSubmission from wagtail.wagtailimages.edit_handlers import ImageChooserPanel -from wagtail.wagtailimages.models import Image, AbstractImage, AbstractRendition -from wagtail.wagtaildocs.edit_handlers import DocumentChooserPanel +from wagtail.wagtailimages.models import (AbstractImage, AbstractRendition, + Image) +from wagtail.wagtailsearch import index from wagtail.wagtailsnippets.edit_handlers import SnippetChooserPanel from wagtail.wagtailsnippets.models import register_snippet -from wagtail.wagtailsearch import index -from wagtail.wagtailcore.query import PageQuerySet -from wagtail.wagtailforms.models import AbstractFormField, FormSubmission -from wagtail.wagtailadmin.utils import send_mail - -from modelcluster.contrib.taggit import ClusterTaggableManager -from modelcluster.models import ClusterableModel -from taggit.models import TaggedItemBase, Tag +from wagtailcaptcha.models import (WagtailCaptchaEmailForm, + WagtailCaptchaFormBuilder) from donations.forms import DonationForm -from donations.mail_admins import mail_exception, full_exc_info -import stripe - -import hashlib - +from donations.mail_admins import full_exc_info, mail_exception +from rca.filters import (combine_filters, get_filters_q, run_filters, + run_filters_q) from rca.standard_stream_page.models import StandardStreamPage -from rca.utils.models import ( - RelatedLinkMixin, SocialFields, SidebarBehaviourFields, - OptionalBlockFields, CarouselItemFields, -) +from rca.utils.models import (CarouselItemFields, OptionalBlockFields, + RelatedLinkMixin, SidebarBehaviourFields, + SocialFields) from rca_ee.models import FormPage -from taxonomy.models import Area, School, Programme, DegreeLevel - -from rca.filters import run_filters, run_filters_q, combine_filters, get_filters_q -import json - -from wagtailcaptcha.models import WagtailCaptchaEmailForm, WagtailCaptchaFormBuilder - from rca_signage.constants import SCREEN_CHOICES -from reachout_choices import REACHOUT_PROJECT_CHOICES, REACHOUT_PARTICIPANTS_CHOICES, REACHOUT_THEMES_CHOICES, REACHOUT_PARTNERSHIPS_CHOICES +from reachout_choices import (REACHOUT_PARTICIPANTS_CHOICES, + REACHOUT_PARTNERSHIPS_CHOICES, + REACHOUT_PROJECT_CHOICES, + REACHOUT_THEMES_CHOICES) +from taxonomy.models import Area, DegreeLevel, Programme, School from .help_text import help_text @@ -4057,6 +4056,7 @@ class NewStudentPage(Page, SocialFields): show_work_type = models.CharField("Work type", max_length=255, choices=SHOW_WORK_TYPE_CHOICES, blank=True, help_text=help_text('rca.NewStudentPage', 'show_work_type')) show_work_location = models.CharField("Work location", max_length=255, choices=CAMPUS_CHOICES, blank=True, help_text=help_text('rca.NewStudentPage', 'show_work_location')) show_work_description = RichTextField(help_text=help_text('rca.NewStudentPage', 'show_work_description'), blank=True) + programme_value_override = models.CharField(max_length=255, blank=True, help_text=help_text('rca.NewStudentPage', 'programme_value_override')) # MPhil details mphil_programme = models.ForeignKey('taxonomy.Programme', verbose_name="Programme", null=True, blank=True, on_delete=models.SET_NULL, related_name='mphil_students', help_text=help_text('rca.NewStudentPage', 'mphil_programme')) @@ -4341,7 +4341,9 @@ def programme(self): return '' def get_ma_programme_display(self): - if not self.ma_programme: + if self.programme_value_override: + return self.programme_value_override + elif not self.ma_programme: return '' return self.ma_programme.get_display_name_for_year(self.ma_graduation_year) @@ -4515,6 +4517,7 @@ def serve(self, request, view='standard'): FieldPanel('ma_programme'), FieldPanel('ma_graduation_year'), FieldPanel('ma_specialism'), + FieldPanel('programme_value_override') ], "MA details", classname="collapsible collapsed"), # Show details diff --git a/django-verdant/rca/static/rca/css/core.less b/django-verdant/rca/static/rca/css/core.less index 1892e354f..330aab9a6 100644 --- a/django-verdant/rca/static/rca/css/core.less +++ b/django-verdant/rca/static/rca/css/core.less @@ -2277,4 +2277,3 @@ a.hidden { @import "streamfield-blocks/two-column-block"; @import "streamfield-blocks/testimonial"; @import "streamfield-blocks/events.less"; - diff --git a/django-verdant/rca/templates/rca/base.html b/django-verdant/rca/templates/rca/base.html index 41de12483..f877f9241 100644 --- a/django-verdant/rca/templates/rca/base.html +++ b/django-verdant/rca/templates/rca/base.html @@ -281,6 +281,10 @@ {% endif %} + {# revert this back to live JS file path before deploying to live #} + + {# #} + {% block show_js %}{% endblock %} {% block extra_js %}{% endblock %} {% endblock %} diff --git a/django-verdant/rca/templates/rca/includes/footer.html b/django-verdant/rca/templates/rca/includes/footer.html index 90a8b0300..d171601a1 100644 --- a/django-verdant/rca/templates/rca/includes/footer.html +++ b/django-verdant/rca/templates/rca/includes/footer.html @@ -74,7 +74,6 @@ SW7 2EU

- diff --git a/django-verdant/rcasite/settings/base.py b/django-verdant/rcasite/settings/base.py index 6df030c6a..fea018531 100644 --- a/django-verdant/rcasite/settings/base.py +++ b/django-verdant/rcasite/settings/base.py @@ -542,3 +542,4 @@ if "CACHE_CONTROL_STALE_IF_ERROR" in env: CACHE_CONTROL_STALE_IF_ERROR = env["CACHE_CONTROL_STALE_IF_ERROR"] + diff --git a/django-verdant/rcasitemaps/views.py b/django-verdant/rcasitemaps/views.py index 378fd4282..569c54747 100644 --- a/django-verdant/rcasitemaps/views.py +++ b/django-verdant/rcasitemaps/views.py @@ -2,9 +2,34 @@ from django.contrib.sitemaps import views as sitemap_views +from django.contrib.sites.shortcuts import get_current_site +from django.core import urlresolvers +from django.template.response import TemplateResponse from .sitemap_generator import Sitemap +def sitemap_views_index(request, sitemaps, + template_name='sitemap_index.xml', content_type='application/xml', + sitemap_url_name='django.contrib.sitemaps.views.sitemap'): + + req_protocol = request.scheme + req_site = get_current_site(request) + + sites = [] + for section, site in sitemaps.items(): + if callable(site): + site = site() + protocol = req_protocol if site.protocol is None else site.protocol + sitemap_url = urlresolvers.reverse( + sitemap_url_name, kwargs={'section': section}) + absolute_url = '%s://%s%s' % (protocol, request.site.hostname, sitemap_url) + sites.append(absolute_url) + for page in range(2, site.paginator.num_pages + 1): + sites.append('%s?p=%s' % (absolute_url, page)) + + return TemplateResponse(request, template_name, {'sitemaps': sites}, + content_type=content_type) + def index(request, sitemaps, **kwargs): sitemaps = prepare_sitemaps(request, sitemaps) @@ -21,6 +46,7 @@ def index(request, sitemaps, **kwargs): def sitemap(request, sitemaps=None, **kwargs): if sitemaps: sitemaps = prepare_sitemaps(request, sitemaps) + else: sitemaps = {'wagtail': Sitemap(request.site)} return sitemap_views.sitemap(request, sitemaps, **kwargs)