extensions-website/reviewers/views.py
Anna Sirota caae613747 Make it possible to fully delete unlisted/unrated extensions and versions (#81)
* removes all soft-deletion;
* shows a "Delete extension" button on the draft page in case it can be deleted;
* shows a "Delete version" button on the version page in case it can be deleted;
* a version can be deleted if
  * its file isn't approved, and it doesn't have any ratings;
* an extension can be deleted if
  * it's not listed, and doesn't have any ratings or abuse reports;
  * all it's versions can also be deleted;
* changes default `File.status` from `APPROVED` to `AWAITING_REVIEW`
  With version's file status being `APPROVED` by default, a version can never be deleted, even when the extension is still a draft.
  This change doesn't affect the approval process because
   * when an extension is approved its latest version becomes approved automatically (no change here);
   * when a new version is uploaded to an approved extension, it's approved automatically (this is new).

This allows authors to delete their drafts, freeing the extension slug and making it possible to re-upload the same file.
This also makes it possible to easily fix mistakes during the drafting of a new extension (e.g. delete a version and re-upload it without bumping a version for each typo/mistake in packaging and so on).
(see #78 and #63)

Reviewed-on: #81
2024-04-19 11:00:13 +02:00

78 lines
2.7 KiB
Python

import logging
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.list import ListView
from django.views.generic import DetailView, FormView
from django.shortcuts import reverse
from files.models import File
from extensions.models import Extension
from reviewers.forms import CommentForm
from reviewers.models import ApprovalActivity
log = logging.getLogger(__name__)
class ApprovalQueueView(ListView):
model = Extension
paginate_by = 100
def get_queryset(self):
return Extension.objects.exclude(status=Extension.STATUSES.APPROVED).order_by(
'-date_created'
)
template_name = 'reviewers/extensions_review_list.html'
class ExtensionsApprovalDetailView(DetailView):
model = Extension
template_name = 'reviewers/extensions_review_detail.html'
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['pending_previews'] = self.object.preview_set.exclude(
file__status=File.STATUSES.APPROVED
)
if self.request.user.is_authenticated:
form = ctx['comment_form'] = CommentForm()
# Remove 'Approved' status from dropdown it not moderator
if not (self.request.user.is_moderator or self.request.user.is_superuser):
filtered_activity_types = [
t
for t in ApprovalActivity.ActivityType.choices
if t[0]
not in [
ApprovalActivity.ActivityType.APPROVED,
ApprovalActivity.ActivityType.AWAITING_CHANGES,
]
]
form.fields['type'].choices = filtered_activity_types
form.fields['type'].widget.choices = filtered_activity_types
return ctx
class ExtensionsApprovalFormView(LoginRequiredMixin, FormView):
form_class = CommentForm
http_method_names = ['post']
def get_success_url(self):
return reverse('reviewers:approval-detail', kwargs={'slug': self.kwargs['slug']})
def approve_if_allowed(self, form):
if form.cleaned_data['type'] != ApprovalActivity.ActivityType.APPROVED:
return
if not (self.request.user.is_moderator or self.request.user.is_superuser):
log.error('Non-moderator tried to approve extension %s' % form.instance.extension)
return
form.instance.extension.approve()
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.extension = Extension.objects.get(slug=self.kwargs['slug'])
form.save()
self.approve_if_allowed(form)
return super().form_valid(form)