extensions-website/reviewers/views.py

150 lines
5.6 KiB
Python

from collections import defaultdict
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
import django.forms
from extensions.models import Extension
from reviewers.forms import CommentForm
from reviewers.models import ApprovalActivity
log = logging.getLogger(__name__)
# the ordering of this list determines the order of rows in approval queue listing
STATUS_CHANGE_TYPES = [
ApprovalActivity.ActivityType.AWAITING_REVIEW,
ApprovalActivity.ActivityType.AWAITING_CHANGES,
ApprovalActivity.ActivityType.APPROVED,
]
class ApprovalQueueView(ListView):
model = Extension
paginate_by = 50
def get_queryset(self):
qs = ApprovalActivity.objects.prefetch_related(
'extension',
'extension__authors',
'extension__icon',
'extension__versions',
'extension__versions__file',
'extension__versions__file__validation',
).order_by('-id')
by_extension = {}
by_date_created = []
for item in qs:
extension = item.extension
stats = by_extension.get(extension, None)
if not stats:
# this check guarantees that we add a record only once per extension,
# and iterating over qs we get by_date_created also ordered by item.date_created
stats = {
'count': 0,
'extension': extension,
'last_activity': None,
'last_type_display': None,
'type': None,
}
by_extension[extension] = stats
by_date_created.append(stats)
stats['count'] += 1
if not stats.get('last_activity', None):
stats['last_activity'] = item
if not stats.get('last_type_display', None) and item.type in STATUS_CHANGE_TYPES:
stats['last_type_display'] = item.get_type_display()
stats['type'] = item.type
groupped_by_type = defaultdict(list)
for stats in by_date_created:
type = stats['type'] or ApprovalActivity.ActivityType.AWAITING_REVIEW
groupped_by_type[type].append(stats)
result = []
for type in STATUS_CHANGE_TYPES:
result.extend(groupped_by_type[type])
return result
template_name = 'reviewers/extensions_review_list.html'
class ExtensionsApprovalDetailView(DetailView):
model = Extension
template_name = 'reviewers/extensions_review_detail.html'
def get_queryset(self):
return self.model.objects.prefetch_related(
'authors',
'preview_set',
'preview_set__file',
'versions',
).all()
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['review_activity'] = (
self.object.review_activity.select_related('user')
.prefetch_related('user__groups')
.order_by('date_created')
.all()
)
ctx['status_change_types'] = STATUS_CHANGE_TYPES
if self.request.user.is_authenticated:
initial = {}
if 'report_compatibility_issue' in self.request.GET:
version = self.request.GET.get('version')
initial['message'] = (
f'Compatibility range for version {version} is outdated\n'
'Platform: ...\n'
'Version of Blender where the add-on is **no longer** working: ?????'
)
form = ctx['comment_form'] = CommentForm(initial=initial)
# anyone can comment
filtered_activity_types = {ApprovalActivity.ActivityType.COMMENT}
user = self.request.user
if self.object.has_maintainer(user):
filtered_activity_types.add(ApprovalActivity.ActivityType.AWAITING_REVIEW)
if user.is_moderator or user.is_superuser:
filtered_activity_types.update(
[
ApprovalActivity.ActivityType.APPROVED,
ApprovalActivity.ActivityType.AWAITING_CHANGES,
]
)
choices = list(
filter(
lambda c: c[0] in filtered_activity_types, ApprovalActivity.ActivityType.choices
)
)
form.fields['type'].choices = choices
form.fields['type'].widget.choices = choices
if len(choices) == 1:
form.fields['type'].widget = django.forms.HiddenInput()
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)