Add activity log and RSS feeds
authorMagnus Hagander <magnus@hagander.net>
Tue, 20 Jan 2015 21:49:30 +0000 (22:49 +0100)
committerMagnus Hagander <magnus@hagander.net>
Tue, 20 Jan 2015 21:49:30 +0000 (22:49 +0100)
This somehow got dropped from the old site in a feature branch that
was never merged...

pgcommitfest/commitfest/feeds.py [new file with mode: 0644]
pgcommitfest/commitfest/templates/activity.html [new file with mode: 0644]
pgcommitfest/commitfest/templates/base.html
pgcommitfest/commitfest/views.py
pgcommitfest/urls.py

diff --git a/pgcommitfest/commitfest/feeds.py b/pgcommitfest/commitfest/feeds.py
new file mode 100644 (file)
index 0000000..dc37924
--- /dev/null
@@ -0,0 +1,38 @@
+from django.contrib.syndication.views import Feed
+
+class ActivityFeed(Feed):
+       title = description = 'Commitfest Activity Log'
+       link = 'https://commitfest.postgresql.org/'
+
+       def __init__(self, activity, cf, *args, **kwargs):
+               super(ActivityFeed, self).__init__(*args, **kwargs)
+               self.activity = activity
+               if cf:
+                       self.cfid = cf.id
+                       self.title = self.description = 'PostgreSQL Commitfest {0} Activity Log'.format(cf.name)
+               else:
+                       self.cfid = None
+
+       def items(self):
+               return self.activity
+
+       def item_title(self, item):
+               if self.cfid:
+                       return item['name']
+               else:
+                       return '{cfname}: {name}'.format(**item)
+
+       def item_description(self, item):
+               if self.cfid:
+                       return "<div>Patch: {name}</div><div>User: {by}</div>\n<div>{what}</div>".format(**item)
+               else:
+                       return "<div>Commitfest: {cfname}</div><div>Patch: {name}</div><div>User: {by}</div><div>{what}</div>".format(**item)
+
+       def item_link(self, item):
+               if self.cfid:
+                       return 'https://commitfest.postgresql.org/{cfid}/{patchid}/'.format(cfid=self.cfid,**item)
+               else:
+                       return 'https://commitfest.postgresql.org/{cfid}/{patchid}/'.format(**item)
+
+       def item_pubdate(self, item):
+               return item['date']
diff --git a/pgcommitfest/commitfest/templates/activity.html b/pgcommitfest/commitfest/templates/activity.html
new file mode 100644 (file)
index 0000000..a864eee
--- /dev/null
@@ -0,0 +1,28 @@
+{%extends "base.html"%}
+{%load commitfest %}
+{%block contents%}
+
+<table class="table table-striped table-bordered table-hover table-condensed">
+ <thead>
+  <tr>
+   <th>Time</th>
+   <th>User</th>
+{%if not commitfest%}<th>CommitFest</th>{%endif%}
+   <th>Patch</th>
+   <th>Activity</th>
+  </tr>
+ </thead>
+ <tbody>
+{%for a in activity %}
+  <tr>
+    <td style="white-space: nowrap;">{{a.date}}</td>
+    <td>{{a.by}}</td>
+{%if not commitfest%}<td>{{a.cfname}}</td>{%endif%}
+    <td><a href="/{%if commitfest%}{{commitfest.id}}{%else%}{{a.cfid}}{%endif%}/{{a.patchid}}/">{{a.name}}</a></td>
+    <td>{{a.what}}</td>
+  </tr>
+{%endfor%}
+ </tbody>
+</table>
+
+{%endblock%}
index 14be28bd3cf0dfa0ea978001977b8ba1f5a8af33..e60f3a9074e1455588805a364e0debbff2442690 100644 (file)
@@ -8,6 +8,7 @@
   <link rel="stylesheet" href="/static/commitfest/css/bootstrap.css" />
   <link rel="stylesheet" href="/static/commitfest/css/bootstrap-theme.min.css" />
   <link rel="shortcut icon" href="/static/commitfest/favicon.ico" />
+{%if rss_alternate%}  <link rel="alternate" type="application/rss+xml" title="{{rss_alternate_title}}" href="{{rss_alternate}}" />{%endif%}
 </head>
 <body>
 <div class="container-fluid">
@@ -24,6 +25,7 @@
  <a href="/account/login/?next={{request.path}}">Log in</a>
 {%endif%}
  </li>
+{%if header_activity%} <li class="pull-right active"><a href="{{header_activity_link}}">{{header_activity}}</a></li>{%endif%}
 </ul>
 
 <h1>{{title}}</h1>
