Skip to content

Commit

Permalink
Merge branch 'develop' into enh/default-questionnaire-help-text
Browse files Browse the repository at this point in the history
  • Loading branch information
Alihassanc5 committed Jan 10, 2023
2 parents 5baf60c + 4c6d4cb commit dfa5d0f
Show file tree
Hide file tree
Showing 27 changed files with 521 additions and 200 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ In `iogt/settings/local.py`, define [parameters from wagtail-transfer](https://g
WAGTAILTRANSFER_SECRET_KEY = 'fake_secret_key'
WAGTAILTRANSFER_SOURCES = {
'iogt_global': {
'BASE_URL': 'http://fake-iogt-url.org',
'BASE_URL': 'http://fake-iogt-url.org/wagtail-transfer/',
'SECRET_KEY': 'fake_secret_key_2',
},
}
Expand Down
Binary file modified cypress.sqlite3
Binary file not shown.
5 changes: 0 additions & 5 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ services:
depends_on:
- elasticsearch
- database
- redis

elasticsearch:
image: 'docker.elastic.co/elasticsearch/elasticsearch:7.12.1'
Expand All @@ -60,10 +59,6 @@ services:
ports:
- 5432:5432

redis:
image: redis:6.2-buster
volumes:
- /var/lib/redis/data

volumes:
es-data01:
Expand Down
40 changes: 40 additions & 0 deletions docs/cache.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Switch on

Set the following environment variables:
```
CACHE_BACKEND=django_redis.cache.RedisCache
CACHE_LOCATION=redis://redis:6379
CACHE_TIMEOUT=300
```

These environment variables will be used to set [cache arguments][1] in the app's Django settings.

# Administration

The page cache is provided by [Wagtail Cache][2]. The page cache can be cleared from the Wagtail Admin by navigating to _Settings > Cache_, or _/admin/cache/_.

# Switch off

To switch off all caching features, it should be sufficient to simply unset the `CACHE_BACKEND` environment variable.

# In development

Most of the time it is probably desirable to switch off any sort of caching when developing the app. To avoid inadvertently committing settings that enable the page cache, it is advisable to place page cache settings in a `docker-compose.override.yml` file, if using Docker Compose.

Example Docker Compose configuration:
```docker-compose-override.yml
services:
django:
environment:
CACHE_BACKEND: django_redis.cache.RedisCache
CACHE_LOCATION: 'redis://cache:6379'
CACHE_TIMEOUT: '300'
depends_on:
- cache
cache:
image: redis:6.2-buster
```


[1]: https://docs.djangoproject.com/en/3.1/topics/cache/#using-a-custom-cache-backend
[2]: https://docs.coderedcorp.com/wagtail-cache/
4 changes: 2 additions & 2 deletions home/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ def _get_images_from_block(self, value):

return image_urls

def _get_stream_data_image_urls(self, stream_data):
def _get_stream_data_image_urls(self, raw_data):
image_urls = []

for block in stream_data:
for block in raw_data:
if block['type'] == 'image':
image_urls += self._get_renditions(block['value'])
if block['type'] == 'paragraph':
Expand Down
6 changes: 3 additions & 3 deletions home/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def get_context(self, request):

@property
def get_image_urls(self):
return self._get_stream_data_image_urls(self.home_featured_content.stream_data)
return self._get_stream_data_image_urls(self.home_featured_content.raw_data)


class FeaturedContent(Orderable):
Expand Down Expand Up @@ -271,7 +271,7 @@ def get_image_urls(self):
if self.image_icon:
image_urls += self._get_renditions(self.image_icon)

image_urls += self._get_stream_data_image_urls(self.body.stream_data)
image_urls += self._get_stream_data_image_urls(self.body.raw_data)

return image_urls

Expand Down Expand Up @@ -414,7 +414,7 @@ def get_image_urls(self):
if self.image_icon:
image_urls += self._get_renditions(self.image_icon)

image_urls += self._get_stream_data_image_urls(self.body.stream_data)
image_urls += self._get_stream_data_image_urls(self.body.raw_data)

return image_urls

Expand Down
28 changes: 19 additions & 9 deletions iogt/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
'wagtail.admin',
'wagtail.core',
'wagtail.contrib.modeladmin',
'wagtailcache',
'wagtailmenus',
'wagtailmedia',
'wagtailmarkdown',
Expand Down Expand Up @@ -93,6 +94,7 @@
]

MIDDLEWARE = [
'wagtailcache.cache.UpdateCacheMiddleware',
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
Expand All @@ -108,6 +110,7 @@
'external_links.middleware.RewriteExternalLinksMiddleware',
'iogt.middleware.CacheControlMiddleware',
'iogt.middleware.GlobalDataMiddleware',
'wagtailcache.cache.FetchFromCacheMiddleware',
]

