mirror of
				https://github.com/ae-utbm/sith.git
				synced 2025-11-04 02:53:06 +00:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			fix-poster
			...
			dependabot
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					1bc6fdd4cf | 
@@ -59,7 +59,7 @@ from com.views import (
 | 
				
			|||||||
    PosterEditBaseView,
 | 
					    PosterEditBaseView,
 | 
				
			||||||
    PosterListBaseView,
 | 
					    PosterListBaseView,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from core.auth.mixins import CanEditMixin, PermissionOrClubBoardRequiredMixin
 | 
					from core.auth.mixins import CanEditMixin
 | 
				
			||||||
from core.models import PageRev
 | 
					from core.models import PageRev
 | 
				
			||||||
from core.views import DetailFormView, PageEditViewBase, UseFragmentsMixin
 | 
					from core.views import DetailFormView, PageEditViewBase, UseFragmentsMixin
 | 
				
			||||||
from core.views.mixins import FragmentMixin, FragmentRenderer, TabedViewMixin
 | 
					from core.views.mixins import FragmentMixin, FragmentRenderer, TabedViewMixin
 | 
				
			||||||
@@ -758,13 +758,11 @@ class MailingAutoGenerationView(View):
 | 
				
			|||||||
        return redirect("club:mailing", club_id=club.id)
 | 
					        return redirect("club:mailing", club_id=club.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PosterListView(
 | 
					class PosterListView(ClubTabsMixin, PosterListBaseView):
 | 
				
			||||||
    PermissionOrClubBoardRequiredMixin, ClubTabsMixin, PosterListBaseView
 | 
					 | 
				
			||||||
):
 | 
					 | 
				
			||||||
    """List communication posters."""
 | 
					    """List communication posters."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    current_tab = "posters"
 | 
					    current_tab = "posters"
 | 
				
			||||||
    permission_required = "com.view_poster"
 | 
					    extra_context = {"app": "club"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_queryset(self):
 | 
					    def get_queryset(self):
 | 
				
			||||||
        return super().get_queryset().filter(club=self.club.id)
 | 
					        return super().get_queryset().filter(club=self.club.id)
 | 
				
			||||||
@@ -772,17 +770,6 @@ class PosterListView(
 | 
				
			|||||||
    def get_object(self):
 | 
					    def get_object(self):
 | 
				
			||||||
        return self.club
 | 
					        return self.club
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					 | 
				
			||||||
        return super().get_context_data(**kwargs) | {
 | 
					 | 
				
			||||||
            "create_url": reverse_lazy(
 | 
					 | 
				
			||||||
                "club:poster_create", kwargs={"club_id": self.club.id}
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            "get_edit_url": lambda poster: reverse(
 | 
					 | 
				
			||||||
                "club:poster_edit",
 | 
					 | 
				
			||||||
                kwargs={"club_id": self.club.id, "poster_id": poster.id},
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PosterCreateView(ClubTabsMixin, PosterCreateBaseView):
 | 
					class PosterCreateView(ClubTabsMixin, PosterCreateBaseView):
 | 
				
			||||||
    """Create communication poster."""
 | 
					    """Create communication poster."""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -402,7 +402,9 @@ class Poster(models.Model):
 | 
				
			|||||||
                groups__id__in=[settings.SITH_GROUP_COM_ADMIN_ID]
 | 
					                groups__id__in=[settings.SITH_GROUP_COM_ADMIN_ID]
 | 
				
			||||||
            ):
 | 
					            ):
 | 
				
			||||||
                Notification.objects.create(
 | 
					                Notification.objects.create(
 | 
				
			||||||
                    user=user, url=reverse("com:poster_list"), type="POSTER_MODERATION"
 | 
					                    user=user,
 | 
				
			||||||
 | 
					                    url=reverse("com:poster_moderate_list"),
 | 
				
			||||||
 | 
					                    type="POSTER_MODERATION",
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
        return super().save(*args, **kwargs)
 | 
					        return super().save(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,8 +20,34 @@
 | 
				
			|||||||
      position: absolute;
 | 
					      position: absolute;
 | 
				
			||||||
      display: flex;
 | 
					      display: flex;
 | 
				
			||||||
      bottom: 5px;
 | 
					      bottom: 5px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      &.left {
 | 
				
			||||||
        left: 0;
 | 
					        left: 0;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      &.right {
 | 
				
			||||||
 | 
					        right: 0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .link {
 | 
				
			||||||
 | 
					        padding: 5px;
 | 
				
			||||||
 | 
					        padding-left: 20px;
 | 
				
			||||||
 | 
					        padding-right: 20px;
 | 
				
			||||||
 | 
					        margin-left: 5px;
 | 
				
			||||||
 | 
					        border-radius: 20px;
 | 
				
			||||||
 | 
					        background-color: hsl(40, 100%, 50%);
 | 
				
			||||||
 | 
					        color: black;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        &:hover {
 | 
				
			||||||
 | 
					          color: black;
 | 
				
			||||||
 | 
					          background-color: hsl(40, 58%, 50%);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        &.delete {
 | 
				
			||||||
 | 
					          background-color: hsl(0, 100%, 40%);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #posters,
 | 
					  #posters,
 | 
				
			||||||
@@ -117,15 +143,43 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      .actions {
 | 
					      .edit,
 | 
				
			||||||
        display: flex;
 | 
					      .moderate,
 | 
				
			||||||
        flex-direction: column;
 | 
					      .slideshow {
 | 
				
			||||||
        align-items: stretch;
 | 
					        padding: 5px;
 | 
				
			||||||
        form {
 | 
					        border-radius: 20px;
 | 
				
			||||||
          margin: unset;
 | 
					        background-color: hsl(40, 100%, 50%);
 | 
				
			||||||
          padding: unset;
 | 
					        color: black;
 | 
				
			||||||
          button {
 | 
					
 | 
				
			||||||
            width: 100%;
 | 
					        &:hover {
 | 
				
			||||||
 | 
					          color: black;
 | 
				
			||||||
 | 
					          background-color: hsl(40, 58%, 50%);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        &:nth-child(2n) {
 | 
				
			||||||
 | 
					          margin-top: 5px;
 | 
				
			||||||
 | 
					          margin-bottom: 5px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .tooltip {
 | 
				
			||||||
 | 
					        visibility: hidden;
 | 
				
			||||||
 | 
					        width: 120px;
 | 
				
			||||||
 | 
					        background-color: hsl(210, 20%, 98%);
 | 
				
			||||||
 | 
					        color: hsl(0, 0%, 0%);
 | 
				
			||||||
 | 
					        text-align: center;
 | 
				
			||||||
 | 
					        padding: 5px 0;
 | 
				
			||||||
 | 
					        border-radius: 6px;
 | 
				
			||||||
 | 
					        position: absolute;
 | 
				
			||||||
 | 
					        z-index: 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ul {
 | 
				
			||||||
 | 
					          margin-left: 0;
 | 
				
			||||||
 | 
					          display: inline-block;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          li {
 | 
				
			||||||
 | 
					            display: list-item;
 | 
				
			||||||
 | 
					            list-style-type: none;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,15 +13,22 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    <div id="title">
 | 
					    <div id="title">
 | 
				
			||||||
      <h3>{% trans %}Posters{% endtrans %}</h3>
 | 
					      <h3>{% trans %}Posters{% endtrans %}</h3>
 | 
				
			||||||
      <div id="links">
 | 
					      <div id="links" class="right">
 | 
				
			||||||
        <a id="create" class="btn btn-blue" href="{{ create_url }}">
 | 
					        {% if app == "com" %}
 | 
				
			||||||
          <i class="fa fa-plus"></i>
 | 
					          <a id="create" class="link" href="{{ url(app + ":poster_create") }}">{% trans %}Create{% endtrans %}</a>
 | 
				
			||||||
          {% trans %}Create{% endtrans %}
 | 
					          <a id="moderation" class="link" href="{{ url("com:poster_moderate_list") }}">{% trans %}Moderation{% endtrans %}</a>
 | 
				
			||||||
        </a>
 | 
					        {% elif app == "club" %}
 | 
				
			||||||
 | 
					          <a id="create" class="link" href="{{ url(app + ":poster_create", club.id) }}">{% trans %}Create{% endtrans %}</a>
 | 
				
			||||||
 | 
					        {% endif %}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div id="posters">
 | 
					    <div id="posters">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      {% if poster_list.count() == 0 %}
 | 
				
			||||||
 | 
					        <div id="no-posters">{% trans %}No posters{% endtrans %}</div>
 | 
				
			||||||
 | 
					      {% else %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {% for poster in poster_list %}
 | 
					        {% for poster in poster_list %}
 | 
				
			||||||
          <div class="poster{% if not poster.is_moderated %} not_moderated{% endif %}">
 | 
					          <div class="poster{% if not poster.is_moderated %} not_moderated{% endif %}">
 | 
				
			||||||
            <div class="name">{{ poster.name }}</div>
 | 
					            <div class="name">{{ poster.name }}</div>
 | 
				
			||||||
@@ -29,37 +36,30 @@
 | 
				
			|||||||
              class="image"
 | 
					              class="image"
 | 
				
			||||||
              hover="{% trans %}Click to expand{% endtrans %}"
 | 
					              hover="{% trans %}Click to expand{% endtrans %}"
 | 
				
			||||||
              @click="active = $el.firstElementChild"
 | 
					              @click="active = $el.firstElementChild"
 | 
				
			||||||
            tooltip="{%- for screen in poster.screens.all() -%}
 | 
					 | 
				
			||||||
                       {{ screen }}
 | 
					 | 
				
			||||||
                     {% endfor %}"
 | 
					 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
            <img src="{{ poster.file.url }}" alt="{{ poster.name }}">
 | 
					              <img src="{{ poster.file.url }}"></img>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div class="dates">
 | 
					            <div class="dates">
 | 
				
			||||||
              <div class="begin">{{ poster.date_begin | localtime | date("d/M/Y H:m") }}</div>
 | 
					              <div class="begin">{{ poster.date_begin | localtime | date("d/M/Y H:m") }}</div>
 | 
				
			||||||
              <div class="end">{{ poster.date_end | localtime | date("d/M/Y H:m") }}</div>
 | 
					              <div class="end">{{ poster.date_end | localtime | date("d/M/Y H:m") }}</div>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
          <div class="actions">
 | 
					            {% if app == "com" %}
 | 
				
			||||||
            {% if poster.is_editable %}
 | 
					              <a class="edit" href="{{ url(app + ":poster_edit", poster.id) }}">{% trans %}Edit{% endtrans %}</a>
 | 
				
			||||||
              <a class="btn btn-blue" href="{{ get_edit_url(poster) }}">
 | 
					            {% elif app == "club" %}
 | 
				
			||||||
                <i class="fa fa-pen-to-square"></i>
 | 
					              <a class="edit" href="{{ url(app + ":poster_edit", club.id, poster.id) }}">{% trans %}Edit{% endtrans %}</a>
 | 
				
			||||||
                {% trans %}Edit{% endtrans %}
 | 
					 | 
				
			||||||
              </a>
 | 
					 | 
				
			||||||
            {% endif %}
 | 
					            {% endif %}
 | 
				
			||||||
            {% if not poster.is_moderated and user.has_perm("com.moderate_poster") %}
 | 
					            <div class="tooltip">
 | 
				
			||||||
              <form action="{{ url("com:poster_moderate", object_id=poster.id) }}" method="post">
 | 
					              <ul>
 | 
				
			||||||
                {% csrf_token %}
 | 
					                {% for screen in poster.screens.all() %}
 | 
				
			||||||
                <button type="submit" class="btn btn-green">
 | 
					                  <li>{{ screen }}</li>
 | 
				
			||||||
                  <i class="fa fa-check"></i>
 | 
					 | 
				
			||||||
                  {% trans %}Moderate{% endtrans %}
 | 
					 | 
				
			||||||
                </button>
 | 
					 | 
				
			||||||
              </form>
 | 
					 | 
				
			||||||
            {% endif %}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      {% else %}
 | 
					 | 
				
			||||||
        <div id="no-posters">{% trans %}No posters{% endtrans %}</div>
 | 
					 | 
				
			||||||
                {% endfor %}
 | 
					                {% endfor %}
 | 
				
			||||||
 | 
					              </ul>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        {% endfor %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      {% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div
 | 
					    <div
 | 
				
			||||||
@@ -68,9 +68,7 @@
 | 
				
			|||||||
      @click="active = null"
 | 
					      @click="active = null"
 | 
				
			||||||
      :class="{active: active !== null}"
 | 
					      :class="{active: active !== null}"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <div id="placeholder">
 | 
					      <div id="placeholder"><img :src="active?.src"></div>
 | 
				
			||||||
        <img :src="active?.src" :alt="active?.name">
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										43
									
								
								com/templates/com/poster_moderate.jinja
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								com/templates/com/poster_moderate.jinja
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					{% extends "core/base.jinja" %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block script %}
 | 
				
			||||||
 | 
					  {{ super() }}
 | 
				
			||||||
 | 
					  <script src="{{ static('com/js/poster_list.js') }}"></script>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block additional_css %}
 | 
				
			||||||
 | 
					  <link rel="stylesheet" href="{{ static('com/css/posters.scss') }}">
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block content %}
 | 
				
			||||||
 | 
					  <div id="poster_list">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div id="title">
 | 
				
			||||||
 | 
					      <div id="links" class="left">
 | 
				
			||||||
 | 
					        <a id="list" class="link" href="{{ url("com:poster_list") }}">{% trans %}List{% endtrans %}</a>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <h3>{% trans %}Posters - moderation{% endtrans %}</h3>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div id="posters">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      {% if object_list.count == 0 %}
 | 
				
			||||||
 | 
					        <div id="no-posters">{% trans %}No objects{% endtrans %}</div>
 | 
				
			||||||
 | 
					      {% else %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        {% for poster in object_list %}
 | 
				
			||||||
 | 
					          <div class="poster{% if not poster.is_moderated %} not_moderated{% endif %}">
 | 
				
			||||||
 | 
					            <div class="name"> {{ poster.name }} </div>
 | 
				
			||||||
 | 
					            <div class="image"> <img src="{{ poster.file.url }}"></img> </div>
 | 
				
			||||||
 | 
					            <a class="moderate" href="{{ url("com:poster_moderate", object_id=poster.id) }}">Moderate</a>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        {% endfor %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      {% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div id="view"><div id="placeholder"></div></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
@@ -17,9 +17,7 @@ from unittest.mock import patch
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
from django.contrib.auth.models import Permission
 | 
					 | 
				
			||||||
from django.contrib.sites.models import Site
 | 
					from django.contrib.sites.models import Site
 | 
				
			||||||
from django.core.files.uploadedfile import SimpleUploadedFile
 | 
					 | 
				
			||||||
from django.test import Client, TestCase
 | 
					from django.test import Client, TestCase
 | 
				
			||||||
from django.urls import reverse
 | 
					from django.urls import reverse
 | 
				
			||||||
from django.utils import html
 | 
					from django.utils import html
 | 
				
			||||||
@@ -29,10 +27,9 @@ from model_bakery import baker
 | 
				
			|||||||
from pytest_django.asserts import assertNumQueries, assertRedirects
 | 
					from pytest_django.asserts import assertNumQueries, assertRedirects
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from club.models import Club, Membership
 | 
					from club.models import Club, Membership
 | 
				
			||||||
from com.models import News, NewsDate, Poster, Sith, Weekmail, WeekmailArticle
 | 
					from com.models import News, NewsDate, Sith, Weekmail, WeekmailArticle
 | 
				
			||||||
from core.baker_recipes import subscriber_user
 | 
					from core.baker_recipes import subscriber_user
 | 
				
			||||||
from core.models import AnonymousUser, Group, User
 | 
					from core.models import AnonymousUser, Group, User
 | 
				
			||||||
from core.utils import RED_PIXEL_PNG
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture()
 | 
					@pytest.fixture()
 | 
				
			||||||
@@ -317,6 +314,7 @@ def test_feed(client: Client):
 | 
				
			|||||||
    [
 | 
					    [
 | 
				
			||||||
        reverse("com:poster_list"),
 | 
					        reverse("com:poster_list"),
 | 
				
			||||||
        reverse("com:poster_create"),
 | 
					        reverse("com:poster_create"),
 | 
				
			||||||
 | 
					        reverse("com:poster_moderate_list"),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
def test_poster_management_views_crash_test(client: Client, url: str):
 | 
					def test_poster_management_views_crash_test(client: Client, url: str):
 | 
				
			||||||
@@ -327,37 +325,3 @@ def test_poster_management_views_crash_test(client: Client, url: str):
 | 
				
			|||||||
    client.force_login(user)
 | 
					    client.force_login(user)
 | 
				
			||||||
    res = client.get(url)
 | 
					    res = client.get(url)
 | 
				
			||||||
    assert res.status_code == 200
 | 
					    assert res.status_code == 200
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@pytest.mark.django_db
 | 
					 | 
				
			||||||
@pytest.mark.parametrize(
 | 
					 | 
				
			||||||
    "referer",
 | 
					 | 
				
			||||||
    [
 | 
					 | 
				
			||||||
        None,
 | 
					 | 
				
			||||||
        reverse("com:poster_list"),
 | 
					 | 
				
			||||||
        reverse("club:poster_list", kwargs={"club_id": settings.SITH_MAIN_CLUB_ID}),
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
def test_moderate_poster(client: Client, referer: str | None):
 | 
					 | 
				
			||||||
    poster = baker.make(
 | 
					 | 
				
			||||||
        Poster,
 | 
					 | 
				
			||||||
        is_moderated=False,
 | 
					 | 
				
			||||||
        file=SimpleUploadedFile("test.png", content=RED_PIXEL_PNG),
 | 
					 | 
				
			||||||
        club_id=settings.SITH_MAIN_CLUB_ID,
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    user = baker.make(
 | 
					 | 
				
			||||||
        User,
 | 
					 | 
				
			||||||
        user_permissions=Permission.objects.filter(
 | 
					 | 
				
			||||||
            codename__in=["view_poster", "moderate_poster"]
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    client.force_login(user)
 | 
					 | 
				
			||||||
    headers = {"REFERER": f"https://{settings.SITH_URL}{referer}"} if referer else {}
 | 
					 | 
				
			||||||
    response = client.post(
 | 
					 | 
				
			||||||
        reverse("com:poster_moderate", kwargs={"object_id": poster.id}), headers=headers
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    result_url = referer or reverse("com:poster_list")
 | 
					 | 
				
			||||||
    assertRedirects(response, result_url)
 | 
					 | 
				
			||||||
    poster.refresh_from_db()
 | 
					 | 
				
			||||||
    assert poster.is_moderated
 | 
					 | 
				
			||||||
    assert poster.moderator == user
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,7 @@ from com.views import (
 | 
				
			|||||||
    PosterDeleteView,
 | 
					    PosterDeleteView,
 | 
				
			||||||
    PosterEditView,
 | 
					    PosterEditView,
 | 
				
			||||||
    PosterListView,
 | 
					    PosterListView,
 | 
				
			||||||
 | 
					    PosterModerateListView,
 | 
				
			||||||
    PosterModerateView,
 | 
					    PosterModerateView,
 | 
				
			||||||
    ScreenCreateView,
 | 
					    ScreenCreateView,
 | 
				
			||||||
    ScreenDeleteView,
 | 
					    ScreenDeleteView,
 | 
				
			||||||
@@ -101,6 +102,11 @@ urlpatterns = [
 | 
				
			|||||||
        PosterDeleteView.as_view(),
 | 
					        PosterDeleteView.as_view(),
 | 
				
			||||||
        name="poster_delete",
 | 
					        name="poster_delete",
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
 | 
					    path(
 | 
				
			||||||
 | 
					        "poster/moderate/",
 | 
				
			||||||
 | 
					        PosterModerateListView.as_view(),
 | 
				
			||||||
 | 
					        name="poster_moderate_list",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
    path(
 | 
					    path(
 | 
				
			||||||
        "poster/<int:object_id>/moderate/",
 | 
					        "poster/<int:object_id>/moderate/",
 | 
				
			||||||
        PosterModerateView.as_view(),
 | 
					        PosterModerateView.as_view(),
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										67
									
								
								com/views.py
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								com/views.py
									
									
									
									
									
								
							@@ -25,7 +25,6 @@ import itertools
 | 
				
			|||||||
from datetime import date, timedelta
 | 
					from datetime import date, timedelta
 | 
				
			||||||
from smtplib import SMTPRecipientsRefused
 | 
					from smtplib import SMTPRecipientsRefused
 | 
				
			||||||
from typing import Any
 | 
					from typing import Any
 | 
				
			||||||
from urllib.parse import urlparse
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dateutil.relativedelta import relativedelta
 | 
					from dateutil.relativedelta import relativedelta
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
@@ -35,7 +34,7 @@ from django.contrib.auth.mixins import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
from django.contrib.syndication.views import Feed
 | 
					from django.contrib.syndication.views import Feed
 | 
				
			||||||
from django.core.exceptions import PermissionDenied, ValidationError
 | 
					from django.core.exceptions import PermissionDenied, ValidationError
 | 
				
			||||||
from django.db.models import Exists, Max, OuterRef, Value
 | 
					from django.db.models import Max
 | 
				
			||||||
from django.forms.models import modelform_factory
 | 
					from django.forms.models import modelform_factory
 | 
				
			||||||
from django.http import HttpResponseRedirect
 | 
					from django.http import HttpResponseRedirect
 | 
				
			||||||
from django.shortcuts import get_object_or_404, redirect
 | 
					from django.shortcuts import get_object_or_404, redirect
 | 
				
			||||||
@@ -46,7 +45,7 @@ from django.utils.translation import gettext_lazy as _
 | 
				
			|||||||
from django.views.generic import DetailView, ListView, TemplateView, View
 | 
					from django.views.generic import DetailView, ListView, TemplateView, View
 | 
				
			||||||
from django.views.generic.edit import CreateView, DeleteView, UpdateView
 | 
					from django.views.generic.edit import CreateView, DeleteView, UpdateView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from club.models import Club, Mailing, Membership
 | 
					from club.models import Club, Mailing
 | 
				
			||||||
from com.forms import NewsDateForm, NewsForm, PosterForm
 | 
					from com.forms import NewsDateForm, NewsForm, PosterForm
 | 
				
			||||||
from com.ics_calendar import IcsCalendar
 | 
					from com.ics_calendar import IcsCalendar
 | 
				
			||||||
from com.models import News, NewsDate, Poster, Screen, Sith, Weekmail, WeekmailArticle
 | 
					from com.models import News, NewsDate, Poster, Screen, Sith, Weekmail, WeekmailArticle
 | 
				
			||||||
@@ -562,26 +561,16 @@ class MailingModerateView(View):
 | 
				
			|||||||
        raise PermissionDenied
 | 
					        raise PermissionDenied
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PosterListBaseView(ListView):
 | 
					class PosterListBaseView(PermissionOrClubBoardRequiredMixin, ListView):
 | 
				
			||||||
    """List communication posters."""
 | 
					    """List communication posters."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    model = Poster
 | 
					    model = Poster
 | 
				
			||||||
    template_name = "com/poster_list.jinja"
 | 
					    template_name = "com/poster_list.jinja"
 | 
				
			||||||
    permission_required = "com.view_poster"
 | 
					    permission_required = "com.view_poster"
 | 
				
			||||||
 | 
					    ordering = ["-date_begin"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_queryset(self):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        qs = Poster.objects.prefetch_related("screens")
 | 
					        return super().get_context_data(**kwargs) | {"club": self.club}
 | 
				
			||||||
        if self.request.user.has_perm("com.edit_poster"):
 | 
					 | 
				
			||||||
            qs = qs.annotate(is_editable=Value(value=True))
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            qs = qs.annotate(
 | 
					 | 
				
			||||||
                is_editable=Exists(
 | 
					 | 
				
			||||||
                    Membership.objects.ongoing()
 | 
					 | 
				
			||||||
                    .board()
 | 
					 | 
				
			||||||
                    .filter(user=self.request.user, club=OuterRef("club_id"))
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        return qs.order_by("-date_begin")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PosterCreateBaseView(PermissionOrClubBoardRequiredMixin, CreateView):
 | 
					class PosterCreateBaseView(PermissionOrClubBoardRequiredMixin, CreateView):
 | 
				
			||||||
@@ -644,17 +633,21 @@ class PosterDeleteBaseView(
 | 
				
			|||||||
    permission_required = "com.delete_poster"
 | 
					    permission_required = "com.delete_poster"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PosterListView(PermissionRequiredMixin, ComTabsMixin, PosterListBaseView):
 | 
					class PosterListView(ComTabsMixin, PosterListBaseView):
 | 
				
			||||||
    """List communication posters."""
 | 
					    """List communication posters."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    current_tab = "posters"
 | 
					    current_tab = "posters"
 | 
				
			||||||
    extra_context = {
 | 
					
 | 
				
			||||||
        "create_url": reverse_lazy("com:poster_create"),
 | 
					    def get_queryset(self):
 | 
				
			||||||
        "get_edit_url": lambda poster: reverse(
 | 
					        qs = super().get_queryset()
 | 
				
			||||||
            "com:poster_edit", kwargs={"poster_id": poster.id}
 | 
					        if self.request.user.has_perm("com.view_poster"):
 | 
				
			||||||
        ),
 | 
					            return qs
 | 
				
			||||||
    }
 | 
					        return qs.filter(club=self.club.id)
 | 
				
			||||||
    permission_required = "com.view_poster"
 | 
					
 | 
				
			||||||
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
 | 
					        kwargs = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					        kwargs["app"] = "com"
 | 
				
			||||||
 | 
					        return kwargs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PosterCreateView(ComTabsMixin, PosterCreateBaseView):
 | 
					class PosterCreateView(ComTabsMixin, PosterCreateBaseView):
 | 
				
			||||||
@@ -679,6 +672,17 @@ class PosterDeleteView(PosterDeleteBaseView):
 | 
				
			|||||||
    success_url = reverse_lazy("com:poster_list")
 | 
					    success_url = reverse_lazy("com:poster_list")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PosterModerateListView(PermissionRequiredMixin, ComTabsMixin, ListView):
 | 
				
			||||||
 | 
					    """Moderate list communication poster."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    current_tab = "posters"
 | 
				
			||||||
 | 
					    model = Poster
 | 
				
			||||||
 | 
					    template_name = "com/poster_moderate.jinja"
 | 
				
			||||||
 | 
					    queryset = Poster.objects.filter(is_moderated=False).all()
 | 
				
			||||||
 | 
					    permission_required = "com.moderate_poster"
 | 
				
			||||||
 | 
					    extra_context = {"app": "com"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PosterModerateView(PermissionRequiredMixin, ComTabsMixin, View):
 | 
					class PosterModerateView(PermissionRequiredMixin, ComTabsMixin, View):
 | 
				
			||||||
    """Moderate communication poster."""
 | 
					    """Moderate communication poster."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -686,21 +690,12 @@ class PosterModerateView(PermissionRequiredMixin, ComTabsMixin, View):
 | 
				
			|||||||
    permission_required = "com.moderate_poster"
 | 
					    permission_required = "com.moderate_poster"
 | 
				
			||||||
    extra_context = {"app": "com"}
 | 
					    extra_context = {"app": "com"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def post(self, request, *args, **kwargs):
 | 
					    def get(self, request, *args, **kwargs):
 | 
				
			||||||
        obj = get_object_or_404(Poster, pk=kwargs["object_id"])
 | 
					        obj = get_object_or_404(Poster, pk=kwargs["object_id"])
 | 
				
			||||||
        obj.is_moderated = True
 | 
					        obj.is_moderated = True
 | 
				
			||||||
        obj.moderator = request.user
 | 
					        obj.moderator = request.user
 | 
				
			||||||
        obj.save()
 | 
					        obj.save()
 | 
				
			||||||
        # The moderation request may be originated from a club context (/club/poster)
 | 
					        return redirect("com:poster_moderate_list")
 | 
				
			||||||
        # or a global context (/com/poster),
 | 
					 | 
				
			||||||
        # so the redirection URL will be the URL of the page that called this view,
 | 
					 | 
				
			||||||
        # as long as the latter belongs to the sith.
 | 
					 | 
				
			||||||
        referer = self.request.META.get("HTTP_REFERER")
 | 
					 | 
				
			||||||
        if referer:
 | 
					 | 
				
			||||||
            parsed = urlparse(referer)
 | 
					 | 
				
			||||||
            if parsed.netloc == settings.SITH_URL:
 | 
					 | 
				
			||||||
                return redirect(parsed.path)
 | 
					 | 
				
			||||||
        return redirect(reverse("com:poster_list"))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ScreenListView(PermissionRequiredMixin, ComTabsMixin, ListView):
 | 
					class ScreenListView(PermissionRequiredMixin, ComTabsMixin, ListView):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,7 +44,7 @@ dependencies = [
 | 
				
			|||||||
    "django-honeypot>=1.3.0,<2",
 | 
					    "django-honeypot>=1.3.0,<2",
 | 
				
			||||||
    "pydantic-extra-types<3.0.0,>=2.10.3",
 | 
					    "pydantic-extra-types<3.0.0,>=2.10.3",
 | 
				
			||||||
    "ical>=11,<12",
 | 
					    "ical>=11,<12",
 | 
				
			||||||
    "redis[hiredis]<7,>=5.3.0",
 | 
					    "redis[hiredis]>=5.3.0,<8",
 | 
				
			||||||
    "environs[django]<15.0.0,>=14.1.1",
 | 
					    "environs[django]<15.0.0,>=14.1.1",
 | 
				
			||||||
    "requests>=2.32.3",
 | 
					    "requests>=2.32.3",
 | 
				
			||||||
    "honcho>=2.0.0",
 | 
					    "honcho>=2.0.0",
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user