index b04030bce878b86752d9a06cfac09fee0311a05d..f9ec991bc7c1319fe24f544ee7f5caf1d4a3c187 100644 (file)
@@ -1,7 +1,7 @@
 from django.shortcuts import render_to_response, get_object_or_404
 from django.http import HttpResponseRedirect, Http404, HttpResponseForbidden
 from django.template import RequestContext
-from django.db import transaction
+from django.db import transaction, connection
 from django.db.models import Q
 from django.contrib import messages
 from django.contrib.auth.decorators import login_required
@@ -19,6 +19,7 @@ from models import CommitFest, Patch, PatchOnCommitFest, PatchHistory, Committer
 from forms import PatchForm, NewPatchForm, CommentForm, CommitFestFilterForm
 from forms import BulkEmailForm
 from ajax import doAttachThread
+from feeds import ActivityFeed
 
 def home(request):
        commitfests = list(CommitFest.objects.all())
@@ -30,6 +31,50 @@ def home(request):
                'opencf': opencf,
                'inprogresscf': inprogresscf,
                'title': 'Commitfests',
+               'header_activity': 'Activity log',
+               'header_activity_link': '/activity/',
+               }, context_instance=RequestContext(request))
+
+
+def activity(request, cfid=None, rss=None):
+       # Number of notes to fetch
+       if rss:
+               num = 50
+       else:
+               num = 100
+
+       if cfid:
+               cf = get_object_or_404(CommitFest, pk=cfid)
+
+               # Yes, we do string concatenation of the were clause. Because
+               # we're evil.  And also because the number has been verified
+               # when looking up the cf itself, so nothing can be injected
+               # there.
+               extrafields = ''
+               where = 'WHERE poc.commitfest_id={0}'.format(cf.id)
+       else:
+               cf = None
+               extrafields = ',poc.commitfest_id AS cfid,cf.name AS cfname'
+               where = ' INNER JOIN commitfest_commitfest cf ON cf.id=poc.commitfest_id'
+
+       sql = "SELECT ph.date, auth_user.username AS by, ph.what, p.id AS patchid, p.name{0} FROM commitfest_patchhistory ph INNER JOIN commitfest_patch p ON ph.patch_id=p.id INNER JOIN auth_user on auth_user.id=ph.by_id INNER JOIN commitfest_patchoncommitfest poc ON poc.patch_id=p.id {1} ORDER BY ph.date DESC LIMIT {2}".format(extrafields,where, num)
+
+       curs = connection.cursor()
+       curs.execute(sql)
+       activity = [dict(zip([c[0] for c in curs.description],r)) for r in curs.fetchall()]
+
+       if rss:
+               # Return RSS feed with these objects
+               return ActivityFeed(activity, cf)(request)
+       else:
+               # Return regular webpage
+               return render_to_response('activity.html', {
+                       'commitfest': cf,
+                       'activity': activity,
+                       'title': cf and 'Commitfest activity' or 'Global Commitfest activity',
+                       'rss_alternate': cf and '/{0}/activity.rss/'.format(cf.id) or '/activity.rss/',
+                       'rss_alternate_title': 'PostgreSQL Commitfest Activity Log',
+                       'breadcrumbs': cf and [{'title': cf.title, 'href': '/%s/' % cf.pk},] or None,
                }, context_instance=RequestContext(request))
 
 def redir(request, what):
@@ -114,6 +159,8 @@ def commitfest(request, cfid):
                'grouping': sortkey==0,
                'sortkey': sortkey,
                'openpatchids': [p.id for p in patches if p.is_open],
+               'header_activity': 'Activity log',
+               'header_activity_link': 'activity/',
                }, context_instance=RequestContext(request))
 
 def global_search(request):
index ef1d38c0fe2f540ee319f684a7604db251133f00..a715c7166d83f52641ae0ea3a28394d0ec29f6b4 100644 (file)
@@ -7,8 +7,10 @@ admin.autodiscover()
 
 urlpatterns = patterns('',
     url(r'^$', 'commitfest.views.home'),
+    url(r'^activity(?P<rss>\.rss)?/', 'commitfest.views.activity'),
     url(r'^(\d+)/$', 'commitfest.views.commitfest'),
     url(r'^(open|inprogress)/$', 'commitfest.views.redir'),
+    url(r'^(?P<cfid>\d+)/activity(?P<rss>\.rss)?/$', 'commitfest.views.activity'),
     url(r'^(\d+)/(\d+)/$', 'commitfest.views.patch'),
     url(r'^(\d+)/(\d+)/edit/$', 'commitfest.views.patchform'),
     url(r'^(\d+)/new/$', 'commitfest.views.newpatch'),