views.py 24.9 KB
Newer Older
1 2 3 4
# -*- coding:utf-8 -*
#
# Copyright 2016,2017
# - Skia <skia@libskia.so>
Sli's avatar
Sli committed
5
# - Sli <antoine@bartuccio.fr>
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#

26
import csv
27 28

from django.conf import settings
Skia's avatar
Skia committed
29
from django import forms
Sli's avatar
Sli committed
30
from django.views.generic import ListView, DetailView, TemplateView, View
Sli's avatar
Sli committed
31
from django.views.generic.edit import DeleteView
Sli's avatar
Sli committed
32
from django.views.generic.detail import SingleObjectMixin
Skia's avatar
Skia committed
33
from django.views.generic.edit import UpdateView, CreateView
34 35 36 37 38 39
from django.http import (
    HttpResponseRedirect,
    HttpResponse,
    Http404,
    StreamingHttpResponse,
)
40
from django.urls import reverse, reverse_lazy
Skia's avatar
Skia committed
41
from django.utils import timezone
Skia's avatar
Skia committed
42
from django.utils.translation import ugettext_lazy as _
Sli's avatar
Sli committed
43
from django.utils.translation import ugettext as _t
44
from django.core.exceptions import PermissionDenied, ValidationError, NON_FIELD_ERRORS
45
from django.core.paginator import Paginator, InvalidPage
Sli's avatar
Sli committed
46
from django.shortcuts import get_object_or_404, redirect
47 48
from django.db.models import Sum

Skia's avatar
Skia committed
49

Sli's avatar
Sli committed
50 51 52 53 54
from core.views import (
    CanCreateMixin,
    CanViewMixin,
    CanEditMixin,
    CanEditPropMixin,
55
    UserIsRootMixin,
Sli's avatar
Sli committed
56 57
    TabedViewMixin,
    PageEditViewBase,
58
    DetailFormView,
Sli's avatar
Sli committed
59
)
60 61 62 63
from core.models import PageRev

from counter.models import Selling

Sli's avatar
Sli committed
64 65 66 67 68 69
from com.views import (
    PosterListBaseView,
    PosterCreateBaseView,
    PosterEditBaseView,
    PosterDeleteBaseView,
)
Sli's avatar
Sli committed
70

71
from club.models import Club, Membership, Mailing, MailingSubscription
72
from club.forms import MailingForm, ClubEditForm, ClubMemberForm, SellingsForm
Sli's avatar
Sli committed
73

74

75 76
class ClubTabsMixin(TabedViewMixin):
    def get_tabs_title(self):
77 78 79
        obj = self.get_object()
        if isinstance(obj, PageRev):
            self.object = obj.page.club
80 81 82 83
        return self.object.get_display_name()

    def get_list_of_tabs(self):
        tab_list = []
Sli's avatar
Sli committed
84 85 86 87 88 89 90
        tab_list.append(
            {
                "url": reverse("club:club_view", kwargs={"club_id": self.object.id}),
                "slug": "infos",
                "name": _("Infos"),
            }
        )
91
        if self.request.user.can_view(self.object):
Sli's avatar
Sli committed
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
            tab_list.append(
                {
                    "url": reverse(
                        "club:club_members", kwargs={"club_id": self.object.id}
                    ),
                    "slug": "members",
                    "name": _("Members"),
                }
            )
            tab_list.append(
                {
                    "url": reverse(
                        "club:club_old_members", kwargs={"club_id": self.object.id}
                    ),
                    "slug": "elderlies",
                    "name": _("Old members"),
                }
            )
110
        if self.object.page:
Sli's avatar
Sli committed
111 112 113 114 115 116 117 118 119
            tab_list.append(
                {
                    "url": reverse(
                        "club:club_hist", kwargs={"club_id": self.object.id}
                    ),
                    "slug": "history",
                    "name": _("History"),
                }
            )
120
        if self.request.user.can_edit(self.object):
