first comit
This commit is contained in:
3
venv/lib/python3.10/site-packages/django/contrib/messages/__init__.py
Executable file
3
venv/lib/python3.10/site-packages/django/contrib/messages/__init__.py
Executable file
@@ -0,0 +1,3 @@
|
||||
from django.contrib.messages.api import * # NOQA
|
||||
from django.contrib.messages.constants import * # NOQA
|
||||
from django.contrib.messages.storage.base import Message # NOQA
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
127
venv/lib/python3.10/site-packages/django/contrib/messages/api.py
Executable file
127
venv/lib/python3.10/site-packages/django/contrib/messages/api.py
Executable file
@@ -0,0 +1,127 @@
|
||||
from django.contrib.messages import constants
|
||||
from django.contrib.messages.storage import default_storage
|
||||
|
||||
__all__ = (
|
||||
"add_message",
|
||||
"get_messages",
|
||||
"get_level",
|
||||
"set_level",
|
||||
"debug",
|
||||
"info",
|
||||
"success",
|
||||
"warning",
|
||||
"error",
|
||||
"MessageFailure",
|
||||
)
|
||||
|
||||
|
||||
class MessageFailure(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def add_message(request, level, message, extra_tags="", fail_silently=False):
|
||||
"""
|
||||
Attempt to add a message to the request using the 'messages' app.
|
||||
"""
|
||||
try:
|
||||
messages = request._messages
|
||||
except AttributeError:
|
||||
if not hasattr(request, "META"):
|
||||
raise TypeError(
|
||||
"add_message() argument must be an HttpRequest object, not "
|
||||
"'%s'." % request.__class__.__name__
|
||||
)
|
||||
if not fail_silently:
|
||||
raise MessageFailure(
|
||||
"You cannot add messages without installing "
|
||||
"django.contrib.messages.middleware.MessageMiddleware"
|
||||
)
|
||||
else:
|
||||
return messages.add(level, message, extra_tags)
|
||||
|
||||
|
||||
def get_messages(request):
|
||||
"""
|
||||
Return the message storage on the request if it exists, otherwise return
|
||||
an empty list.
|
||||
"""
|
||||
return getattr(request, "_messages", [])
|
||||
|
||||
|
||||
def get_level(request):
|
||||
"""
|
||||
Return the minimum level of messages to be recorded.
|
||||
|
||||
The default level is the ``MESSAGE_LEVEL`` setting. If this is not found,
|
||||
use the ``INFO`` level.
|
||||
"""
|
||||
storage = getattr(request, "_messages", default_storage(request))
|
||||
return storage.level
|
||||
|
||||
|
||||
def set_level(request, level):
|
||||
"""
|
||||
Set the minimum level of messages to be recorded, and return ``True`` if
|
||||
the level was recorded successfully.
|
||||
|
||||
If set to ``None``, use the default level (see the get_level() function).
|
||||
"""
|
||||
if not hasattr(request, "_messages"):
|
||||
return False
|
||||
request._messages.level = level
|
||||
return True
|
||||
|
||||
|
||||
def debug(request, message, extra_tags="", fail_silently=False):
|
||||
"""Add a message with the ``DEBUG`` level."""
|
||||
add_message(
|
||||
request,
|
||||
constants.DEBUG,
|
||||
message,
|
||||
extra_tags=extra_tags,
|
||||
fail_silently=fail_silently,
|
||||
)
|
||||
|
||||
|
||||
def info(request, message, extra_tags="", fail_silently=False):
|
||||
"""Add a message with the ``INFO`` level."""
|
||||
add_message(
|
||||
request,
|
||||
constants.INFO,
|
||||
message,
|
||||
extra_tags=extra_tags,
|
||||
fail_silently=fail_silently,
|
||||
)
|
||||
|
||||
|
||||
def success(request, message, extra_tags="", fail_silently=False):
|
||||
"""Add a message with the ``SUCCESS`` level."""
|
||||
add_message(
|
||||
request,
|
||||
constants.SUCCESS,
|
||||
message,
|
||||
extra_tags=extra_tags,
|
||||
fail_silently=fail_silently,
|
||||
)
|
||||
|
||||
|
||||
def warning(request, message, extra_tags="", fail_silently=False):
|
||||
"""Add a message with the ``WARNING`` level."""
|
||||
add_message(
|
||||
request,
|
||||
constants.WARNING,
|
||||
message,
|
||||
extra_tags=extra_tags,
|
||||
fail_silently=fail_silently,
|
||||
)
|
||||
|
||||
|
||||
def error(request, message, extra_tags="", fail_silently=False):
|
||||
"""Add a message with the ``ERROR`` level."""
|
||||
add_message(
|
||||
request,
|
||||
constants.ERROR,
|
||||
message,
|
||||
extra_tags=extra_tags,
|
||||
fail_silently=fail_silently,
|
||||
)
|
||||
19
venv/lib/python3.10/site-packages/django/contrib/messages/apps.py
Executable file
19
venv/lib/python3.10/site-packages/django/contrib/messages/apps.py
Executable file
@@ -0,0 +1,19 @@
|
||||
from django.apps import AppConfig
|
||||
from django.contrib.messages.storage import base
|
||||
from django.contrib.messages.utils import get_level_tags
|
||||
from django.core.signals import setting_changed
|
||||
from django.utils.functional import SimpleLazyObject
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
def update_level_tags(setting, **kwargs):
|
||||
if setting == "MESSAGE_TAGS":
|
||||
base.LEVEL_TAGS = SimpleLazyObject(get_level_tags)
|
||||
|
||||
|
||||
class MessagesConfig(AppConfig):
|
||||
name = "django.contrib.messages"
|
||||
verbose_name = _("Messages")
|
||||
|
||||
def ready(self):
|
||||
setting_changed.connect(update_level_tags)
|
||||
21
venv/lib/python3.10/site-packages/django/contrib/messages/constants.py
Executable file
21
venv/lib/python3.10/site-packages/django/contrib/messages/constants.py
Executable file
@@ -0,0 +1,21 @@
|
||||
DEBUG = 10
|
||||
INFO = 20
|
||||
SUCCESS = 25
|
||||
WARNING = 30
|
||||
ERROR = 40
|
||||
|
||||
DEFAULT_TAGS = {
|
||||
DEBUG: "debug",
|
||||
INFO: "info",
|
||||
SUCCESS: "success",
|
||||
WARNING: "warning",
|
||||
ERROR: "error",
|
||||
}
|
||||
|
||||
DEFAULT_LEVELS = {
|
||||
"DEBUG": DEBUG,
|
||||
"INFO": INFO,
|
||||
"SUCCESS": SUCCESS,
|
||||
"WARNING": WARNING,
|
||||
"ERROR": ERROR,
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
from django.contrib.messages.api import get_messages
|
||||
from django.contrib.messages.constants import DEFAULT_LEVELS
|
||||
|
||||
|
||||
def messages(request):
|
||||
"""
|
||||
Return a lazy 'messages' context variable as well as
|
||||
'DEFAULT_MESSAGE_LEVELS'.
|
||||
"""
|
||||
return {
|
||||
"messages": get_messages(request),
|
||||
"DEFAULT_MESSAGE_LEVELS": DEFAULT_LEVELS,
|
||||
}
|
||||
26
venv/lib/python3.10/site-packages/django/contrib/messages/middleware.py
Executable file
26
venv/lib/python3.10/site-packages/django/contrib/messages/middleware.py
Executable file
@@ -0,0 +1,26 @@
|
||||
from django.conf import settings
|
||||
from django.contrib.messages.storage import default_storage
|
||||
from django.utils.deprecation import MiddlewareMixin
|
||||
|
||||
|
||||
class MessageMiddleware(MiddlewareMixin):
|
||||
"""
|
||||
Middleware that handles temporary messages.
|
||||
"""
|
||||
|
||||
def process_request(self, request):
|
||||
request._messages = default_storage(request)
|
||||
|
||||
def process_response(self, request, response):
|
||||
"""
|
||||
Update the storage backend (i.e., save the messages).
|
||||
|
||||
Raise ValueError if not all messages could be stored and DEBUG is True.
|
||||
"""
|
||||
# A higher middleware layer may return a request which does not contain
|
||||
# messages storage, so make no assumption that it will be there.
|
||||
if hasattr(request, "_messages"):
|
||||
unstored_messages = request._messages.update(response)
|
||||
if unstored_messages and settings.DEBUG:
|
||||
raise ValueError("Not all temporary messages could be stored.")
|
||||
return response
|
||||
@@ -0,0 +1,12 @@
|
||||
from django.conf import settings
|
||||
from django.utils.module_loading import import_string
|
||||
|
||||
|
||||
def default_storage(request):
|
||||
"""
|
||||
Callable with the same interface as the storage classes.
|
||||
|
||||
This isn't just default_storage = import_string(settings.MESSAGE_STORAGE)
|
||||
to avoid accessing the settings at the module level.
|
||||
"""
|
||||
return import_string(settings.MESSAGE_STORAGE)(request)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
183
venv/lib/python3.10/site-packages/django/contrib/messages/storage/base.py
Executable file
183
venv/lib/python3.10/site-packages/django/contrib/messages/storage/base.py
Executable file
@@ -0,0 +1,183 @@
|
||||
from django.conf import settings
|
||||
from django.contrib.messages import constants, utils
|
||||
from django.utils.functional import SimpleLazyObject
|
||||
|
||||
LEVEL_TAGS = SimpleLazyObject(utils.get_level_tags)
|
||||
|
||||
|
||||
class Message:
|
||||
"""
|
||||
Represent an actual message that can be stored in any of the supported
|
||||
storage classes (typically session- or cookie-based) and rendered in a view
|
||||
or template.
|
||||
"""
|
||||
|
||||
def __init__(self, level, message, extra_tags=None):
|
||||
self.level = int(level)
|
||||
self.message = message
|
||||
self.extra_tags = extra_tags
|
||||
|
||||
def _prepare(self):
|
||||
"""
|
||||
Prepare the message for serialization by forcing the ``message``
|
||||
and ``extra_tags`` to str in case they are lazy translations.
|
||||
"""
|
||||
self.message = str(self.message)
|
||||
self.extra_tags = str(self.extra_tags) if self.extra_tags is not None else None
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, Message):
|
||||
return NotImplemented
|
||||
return self.level == other.level and self.message == other.message
|
||||
|
||||
def __str__(self):
|
||||
return str(self.message)
|
||||
|
||||
def __repr__(self):
|
||||
extra_tags = f", extra_tags={self.extra_tags!r}" if self.extra_tags else ""
|
||||
return f"Message(level={self.level}, message={self.message!r}{extra_tags})"
|
||||
|
||||
@property
|
||||
def tags(self):
|
||||
return " ".join(tag for tag in [self.extra_tags, self.level_tag] if tag)
|
||||
|
||||
@property
|
||||
def level_tag(self):
|
||||
return LEVEL_TAGS.get(self.level, "")
|
||||
|
||||
|
||||
class BaseStorage:
|
||||
"""
|
||||
This is the base backend for temporary message storage.
|
||||
|
||||
This is not a complete class; to be a usable storage backend, it must be
|
||||
subclassed and the two methods ``_get`` and ``_store`` overridden.
|
||||
"""
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
self._queued_messages = []
|
||||
self.used = False
|
||||
self.added_new = False
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def __len__(self):
|
||||
return len(self._loaded_messages) + len(self._queued_messages)
|
||||
|
||||
def __iter__(self):
|
||||
self.used = True
|
||||
if self._queued_messages:
|
||||
self._loaded_messages.extend(self._queued_messages)
|
||||
self._queued_messages = []
|
||||
return iter(self._loaded_messages)
|
||||
|
||||
def __contains__(self, item):
|
||||
return item in self._loaded_messages or item in self._queued_messages
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__qualname__}: request={self.request!r}>"
|
||||
|
||||
@property
|
||||
def _loaded_messages(self):
|
||||
"""
|
||||
Return a list of loaded messages, retrieving them first if they have
|
||||
not been loaded yet.
|
||||
"""
|
||||
if not hasattr(self, "_loaded_data"):
|
||||
messages, all_retrieved = self._get()
|
||||
self._loaded_data = messages or []
|
||||
return self._loaded_data
|
||||
|
||||
def _get(self, *args, **kwargs):
|
||||
"""
|
||||
Retrieve a list of stored messages. Return a tuple of the messages
|
||||
and a flag indicating whether or not all the messages originally
|
||||
intended to be stored in this storage were, in fact, stored and
|
||||
retrieved; e.g., ``(messages, all_retrieved)``.
|
||||
|
||||
**This method must be implemented by a subclass.**
|
||||
|
||||
If it is possible to tell if the backend was not used (as opposed to
|
||||
just containing no messages) then ``None`` should be returned in
|
||||
place of ``messages``.
|
||||
"""
|
||||
raise NotImplementedError(
|
||||
"subclasses of BaseStorage must provide a _get() method"
|
||||
)
|
||||
|
||||
def _store(self, messages, response, *args, **kwargs):
|
||||
"""
|
||||
Store a list of messages and return a list of any messages which could
|
||||
not be stored.
|
||||
|
||||
One type of object must be able to be stored, ``Message``.
|
||||
|
||||
**This method must be implemented by a subclass.**
|
||||
"""
|
||||
raise NotImplementedError(
|
||||
"subclasses of BaseStorage must provide a _store() method"
|
||||
)
|
||||
|
||||
def _prepare_messages(self, messages):
|
||||
"""
|
||||
Prepare a list of messages for storage.
|
||||
"""
|
||||
for message in messages:
|
||||
message._prepare()
|
||||
|
||||
def update(self, response):
|
||||
"""
|
||||
Store all unread messages.
|
||||
|
||||
If the backend has yet to be iterated, store previously stored messages
|
||||
again. Otherwise, only store messages added after the last iteration.
|
||||
"""
|
||||
self._prepare_messages(self._queued_messages)
|
||||
if self.used:
|
||||
return self._store(self._queued_messages, response)
|
||||
elif self.added_new:
|
||||
messages = self._loaded_messages + self._queued_messages
|
||||
return self._store(messages, response)
|
||||
|
||||
def add(self, level, message, extra_tags=""):
|
||||
"""
|
||||
Queue a message to be stored.
|
||||
|
||||
The message is only queued if it contained something and its level is
|
||||
not less than the recording level (``self.level``).
|
||||
"""
|
||||
if not message:
|
||||
return
|
||||
# Check that the message level is not less than the recording level.
|
||||
level = int(level)
|
||||
if level < self.level:
|
||||
return
|
||||
# Add the message.
|
||||
self.added_new = True
|
||||
message = Message(level, message, extra_tags=extra_tags)
|
||||
self._queued_messages.append(message)
|
||||
|
||||
def _get_level(self):
|
||||
"""
|
||||
Return the minimum recorded level.
|
||||
|
||||
The default level is the ``MESSAGE_LEVEL`` setting. If this is
|
||||
not found, the ``INFO`` level is used.
|
||||
"""
|
||||
if not hasattr(self, "_level"):
|
||||
self._level = getattr(settings, "MESSAGE_LEVEL", constants.INFO)
|
||||
return self._level
|
||||
|
||||
def _set_level(self, value=None):
|
||||
"""
|
||||
Set a custom minimum recorded level.
|
||||
|
||||
If set to ``None``, the default level will be used (see the
|
||||
``_get_level`` method).
|
||||
"""
|
||||
if value is None and hasattr(self, "_level"):
|
||||
del self._level
|
||||
else:
|
||||
self._level = int(value)
|
||||
|
||||
level = property(_get_level, _set_level, _set_level)
|
||||
248
venv/lib/python3.10/site-packages/django/contrib/messages/storage/cookie.py
Executable file
248
venv/lib/python3.10/site-packages/django/contrib/messages/storage/cookie.py
Executable file
@@ -0,0 +1,248 @@
|
||||
import binascii
|
||||
import json
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.messages.storage.base import BaseStorage, Message
|
||||
from django.core import signing
|
||||
from django.http import SimpleCookie
|
||||
from django.utils.safestring import SafeData, mark_safe
|
||||
|
||||
|
||||
class MessageEncoder(json.JSONEncoder):
|
||||
"""
|
||||
Compactly serialize instances of the ``Message`` class as JSON.
|
||||
"""
|
||||
|
||||
message_key = "__json_message"
|
||||
|
||||
def default(self, obj):
|
||||
if isinstance(obj, Message):
|
||||
# Using 0/1 here instead of False/True to produce more compact json
|
||||
is_safedata = 1 if isinstance(obj.message, SafeData) else 0
|
||||
message = [self.message_key, is_safedata, obj.level, obj.message]
|
||||
if obj.extra_tags is not None:
|
||||
message.append(obj.extra_tags)
|
||||
return message
|
||||
return super().default(obj)
|
||||
|
||||
|
||||
class MessageDecoder(json.JSONDecoder):
|
||||
"""
|
||||
Decode JSON that includes serialized ``Message`` instances.
|
||||
"""
|
||||
|
||||
def process_messages(self, obj):
|
||||
if isinstance(obj, list) and obj:
|
||||
if obj[0] == MessageEncoder.message_key:
|
||||
if obj[1]:
|
||||
obj[3] = mark_safe(obj[3])
|
||||
return Message(*obj[2:])
|
||||
return [self.process_messages(item) for item in obj]
|
||||
if isinstance(obj, dict):
|
||||
return {key: self.process_messages(value) for key, value in obj.items()}
|
||||
return obj
|
||||
|
||||
def decode(self, s, **kwargs):
|
||||
decoded = super().decode(s, **kwargs)
|
||||
return self.process_messages(decoded)
|
||||
|
||||
|
||||
class MessagePartSerializer:
|
||||
def dumps(self, obj):
|
||||
return [
|
||||
json.dumps(
|
||||
o,
|
||||
separators=(",", ":"),
|
||||
cls=MessageEncoder,
|
||||
)
|
||||
for o in obj
|
||||
]
|
||||
|
||||
|
||||
class MessagePartGatherSerializer:
|
||||
def dumps(self, obj):
|
||||
"""
|
||||
The parameter is an already serialized list of Message objects. No need
|
||||
to serialize it again, only join the list together and encode it.
|
||||
"""
|
||||
return ("[" + ",".join(obj) + "]").encode("latin-1")
|
||||
|
||||
|
||||
class MessageSerializer:
|
||||
def loads(self, data):
|
||||
return json.loads(data.decode("latin-1"), cls=MessageDecoder)
|
||||
|
||||
|
||||
class CookieStorage(BaseStorage):
|
||||
"""
|
||||
Store messages in a cookie.
|
||||
"""
|
||||
|
||||
cookie_name = "messages"
|
||||
# uwsgi's default configuration enforces a maximum size of 4kb for all the
|
||||
# HTTP headers. In order to leave some room for other cookies and headers,
|
||||
# restrict the session cookie to 1/2 of 4kb. See #18781.
|
||||
max_cookie_size = 2048
|
||||
not_finished = "__messagesnotfinished__"
|
||||
not_finished_json = json.dumps("__messagesnotfinished__")
|
||||
key_salt = "django.contrib.messages"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.signer = signing.get_cookie_signer(salt=self.key_salt)
|
||||
|
||||
def _get(self, *args, **kwargs):
|
||||
"""
|
||||
Retrieve a list of messages from the messages cookie. If the
|
||||
not_finished sentinel value is found at the end of the message list,
|
||||
remove it and return a result indicating that not all messages were
|
||||
retrieved by this storage.
|
||||
"""
|
||||
data = self.request.COOKIES.get(self.cookie_name)
|
||||
messages = self._decode(data)
|
||||
all_retrieved = not (messages and messages[-1] == self.not_finished)
|
||||
if messages and not all_retrieved:
|
||||
# remove the sentinel value
|
||||
messages.pop()
|
||||
return messages, all_retrieved
|
||||
|
||||
def _update_cookie(self, encoded_data, response):
|
||||
"""
|
||||
Either set the cookie with the encoded data if there is any data to
|
||||
store, or delete the cookie.
|
||||
"""
|
||||
if encoded_data:
|
||||
response.set_cookie(
|
||||
self.cookie_name,
|
||||
encoded_data,
|
||||
domain=settings.SESSION_COOKIE_DOMAIN,
|
||||
secure=settings.SESSION_COOKIE_SECURE or None,
|
||||
httponly=settings.SESSION_COOKIE_HTTPONLY or None,
|
||||
samesite=settings.SESSION_COOKIE_SAMESITE,
|
||||
)
|
||||
else:
|
||||
response.delete_cookie(
|
||||
self.cookie_name,
|
||||
domain=settings.SESSION_COOKIE_DOMAIN,
|
||||
samesite=settings.SESSION_COOKIE_SAMESITE,
|
||||
)
|
||||
|
||||
def _store(self, messages, response, remove_oldest=True, *args, **kwargs):
|
||||
"""
|
||||
Store the messages to a cookie and return a list of any messages which
|
||||
could not be stored.
|
||||
|
||||
If the encoded data is larger than ``max_cookie_size``, remove
|
||||
messages until the data fits (these are the messages which are
|
||||
returned), and add the not_finished sentinel value to indicate as much.
|
||||
"""
|
||||
unstored_messages = []
|
||||
serialized_messages = MessagePartSerializer().dumps(messages)
|
||||
encoded_data = self._encode_parts(serialized_messages)
|
||||
if self.max_cookie_size:
|
||||
# data is going to be stored eventually by SimpleCookie, which
|
||||
# adds its own overhead, which we must account for.
|
||||
cookie = SimpleCookie() # create outside the loop
|
||||
|
||||
def is_too_large_for_cookie(data):
|
||||
return data and len(cookie.value_encode(data)[1]) > self.max_cookie_size
|
||||
|
||||
def compute_msg(some_serialized_msg):
|
||||
return self._encode_parts(
|
||||
some_serialized_msg + [self.not_finished_json],
|
||||
encode_empty=True,
|
||||
)
|
||||
|
||||
if is_too_large_for_cookie(encoded_data):
|
||||
if remove_oldest:
|
||||
idx = bisect_keep_right(
|
||||
serialized_messages,
|
||||
fn=lambda m: is_too_large_for_cookie(compute_msg(m)),
|
||||
)
|
||||
unstored_messages = messages[:idx]
|
||||
encoded_data = compute_msg(serialized_messages[idx:])
|
||||
else:
|
||||
idx = bisect_keep_left(
|
||||
serialized_messages,
|
||||
fn=lambda m: is_too_large_for_cookie(compute_msg(m)),
|
||||
)
|
||||
unstored_messages = messages[idx:]
|
||||
encoded_data = compute_msg(serialized_messages[:idx])
|
||||
|
||||
self._update_cookie(encoded_data, response)
|
||||
return unstored_messages
|
||||
|
||||
def _encode_parts(self, messages, encode_empty=False):
|
||||
"""
|
||||
Return an encoded version of the serialized messages list which can be
|
||||
stored as plain text.
|
||||
|
||||
Since the data will be retrieved from the client-side, the encoded data
|
||||
also contains a hash to ensure that the data was not tampered with.
|
||||
"""
|
||||
if messages or encode_empty:
|
||||
return self.signer.sign_object(
|
||||
messages, serializer=MessagePartGatherSerializer, compress=True
|
||||
)
|
||||
|
||||
def _encode(self, messages, encode_empty=False):
|
||||
"""
|
||||
Return an encoded version of the messages list which can be stored as
|
||||
plain text.
|
||||
|
||||
Proxies MessagePartSerializer.dumps and _encoded_parts.
|
||||
"""
|
||||
serialized_messages = MessagePartSerializer().dumps(messages)
|
||||
return self._encode_parts(serialized_messages, encode_empty=encode_empty)
|
||||
|
||||
def _decode(self, data):
|
||||
"""
|
||||
Safely decode an encoded text stream back into a list of messages.
|
||||
|
||||
If the encoded text stream contained an invalid hash or was in an
|
||||
invalid format, return None.
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
try:
|
||||
return self.signer.unsign_object(data, serializer=MessageSerializer)
|
||||
except (signing.BadSignature, binascii.Error, json.JSONDecodeError):
|
||||
pass
|
||||
# Mark the data as used (so it gets removed) since something was wrong
|
||||
# with the data.
|
||||
self.used = True
|
||||
return None
|
||||
|
||||
|
||||
def bisect_keep_left(a, fn):
|
||||
"""
|
||||
Find the index of the first element from the start of the array that
|
||||
verifies the given condition.
|
||||
The function is applied from the start of the array to the pivot.
|
||||
"""
|
||||
lo = 0
|
||||
hi = len(a)
|
||||
while lo < hi:
|
||||
mid = (lo + hi) // 2
|
||||
if fn(a[: mid + 1]):
|
||||
hi = mid
|
||||
else:
|
||||
lo = mid + 1
|
||||
return lo
|
||||
|
||||
|
||||
def bisect_keep_right(a, fn):
|
||||
"""
|
||||
Find the index of the first element from the end of the array that verifies
|
||||
the given condition.
|
||||
The function is applied from the pivot to the end of array.
|
||||
"""
|
||||
lo = 0
|
||||
hi = len(a)
|
||||
while lo < hi:
|
||||
mid = (lo + hi) // 2
|
||||
if fn(a[mid:]):
|
||||
lo = mid + 1
|
||||
else:
|
||||
hi = mid
|
||||
return lo
|
||||
@@ -0,0 +1,56 @@
|
||||
from django.contrib.messages.storage.base import BaseStorage
|
||||
from django.contrib.messages.storage.cookie import CookieStorage
|
||||
from django.contrib.messages.storage.session import SessionStorage
|
||||
|
||||
|
||||
class FallbackStorage(BaseStorage):
|
||||
"""
|
||||
Try to store all messages in the first backend. Store any unstored
|
||||
messages in each subsequent backend.
|
||||
"""
|
||||
|
||||
storage_classes = (CookieStorage, SessionStorage)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.storages = [
|
||||
storage_class(*args, **kwargs) for storage_class in self.storage_classes
|
||||
]
|
||||
self._used_storages = set()
|
||||
|
||||
def _get(self, *args, **kwargs):
|
||||
"""
|
||||
Get a single list of messages from all storage backends.
|
||||
"""
|
||||
all_messages = []
|
||||
for storage in self.storages:
|
||||
messages, all_retrieved = storage._get()
|
||||
# If the backend hasn't been used, no more retrieval is necessary.
|
||||
if messages is None:
|
||||
break
|
||||
if messages:
|
||||
self._used_storages.add(storage)
|
||||
all_messages.extend(messages)
|
||||
# If this storage class contained all the messages, no further
|
||||
# retrieval is necessary
|
||||
if all_retrieved:
|
||||
break
|
||||
return all_messages, all_retrieved
|
||||
|
||||
def _store(self, messages, response, *args, **kwargs):
|
||||
"""
|
||||
Store the messages and return any unstored messages after trying all
|
||||
backends.
|
||||
|
||||
For each storage backend, any messages not stored are passed on to the
|
||||
next backend.
|
||||
"""
|
||||
for storage in self.storages:
|
||||
if messages:
|
||||
messages = storage._store(messages, response, remove_oldest=False)
|
||||
# Even if there are no more messages, continue iterating to ensure
|
||||
# storages which contained messages are flushed.
|
||||
elif storage in self._used_storages:
|
||||
storage._store([], response)
|
||||
self._used_storages.remove(storage)
|
||||
return messages
|
||||
52
venv/lib/python3.10/site-packages/django/contrib/messages/storage/session.py
Executable file
52
venv/lib/python3.10/site-packages/django/contrib/messages/storage/session.py
Executable file
@@ -0,0 +1,52 @@
|
||||
import json
|
||||
|
||||
from django.contrib.messages.storage.base import BaseStorage
|
||||
from django.contrib.messages.storage.cookie import MessageDecoder, MessageEncoder
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
|
||||
class SessionStorage(BaseStorage):
|
||||
"""
|
||||
Store messages in the session (that is, django.contrib.sessions).
|
||||
"""
|
||||
|
||||
session_key = "_messages"
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
if not hasattr(request, "session"):
|
||||
raise ImproperlyConfigured(
|
||||
"The session-based temporary message storage requires session "
|
||||
"middleware to be installed, and come before the message "
|
||||
"middleware in the MIDDLEWARE list."
|
||||
)
|
||||
super().__init__(request, *args, **kwargs)
|
||||
|
||||
def _get(self, *args, **kwargs):
|
||||
"""
|
||||
Retrieve a list of messages from the request's session. This storage
|
||||
always stores everything it is given, so return True for the
|
||||
all_retrieved flag.
|
||||
"""
|
||||
return (
|
||||
self.deserialize_messages(self.request.session.get(self.session_key)),
|
||||
True,
|
||||
)
|
||||
|
||||
def _store(self, messages, response, *args, **kwargs):
|
||||
"""
|
||||
Store a list of messages to the request's session.
|
||||
"""
|
||||
if messages:
|
||||
self.request.session[self.session_key] = self.serialize_messages(messages)
|
||||
else:
|
||||
self.request.session.pop(self.session_key, None)
|
||||
return []
|
||||
|
||||
def serialize_messages(self, messages):
|
||||
encoder = MessageEncoder()
|
||||
return encoder.encode(messages)
|
||||
|
||||
def deserialize_messages(self, data):
|
||||
if data and isinstance(data, str):
|
||||
return json.loads(data, cls=MessageDecoder)
|
||||
return data
|
||||
8
venv/lib/python3.10/site-packages/django/contrib/messages/test.py
Executable file
8
venv/lib/python3.10/site-packages/django/contrib/messages/test.py
Executable file
@@ -0,0 +1,8 @@
|
||||
from .api import get_messages
|
||||
|
||||
|
||||
class MessagesTestMixin:
|
||||
def assertMessages(self, response, expected_messages, *, ordered=True):
|
||||
request_messages = list(get_messages(response.wsgi_request))
|
||||
assertion = self.assertEqual if ordered else self.assertCountEqual
|
||||
assertion(request_messages, expected_messages)
|
||||
12
venv/lib/python3.10/site-packages/django/contrib/messages/utils.py
Executable file
12
venv/lib/python3.10/site-packages/django/contrib/messages/utils.py
Executable file
@@ -0,0 +1,12 @@
|
||||
from django.conf import settings
|
||||
from django.contrib.messages import constants
|
||||
|
||||
|
||||
def get_level_tags():
|
||||
"""
|
||||
Return the message level tags.
|
||||
"""
|
||||
return {
|
||||
**constants.DEFAULT_TAGS,
|
||||
**getattr(settings, "MESSAGE_TAGS", {}),
|
||||
}
|
||||
19
venv/lib/python3.10/site-packages/django/contrib/messages/views.py
Executable file
19
venv/lib/python3.10/site-packages/django/contrib/messages/views.py
Executable file
@@ -0,0 +1,19 @@
|
||||
from django.contrib import messages
|
||||
|
||||
|
||||
class SuccessMessageMixin:
|
||||
"""
|
||||
Add a success message on successful form submission.
|
||||
"""
|
||||
|
||||
success_message = ""
|
||||
|
||||
def form_valid(self, form):
|
||||
response = super().form_valid(form)
|
||||
success_message = self.get_success_message(form.cleaned_data)
|
||||
if success_message:
|
||||
messages.success(self.request, success_message)
|
||||
return response
|
||||
|
||||
def get_success_message(self, cleaned_data):
|
||||
return self.success_message % cleaned_data
|
||||
Reference in New Issue
Block a user