WIP: gestion des permissions pour l'édition des émissions #130
@ -1,19 +1,6 @@
 | 
				
			|||||||
{% extends "aircox/basepage_detail.html" %}
 | 
					{% extends "aircox/basepage_detail.html" %}
 | 
				
			||||||
{% load static i18n humanize honeypot aircox %}
 | 
					{% load static i18n humanize honeypot aircox %}
 | 
				
			||||||
{% comment %}
 | 
					 | 
				
			||||||
Base template used to display a Page
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Context:
 | 
					 | 
				
			||||||
- page: page
 | 
					 | 
				
			||||||
- parent: parent page
 | 
					 | 
				
			||||||
{% endcomment %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{% block header_crumbs %}
 | 
					 | 
				
			||||||
{{ block.super }}
 | 
					 | 
				
			||||||
{% if page.category %}
 | 
					 | 
				
			||||||
{% if parent %} / {% endif %} {{ page.category.title }}
 | 
					 | 
				
			||||||
{% endif %}
 | 
					 | 
				
			||||||
{% endblock %}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block top-nav-tools %}
 | 
					{% block top-nav-tools %}
 | 
				
			||||||
<a class="navbar-item" href="{% url 'program-detail' object.slug %}"
 | 
					<a class="navbar-item" href="{% url 'program-detail' object.slug %}"
 | 
				
			||||||
@ -27,65 +14,11 @@ Context:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
{% block main %}
 | 
					{% block main %}
 | 
				
			||||||
<form method="post">{% csrf_token %}
 | 
					<form method="post">{% csrf_token %}
 | 
				
			||||||
        {{ form.as_p }}
 | 
					    <table>
 | 
				
			||||||
 | 
					        {{ form.as_table }}
 | 
				
			||||||
 | 
					        {% render_honeypot_field "website" %}
 | 
				
			||||||
 | 
					    </table>
 | 
				
			||||||
 | 
					    <br/>
 | 
				
			||||||
    <input type="submit" value="Update" class="button is-success">
 | 
					    <input type="submit" value="Update" class="button is-success">
 | 
				
			||||||
</form>
 | 
					</form>
 | 
				
			||||||
{{ block.super }}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{% block comments %}
 | 
					 | 
				
			||||||
{% if comments or comment_form %}
 | 
					 | 
				
			||||||