Sli's avatar
Sli committed
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
            tab_list.append(
                {
                    "url": reverse("club:tools", kwargs={"club_id": self.object.id}),
                    "slug": "tools",
                    "name": _("Tools"),
                }
            )
            tab_list.append(
                {
                    "url": reverse(
                        "club:club_edit", kwargs={"club_id": self.object.id}
                    ),
                    "slug": "edit",
                    "name": _("Edit"),
                }
            )
137
            if self.object.page and self.request.user.can_edit(self.object.page):
Sli's avatar
Sli committed
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
                tab_list.append(
                    {
                        "url": reverse(
                            "core:page_edit",
                            kwargs={"page_name": self.object.page.get_full_name()},
                        ),
                        "slug": "page_edit",
                        "name": _("Edit club page"),
                    }
                )
            tab_list.append(
                {
                    "url": reverse(
                        "club:club_sellings", kwargs={"club_id": self.object.id}
                    ),
                    "slug": "sellings",
                    "name": _("Sellings"),
                }
            )
            tab_list.append(
                {
                    "url": reverse("club:mailing", kwargs={"club_id": self.object.id}),
                    "slug": "mailing",
                    "name": _("Mailing list"),
                }
            )
            tab_list.append(
                {
                    "url": reverse(
                        "club:poster_list", kwargs={"club_id": self.object.id}
                    ),
                    "slug": "posters",
                    "name": _("Posters list"),
                }
            )
173
        if self.request.user.is_owner(self.object):
Sli's avatar
Sli committed
174 175 176 177 178 179 180 181 182
            tab_list.append(
                {
                    "url": reverse(
                        "club:club_prop", kwargs={"club_id": self.object.id}
                    ),
                    "slug": "props",
                    "name": _("Props"),
                }
            )
183 184
        return tab_list

Krophil's avatar
Krophil committed
185

Skia's avatar
Skia committed
186
class ClubListView(ListView):
Skia's avatar
Skia committed
187 188 189
    """
    List the Clubs
    """
Sli's avatar
Sli committed
190

191
    model = Club
Sli's avatar
Sli committed
192
    template_name = "club/club_list.jinja"
193

Krophil's avatar
Krophil committed
194

195
class ClubView(ClubTabsMixin, DetailView):
Skia's avatar
Skia committed
196 197 198
    """
    Front page of a Club
    """
Sli's avatar
Sli committed
199

200 201
    model = Club
    pk_url_kwarg = "club_id"
Sli's avatar
Sli committed
202
    template_name = "club/club_detail.jinja"
203
    current_tab = "infos"
204

205 206 207
    def get_context_data(self, **kwargs):
        kwargs = super(ClubView, self).get_context_data(**kwargs)
        if self.object.page and self.object.page.revisions.exists():
Sli's avatar
Sli committed
208
            kwargs["page_revision"] = self.object.page.revisions.last().content
209 210 211 212 213 214 215
        return kwargs


class ClubRevView(ClubView):
    """
    Display a specific page revision
    """
Sli's avatar
Sli committed
216

217 218
    def dispatch(self, request, *args, **kwargs):
        obj = self.get_object()
Sli's avatar
Sli committed
219
        self.revision = get_object_or_404(PageRev, pk=kwargs["rev_id"], page__club=obj)
