From 81884005d8496e12f9636e872eaedff33af77e30 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Wed, 5 Oct 2011 10:33:54 -0500 Subject: Allow developer index to work with a non-authenticated user This is not the normal case given the decorator on the view, but during testing and development it is sometimes useful so others don't have to log in over a non-secure connection to check things out. Signed-off-by: Dan McGee --- devel/views.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'devel/views.py') diff --git a/devel/views.py b/devel/views.py index 79eef318..ebae3b32 100644 --- a/devel/views.py +++ b/devel/views.py @@ -31,7 +31,12 @@ @never_cache def index(request): '''the developer dashboard''' - inner_q = PackageRelation.objects.filter(user=request.user).values('pkgbase') + if(request.user.is_authenticated()): + inner_q = PackageRelation.objects.filter(user=request.user) + else: + inner_q = PackageRelation.objects.none() + inner_q = inner_q.values('pkgbase') + flagged = Package.objects.normal().filter( flag_date__isnull=False, pkgbase__in=inner_q).order_by('pkgname') -- cgit v1.2.3-54-g00ecf From d8e34919811728149a12e30d438318a3c1036a83 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 3 Nov 2011 15:50:06 -0500 Subject: Use UTC now everywhere Signed-off-by: Dan McGee --- devel/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'devel/views.py') diff --git a/devel/views.py b/devel/views.py index ebae3b32..694ed6dc 100644 --- a/devel/views.py +++ b/devel/views.py @@ -80,9 +80,9 @@ def clock(request): devs = User.objects.filter(is_active=True).order_by( 'username').select_related('userprofile') - # now annotate each dev object with their current time now = datetime.now() utc_now = datetime.utcnow().replace(tzinfo=pytz.utc) + # now annotate each dev object with their current time for dev in devs: tz = pytz.timezone(dev.userprofile.time_zone) dev.current_time = utc_now.astimezone(tz) @@ -147,12 +147,12 @@ def report(request, report, username=None): if report == 'old': title = 'Packages last built more than two years ago' - cutoff = datetime.now() - timedelta(days=365 * 2) + cutoff = datetime.utcnow() - timedelta(days=365 * 2) packages = packages.filter( build_date__lt=cutoff).order_by('build_date') elif report == 'long-out-of-date': title = 'Packages marked out-of-date more than 90 days ago' - cutoff = datetime.now() - timedelta(days=90) + cutoff = datetime.utcnow() - timedelta(days=90) packages = packages.filter( flag_date__lt=cutoff).order_by('flag_date') elif report == 'big': -- cgit v1.2.3-54-g00ecf From 022692b3f33de8c45741d3cb27fa95f9f6facdea Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 11 Nov 2011 10:43:18 -0600 Subject: Show relevant signoffs on dashboard Signed-off-by: Dan McGee --- devel/views.py | 5 +++++ packages/utils.py | 7 ++++++- templates/devel/index.html | 50 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 59 insertions(+), 3 deletions(-) (limited to 'devel/views.py') diff --git a/devel/views.py b/devel/views.py index 694ed6dc..0002df04 100644 --- a/devel/views.py +++ b/devel/views.py @@ -18,6 +18,7 @@ from main.models import Arch, Repo from main.models import UserProfile from packages.models import PackageRelation +from packages.utils import get_signoff_groups from todolists.utils import get_annotated_todolists from .utils import get_annotated_maintainers @@ -48,6 +49,9 @@ def index(request): todolists = get_annotated_todolists() todolists = [todolist for todolist in todolists if todolist.incomplete_count > 0] + signoffs = sorted(get_signoff_groups(user=request.user), + key=operator.attrgetter('pkgbase')) + maintainers = get_annotated_maintainers() maintained = PackageRelation.objects.filter( @@ -70,6 +74,7 @@ def index(request): 'orphan': orphan, 'flagged' : flagged, 'todopkgs' : todopkgs, + 'signoffs': signoffs } return direct_to_template(request, 'devel/index.html', page_dict) diff --git a/packages/utils.py b/packages/utils.py index b21ac557..0df0e382 100644 --- a/packages/utils.py +++ b/packages/utils.py @@ -330,7 +330,7 @@ def get_target_repo_map(repos): cursor.execute(sql, params) return dict(cursor.fetchall()) -def get_signoff_groups(repos=None): +def get_signoff_groups(repos=None, user=None): if repos is None: repos = Repo.objects.filter(testing=True) repo_ids = [r.pk for r in repos] @@ -340,6 +340,11 @@ def get_signoff_groups(repos=None): packages = test_pkgs.order_by('pkgname') packages = attach_maintainers(packages) + # Filter by user if asked to do so + if user is not None: + packages = [p for p in packages if user == p.packager + or user in p.maintainers] + # Collect all pkgbase values in testing repos pkgtorepo = get_target_repo_map(repos) diff --git a/templates/devel/index.html b/templates/devel/index.html index d3f7ec3b..06cf10ab 100644 --- a/templates/devel/index.html +++ b/templates/devel/index.html @@ -15,8 +15,8 @@

My Flagged Packages

Name - Repo Version + Repo Arch Flagged Last Updated @@ -26,8 +26,8 @@

My Flagged Packages

{% for pkg in flagged %} {% pkg_details_link pkg %} - {{ pkg.repo.name }} {{ pkg.full_version }} + {{ pkg.repo.name }} {{ pkg.arch.name }} {{ pkg.flag_date|date }} {{ pkg.last_update|date }} @@ -96,6 +96,47 @@

Package Todo Lists

+

Signoff Status

+ + + + + + + + + + + + + + + {% for group in signoffs %} + + + + + + + {% if group.specification.known_bad %} + + {% else %} + {% if not group.specification.enabled %} + + {% else %} + + {% endif %} + {% endif %} + + + {% endfor %} + +
NameVersionArchTarget RepoLast UpdatedApprovedSignoffs
{% pkg_details_link group.package %}{{ group.version }}{{ group.arch.name }}{{ group.target_repo }}{{ group.last_update|date }}BadDisabled{{ group.approved|yesno|capfirst }}
    + {% for signoff in group.signoffs %} +
  • {{ signoff.user }}{% if signoff.revoked %} (revoked){% endif %}
  • + {% endfor %} +
+

Developer Reports

  • Big: @@ -255,6 +296,11 @@

    Stats by Developer

    {widgets: ['zebra'], sortList: [[0,0], [1,0]]}); $("#dash-todo:not(:has(tbody tr.empty))").tablesorter( {widgets: ['zebra'], sortList: [[1,1]]}); + $("#dash-signoffs:not(:has(tbody tr.empty))").tablesorter({ + widgets: ['zebra'], + sortList: [[0,0]], + headers: { 6: {sorter: false } } + }); $(".dash-stats").tablesorter({ widgets: ['zebra'], sortList: [[0,0]], -- cgit v1.2.3-54-g00ecf From 85657db05d7f65604340699cfcb9967c9e81a0ef Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 21 Nov 2011 10:08:23 -0600 Subject: Better support for non-latin full names Add a 'latin_name' field to the user profile so we can better support those developers with names in non-Latin scripts, and yet still show a Latin name as necessary on the developer profile page. This field only shows up if populated. Also, use consistent sorting everywhere- rather than using username, always use first_name and last_name fields. Signed-off-by: Dan McGee --- devel/views.py | 2 +- .../0057_auto__add_field_userprofile_latin_name.py | 153 +++++++++++++++++++++ main/models.py | 2 + packages/views/search.py | 3 +- public/views.py | 6 +- templates/devel/clock.html | 2 +- templates/public/developer_list.html | 2 +- 7 files changed, 164 insertions(+), 6 deletions(-) create mode 100644 main/migrations/0057_auto__add_field_userprofile_latin_name.py (limited to 'devel/views.py') diff --git a/devel/views.py b/devel/views.py index 0002df04..08b19cd7 100644 --- a/devel/views.py +++ b/devel/views.py @@ -83,7 +83,7 @@ def index(request): @never_cache def clock(request): devs = User.objects.filter(is_active=True).order_by( - 'username').select_related('userprofile') + 'first_name', 'last_name').select_related('userprofile') now = datetime.now() utc_now = datetime.utcnow().replace(tzinfo=pytz.utc) diff --git a/main/migrations/0057_auto__add_field_userprofile_latin_name.py b/main/migrations/0057_auto__add_field_userprofile_latin_name.py new file mode 100644 index 00000000..ffde1885 --- /dev/null +++ b/main/migrations/0057_auto__add_field_userprofile_latin_name.py @@ -0,0 +1,153 @@ +# encoding: utf-8 +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + db.add_column('user_profiles', 'latin_name', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True), keep_default=False) + + def backwards(self, orm): + db.delete_column('user_profiles', 'latin_name') + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'main.arch': { + 'Meta': {'ordering': "['name']", 'object_name': 'Arch', 'db_table': "'arches'"}, + 'agnostic': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) + }, + 'main.donor': { + 'Meta': {'ordering': "('name',)", 'object_name': 'Donor', 'db_table': "'donors'"}, + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'visible': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'main.package': { + 'Meta': {'ordering': "('pkgname',)", 'unique_together': "(('pkgname', 'repo', 'arch'),)", 'object_name': 'Package', 'db_table': "'packages'"}, + 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}), + 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'compressed_size': ('main.models.PositiveBigIntegerField', [], {}), + 'epoch': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'installed_size': ('main.models.PositiveBigIntegerField', [], {}), + 'last_update': ('django.db.models.fields.DateTimeField', [], {}), + 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), + 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pgp_signature': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'pkgdesc': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}), + 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) + }, + 'main.packagedepend': { + 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, + 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'depvcmp': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'optional': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) + }, + 'main.packagefile': { + 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, + 'directory': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_directory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) + }, + 'main.repo': { + 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"}, + 'bugs_category': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'bugs_project': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'staging': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}), + 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'main.todolist': { + 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'main.todolistpkg': { + 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, + 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) + }, + 'main.userprofile': { + 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, + 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), + 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'latin_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'pgp_key': ('main.models.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), + 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), + 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'time_zone': ('django.db.models.fields.CharField', [], {'default': "'UTC'", 'max_length': '100'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'userprofile'", 'unique': 'True', 'to': "orm['auth.User']"}), + 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['main'] diff --git a/main/models.py b/main/models.py index b37468f9..d7780b91 100644 --- a/main/models.py +++ b/main/models.py @@ -77,6 +77,8 @@ class UserProfile(models.Model): help_text="Ideally 125px by 125px") user = models.OneToOneField(User, related_name='userprofile') allowed_repos = models.ManyToManyField('Repo', blank=True) + latin_name = models.CharField(max_length=255, null=True, blank=True, + help_text="Latin-form name; used only for non-Latin full names") class Meta: db_table = 'user_profiles' diff --git a/packages/views/search.py b/packages/views/search.py index 57481614..65fcddb3 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -60,7 +60,8 @@ def __init__(self, *args, **kwargs): self.fields['arch'].choices = make_choice( [arch.name for arch in Arch.objects.all()]) self.fields['q'].widget.attrs.update({"size": "30"}) - maints = User.objects.filter(is_active=True).order_by('username') + maints = User.objects.filter(is_active=True).order_by( + 'first_name', 'last_name') self.fields['maintainer'].choices = \ [('', 'All'), ('orphan', 'Orphan')] + \ [(m.username, m.get_full_name()) for m in maints] diff --git a/public/views.py b/public/views.py index 14dd6353..c28fd303 100644 --- a/public/views.py +++ b/public/views.py @@ -34,13 +34,15 @@ def index(request): } def userlist(request, user_type='devs'): - users = User.objects.order_by('username').select_related('userprofile') + users = User.objects.order_by( + 'first_name', 'last_name').select_related('userprofile') if user_type == 'devs': users = users.filter(is_active=True, groups__name="Developers") elif user_type == 'tus': users = users.filter(is_active=True, groups__name="Trusted Users") elif user_type == 'fellows': - users = users.filter(is_active=False, groups__name__in=["Developers", "Trusted Users"]) + users = users.filter(is_active=False, + groups__name__in=["Developers", "Trusted Users"]) else: raise Http404 diff --git a/templates/devel/clock.html b/templates/devel/clock.html index 0f0e20c5..d2eb0a8d 100644 --- a/templates/devel/clock.html +++ b/templates/devel/clock.html @@ -45,7 +45,7 @@

    Developer World Clocks

    {% endblock %} diff --git a/templates/public/developer_list.html b/templates/public/developer_list.html index 0ac444e5..5aa4c6b2 100644 --- a/templates/public/developer_list.html +++ b/templates/public/developer_list.html @@ -21,7 +21,7 @@ - + -- cgit v1.2.3-54-g00ecf
    Name:{{ dev.get_full_name }}{{ dev.get_full_name }}{% if prof.latin_name %} ({{ prof.latin_name}}){% endif %}
    Alias: {{ prof.alias }}