<section class="mt-6">
 | 
					 | 
				
			||||||
    <h4 class="title is-4">{% translate "Comments" %}</h4>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    {% for comment in comments %}
 | 
					 | 
				
			||||||
    <div class="media box">
 | 
					 | 
				
			||||||
        <div class="media-content">
 | 
					 | 
				
			||||||
            <p>
 | 
					 | 
				
			||||||
                <strong class="mr-2">{{ comment.nickname }}</strong>
 | 
					 | 
				
			||||||
                <time datetime="{{ comment.date }}" title="{{ comment.date }}">
 | 
					 | 
				
			||||||
                    <small>{{ comment.date|naturaltime }}</small>
 | 
					 | 
				
			||||||
                </time>
 | 
					 | 
				
			||||||
                <br>
 | 
					 | 
				
			||||||
                {{ comment.content }}
 | 
					 | 
				
			||||||
            </p>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
    {% endfor %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    {% if comment_form %}
 | 
					 | 
				
			||||||
    <form method="POST">
 | 
					 | 
				
			||||||
        <h5 class="title is-5">{% translate "Post a comment" %}</h5>
 | 
					 | 
				
			||||||
        {% csrf_token %}
 | 
					 | 
				
			||||||
        {% render_honeypot_field "website" %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        {% for field in comment_form %}
 | 
					 | 
				
			||||||
        <div class="field is-horizontal">
 | 
					 | 
				
			||||||
            <div class="field-label is-normal">
 | 
					 | 
				
			||||||
                <label class="label">
 | 
					 | 
				
			||||||
                    {{ field.label_tag }}
 | 
					 | 
				
			||||||
                </label>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
            <div class="field-body">
 | 
					 | 
				
			||||||
                <div class="field">
 | 
					 | 
				
			||||||
                    <p class="control is-expanded">{{ field }}</p>
 | 
					 | 
				
			||||||
                    {% if field.errors %}
 | 
					 | 
				
			||||||
                    <p class="help is-danger">{{ field.errors }}</p>
 | 
					 | 
				
			||||||
                    {% endif %}
 | 
					 | 
				
			||||||
                    {% if field.help_text %}
 | 
					 | 
				
			||||||
                    <p class="help">{{ field.help_text|safe }}</p>
 | 
					 | 
				
			||||||
                    {% endif %}
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        {% endfor %}
 | 
					 | 
				
			||||||
        <div class="has-text-right">
 | 
					 | 
				
			||||||
            <button type="reset" class="button is-danger">{% translate "Reset" %}</button>
 | 
					 | 
				
			||||||
            <button type="submit" class="button is-success">{% translate "Post comment" %}</button>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
    </form>
 | 
					 | 
				
			||||||
    {% endif %}
 | 
					 | 
				
			||||||
</section>
 | 
					 | 
				
			||||||
{% endif %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{% endblock %}
 | 
					 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,14 @@
 | 
				
			|||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from django.urls import reverse
 | 
					from django.urls import reverse
 | 
				
			||||||
 | 
					from django.core.files.uploadedfile import SimpleUploadedFile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from aircox.models import Program
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					png_content = (
 | 
				
			||||||
 | 
					    b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90wS\xde"
 | 
				
			||||||
 | 
					    + b"\x00\x00\x00\x0cIDATx\x9cc`\xf8\xcf\x00\x00\x02\x02\x01\x00{\t\x81x\x00\x00\x00\x00IEND\xaeB`\x82"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.django_db()
 | 
					@pytest.mark.django_db()
 | 
				
			||||||
@ -15,3 +24,17 @@ def test_edit_program(user, client, program):
 | 
				
			|||||||
    response = client.post(reverse("program-edit", kwargs={"pk": program.pk}), {"content": "foobar"})
 | 
					    response = client.post(reverse("program-edit", kwargs={"pk": program.pk}), {"content": "foobar"})
 | 
				
			||||||
    response = client.get(reverse("program-detail", kwargs={"slug": program.slug}))
 | 
					    response = client.get(reverse("program-detail", kwargs={"slug": program.slug}))
 | 
				
			||||||
    assert b"foobar" in response.content
 | 
					    assert b"foobar" in response.content
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.django_db()
 | 
				
			||||||
 | 
					def test_add_cover(user, client, program):
 | 
				
			||||||
 | 
					    assert program.cover is None
 | 
				
			||||||
 | 
					    user.groups.add(program.editors)
 | 
				
			||||||
 | 
					    client.force_login(user)
 | 
				
			||||||
 | 
					    cover = SimpleUploadedFile("cover1.png", png_content, content_type="image/png")
 | 
				
			||||||
 | 
					    r = client.post(
 | 
				
			||||||
 | 
					        reverse("program-edit", kwargs={"pk": program.pk}), {"content": "foobar", "new_cover": cover}, follow=True
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    assert r.status_code == 200
 | 
				
			||||||
 | 
					    p = Program.objects.get(pk=program.pk)
 | 
				
			||||||
 | 
					    assert "cover1.png" in p.cover.url
 | 
				
			||||||
 | 
				
			|||||||
@ -142,4 +142,7 @@ class PageDetailView(BasePageDetailView):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PageUpdateView(BaseView, UpdateView):
 | 
					class PageUpdateView(BaseView, UpdateView):
 | 
				
			||||||
    pass
 | 
					    context_object_name = "page"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_page(self):
 | 
				
			||||||
 | 
					        return self.object
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,8 @@
 | 
				
			|||||||
 | 
					from django.contrib.auth.mixins import UserPassesTestMixin
 | 
				
			||||||
 | 
					from django.forms import ModelForm, ImageField
 | 
				
			||||||
from django.urls import reverse
 | 
					from django.urls import reverse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.contrib.auth.mixins import UserPassesTestMixin
 | 
					from filer.models.imagemodels import Image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ..models import Page, Program, StaticPage
 | 
					from ..models import Page, Program, StaticPage
 | 
				
			||||||
from .mixins import ParentMixin
 | 
					from .mixins import ParentMixin
 | 
				
			||||||
@ -32,10 +34,25 @@ class ProgramDetailView(BaseProgramMixin, PageDetailView):
 | 
				
			|||||||
        return super().get_sidebar_queryset().filter(parent=self.program)
 | 
					        return super().get_sidebar_queryset().filter(parent=self.program)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProgramUpdateView(UserPassesTestMixin, BaseProgramMixin, PageUpdateView):
 | 
					class ProgramForm(ModelForm):
 | 
				
			||||||
 | 
					    new_cover = ImageField(required=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
        model = Program
 | 
					        model = Program
 | 
				
			||||||
        fields = ["content"]
 | 
					        fields = ["content"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save(self, commit=True):
 | 
				
			||||||
 | 
					        file_obj = self.cleaned_data["new_cover"]
 | 
				
			||||||
 | 
					        if file_obj:
 | 
				
			||||||
 | 
					            obj, _ = Image.objects.get_or_create(original_filename=file_obj.name, file=file_obj)
 | 
				
			||||||
 | 
					            self.instance.cover = obj
 | 
				
			||||||
 | 
					        super().save(commit=commit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProgramUpdateView(UserPassesTestMixin, BaseProgramMixin, PageUpdateView):
 | 
				
			||||||
 | 
					    model = Program
 | 
				
			||||||
 | 
					    form_class = ProgramForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_sidebar_queryset(self):
 | 
					    def get_sidebar_queryset(self):
 | 
				
			||||||
        return super().get_sidebar_queryset().filter(parent=self.program)
 | 
					        return super().get_sidebar_queryset().filter(parent=self.program)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -43,6 +60,9 @@ class ProgramUpdateView(UserPassesTestMixin, BaseProgramMixin, PageUpdateView):
 | 
				
			|||||||
        program = self.get_object()
 | 
					        program = self.get_object()
 | 
				
			||||||
        return self.request.user.has_perm("aircox.%s" % program.change_permission_codename)
 | 
					        return self.request.user.has_perm("aircox.%s" % program.change_permission_codename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_success_url(self):
 | 
				
			||||||
 | 
					        return reverse("program-detail", kwargs={"slug": self.get_object().slug})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProgramListView(PageListView):
 | 
					class ProgramListView(PageListView):
 | 
				
			||||||
    model = Program
 | 
					    model = Program
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user