evorepo/packages/views/signoff.py

189 lines
7.1 KiB
Python
Raw Normal View History

from datetime import datetime
from operator import attrgetter
from django import forms
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.models import User
from django.core.serializers.json import DjangoJSONEncoder
from django.db import transaction
from django.http import HttpResponse, Http404
from django.shortcuts import get_list_or_404, redirect, render
from django.utils import simplejson
from django.views.decorators.cache import never_cache
from django.views.generic.simple import direct_to_template
from main.models import Package, Arch, Repo
from ..models import SignoffSpecification, Signoff
from ..utils import (get_signoff_groups, approved_by_signoffs,
PackageSignoffGroup)
@permission_required('main.change_package')
@never_cache
def signoffs(request):
signoff_groups = sorted(get_signoff_groups(), key=attrgetter('pkgbase'))
for group in signoff_groups:
group.user = request.user
context = {
'signoff_groups': signoff_groups,
'arches': Arch.objects.all(),
'repo_names': sorted(set(g.target_repo for g in signoff_groups)),
}
return direct_to_template(request, 'packages/signoffs.html', context)
@permission_required('main.change_package')
@never_cache
def signoff_package(request, name, repo, arch, revoke=False):
packages = get_list_or_404(Package, pkgbase=name,
arch__name=arch, repo__name__iexact=repo, repo__testing=True)
package = packages[0]
spec = SignoffSpecification.objects.get_or_default_from_package(package)
if revoke:
try:
signoff = Signoff.objects.get_from_package(
package, request.user, False)
except Signoff.DoesNotExist:
raise Http404
signoff.revoked = datetime.utcnow()
signoff.save()
created = False
else:
# ensure we should even be accepting signoffs
if spec.known_bad or not spec.enabled:
return render(request, '403.html', status=403)
signoff, created = Signoff.objects.get_or_create_from_package(
package, request.user)
all_signoffs = Signoff.objects.for_package(package)
if request.is_ajax():
data = {
'created': created,
'revoked': bool(signoff.revoked),
'approved': approved_by_signoffs(all_signoffs, spec),
'required': spec.required,
'enabled': spec.enabled,
'known_bad': spec.known_bad,
'user': str(request.user),
}
return HttpResponse(simplejson.dumps(data, ensure_ascii=False),
mimetype='application/json')
return redirect('package-signoffs')
class SignoffOptionsForm(forms.ModelForm):
apply_all = forms.BooleanField(required=False,
help_text="Apply these options to all architectures?")
class Meta:
model = SignoffSpecification
fields = ('required', 'enabled', 'known_bad', 'comments')
def _signoff_options_all(request, name, repo):
seen_ids = set()
with transaction.commit_on_success():
# find or create a specification for all architectures, then
# graft the form data onto them
packages = Package.objects.filter(pkgbase=name,
repo__name__iexact=repo, repo__testing=True)
for package in packages:
try:
spec = SignoffSpecification.objects.get_from_package(package)
if spec.pk in seen_ids:
continue
except SignoffSpecification.DoesNotExist:
spec = SignoffSpecification(pkgbase=package.pkgbase,
pkgver=package.pkgver, pkgrel=package.pkgrel,
epoch=package.epoch, arch=package.arch,
repo=package.repo)
spec.user = request.user
form = SignoffOptionsForm(request.POST, instance=spec)
if form.is_valid():
form.save()
seen_ids.add(form.instance.pk)
@permission_required('main.change_package')
@never_cache
def signoff_options(request, name, repo, arch):
packages = get_list_or_404(Package, pkgbase=name,
arch__name=arch, repo__name__iexact=repo, repo__testing=True)
package = packages[0]
if request.user != package.packager and \
request.user not in package.maintainers:
return render(request, '403.html', status=403)
try:
spec = SignoffSpecification.objects.get_from_package(package)
except SignoffSpecification.DoesNotExist:
# create a fake one, but don't save it just yet
spec = SignoffSpecification(pkgbase=package.pkgbase,
pkgver=package.pkgver, pkgrel=package.pkgrel,
epoch=package.epoch, arch=package.arch, repo=package.repo)
spec.user = request.user
if request.POST:
form = SignoffOptionsForm(request.POST, instance=spec)
if form.is_valid():
if form.cleaned_data['apply_all']:
_signoff_options_all(request, name, repo)
else:
form.save()
return redirect('package-signoffs')
else:
form = SignoffOptionsForm(instance=spec)
context = {
'packages': packages,
'package': package,
'form': form,
}
return direct_to_template(request, 'packages/signoff_options.html', context)
class SignoffJSONEncoder(DjangoJSONEncoder):
'''Base JSONEncoder extended to handle all serialization of all classes
related to signoffs.'''
signoff_group_attrs = ['arch', 'last_update', 'maintainers', 'packager',
'pkgbase', 'repo', 'signoffs', 'target_repo', 'version']
signoff_spec_attrs = ['required', 'enabled', 'known_bad', 'comments']
signoff_attrs = ['user', 'created', 'revoked']
def default(self, obj):
if isinstance(obj, PackageSignoffGroup):
data = dict((attr, getattr(obj, attr))
for attr in self.signoff_group_attrs)
data['pkgnames'] = [p.pkgname for p in obj.packages]
data['package_count'] = len(obj.packages)
data['approved'] = obj.approved()
data.update((attr, getattr(obj.specification, attr))
for attr in self.signoff_spec_attrs)
return data
elif isinstance(obj, Signoff):
data = dict((attr, getattr(obj, attr))
for attr in self.signoff_attrs)
return data
elif isinstance(obj, Arch) or isinstance(obj, Repo):
return unicode(obj)
elif isinstance(obj, User):
return obj.username
elif isinstance(obj, set):
return list(obj)
return super(SignoffJSONEncoder, self).default(obj)
@permission_required('main.change_package')
@never_cache
def signoffs_json(request):
signoff_groups = sorted(get_signoff_groups(), key=attrgetter('pkgbase'))
data = {
'version': 1,
'signoff_groups': signoff_groups,
}
to_json = simplejson.dumps(data, ensure_ascii=False,
cls=SignoffJSONEncoder)
response = HttpResponse(to_json, mimetype='application/json')
return response
# vim: set ts=4 sw=4 et: