Skip to content

Commit

Permalink
Merge pull request #7 from mozmeao/5-customisable-max-age
Browse files Browse the repository at this point in the history
Support custom max age + multiple links per Revision
  • Loading branch information
stevejalim authored Dec 4, 2024
2 parents d829af8 + ae030bf commit 768b989
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 66 deletions.
26 changes: 19 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,25 +67,37 @@ draft version saved since the last time the page was published

## Settings

The following settings can be added to your Django settings file:
The following settings can be added to your Django settings file as keys in a `WAGTAILDRAFTSHARING` dictionary

### ``WAGTAILDRAFTSHARING_MAX_AGE``
```
WAGTAILDRAFTSHARING = {
...
"MAX_TTL": 123456,
...
}
```

The default expiry time for generated links, in seconds. Defaults to 1 week. Set it to a negative value to disable expiry.
### ``MAX_TTL``

### ```WAGTAILDRAFTSHARING_ADMIN_MENU_POSITION```
The default expiry time for generated links, in seconds. Defaults to 28 days. Set it to a negative value to disable expiry.

### ```ADMIN_MENU_POSITION```

Set the integer priority to control where in the admin menu
the link to the list of generated links sits. Defaults to 200.

### ```WAGTAILDRAFTSHARING_VERBOSE_NAME```
### ```VERBOSE_NAME```

Provide a different singular label for a link. Defaults to "Draftsharing Link"

### ```WAGTAILDRAFTSHARING_VERBOSE_NAME_PLURAL```
### ```VERBOSE_NAME_PLURAL```

Provide a different plural label for a link. Defaults to "Draftsharing Links"

### ```WAGTAILDRAFTSHARING_MENU_ITEM_LABEL```
### ```MENU_ITEM_LABEL```

Customise the label used in the page-level Action Menu for creating a link. Defaults to "Create draft sharing link",

## Testing

To install testing dependencies locally run `pip install -e ".[testing]"`
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "wagtaildraftsharing"
version = "0.1.3"
version = "0.2.0"
description = "Share wagtail drafts with private URLs."
readme = "README.md"
requires-python = ">=3.9"
Expand Down
13 changes: 13 additions & 0 deletions wagtaildraftsharing/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from wagtail.log_actions import LogFormatter

WAGTAILDRAFTSHARING_CREATE_SHARING_LINK = "wagtaildraftsharing.create_sharing_link"
WAGTAILDRAFTSHARING_REUSE_SHARING_LINK = "wagtaildraftsharing.reuse_sharing_link"


def register_wagtaildraftsharing_log_actions(actions):
Expand All @@ -16,3 +17,15 @@ def format_message(self, log_entry):
revision_id=log_entry.data["revision"],
username=log_entry.user,
)

@actions.register_action(WAGTAILDRAFTSHARING_REUSE_SHARING_LINK)
class ReuseSharingLink(LogFormatter):
label = _("Reuse sharing link")

def format_message(self, log_entry):
return _(
"{username} reused sharing link for revision {revision_id}"
).format(
revision_id=log_entry.data["revision"],
username=log_entry.user,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 5.1.1 on 2024-12-04 10:56

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("wagtaildraftsharing", "0002_alter_wagtaildraftsharinglink_created_by"),
]

operations = [
migrations.AlterField(
model_name="wagtaildraftsharinglink",
name="revision",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="+",
to="wagtailcore.revision",
),
),
]
68 changes: 54 additions & 14 deletions wagtaildraftsharing/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,59 @@
from django.utils.timezone import timedelta
from wagtail.log_actions import log

from wagtaildraftsharing.actions import WAGTAILDRAFTSHARING_CREATE_SHARING_LINK
from wagtaildraftsharing.actions import (
WAGTAILDRAFTSHARING_CREATE_SHARING_LINK,
WAGTAILDRAFTSHARING_REUSE_SHARING_LINK,
)
from wagtaildraftsharing.utils import tz_aware_utc_now

from . import settings as draftsharing_settings

max_age = draftsharing_settings.WAGTAILDRAFTSHARING_MAX_AGE
from .settings import settings as draftsharing_settings


class WagtaildraftsharingLinkManager(models.Manager):
def get_or_create_for_revision(self, *, revision, user):
key = uuid.uuid4()
if max_age > 0:
active_until = tz_aware_utc_now() + timedelta(seconds=max_age)
def _get_active_until(self, max_ttl):
if max_ttl is None:
max_ttl = draftsharing_settings.MAX_TTL
if max_ttl > 0:
active_until = tz_aware_utc_now() + timedelta(seconds=max_ttl)
else:
active_until = None

return active_until

def create_for_revision(self, *, revision, user, max_ttl=None):
# Always creates a new sharing link
sharing_link = WagtaildraftsharingLink.objects.create(
revision=revision,
key=uuid.uuid4(),
created_by=user,
active_until=self._get_active_until(max_ttl=max_ttl),
)
log(
instance=revision.content_object,
action=WAGTAILDRAFTSHARING_CREATE_SHARING_LINK,
user=user,
revision=revision,
data={"revision": revision.id},
)

return sharing_link

def get_or_create_for_revision(self, *, revision, user, max_ttl=None):
"""
Deprecated: prefer self.create_for_revision() instead
Creates a new sharing link if it doesn't exist, else returns an
existing one. Note that this may give you a link that is soon to
expire if it was made close to max_ttl seconds ago...
"""