220 221 222 223
        return super(ClubRevView, self).dispatch(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        kwargs = super(ClubRevView, self).get_context_data(**kwargs)
Sli's avatar
Sli committed
224
        kwargs["page_revision"] = self.revision.content
225 226 227 228
        return kwargs


class ClubPageEditView(ClubTabsMixin, PageEditViewBase):
Sli's avatar
Sli committed
229
    template_name = "club/pagerev_edit.jinja"
230 231 232
    current_tab = "page_edit"

    def dispatch(self, request, *args, **kwargs):
Sli's avatar
Sli committed
233
        self.club = get_object_or_404(Club, pk=kwargs["club_id"])
234 235 236 237 238 239 240 241 242
        if not self.club.page:
            raise Http404
        return super(ClubPageEditView, self).dispatch(request, *args, **kwargs)

    def get_object(self):
        self.page = self.club.page
        return self._get_revision()

    def get_success_url(self, **kwargs):
Sli's avatar
Sli committed
243
        return reverse_lazy("club:club_view", kwargs={"club_id": self.club.id})
244 245 246 247 248 249


class ClubPageHistView(ClubTabsMixin, CanViewMixin, DetailView):
    """
    Modification hostory of the page
    """
Sli's avatar
Sli committed
250

251 252
    model = Club
    pk_url_kwarg = "club_id"
Sli's avatar
Sli committed
253
    template_name = "club/page_history.jinja"
254 255
    current_tab = "history"

Krophil's avatar
Krophil committed
256

257
class ClubToolsView(ClubTabsMixin, CanEditMixin, DetailView):
Skia's avatar
Skia committed
258 259 260
    """
    Tools page of a Club
    """
Sli's avatar
Sli committed
261

Skia's avatar
Skia committed
262 263
    model = Club
    pk_url_kwarg = "club_id"
Sli's avatar
Sli committed
264
    template_name = "club/club_tools.jinja"
265
    current_tab = "tools"
Skia's avatar
Skia committed
266

Krophil's avatar
Krophil committed
267

268
class ClubMembersView(ClubTabsMixin, CanViewMixin, DetailFormView):
Skia's avatar
Skia committed
269 270 271
    """
    View of a club's members
    """
Sli's avatar
Sli committed
272

273 274
    model = Club
    pk_url_kwarg = "club_id"
Skia's avatar
Skia committed
275
    form_class = ClubMemberForm
Sli's avatar
Sli committed
276
    template_name = "club/club_members.jinja"
277
    current_tab = "members"
278

279 280
    def get_form_kwargs(self):
        kwargs = super(ClubMembersView, self).get_form_kwargs()
281
        kwargs["request_user"] = self.request.user
282
        kwargs["club"] = self.get_object()
Sli's avatar
Sli committed
283
        kwargs["club_members"] = self.members
284 285 286 287
        return kwargs

    def get_context_data(self, *args, **kwargs):
        kwargs = super(ClubMembersView, self).get_context_data(*args, **kwargs)
Sli's avatar
Sli committed
288
        kwargs["members"] = self.members
289
        return kwargs
Skia's avatar
Skia committed
290

291
    def form_valid(self, form):
Sli's avatar
Sli committed
292 293 294
        """
            Check user rights
        """
295 296 297 298
        resp = super(ClubMembersView, self).form_valid(form)

        data = form.clean()
        users = data.pop("users", [])
Sli's avatar
Sli committed
299
        users_old = data.pop("users_old", [])
300 301
        for user in users:
            Membership(club=self.get_object(), user=user, **data).save()
Sli's avatar
Sli committed
302 303 304 305
        for user in users_old:
            membership = self.get_object().get_membership_for(user)
            membership.end_date = timezone.now()
            membership.save()
306
        return resp
Sli's avatar
Sli committed
307

308
    def dispatch(self, request, *args, **kwargs):
Sli's avatar
Sli committed
309 310 311
        self.members = (
            self.get_object().members.filter(end_date=None).order_by("-role").all()
        )
312 313 314
        return super(ClubMembersView, self).dispatch(request, *args, **kwargs)

    def get_success_url(self, **kwargs):
315 316 317
        return reverse_lazy(
            "club:club_members", kwargs={"club_id": self.get_object().id}
        )
318

Krophil's avatar
Krophil committed
319

320
class ClubOldMembersView(ClubTabsMixin, CanViewMixin, DetailView):
Skia's avatar
Skia committed
321 322 323
    """
    Old members of a club
    """
Sli's avatar
Sli committed
324

Skia's avatar
Skia committed
325 326
    model = Club
    pk_url_kwarg = "club_id"
Sli's avatar
Sli committed
327
    template_name = "club/club_old_members.jinja"
328
    current_tab = "elderlies"
Skia's avatar
Skia committed
329

Krophil's avatar
Krophil committed
330

331
class ClubSellingView(ClubTabsMixin, CanEditMixin, DetailFormView):
Skia's avatar
Skia committed
332 333 334
    """
    Sellings of a club
    """
Sli's avatar
Sli committed
335

Skia's avatar
Skia committed
336 337
    model = Club
    pk_url_kwarg = "club_id"
Sli's avatar
Sli committed
338
    template_name = "club/club_sellings.jinja"
Skia's avatar
Skia committed
339
    current_tab = "sellings"
340
    form_class = SellingsForm
341 342 343 344 345 346 347 348
    paginate_by = 70

    def dispatch(self, request, *args, **kwargs):
        try:
            self.asked_page = int(request.GET.get("page", 1))
        except ValueError:
            raise Http404
        return super(ClubSellingView, self).dispatch(request, *args, **kwargs)
Skia's avatar
Skia committed
349

350 351 352 353 354 355 356
    def get_form_kwargs(self):
        kwargs = super(ClubSellingView, self).get_form_kwargs()
        kwargs["club"] = self.object
        return kwargs

    def post(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)
Skia's avatar
Skia committed
357 358 359 360

    def get_context_data(self, **kwargs):
        kwargs = super(ClubSellingView, self).get_context_data(**kwargs)
        qs = Selling.objects.filter(club=self.object)
361 362

        kwargs["result"] = qs[:0]
363
        kwargs["paginated_result"] = kwargs["result"]
364 365 366 367 368
        kwargs["total"] = 0
        kwargs["total_quantity"] = 0
        kwargs["benefit"] = 0

        form = self.get_form()
Skia's avatar
Skia committed
369
        if form.is_valid():
Skia's avatar
Skia committed
370 371
            if not len([v for v in form.cleaned_data.values() if v is not None]):
                qs = Selling.objects.filter(id=-1)
Sli's avatar
Sli committed
372 373 374 375
            if form.cleaned_data["begin_date"]:
                qs = qs.filter(date__gte=form.cleaned_data["begin_date"])
            if form.cleaned_data["end_date"]:
                qs = qs.filter(date__lte=form.cleaned_data["end_date"])
376 377 378 379

            if form.cleaned_data["counters"]:
                qs = qs.filter(counter__in=form.cleaned_data["counters"])

380
            selected_products = []
381 382 383
            if form.cleaned_data["products"]:
                selected_products.extend(form.cleaned_data["products"])
            if form.cleaned_data["archived_products"]:
Sli's avatar
Sli committed
384
                selected_products.extend(form.cleaned_data["archived_products"])
385

386
            if len(selected_products) > 0:
387 388
                qs = qs.filter(product__in=selected_products)

Sli's avatar
Sli committed
389
            kwargs["result"] = qs.all().order_by("-id")
390 391 392 393 394 395 396 397 398
            kwargs["total"] = sum([s.quantity * s.unit_price for s in kwargs["result"]])
            total_quantity = qs.all().aggregate(Sum("quantity"))
            if total_quantity["quantity__sum"]:
                kwargs["total_quantity"] = total_quantity["quantity__sum"]
            benefit = (
                qs.exclude(product=None).all().aggregate(Sum("product__purchase_price"))
            )
            if benefit["product__purchase_price__sum"]:
                kwargs["benefit"] = benefit["product__purchase_price__sum"]
399

400 401
        kwargs["paginator"] = Paginator(kwargs["result"], self.paginate_by)
        try:
402
            kwargs["paginated_result"] = kwargs["paginator"].page(self.asked_page)
403 404 405
        except InvalidPage:
            raise Http404

Skia's avatar
Skia committed
406 407
        return kwargs

Krophil's avatar
Krophil committed
408

Sli's avatar
Sli committed
409 410 411 412 413
class ClubSellingCSVView(ClubSellingView):
    """
    Generate sellings in csv for a given period
    """

414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
    class StreamWriter:
        """Implements a file-like interface for streaming the CSV"""

        def write(self, value):
            """Write the value by returning it, instead of storing in a buffer."""
            return value

    def write_selling(self, selling):
        row = [selling.date, selling.counter]
        if selling.seller:
            row.append(selling.seller.get_display_name())
        else:
            row.append("")
        if selling.customer:
            row.append(selling.customer.user.get_display_name())
        else:
            row.append("")
        row = row + [
            selling.label,
            selling.quantity,
            selling.quantity * selling.unit_price,
            selling.get_payment_method_display(),
        ]
        if selling.product:
            row.append(selling.product.selling_price)
            row.append(selling.product.purchase_price)
            row.append(selling.product.selling_price - selling.product.purchase_price)
        else:
            row = row + ["", "", ""]
        return row

Sli's avatar
Sli committed
445
    def get(self, request, *args, **kwargs):
Sli's avatar
Sli committed
446

Sli's avatar
Sli committed
447 448
        self.object = self.get_object()
        kwargs = self.get_context_data(**kwargs)
449 450 451

        # Use the StreamWriter class instead of request for streaming
        pseudo_buffer = self.StreamWriter()
Sli's avatar
Sli committed
452
        writer = csv.writer(
453
            pseudo_buffer, delimiter=";", lineterminator="\n", quoting=csv.QUOTE_ALL
Sli's avatar
Sli committed
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
        )

        writer.writerow([_t("Quantity"), kwargs["total_quantity"]])
        writer.writerow([_t("Total"), kwargs["total"]])
        writer.writerow([_t("Benefit"), kwargs["benefit"]])
        writer.writerow(
            [
                _t("Date"),
                _t("Counter"),
                _t("Barman"),
                _t("Customer"),
                _t("Label"),
                _t("Quantity"),
                _t("Total"),
                _t("Payment method"),
                _t("Selling price"),
                _t("Purchase price"),
                _t("Benefit"),
            ]
        )
474 475 476 477 478 479 480 481 482 483 484

        # Stream response
        response = StreamingHttpResponse(
            (
                writer.writerow(self.write_selling(selling))
                for selling in kwargs["result"]
            ),
            content_type="text/csv",
        )
        name = _("Sellings") + "_" + self.object.name + ".csv"
        response["Content-Disposition"] = "filename=" + name
Sli's avatar
Sli committed
485 486 487

        return response

Krophil's avatar
Krophil committed
488

489
class ClubEditView(ClubTabsMixin, CanEditMixin, UpdateView):
Skia's avatar
Skia committed
490 491 492
    """
    Edit a Club's main informations (for the club's members)
    """
Sli's avatar
Sli committed
493

Skia's avatar
Skia committed
494 495
    model = Club
    pk_url_kwarg = "club_id"
496
    form_class = ClubEditForm
Sli's avatar
Sli committed
497
    template_name = "core/edit.jinja"
498
    current_tab = "edit"
Skia's avatar
Skia committed
499

Krophil's avatar
Krophil committed
500

501
class ClubEditPropView(ClubTabsMixin, CanEditPropMixin, UpdateView):
Skia's avatar
Skia committed
502 503 504
    """
    Edit the properties of a Club object (for the Sith admins)
    """
Sli's avatar
Sli committed
505

506 507
    model = Club
    pk_url_kwarg = "club_id"
Sli's avatar
Sli committed
508 509
    fields = ["name", "unix_name", "parent", "is_active"]
    template_name = "core/edit.jinja"
510
    current_tab = "props"
Skia's avatar
Skia committed
511

Krophil's avatar
Krophil committed
512

tleb's avatar
tleb committed
513
class ClubCreateView(CanCreateMixin, CreateView):
Skia's avatar
Skia committed
514 515 516
    """
    Create a club (for the Sith admin)
    """
Sli's avatar
Sli committed
517

Skia's avatar
Skia committed
518 519
    model = Club
    pk_url_kwarg = "club_id"
Sli's avatar
Sli committed
520 521
    fields = ["name", "unix_name", "parent"]
    template_name = "core/edit.jinja"
Skia's avatar
Skia committed
522

Krophil's avatar
Krophil committed
523

Skia's avatar
Skia committed
524 525 526 527
class MembershipSetOldView(CanEditMixin, DetailView):
    """
    Set a membership as beeing old
    """
Sli's avatar
Sli committed
528

Skia's avatar
Skia committed
529 530 531 532 533 534 535
    model = Membership
    pk_url_kwarg = "membership_id"

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        self.object.end_date = timezone.now()
        self.object.save()
Sli's avatar
Sli committed
536 537 538 539 540 541 542
        return HttpResponseRedirect(
            reverse(
                "club:club_members",
                args=self.args,
                kwargs={"club_id": self.object.club.id},
            )
        )
Skia's avatar
Skia committed
543 544 545

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
Sli's avatar
Sli committed
546 547 548 549 550 551 552
        return HttpResponseRedirect(
            reverse(
                "club:club_members",
                args=self.args,
                kwargs={"club_id": self.object.club.id},
            )
        )
Skia's avatar
Skia committed
553

Krophil's avatar
Krophil committed
554

555 556 557 558 559 560 561 562 563 564 565 566 567
class MembershipDeleteView(UserIsRootMixin, DeleteView):
    """
    Delete a membership (for admins only)
    """

    model = Membership
    pk_url_kwarg = "membership_id"
    template_name = "core/delete_confirm.jinja"

    def get_success_url(self):
        return reverse_lazy("core:user_clubs", kwargs={"user_id": self.object.user.id})


Skia's avatar
Skia committed
568
class ClubStatView(TemplateView):
Krophil's avatar
Krophil committed
569
    template_name = "club/stats.jinja"
Skia's avatar
Skia committed
570 571 572

    def get_context_data(self, **kwargs):
        kwargs = super(ClubStatView, self).get_context_data(**kwargs)
Sli's avatar
Sli committed
573
        kwargs["club_list"] = Club.objects.all()
Skia's avatar
Skia committed
574
        return kwargs
Sli's avatar
Sli committed
575 576


577
class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView):
Sli's avatar
Sli committed
578 579 580
    """
    A list of mailing for a given club
    """
