diff options
author | Nicolás Reynolds <fauno@kiwwwi.com.ar> | 2011-05-21 02:11:13 -0300 |
---|---|---|
committer | Nicolás Reynolds <fauno@kiwwwi.com.ar> | 2011-05-21 02:11:13 -0300 |
commit | a30350ac6e76c66d14f6d78ed2b5ae4e5799c79c (patch) | |
tree | a2b7127366a1b9d8d5be9fcda5abefacef7d2579 /devel | |
parent | d8f82d9d72eec6042536797f75e06a9296f4cc71 (diff) | |
parent | 2470c543d60c96343a5b0fefe04464b5b445b859 (diff) |
Merge branch 'master' of git://projects.archlinux.org/archweb
Conflicts:
devel/views.py
feeds.py
templates/devel/index.html
templates/packages/flag.html
templates/public/index.html
todolists/views.py
urls.py
Diffstat (limited to 'devel')
-rw-r--r-- | devel/management/commands/reporead.py | 6 | ||||
-rw-r--r-- | devel/urls.py | 9 | ||||
-rw-r--r-- | devel/views.py | 142 |
3 files changed, 130 insertions, 27 deletions
diff --git a/devel/management/commands/reporead.py b/devel/management/commands/reporead.py index e26bb800..a8875c7e 100644 --- a/devel/management/commands/reporead.py +++ b/devel/management/commands/reporead.py @@ -315,7 +315,7 @@ def populate_files(dbpkg, repopkg, force=False): directory=dirname + '/', filename=filename) pkgfile.save(force_insert=True) - dbpkg.files_last_update = datetime.now() + dbpkg.files_last_update = datetime.utcnow() dbpkg.save() @transaction.commit_on_success @@ -374,7 +374,7 @@ def db_update(archname, reponame, pkgs, options): for p in [x for x in pkgs if x.name in in_sync_not_db]: logger.info("Adding package %s", p.name) pkg = Package(pkgname = p.name, arch = architecture, repo = repository) - populate_pkg(pkg, p, timestamp=datetime.now()) + populate_pkg(pkg, p, timestamp=datetime.utcnow()) # packages in database and not in syncdb (remove from database) in_db_not_sync = dbset - syncset @@ -398,7 +398,7 @@ def db_update(archname, reponame, pkgs, options): if not force: continue else: - timestamp = datetime.now() + timestamp = datetime.utcnow() if filesonly: logger.debug("Checking files for package %s in database", p.name) populate_files(dbp, p, force=force) diff --git a/devel/urls.py b/devel/urls.py index 41be2b31..9bf50f45 100644 --- a/devel/urls.py +++ b/devel/urls.py @@ -1,12 +1,13 @@ from django.conf.urls.defaults import patterns urlpatterns = patterns('devel.views', - (r'^$', 'index'), + (r'^admin_log/$','admin_log'), + (r'^admin_log/(?P<username>.*)/$','admin_log'), (r'^clock/$', 'clock'), - (r'^profile/$', 'change_profile'), + (r'^$', 'index'), (r'^newuser/$', 'new_user_form'), - (r'^admin_log/(?P<username>.*)/$','admin_log'), - (r'^admin_log/$','admin_log'), + (r'^profile/$', 'change_profile'), + (r'^reports/(?P<report>.*)/$', 'report'), ) # vim: set ts=4 sw=4 et: diff --git a/devel/views.py b/devel/views.py index 5b03f8c0..5d34cc41 100644 --- a/devel/views.py +++ b/devel/views.py @@ -2,21 +2,27 @@ from django import forms from django.http import HttpResponseRedirect from django.contrib.auth.decorators import \ login_required, permission_required, user_passes_test -from django.contrib.auth.models import User +from django.contrib.auth.models import User, Group from django.contrib.sites.models import Site from django.core.mail import send_mail +from django.db import transaction +from django.db.models import Q +from django.http import Http404 from django.shortcuts import get_object_or_404 from django.template import loader, Context +from django.template.defaultfilters import filesizeformat from django.views.decorators.cache import never_cache from django.views.generic.simple import direct_to_template -from main.models import Package, Todolist, TodolistPkg +from main.models import Package, PackageDepend, PackageFile, TodolistPkg from main.models import Arch, Repo from main.models import UserProfile from packages.models import PackageRelation +from todolists.utils import get_annotated_todolists from .utils import get_annotated_maintainers -import datetime +from datetime import datetime, timedelta +import operator import pytz import random from string import ascii_letters, digits @@ -24,7 +30,7 @@ from string import ascii_letters, digits @login_required @never_cache def index(request): - '''the Developer dashboard''' + '''the developer dashboard''' inner_q = PackageRelation.objects.filter(user=request.user).values('pkgbase') flagged = Package.objects.select_related('arch', 'repo').filter( flag_date__isnull=False, pkgbase__in=inner_q).order_by('pkgname') @@ -34,6 +40,9 @@ def index(request): todopkgs = todopkgs.filter(pkg__pkgbase__in=inner_q).order_by( 'list__name', 'pkg__pkgname') + todolists = get_annotated_todolists() + todolists = [todolist for todolist in todolists if todolist.incomplete_count > 0] + maintainers = get_annotated_maintainers() maintained = PackageRelation.objects.filter( @@ -47,7 +56,7 @@ def index(request): } page_dict = { - 'todos': Todolist.objects.incomplete().order_by('-date_added'), + 'todos': todolists, 'repos': Repo.objects.all(), 'arches': Arch.objects.all(), 'maintainers': maintainers, @@ -65,8 +74,8 @@ def clock(request): 'username').select_related('userprofile') # now annotate each dev object with their current time - now = datetime.datetime.now() - utc_now = datetime.datetime.utcnow().replace(tzinfo=pytz.utc) + now = datetime.now() + utc_now = datetime.utcnow().replace(tzinfo=pytz.utc) for dev in devs: # Work around https://bugs.launchpad.net/pytz/+bug/718673 timezone = str(dev.userprofile.time_zone) @@ -118,14 +127,84 @@ def change_profile(request): return direct_to_template(request, 'devel/profile.html', {'form': form, 'profile_form': profile_form}) +@login_required +def report(request, report): + title = 'Developer Report' + packages = Package.objects.select_related('arch', 'repo') + names = attrs = None + if report == 'old': + title = 'Packages last built more than two years ago' + cutoff = datetime.now() - timedelta(days=730) + packages = packages.filter(build_date__lt=cutoff).order_by('build_date') + elif report == 'big': + title = 'Packages with compressed size > 50 MiB' + cutoff = 50 * 1024 * 1024 + packages = packages.filter(compressed_size__gte=cutoff).order_by('-compressed_size') + names = [ 'Compressed Size', 'Installed Size' ] + attrs = [ 'compressed_size_pretty', 'installed_size_pretty' ] + # Format the compressed and installed sizes with MB/GB/etc suffixes + for package in packages: + package.compressed_size_pretty = filesizeformat( + package.compressed_size) + package.installed_size_pretty = filesizeformat( + package.installed_size) + elif report == 'uncompressed-man': + title = 'Packages with uncompressed manpages' + # magic going on here! Checking for all '.1'...'.9' extensions + invalid_endings = [Q(filename__endswith='.%d' % n) for n in range(1,10)] + invalid_endings.append(Q(filename__endswith='.n')) + bad_files = PackageFile.objects.filter(Q(directory__contains='man') & ( + reduce(operator.or_, invalid_endings)) + ).values_list('pkg_id', flat=True).distinct() + packages = packages.filter(id__in=set(bad_files)) + elif report == 'uncompressed-info': + title = 'Packages with uncompressed infopages' + # we don't worry abut looking for '*.info-1', etc., given that an + # uncompressed root page probably exists in the package anyway + bad_files = PackageFile.objects.filter(directory__endswith='/info/', + filename__endswith='.info').values_list( + 'pkg_id', flat=True).distinct() + packages = packages.filter(id__in=set(bad_files)) + elif report == 'unneeded-orphans': + title = 'Orphan packages required by no other packages' + owned = PackageRelation.objects.all().values('pkgbase') + required = PackageDepend.objects.all().values('depname') + # The two separate calls to exclude is required to do the right thing + packages = packages.exclude(pkgbase__in=owned).exclude( + pkgname__in=required) + else: + raise Http404 + + context = { + 'title': title, + 'packages': packages, + 'column_names': names, + 'column_attrs': attrs, + } + return direct_to_template(request, 'devel/packages.html', context) + + class NewUserForm(forms.ModelForm): - class Meta: - model = UserProfile - exclude = ('picture', 'user') username = forms.CharField(max_length=30) - email = forms.EmailField() + private_email = forms.EmailField() first_name = forms.CharField(required=False) last_name = forms.CharField(required=False) + groups = forms.ModelMultipleChoiceField(required=False, + queryset=Group.objects.all()) + + class Meta: + model = UserProfile + exclude = ('picture', 'user') + + def __init__(self, *args, **kwargs): + super(NewUserForm, self).__init__(*args, **kwargs) + # Hack ourself so certain fields appear first. self.fields is a + # SortedDict object where we can manipulate the keyOrder list. + order = self.fields.keyOrder + keys = ('username', 'private_email', 'first_name', 'last_name') + for key in reversed(keys): + order.remove(key) + order.insert(0, key) def clean_username(self): username = self.cleaned_data['username'] @@ -134,38 +213,61 @@ class NewUserForm(forms.ModelForm): "A user with that username already exists.") return username - def save(self): - profile = forms.ModelForm.save(self, False) + def save(self, commit=True): + profile = super(NewUserForm, self).save(False) pwletters = ascii_letters + digits password = ''.join([random.choice(pwletters) for i in xrange(8)]) user = User.objects.create_user(username=self.cleaned_data['username'], - email=self.cleaned_data['email'], password=password) + email=self.cleaned_data['private_email'], password=password) user.first_name = self.cleaned_data['first_name'] user.last_name = self.cleaned_data['last_name'] user.save() + # sucks that the MRM.add() method can't take a list directly... we have + # to resort to dirty * magic. + user.groups.add(*self.cleaned_data['groups']) profile.user = user - profile.save() + if commit: + profile.save() + self.save_m2m() - t = loader.get_template('devel/new_account.txt') - c = Context({ + template = loader.get_template('devel/new_account.txt') + ctx = Context({ 'site': Site.objects.get_current(), 'user': user, 'password': password, }) - send_mail("Your new archweb account", - t.render(c), + send_mail("Your new parabolaweb account", + template.render(ctx), 'Parabola <dev@list.parabolagnulinux.org>', [user.email], fail_silently=False) +def log_addition(request, obj): + """Cribbed from ModelAdmin.log_addition.""" + from django.contrib.admin.models import LogEntry, ADDITION + from django.contrib.contenttypes.models import ContentType + from django.utils.encoding import force_unicode + LogEntry.objects.log_action( + user_id = request.user.pk, + content_type_id = ContentType.objects.get_for_model(obj).pk, + object_id = obj.pk, + object_repr = force_unicode(obj), + action_flag = ADDITION, + change_message = "Added via Create New User form." + ) + @permission_required('auth.add_user') @never_cache def new_user_form(request): if request.POST: form = NewUserForm(request.POST) if form.is_valid(): - form.save() + @transaction.commit_on_success + def inner_save(): + form.save() + log_addition(request, form.instance.user) + inner_save() return HttpResponseRedirect('/admin/auth/user/%d/' % \ form.instance.user.id) else: |