active_until = self._get_active_until(max_ttl=max_ttl)

sharing_link, created = WagtaildraftsharingLink.objects.get_or_create(
revision=revision,
defaults={
"key": key,
"key": uuid.uuid4(),
"created_by": user,
"active_until": active_until,
},
Expand All @@ -39,6 +73,14 @@ def get_or_create_for_revision(self, *, revision, user):
revision=revision,
data={"revision": revision.id},
)
else:
log(
instance=revision.content_object,
action=WAGTAILDRAFTSHARING_REUSE_SHARING_LINK,
user=user,
revision=revision,
data={"revision": revision.id},
)

return sharing_link

Expand All @@ -50,7 +92,7 @@ class WagtaildraftsharingLink(models.Model):
editable=False,
primary_key=False,
)
revision = models.OneToOneField(
revision = models.ForeignKey(
"wagtailcore.Revision",
on_delete=models.CASCADE,
related_name="+",
Expand All @@ -77,10 +119,8 @@ def __init__(self, *args, **kwargs):

# Set the verbose names from settings,
# in a way that doesn't trigger migrations
self._meta.verbose_name = draftsharing_settings.WAGTAILDRAFTSHARING_VERBOSE_NAME
self._meta.verbose_name_plural = (
draftsharing_settings.WAGTAILDRAFTSHARING_VERBOSE_NAME_PLURAL
)
self._meta.verbose_name = draftsharing_settings.VERBOSE_NAME
self._meta.verbose_name_plural = draftsharing_settings.VERBOSE_NAME_PLURAL

def __str__(self):
return f"Revision {self.revision_id} of {self.revision.content_object}"
Expand Down
76 changes: 44 additions & 32 deletions wagtaildraftsharing/settings.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,44 @@
from django.conf import settings

WAGTAILDRAFTSHARING_ADMIN_MENU_POSITION = getattr(
settings,
"WAGTAILDRAFTSHARING_ADMIN_MENU_POSITION",
200,
)

WAGTAILDRAFTSHARING_VERBOSE_NAME = getattr(
settings,
"WAGTAILDRAFTSHARING_VERBOSE_NAME",
"Draftsharing Link",
)

WAGTAILDRAFTSHARING_VERBOSE_NAME_PLURAL = getattr(
settings,
"WAGTAILDRAFTSHARING_VERBOSE_NAME_PLURAL",
"Draftsharing Links",
)

WAGTAILDRAFTSHARING_MENU_ITEM_LABEL = getattr(
settings,
"WAGTAILDRAFTSHARING_MENU_ITEM_LABEL",
"Create draft sharing link",
)

DEFAULT_MAX_AGE = 7 * 24 * 60 * 60 # 7 days
WAGTAILDRAFTSHARING_MAX_AGE = getattr(
settings,
"WAGTAILDRAFTSHARING_MAX_AGE",
DEFAULT_MAX_AGE,
)
import dataclasses
from typing import cast

from django.conf import settings as django_settings
from django.utils.functional import SimpleLazyObject

_DEFAULT_MAX_TTL = 28 * 24 * 60 * 60 # 28 days


@dataclasses.dataclass
class WagtaildraftsharingSettings:
ADMIN_MENU_POSITION: int = 200
VERBOSE_NAME: str = "Draftsharing Link"
VERBOSE_NAME_PLURAL: str = "Draftsharing Links"
MENU_ITEM_LABEL: str = "Create draft sharing link"
MAX_TTL: int = _DEFAULT_MAX_TTL


def _init_settings():
"""
Get and validate Wagtaildraftsharing settings from the Django settings.
"""

setting_name = "WAGTAILDRAFTSHARING"
django_settings_dict = getattr(django_settings, setting_name, {})

overriden_defaults = {}

for optional_setting_name in [
"ADMIN_MENU_POSITION",
"VERBOSE_NAME",
"VERBOSE_NAME_PLURAL",
"MENU_ITEM_LABEL",
"MAX_TTL",
]:
if optional_setting_name in django_settings_dict:
overriden_defaults[optional_setting_name] = django_settings_dict[
optional_setting_name
]

return WagtaildraftsharingSettings(**overriden_defaults)


settings = cast(WagtaildraftsharingSettings, SimpleLazyObject(_init_settings))
4 changes: 2 additions & 2 deletions wagtaildraftsharing/snippets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

from wagtaildraftsharing.models import WagtaildraftsharingLink

from . import settings as draftsharing_settings
from .settings import settings as draftsharing_settings


class WagtaildraftsharingLinkSnippetViewSet(SnippetViewSet):
model = WagtaildraftsharingLink
base_url_path = "wagtaildraftsharing"
menu_icon = "view"
menu_order = draftsharing_settings.WAGTAILDRAFTSHARING_ADMIN_MENU_POSITION
menu_order = draftsharing_settings.ADMIN_MENU_POSITION
add_to_settings_menu = False
add_to_admin_menu = True
list_display = ("__str__", "is_active", "created_by", "share_url")
Expand Down
7 changes: 7 additions & 0 deletions wagtaildraftsharing/tests/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,10 @@
WAGTAILADMIN_BASE_URL = "http://localhost:8000"

USE_TZ = True

# Wagtaildraftsharing settings

WAGTAILDRAFTSHARING = {
# Here is where settings would be overridden in a real project
# "MAX_TTL": 12312321,
}
Loading

0 comments on commit 768b989

Please sign in to comment.