Sli's avatar
Sli committed
581

582 583 584
    model = Club
    form_class = MailingForm
    pk_url_kwarg = "club_id"
Sli's avatar
Sli committed
585
    template_name = "club/mailing.jinja"
Sli's avatar
Sli committed
586
    current_tab = "mailing"
Sli's avatar
Sli committed
587

588 589
    def get_form_kwargs(self):
        kwargs = super(ClubMailingView, self).get_form_kwargs()
590 591
        kwargs["club_id"] = self.get_object().id
        kwargs["user_id"] = self.request.user.id
592
        kwargs["mailings"] = self.mailings
593 594
        return kwargs

595 596 597 598
    def dispatch(self, request, *args, **kwargs):
        self.mailings = Mailing.objects.filter(club_id=self.get_object().id).all()
        return super(ClubMailingView, self).dispatch(request, *args, **kwargs)

Sli's avatar
Sli committed
599 600
    def get_context_data(self, **kwargs):
        kwargs = super(ClubMailingView, self).get_context_data(**kwargs)
601 602
        kwargs["club"] = self.get_object()
        kwargs["user"] = self.request.user
603
        kwargs["mailings"] = self.mailings
604 605 606
        kwargs["mailings_moderated"] = (
            kwargs["mailings"].exclude(is_moderated=False).all()
        )
