mirror of
https://github.com/ae-utbm/sith.git
synced 2025-11-22 12:46:58 +00:00
reuse last PageRev if same author and short time diff
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
{% extends "core/page/base.jinja" %}
|
||||
{% from 'core/page/macros.jinja' import page_edit_form %}
|
||||
|
||||
{% block page %}
|
||||
{{ page_edit_form(form, url('core:page_edit', page_name=page.get_full_name())) }}
|
||||
<h2>{% trans %}Edit page{% endtrans %}</h2>
|
||||
<form action="{{ url('core:page_edit', page_name=page.get_full_name()) }}" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p() }}
|
||||
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
||||
@@ -17,12 +17,3 @@
|
||||
{%- endfor -%}
|
||||
</ul>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro page_edit_form(form, url) %}
|
||||
<h2>{% trans %}Edit page{% endtrans %}</h2>
|
||||
<form action="{{ url }}" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p() }}
|
||||
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
|
||||
</form>
|
||||
{% endmacro %}
|
||||
|
||||
@@ -1,33 +1,72 @@
|
||||
from datetime import timedelta
|
||||
|
||||
import freezegun
|
||||
import pytest
|
||||
from bs4 import BeautifulSoup
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.test import Client
|
||||
from django.urls import reverse
|
||||
from django.utils.timezone import now
|
||||
from model_bakery import baker
|
||||
from pytest_django.asserts import assertHTMLEqual, assertRedirects
|
||||
|
||||
from club.models import Club
|
||||
from core.baker_recipes import board_user, subscriber_user
|
||||
from core.markdown import markdown
|
||||
from core.models import AnonymousUser, Page, PageRev, User
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_edit_page(client: Client):
|
||||
user = board_user.make()
|
||||
page = baker.prepare(Page)
|
||||
page.save(force_lock=True)
|
||||
page.view_groups.add(user.groups.first())
|
||||
client.force_login(user)
|
||||
class TestEditPage:
|
||||
def test_edit_page(self, client: Client):
|
||||
user = board_user.make()
|
||||
page = baker.prepare(Page)
|
||||
page.save(force_lock=True)
|
||||
page.view_groups.add(user.groups.first())
|
||||
page.edit_groups.add(user.groups.first())
|
||||
client.force_login(user)
|
||||
|
||||
url = reverse("core:page_edit", kwargs={"page_name": page._full_name})
|
||||
res = client.get(url)
|
||||
assert res.status_code == 200
|
||||
url = reverse("core:page_edit", kwargs={"page_name": page._full_name})
|
||||
res = client.get(url)
|
||||
assert res.status_code == 200
|
||||
|
||||
res = client.post(url, data={"content": "Hello World"})
|
||||
assertRedirects(res, reverse("core:page", kwargs={"page_name": page._full_name}))
|
||||
revision = page.revisions.last()
|
||||
assert revision.content == "Hello World"
|
||||
res = client.post(url, data={"content": "Hello World"})
|
||||
assertRedirects(
|
||||
res, reverse("core:page", kwargs={"page_name": page._full_name})
|
||||
)
|
||||
revision = page.revisions.last()
|
||||
assert revision.content == "Hello World"
|
||||
|
||||
def test_pagerev_reused(self, client):
|
||||
"""Test that the previous revision is edited, if same author and small time diff"""
|
||||
user = baker.make(User, is_superuser=True)
|
||||
page = baker.prepare(Page)
|
||||
page.save(force_lock=True)
|
||||
first_rev = baker.make(PageRev, author=user, page=page, date=now())
|
||||
client.force_login(user)
|
||||
url = reverse("core:page_edit", kwargs={"page_name": page._full_name})
|
||||
client.post(url, data={"content": "Hello World"})
|
||||
assert page.revisions.count() == 1
|
||||
assert page.revisions.last() == first_rev
|
||||
first_rev.refresh_from_db()
|
||||
assert first_rev.author == user
|
||||
assert first_rev.content == "Hello World"
|
||||
|
||||
def test_pagerev_not_reused(self, client):
|
||||
"""Test that a new revision is created if too much time
|
||||
passed since the last one.
|
||||
"""
|
||||
user = baker.make(User, is_superuser=True)
|
||||
page = baker.prepare(Page)
|
||||
page.save(force_lock=True)
|
||||
first_rev = baker.make(PageRev, author=user, page=page, date=now())
|
||||
client.force_login(user)
|
||||
url = reverse("core:page_edit", kwargs={"page_name": page._full_name})
|
||||
with freezegun.freeze_time(now() + timedelta(minutes=30)):
|
||||
client.post(url, data={"content": "Hello World"})
|
||||
assert page.revisions.count() == 2
|
||||
assert page.revisions.last() != first_rev
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#
|
||||
#
|
||||
import re
|
||||
from datetime import date, datetime
|
||||
from datetime import date, datetime, timedelta
|
||||
from io import BytesIO
|
||||
|
||||
from captcha.fields import CaptchaField
|
||||
@@ -47,7 +47,7 @@ from phonenumber_field.widgets import RegionalPhoneNumberWidget
|
||||
from PIL import Image
|
||||
|
||||
from antispam.forms import AntiSpamEmailField
|
||||
from core.models import Gift, Group, Page, SithFile, User
|
||||
from core.models import Gift, Group, Page, PageRev, SithFile, User
|
||||
from core.utils import resize_image
|
||||
from core.views.widgets.ajax_select import (
|
||||
AutoCompleteSelect,
|
||||
@@ -55,6 +55,7 @@ from core.views.widgets.ajax_select import (
|
||||
AutoCompleteSelectMultipleGroup,
|
||||
AutoCompleteSelectUser,
|
||||
)
|
||||
from core.views.widgets.markdown import MarkdownInput
|
||||
|
||||
# Widgets
|
||||
|
||||
@@ -379,6 +380,41 @@ class PageForm(forms.ModelForm):
|
||||
)
|
||||
|
||||
|
||||
class PageRevisionForm(forms.ModelForm):
|
||||
"""Form to add a new revision to a page.
|
||||
|
||||
Notes:
|
||||
Saving this form won't always result in a new revision.
|
||||
If the previous revision on the same page was made less
|
||||
than 20 minutes ago by the same author,
|
||||
then the latter will be edited and the new revision won't be created.
|
||||
"""
|
||||
|
||||
UPDATE_THRESHOLD = timedelta(minutes=20)
|
||||
|
||||
class Meta:
|
||||
model = PageRev
|
||||
fields = ["title", "content"]
|
||||
widgets = {"content": MarkdownInput}
|
||||
|
||||
def __init__(self, *args, author: User, page: Page, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.author = author
|
||||
self.page = page
|
||||
|
||||
def save(self, commit=True): # noqa FBT002
|
||||
revision: PageRev = self.instance
|
||||
if (
|
||||
revision._state.adding
|
||||
or revision.author != self.author
|
||||
or revision.date + self.UPDATE_THRESHOLD < now()
|
||||
):
|
||||
revision.author = self.author
|
||||
revision.page = self.page
|
||||
revision.id = None # if id is None, Django will create a new record
|
||||
return super().save(commit=commit)
|
||||
|
||||
|
||||
class GiftForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Gift
|
||||
|
||||
@@ -13,26 +13,19 @@
|
||||
#
|
||||
#
|
||||
|
||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||
from django.contrib.auth.mixins import PermissionRequiredMixin, UserPassesTestMixin
|
||||
from django.db.models import F, OuterRef, Subquery
|
||||
from django.db.models.functions import Coalesce
|
||||
|
||||
# This file contains all the views that concern the page model
|
||||
from django.forms.models import modelform_factory
|
||||
from django.http import Http404
|
||||
from django.shortcuts import redirect
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.functional import cached_property
|
||||
from django.views.generic import DetailView, ListView
|
||||
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||
|
||||
from core.auth.mixins import (
|
||||
CanEditMixin,
|
||||
CanEditPropMixin,
|
||||
CanViewMixin,
|
||||
)
|
||||
from core.auth.mixins import CanEditPropMixin, CanViewMixin
|
||||
from core.models import Page, PageRev
|
||||
from core.views.forms import PageForm, PagePropForm
|
||||
from core.views.widgets.markdown import MarkdownInput
|
||||
from core.views.forms import PageForm, PagePropForm, PageRevisionForm
|
||||
|
||||
|
||||
class PageNotFound(Http404):
|
||||
@@ -161,36 +154,37 @@ class PagePropView(CanEditPagePropMixin, UpdateView):
|
||||
return self.page
|
||||
|
||||
|
||||
class PageEditViewBase(CanEditMixin, UpdateView):
|
||||
class BasePageEditView(UserPassesTestMixin, UpdateView):
|
||||
model = PageRev
|
||||
form_class = modelform_factory(
|
||||
model=PageRev, fields=["title", "content"], widgets={"content": MarkdownInput}
|
||||
)
|
||||
form_class = PageRevisionForm
|
||||
template_name = "core/page/edit.jinja"
|
||||
|
||||
def test_func(self):
|
||||
return self.request.user.can_edit(self.page)
|
||||
|
||||
@cached_property
|
||||
def page(self) -> Page:
|
||||
page = get_page_or_404(full_name=self.kwargs["page_name"])
|
||||
page.set_lock(self.request.user)
|
||||
return page
|
||||
|
||||
def get_object(self, *args, **kwargs):
|
||||
self.page = get_page_or_404(full_name=self.kwargs["page_name"])
|
||||
self.page.set_lock(self.request.user)
|
||||
return self.page.revisions.last()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
return super().get_context_data(**kwargs) | {"page": self.page}
|
||||
|
||||
def form_valid(self, form):
|
||||
# TODO : factor that, but first make some tests
|
||||
rev = form.instance
|
||||
new_rev = PageRev(title=rev.title, content=rev.content)
|
||||
new_rev.author = self.request.user
|
||||
new_rev.page = self.page
|
||||
form.instance = new_rev
|
||||
return super().form_valid(form)
|
||||
def get_form_kwargs(self):
|
||||
return super().get_form_kwargs() | {
|
||||
"author": self.request.user,
|
||||
"page": self.page,
|
||||
}
|
||||
|
||||
|
||||
class PageEditView(PageEditViewBase):
|
||||
class PageEditView(BasePageEditView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
if self.object and self.object.page.need_club_redirection:
|
||||
return redirect("club:club_edit_page", club_id=self.object.page.club.id)
|
||||
if self.page.need_club_redirection:
|
||||
return redirect("club:club_edit_page", club_id=self.page.club.id)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user