Simplified the stored post forms in a way that only store one form for use at once, like PHP Laravel, and merge it to the Mia core utilities in the Mia core application.

This commit is contained in:
依瑪貓 2020-10-20 22:51:00 +08:00
parent 54d18ca8b3
commit a554974ea0
3 changed files with 34 additions and 126 deletions

View File

@ -1,121 +0,0 @@
# The core application of the Mia project.
# by imacat <imacat@mail.imacat.idv.tw>, 2020/7/24
# Copyright (c) 2020 imacat.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""The session-based POST data storage management of the Mia core application.
"""
import random
from typing import Dict, Mapping, Any, Optional
from django.http import HttpResponseRedirect, HttpRequest
from django.shortcuts import redirect
from .utils import UrlBuilder
STORAGE_KEY: str = "stored_post"
def error_redirect(request: HttpRequest, url: str,
post: Dict[str, str]) -> HttpResponseRedirect:
"""Redirects to a specific URL on error, with the POST data ID appended
as the query parameter "s". The POST data can be loaded with the
get_previous_post() utility.
Args:
request (HttpRequest): The request.
url (str): The destination URL.
post (dict[str]): The POST data.
Returns:
HttpResponseRedirect: The redirect response.
"""
post_id = _store(request, post)
return redirect(str(UrlBuilder(url).query(s=post_id)))
def get_previous_post(request: HttpRequest) -> Optional[Dict[str, str]]:
"""Retrieves the previously-stored POST data.
Args:
request (HttpRequest): The request.
Returns:
dict: The previously-stored POST data.
"""
if "s" not in request.GET:
return None
return _retrieve(request, request.GET["s"])
def _store(request: HttpRequest, post: Dict[str, str]) -> str:
"""Stores the POST data into the session, and returns the POST data ID that
can be used to retrieve it later with _retrieve().
Args:
request: The request.
post: The POST data.
Returns:
The POST data ID
"""
if STORAGE_KEY not in request.session:
request.session[STORAGE_KEY] = {}
post_id = _new_post_id(request.session[STORAGE_KEY])
request.session[STORAGE_KEY][post_id] = post
return post_id
def _retrieve(request: HttpRequest, post_id: str) -> Optional[Dict[str, str]]:
"""Retrieves the POST data from the storage.
Args:
request: The request.
post_id: The POST data ID.
Returns:
The POST data, or None if the corresponding data does not exist.
"""
if STORAGE_KEY not in request.session:
return None
if post_id not in request.session[STORAGE_KEY]:
return None
return request.session[STORAGE_KEY][post_id]
def _new_post_id(post_store: Mapping[int, Any]) -> str:
"""Generates and returns a new POST ID that does not exist yet.
Args:
post_store (dict): The POST storage.
Returns:
str: The newly-generated POST ID.
"""
while True:
post_id = ""
while len(post_id) < 16:
n = random.randint(1, 64)
if n < 26:
post_id = post_id + chr(ord("a") + n)
elif n < 52:
post_id = post_id + chr(ord("a") + (n - 26))
elif n < 62:
post_id = post_id + chr(ord("0") + (n - 52))
else:
post_id = post_id + "-_."[n - 62]
if post_id not in post_store:
return post_id

View File

@ -21,7 +21,7 @@
import datetime
import random
import urllib.parse
from typing import Dict, List, Any, Type
from typing import Dict, List, Any, Type, Optional
from django.conf import settings
from django.db.models import Model
@ -59,6 +59,35 @@ def strip_post(post: Dict[str, str]) -> None:
del post[key]
STORAGE_KEY: str = "stored_post"
def store_post(request: HttpRequest, post: Dict[str, str]):
"""Stores the POST data into the session.
Args:
request: The request.
post: The POST data.
"""
request.session[STORAGE_KEY] = post
def retrieve_store(request: HttpRequest) -> Optional[Dict[str, str]]:
"""Retrieves the POST data from the storage.
Args:
request: The request.
Returns:
The POST data, or None if the previously-stored data does not exist.
"""
if STORAGE_KEY not in request.session:
return None
post = request.session[STORAGE_KEY]
del request.session[STORAGE_KEY]
return post
def parse_date(s: str):
"""Parses a string for a date. The date can be either YYYY-MM-DD,
Y/M/D, or M/D/Y.

View File

@ -34,7 +34,7 @@ from django.views.generic import DeleteView as CoreDeleteView, \
RedirectView as CoreRedirectView
from django.views.generic.base import View
from . import stored_post, utils
from . import utils
from .models import StampedModel
from .utils import UrlBuilder
@ -109,7 +109,7 @@ class FormView(View):
utils.strip_post(post)
return self.make_form_from_post(post)
else:
previous_post = stored_post.get_previous_post(self.request)
previous_post = utils.retrieve_store(self.request)
if previous_post is not None:
return self.make_form_from_post(previous_post)
if self.object is not None:
@ -146,8 +146,8 @@ class FormView(View):
def form_invalid(self, form: forms.Form) -> HttpResponseRedirect:
"""Handles the action when the POST form is invalid."""
return stored_post.error_redirect(
self.request, self.get_error_url(), form.data)
utils.store_post(self.request, form.data)
return redirect(self.get_error_url())
def form_valid(self, form: forms.Form) -> HttpResponseRedirect:
"""Handles the action when the POST form is valid."""