607 608 609
        kwargs["mailings_not_moderated"] = (
            kwargs["mailings"].exclude(is_moderated=True).all()
        )
610 611 612
        kwargs["form_actions"] = {
            "NEW_MALING": self.form_class.ACTION_NEW_MAILING,
            "NEW_SUBSCRIPTION": self.form_class.ACTION_NEW_SUBSCRIPTION,
613
            "REMOVE_SUBSCRIPTION": self.form_class.ACTION_REMOVE_SUBSCRIPTION,
614
        }
Sli's avatar
Sli committed
615 616
        return kwargs

617
    def add_new_mailing(self, cleaned_data) -> ValidationError:
618 619 620 621
        """
        Create a new mailing list from the form
        """
        mailing = Mailing(
622
            club=self.get_object(),
623
            email=cleaned_data["mailing_email"],
624
            moderator=self.request.user,
625 626
            is_moderated=False,
        )
627 628 629 630
        try:
            mailing.clean()
        except ValidationError as validation_error:
            return validation_error
631
        mailing.save()
632
        return None
Sli's avatar
Sli committed
633

634
    def add_new_subscription(self, cleaned_data) -> ValidationError:
635 636 637
        """
        Add mailing subscriptions for each user given and/or for the specified email in form
        """
Sli's avatar
Sli committed
638 639
        users_to_save = []

