Initial commit
This commit is contained in:
263
env/lib/python3.10/site-packages/wagtail/locks.py
vendored
Normal file
263
env/lib/python3.10/site-packages/wagtail/locks.py
vendored
Normal file
@@ -0,0 +1,263 @@
|
||||
from django.conf import settings
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.text import capfirst
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from wagtail.admin.utils import get_latest_str, get_user_display_name
|
||||
from wagtail.utils.timestamps import render_timestamp
|
||||
|
||||
|
||||
class BaseLock:
|
||||
"""
|
||||
Holds information about a lock on an object.
|
||||
|
||||
Returned by LockableMixin.get_lock() (or Page.get_lock()).
|
||||
"""
|
||||
|
||||
def __init__(self, object):
|
||||
from wagtail.models import Page
|
||||
|
||||
self.object = object
|
||||
self.is_page = isinstance(object, Page)
|
||||
# Use the base page's model name instead of the specific type for brevity
|
||||
self.model_name = (Page if self.is_page else object)._meta.verbose_name
|
||||
|
||||
def for_user(self, user):
|
||||
"""
|
||||
Returns True if the lock applies to the given user.
|
||||
"""
|
||||
return NotImplemented
|
||||
|
||||
def get_message(self, user):
|
||||
"""
|
||||
Returns a message to display to the given user describing the lock.
|
||||
"""
|
||||
return None
|
||||
|
||||
def get_icon(self, user):
|
||||
"""
|
||||
Returns the name of the icon to use for the lock.
|
||||
"""
|
||||
return "lock"
|
||||
|
||||
def get_locked_by(self, user):
|
||||
"""
|
||||
Returns a string that represents the user or mechanism that locked the object.
|
||||
"""
|
||||
return _("Locked")
|
||||
|
||||
def get_description(self, user):
|
||||
"""
|
||||
Returns a description of the lock to display to the given user.
|
||||
"""
|
||||
return capfirst(
|
||||
_("No one can make changes while the %(model_name)s is locked")
|
||||
% {"model_name": self.model_name}
|
||||
)
|
||||
|
||||
def get_context_for_user(self, user, parent_context=None):
|
||||
"""
|
||||
Returns a context dictionary to use in templates for the given user.
|
||||
"""
|
||||
return {
|
||||
"locked": self.for_user(user),
|
||||
"message": self.get_message(user),
|
||||
"icon": self.get_icon(user),
|
||||
"locked_by": self.get_locked_by(user),
|
||||
"description": self.get_description(user),
|
||||
}
|
||||
|
||||
|
||||
class BasicLock(BaseLock):
|
||||
"""
|
||||
A lock that is enabled when the "locked" attribute of an object is True.
|
||||
|
||||
The object may be editable by a user depending on whether the locked_by field is set
|
||||
and if WAGTAILADMIN_GLOBAL_EDIT_LOCK is not set to True.
|
||||
"""
|
||||
|
||||
def for_user(self, user):
|
||||
global_edit_lock = getattr(settings, "WAGTAILADMIN_GLOBAL_EDIT_LOCK", None)
|
||||
return global_edit_lock or user.pk != self.object.locked_by_id
|
||||
|
||||
def get_message(self, user):
|
||||
title = get_latest_str(self.object)
|
||||
|
||||
if self.object.locked_by_id == user.pk:
|
||||
if self.object.locked_at:
|
||||
return format_html(
|
||||
# nosemgrep: translation-no-new-style-formatting (new-style only w/ format_html)
|
||||
_(
|
||||
"<b>'{title}' was locked</b> by <b>you</b> on <b>{datetime}</b>."
|
||||
),
|
||||
title=title,
|
||||
datetime=render_timestamp(self.object.locked_at),
|
||||
)
|
||||
|
||||
else:
|
||||
return format_html(
|
||||
# nosemgrep: translation-no-new-style-formatting (new-style only w/ format_html)
|
||||
_("<b>'{title}' is locked</b> by <b>you</b>."),
|
||||
title=title,
|
||||
)
|
||||
else:
|
||||
if self.object.locked_by and self.object.locked_at:
|
||||
return format_html(
|
||||
# nosemgrep: translation-no-new-style-formatting (new-style only w/ format_html)
|
||||
_(
|
||||
"<b>'{title}' was locked</b> by <b>{user}</b> on <b>{datetime}</b>."
|
||||
),
|
||||
title=title,
|
||||
user=get_user_display_name(self.object.locked_by),
|
||||
datetime=render_timestamp(self.object.locked_at),
|
||||
)
|
||||
else:
|
||||
# Object was probably locked with an old version of Wagtail, or a script
|
||||
return format_html(
|
||||
# nosemgrep: translation-no-new-style-formatting (new-style only w/ format_html)
|
||||
_("<b>'{title}' is locked</b>."),
|
||||
title=title,
|
||||
)
|
||||
|
||||
def get_locked_by(self, user):
|
||||
if self.object.locked_by_id == user.pk:
|
||||
return _("Locked by you")
|
||||
if self.object.locked_by_id:
|
||||
return _("Locked by another user")
|
||||
return super().get_locked_by(user)
|
||||
|
||||
def get_description(self, user):
|
||||
if self.object.locked_by_id == user.pk:
|
||||
return capfirst(
|
||||
_("Only you can make changes while the %(model_name)s is locked")
|
||||
% {"model_name": self.model_name}
|
||||
)
|
||||
if self.object.locked_by_id:
|
||||
return capfirst(
|
||||
_("Only %(user)s can make changes while the %(model_name)s is locked")
|
||||
% {
|
||||
"user": get_user_display_name(self.object.locked_by),
|
||||
"model_name": self.model_name,
|
||||
}
|
||||
)
|
||||
return super().get_description(user)
|
||||
|
||||
|
||||
class WorkflowLock(BaseLock):
|
||||
"""
|
||||
A lock that requires the user to pass the Task.locked_for_user test on the given workflow task.
|
||||
"""
|
||||
|
||||
def __init__(self, object, task):
|
||||
super().__init__(object)
|
||||
self.task = task
|
||||
|
||||
def for_user(self, user):
|
||||
return self.task.locked_for_user(self.object, user)
|
||||
|
||||
def get_message(self, user):
|
||||
if self.for_user(user):
|
||||
current_workflow_state = self.object.current_workflow_state
|
||||
if (
|
||||
current_workflow_state
|
||||
and len(current_workflow_state.all_tasks_with_status()) == 1
|
||||
):
|
||||
# If only one task in workflow, show simple message
|
||||
workflow_info = capfirst(
|
||||
_("This %(model_name)s is currently awaiting moderation.")
|
||||
% {"model_name": self.model_name}
|
||||
)
|
||||
else:
|
||||
workflow_info = format_html(
|
||||
# nosemgrep: translation-no-new-style-formatting (new-style only w/ format_html)
|
||||
_(
|
||||
"This {model_name} is awaiting <b>'{task_name}'</b> in the <b>'{workflow_name}'</b> workflow."
|
||||
),
|
||||
model_name=self.model_name,
|
||||
task_name=self.task.name,
|
||||
workflow_name=current_workflow_state.workflow.name,
|
||||
)
|
||||
# Make sure message is correctly capitalised even if it
|
||||
# starts with model_name.
|
||||
workflow_info = mark_safe(capfirst(workflow_info))
|
||||
|
||||
reviewers_info = capfirst(
|
||||
_("Only reviewers for this task can edit the %(model_name)s.")
|
||||
% {"model_name": self.model_name}
|
||||
)
|
||||
|
||||
return mark_safe(workflow_info + " " + reviewers_info)
|
||||
|
||||
def get_icon(self, user, can_lock=False):
|
||||
if can_lock:
|
||||
return "lock-open"
|
||||
return super().get_icon(user)
|
||||
|
||||
def get_locked_by(self, user, can_lock=False):
|
||||
if can_lock:
|
||||
return _("Unlocked")
|
||||
return _("Locked by workflow")
|
||||
|
||||
def get_description(self, user, can_lock=False):
|
||||
if can_lock:
|
||||
return capfirst(
|
||||
_(
|
||||
"Reviewers can edit this %(model_name)s – lock it to prevent other reviewers from editing"
|
||||
)
|
||||
% {"model_name": self.model_name}
|
||||
)
|
||||
return capfirst(
|
||||
_("Only reviewers can edit and approve the %(model_name)s")
|
||||
% {"model_name": self.model_name}
|
||||
)
|
||||
|
||||
def get_context_for_user(self, user, parent_context=None):
|
||||
context = super().get_context_for_user(user, parent_context)
|
||||
# BasicLock can still be applied on top of WorkflowLock, so we need to
|
||||
# check if the user can lock the object based on the parent context.
|
||||
# We're utilising the parent context instead of self.task.user_can_lock()
|
||||
# because the latter does not take into account the user's permissions,
|
||||
# while the parent context does and also checks self.task.user_can_lock().
|
||||
if parent_context and "user_can_lock" in parent_context:
|
||||
can_lock = parent_context.get("user_can_lock", False)
|
||||
context.update(
|
||||
{
|
||||
"icon": self.get_icon(user, can_lock),
|
||||
"locked_by": self.get_locked_by(user, can_lock),
|
||||
"description": self.get_description(user, can_lock),
|
||||
}
|
||||
)
|
||||
return context
|
||||
|
||||
|
||||
class ScheduledForPublishLock(BaseLock):
|
||||
"""
|
||||
A lock that occurs when something is scheduled to be published.
|
||||
|
||||
This prevents it becoming difficult for users to see which version is going to be published.
|
||||
Nobody can edit something that's scheduled for publish.
|
||||
"""
|
||||
|
||||
def for_user(self, user):
|
||||
return True
|
||||
|
||||
def get_message(self, user):
|
||||
scheduled_revision = self.object.scheduled_revision
|
||||
|
||||
message = format_html(
|
||||
# nosemgrep: translation-no-new-style-formatting (new-style only w/ format_html)
|
||||
_(
|
||||
"{model_name} '{title}' is locked and has been scheduled to go live at {datetime}"
|
||||
),
|
||||
model_name=self.model_name,
|
||||
title=scheduled_revision.object_str,
|
||||
datetime=render_timestamp(scheduled_revision.approved_go_live_at),
|
||||
)
|
||||
return mark_safe(capfirst(message))
|
||||
|
||||
def get_locked_by(self, user):
|
||||
return _("Locked by schedule")
|
||||
|
||||
def get_description(self, user):
|
||||
return _("Currently locked and will go live on the scheduled date")
|
||||
Reference in New Issue
Block a user