# Prevent Wagtail's built in menu from showing in Admin > Settings
Expand Down Expand Up @@ -473,9 +476,6 @@
'rest_framework.authentication.BasicAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
),
Expand All @@ -485,24 +485,34 @@
'ACCESS_TOKEN_LIFETIME': timedelta(days=365),
}

SESSION_ENGINE='django.contrib.sessions.backends.db'

CACHE_BACKEND = os.getenv('CACHE_BACKEND')
if CACHE_BACKEND:
DJANGO_REDIS_IGNORE_EXCEPTIONS = True
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
WAGTAIL_CACHE_BACKEND = 'pagecache'
CACHE_LOCATION = os.getenv('CACHE_LOCATION', '')
CACHE_TIMEOUT = int(os.getenv('CACHE_TIMEOUT', '0'))
CACHES = {
"default": {
"BACKEND": CACHE_BACKEND,
"LOCATION": CACHE_LOCATION,
"TIMEOUT": CACHE_TIMEOUT,
'default': {
'BACKEND': CACHE_BACKEND,
'LOCATION': CACHE_LOCATION,
'TIMEOUT': CACHE_TIMEOUT,
},
'renditions': {
'BACKEND': CACHE_BACKEND,
'LOCATION': CACHE_LOCATION,
'TIMEOUT': CACHE_TIMEOUT,
},
'pagecache': {
'BACKEND': CACHE_BACKEND,
'LOCATION': CACHE_LOCATION,
'TIMEOUT': CACHE_TIMEOUT,
'KEY_PREFIX': 'pagecache',
},
}
else:
WAGTAIL_CACHE = False
SESSION_ENGINE='django.contrib.sessions.backends.db'

SITE_VERSION = os.getenv('SITE_VERSION', 'unknown')

Expand Down
8 changes: 0 additions & 8 deletions iogt/settings/docker_compose_dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,6 @@
}


WAGTAILTRANSFER_SECRET_KEY = os.environ.get('WAGTAILTRANSFER_SECRET_KEY')
WAGTAILTRANSFER_SOURCES = {
os.environ.get('WAGTAILTRANSFER_SOURCE_NAME', 'default'): {
'BASE_URL': os.environ.get('WAGTAILTRANSFER_SOURCE_BASE_URL'),
'SECRET_KEY': os.environ.get('WAGTAILTRANSFER_SOURCE_SECRET_KEY'),
},
}

# Uncomment if you want to run Postgres
# DATABASES = {
# 'default': {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@ <h2>{% trans "Object permissions" %}</h2>
<col width="15%" />
<col width="15%" />
<col width="15%" />
{% if custom_perms_exist %}
<col width="30%" />
{% endif %}
<thead>
<tr>
<th>{% trans "Name" %}</th>
<th>{% trans "Add" %}</th>
<th>{% trans "Change" %}</th>
<th>{% trans "Delete" %}</th>
{% if custom_perms_exist %}
<th>{% trans "Custom permissions" %}</th>
{% endif %}
</tr>
</thead>
<tbody>
Expand All @@ -41,6 +47,21 @@ <h2>{% trans "Object permissions" %}</h2>
{{ content_perms_dict.delete.checkbox.tag }}
{% endif %}
</td>
{% if custom_perms_exist %}
<td>
{% if content_perms_dict.custom %}
<fieldset class="custom-permissions">
<legend>{% trans "Custom permissions" %}</legend>
{% for custom_perm in content_perms_dict.custom %}
<label class="custom-permissions-item">
<input type="checkbox" name="permissions" value="{{ custom_perm.perm.id }}" {% if custom_perm.selected %}checked{% endif %}>
{{ custom_perm.name }}
</label>
{% endfor %}
</fieldset>
{% endif %}
</td>
{% endif %}
</tr>
{% endif %}
{% endfor %}
Expand Down
4 changes: 3 additions & 1 deletion iogt/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.urls import reverse
from rest_framework import status
from wagtail.core.models import Site
from wagtail.images.models import Image