640 641 642 643
        for user in cleaned_data["subscription_users"]:
            sub = MailingSubscription(
                mailing=cleaned_data["subscription_mailing"], user=user
            )
Sli's avatar
Sli committed
644 645 646 647 648
            try:
                sub.clean()
            except ValidationError as validation_error:
                return validation_error

649 650
            sub.save()
            users_to_save.append(sub)
Sli's avatar
Sli committed
651

652 653 654 655 656
        if cleaned_data["subscription_email"]:
            sub = MailingSubscription(
                mailing=cleaned_data["subscription_mailing"],
                email=cleaned_data["subscription_email"],
            )
657 658

        try:
659
            sub.clean()
660 661 662 663
        except ValidationError as validation_error:
            return validation_error
        sub.save()

Sli's avatar
Sli committed
664 665 666 667
        # Save users after we are sure there is no error
        for user in users_to_save:
            user.save()

668
        return None
Sli's avatar
Sli committed
669

670 671 672 673 674 675 676 677 678 679 680 681 682
    def remove_subscription(self, cleaned_data):
        """
        Remove specified users from a mailing list
        """
        fields = [
            cleaned_data[key]
            for key in cleaned_data.keys()
            if key.startswith("removal_")
        ]
        for field in fields:
            for sub in field:
                sub.delete()

683 684
    def form_valid(self, form):
        resp = super(ClubMailingView, self).form_valid(form)
Sli's avatar
Sli committed
685

686
        cleaned_data = form.clean()
687
        error = None
Sli's avatar
Sli committed
688

689
        if cleaned_data["action"] == self.form_class.ACTION_NEW_MAILING:
690
            error = self.add_new_mailing(cleaned_data)
Sli's avatar
Sli committed
691

692
        if cleaned_data["action"] == self.form_class.ACTION_NEW_SUBSCRIPTION:
693
            error = self.add_new_subscription(cleaned_data)
694

695 696 697
        if cleaned_data["action"] == self.form_class.ACTION_REMOVE_SUBSCRIPTION:
            self.remove_subscription(cleaned_data)

698 699 700 701
        if error:
            form.add_error(NON_FIELD_ERRORS, error)
            return self.form_invalid(form)

702
        return resp
Sli's avatar
Sli committed
703 704

    def get_success_url(self, **kwargs):
705
        return reverse_lazy("club:mailing", kwargs={"club_id": self.get_object().id})
Sli's avatar
Sli committed
706 707 708 709 710


class MailingDeleteView(CanEditMixin, DeleteView):

    model = Mailing
Sli's avatar
Sli committed
711
    template_name = "core/delete_confirm.jinja"
Sli's avatar
Sli committed
712
    pk_url_kwarg = "mailing_id"
Sli's avatar
Sli committed
713
    redirect_page = None
Sli's avatar
Sli committed
714 715 716 717 718 719

    def dispatch(self, request, *args, **kwargs):
        self.club_id = self.get_object().club.id
        return super(MailingDeleteView, self).dispatch(request, *args, **kwargs)

    def get_success_url(self, **kwargs):
Sli's avatar
Sli committed
720 721 722
        if self.redirect_page:
            return reverse_lazy(self.redirect_page)
        else:
Sli's avatar
Sli committed
723
            return reverse_lazy("club:mailing", kwargs={"club_id": self.club_id})
Sli's avatar
Sli committed
724 725 726 727 728


class MailingSubscriptionDeleteView(CanEditMixin, DeleteView):

    model = MailingSubscription