from home.factories import (
SectionFactory,
Expand Down Expand Up @@ -36,7 +37,8 @@ def setUp(self):
self.article = ArticleFactory(parent=self.en_home_page, body=[("image", ImageFactory())])
self.section_lead_image_rendition = self.section.lead_image.get_rendition('fill-360x360')
self.article_lead_image_rendition = self.article.lead_image.get_rendition('fill-360x360')
self.article_body_image_rendition = self.article.body.stream_data[0][1].get_rendition('fill-360x360')
self.article_body_image_rendition = Image.objects.get(
id=self.article.body.raw_data[0]['value']).get_rendition('fill-360x360')
self.svg_to_png_map = SVGToPNGMapFactory()

def test_root_page_is_returned(self):
Expand Down
50 changes: 20 additions & 30 deletions iogt_content_migration/management/commands/load_v1_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -1668,27 +1668,23 @@ def migrate_featured_articles_for_homepage(self):
def add_article_as_featured_content_in_home_page(self, article):
home_page = self.home_page.get_translation_or_none(article.locale)
if home_page:
home_featured_content = home_page.home_featured_content.stream_data
home_featured_content.append({
'type': 'article',
'value': {
'article': article.id,
home_page.home_featured_content.append((
'article', {
'article': article,
'display_section_title': True,
},
})
}
))
home_page.save()

def add_section_as_featured_content_in_home_page(self, section):
home_page = self.home_page.get_translation_or_none(section.locale)
if home_page:
home_featured_content = home_page.home_featured_content.stream_data
home_featured_content.append({
'type': 'page_button',
'value': {
'page': section.id,
home_page.home_featured_content.append((
'page_button', {
'page': section,
'text': '',
},
})
}
))
home_page.save()

def attach_banners_to_home_page(self):
Expand Down Expand Up @@ -1922,17 +1918,14 @@ def add_polls_from_polls_index_page_to_home_page_featured_content(self):
poll_index_pages = self.poll_index_page.get_translations(inclusive=True)
for poll_index_page in poll_index_pages:
home_page = self.home_page.get_translation_or_none(poll_index_page.locale)
home_featured_content = home_page.home_featured_content.stream_data
polls = poll_index_page.get_children().live()
for poll in polls:
home_featured_content.append({
'type': 'embedded_poll',
'value': {
home_page.home_featured_content.append((
'embedded_poll', {
'direct_display': True,
'poll': poll.id,
},
})
home_page.home_featured_content = json.dumps(home_featured_content)
'poll': poll,
}
))
home_page.save()

self.stdout.write('Added polls from poll index page to home page featured content.')
Expand All @@ -1943,17 +1936,14 @@ def add_surveys_from_surveys_index_page_to_home_page_featured_content(self):
survey_index_pages = self.survey_index_page.get_translations(inclusive=True)
for survey_index_page in survey_index_pages:
home_page = self.home_page.get_translation_or_none(survey_index_page.locale)
home_featured_content = home_page.home_featured_content.stream_data
surveys = survey_index_page.get_children().live()
for survey in surveys:
home_featured_content.append({
'type': 'embedded_survey',
'value': {
home_page.home_featured_content.append((
'embedded_survey', {
'direct_display': survey.specific.direct_display,
'survey': survey.id,
},
})
home_page.home_featured_content = json.dumps(home_featured_content)
'survey': survey,
}
))
home_page.save()

self.stdout.write('Added surveys from survey index page to home page featured content.')
Expand Down
44 changes: 44 additions & 0 deletions notifications/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Notifications

The IoGT notification system relies on the [Web Push Protocol][1] to ensure the delivery of messages to users. In order to authenticate itself to a Push Service, every deployment of IoGT must generate its own public-private key pair for use with [VAPID][3].

To enable notifications in IoGT the following steps must be performed:

- Generate VAPID keys
- Set required settings (as environment variables)

# Generate VAPID keys

## Using openssl

This method guarantees that the private key remains secret (unless you expose it) and should be suitable for production deployments.

```
openssl ecparam -genkey -name prime256v1 -out private_key.pem
openssl ec -in private_key.pem -pubout -outform DER | tail -c 65 | base64 | tr -d '=' | tr '/+' '_-' >> public_key.txt
openssl ec -in private_key.pem -outform DER | tail -c +8 | head -c 32 | base64 | tr -d '=' | tr '/+' '_-' >> private_key.txt
```

The public and private keys will be written as plaintext to `public_key.txt` and `private_key.txt`, respectively.

## Using online generators

This method is more convenient, especially if openssl is not available, however, it is *not* recommended for production deployments.

- Go to [Web Push Codelab][2].
- Copy the public and private keys directly from the page.

# Set required settings

The notification feature requires several settings, and the easiest way to set them is to provide them to the app as environment variables.

- `VAPID_PUBLIC_KEY`: the VAPID public key in plaintext
- `VAPID_PRIVATE_KEY`: the VAPID private key in plaintext
- `VAPID_ADMIN_EMAIL`: the email address of a person/team responsible for hosting the IoGT application e.g. system administrator

It’s best if `VAPID_ADMIN_EMAIL` is not a personal email address, but rather a group email so that if a person leaves an organization, is unavailable for an extended period, or otherwise can’t respond, someone else on the list can. A Push Service provider may use this to contact you if there is a problem between the app and the push service.


[1]: https://web.dev/push-notifications-web-push-protocol/
[2]: https://web-push-codelab.glitch.me
[3]: https://datatracker.ietf.org/doc/html/draft-thomson-webpush-vapid
Loading

0 comments on commit dfa5d0f

Please sign in to comment.