Sli's avatar
Sli committed
729
    template_name = "core/delete_confirm.jinja"
Sli's avatar
Sli committed
730 731 732 733
    pk_url_kwarg = "mailing_subscription_id"

    def dispatch(self, request, *args, **kwargs):
        self.club_id = self.get_object().mailing.club.id
Sli's avatar
Sli committed
734 735 736
        return super(MailingSubscriptionDeleteView, self).dispatch(
            request, *args, **kwargs
        )
Sli's avatar
Sli committed
737 738

    def get_success_url(self, **kwargs):
Sli's avatar
Sli committed
739
        return reverse_lazy("club:mailing", kwargs={"club_id": self.club_id})
Sli's avatar
Sli committed
740

741

Sli's avatar
Sli committed
742 743
class MailingAutoGenerationView(View):
    def dispatch(self, request, *args, **kwargs):
Sli's avatar
Sli committed
744
        self.mailing = get_object_or_404(Mailing, pk=kwargs["mailing_id"])
Sli's avatar
Sli committed
745 746 747 748 749 750
        if not request.user.can_edit(self.mailing):
            raise PermissionDenied
        return super(MailingAutoGenerationView, self).dispatch(request, *args, **kwargs)

    def get(self, request, *args, **kwargs):
        club = self.mailing.club
751
        self.mailing.subscriptions.all().delete()
Sli's avatar
Sli committed
752 753 754
        members = club.members.filter(
            role__gte=settings.SITH_CLUB_ROLES_ID["Board member"]
        ).exclude(end_date__lte=timezone.now())
Sli's avatar
Sli committed
755 756
        for member in members.all():
            MailingSubscription(user=member.user, mailing=self.mailing).save()
Sli's avatar
Sli committed
757
        return redirect("club:mailing", club_id=club.id)
Sli's avatar
Sli committed
758

759

760
class PosterListView(ClubTabsMixin, PosterListBaseView, CanViewMixin):
761 762
    """List communication posters"""

Sli's avatar
Sli committed
763 764
    def get_object(self):
        return self.club
Nicolas Ballet's avatar
Nicolas Ballet committed
765

766 767
    def get_context_data(self, **kwargs):
        kwargs = super(PosterListView, self).get_context_data(**kwargs)
Sli's avatar
Sli committed
768 769
        kwargs["app"] = "club"
        kwargs["club"] = self.club
770 771 772
        return kwargs


Nicolas Ballet's avatar
Nicolas Ballet committed
773
class PosterCreateView(PosterCreateBaseView, CanCreateMixin):
774 775
    """Create communication poster"""

776
    pk_url_kwarg = "club_id"
777

778 779 780 781 782 783 784
    def get_object(self):
        obj = super(PosterCreateView, self).get_object()
        if not obj:
            return self.club
        return obj

    def get_success_url(self, **kwargs):
Sli's avatar
Sli committed
785
        return reverse_lazy("club:poster_list", kwargs={"club_id": self.club.id})
786

Nicolas Ballet's avatar
Nicolas Ballet committed
787 788

class PosterEditView(ClubTabsMixin, PosterEditBaseView, CanEditMixin):
789 790
    """Edit communication poster"""

Nicolas Ballet's avatar
Nicolas Ballet committed
791
    def get_success_url(self):
Sli's avatar
Sli committed
792
        return reverse_lazy("club:poster_list", kwargs={"club_id": self.club.id})
793 794 795

    def get_context_data(self, **kwargs):
        kwargs = super(PosterEditView, self).get_context_data(**kwargs)
Sli's avatar
Sli committed
796
        kwargs["app"] = "club"
797 798
        return kwargs

Nicolas Ballet's avatar
Nicolas Ballet committed
799 800 801 802 803

class PosterDeleteView(PosterDeleteBaseView, ClubTabsMixin, CanEditMixin):
    """Delete communication poster"""

    def get_success_url(self):
Sli's avatar
Sli committed
804
        return reverse_lazy("club:poster_list", kwargs={"club_id": self.club.id})