Merge lp:~andrewsomething/dat-overview/new_contacted_logic into lp:dat-overview
- new_contacted_logic
- Merge into trunk
Proposed by
Andrew Starr-Bochicchio
Status: | Merged |
---|---|
Merged at revision: | 32 |
Proposed branch: | lp:~andrewsomething/dat-overview/new_contacted_logic |
Merge into: | lp:dat-overview |
Diff against target: |
633 lines (+242/-109) 12 files modified
overview/local_settings.py.sample (+4/-2) overview/media/css/base.css (+27/-0) overview/settings.py (+6/-0) overview/templates/first_timers.html (+13/-8) overview/templates/lost_contributors.html (+3/-1) overview/templates/person.html (+41/-9) overview/templates/potential_devs.html (+5/-1) overview/uploads/forms.py (+0/-3) overview/uploads/models.py (+3/-1) overview/uploads/templatetags/custom_tags.py (+5/-0) overview/uploads/views.py (+133/-83) overview/urls.py (+2/-1) |
To merge this branch: | bzr merge lp:~andrewsomething/dat-overview/new_contacted_logic |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel Holbach | Approve | ||
Review via email: mp+170988@code.launchpad.net |
Commit message
Description of the change
This branch adds the comment-style system for tracking contacts. It also
provides some optimization of the queries used to generate the views making
things a bit snappier.
To post a comment you must log in.
Revision history for this message
Bhavani Shankar (bhavi) wrote : | # |
Revision history for this message
Daniel Holbach (dholbach) wrote : | # |
That's excellent work! :)
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'overview/local_settings.py.sample' |
2 | --- overview/local_settings.py.sample 2013-04-06 18:45:17 +0000 |
3 | +++ overview/local_settings.py.sample 2013-06-23 19:42:22 +0000 |
4 | @@ -18,5 +18,7 @@ |
5 | } |
6 | } |
7 | |
8 | - |
9 | - |
10 | +# Uncomment to use django debug_toolbar. Requires: python-django-ebug-toolbar |
11 | +#DEBUG_MIDDLEWARE_CLASSES = ('debug_toolbar.middleware.DebugToolbarMiddleware',) |
12 | +#DEBUG_APPS = ('debug_toolbar',) |
13 | +#INTERNAL_IPS = ('127.0.0.1',) |
14 | |
15 | === modified file 'overview/media/css/base.css' |
16 | --- overview/media/css/base.css 2013-06-18 23:57:17 +0000 |
17 | +++ overview/media/css/base.css 2013-06-23 19:42:22 +0000 |
18 | @@ -364,6 +364,29 @@ |
19 | box-shadow: 1px 1px 5px #CCC; |
20 | } |
21 | |
22 | +#comment{ |
23 | + max-width: 600px; |
24 | + border-radius: 3px; |
25 | + border: 1px solid #CCC; |
26 | + padding: 8px; |
27 | + font-weight: 200; |
28 | + font-size: 15px; |
29 | + font-family: Ubuntu; |
30 | + box-shadow: 1px 1px 5px #CCC; |
31 | + position: relative; |
32 | +} |
33 | + |
34 | +#comment-details{ |
35 | + padding-left:275px; |
36 | +} |
37 | + |
38 | +#comment h3{ |
39 | + position: absolute; |
40 | + bottom: 0; |
41 | + right: 5px; |
42 | + color:#A9A9A9; |
43 | +} |
44 | + |
45 | .legend{ |
46 | float:right; |
47 | } |
48 | @@ -380,3 +403,7 @@ |
49 | min-height: 304px; |
50 | background-repeat: no-repeat, repeat; |
51 | } |
52 | + |
53 | +#id_honeypot { |
54 | + display: none; |
55 | +} |
56 | |
57 | === modified file 'overview/settings.py' |
58 | --- overview/settings.py 2013-06-10 16:42:05 +0000 |
59 | +++ overview/settings.py 2013-06-23 19:42:22 +0000 |
60 | @@ -121,6 +121,7 @@ |
61 | 'django.contrib.staticfiles', |
62 | 'django_openid_auth', |
63 | 'django.contrib.admin', |
64 | + 'django.contrib.comments', |
65 | # Uncomment the next line to enable admin documentation: |
66 | # 'django.contrib.admindocs', |
67 | 'uploads', |
68 | @@ -187,7 +188,12 @@ |
69 | } |
70 | } |
71 | |
72 | + |
73 | +DEBUG_APPS = () |
74 | +DEBUG_MIDDLEWARE_CLASSES = () |
75 | try: |
76 | from local_settings import * |
77 | + INSTALLED_APPS += DEBUG_APPS |
78 | + MIDDLEWARE_CLASSES += DEBUG_MIDDLEWARE_CLASSES |
79 | except ImportError: |
80 | logging.warning("No local_settings.py were found. See INSTALL for instructions.") |
81 | |
82 | === modified file 'overview/templates/first_timers.html' |
83 | --- overview/templates/first_timers.html 2013-06-19 20:56:21 +0000 |
84 | +++ overview/templates/first_timers.html 2013-06-23 19:42:22 +0000 |
85 | @@ -1,4 +1,5 @@ |
86 | {% extends "base.html" %} |
87 | +{% load custom_tags %} |
88 | |
89 | {% block content %} |
90 | |
91 | @@ -29,8 +30,9 @@ |
92 | {% for i in output|dictsortreversed:"p.first_upload.timestamp" %} |
93 | {% if 'saucy' in i.p.first_upload.release %} |
94 | <tr class='{{ i.color }}'> |
95 | - <td>{% if i.p.contacted %} |
96 | - <center>✓</center>{% endif %} |
97 | + <td>{% if i.p|recent_contact %} |
98 | + <center>✓</center> |
99 | + {% endif %} |
100 | </td> |
101 | <td><a href="{{ i.p.lpid }}">{{ i.p.name }}</a></td> |
102 | <td> |
103 | @@ -68,8 +70,9 @@ |
104 | {% for i in output|dictsortreversed:"p.first_upload.timestamp" %} |
105 | {% if 'raring' in i.p.first_upload.release %} |
106 | <tr class='{{ i.color }}'> |
107 | - <td>{% if i.p.contacted %} |
108 | - <center>✓</center>{% endif %} |
109 | + <td>{% if i.p|recent_contact %} |
110 | + <center>✓</center> |
111 | + {% endif %} |
112 | </td> |
113 | <td><a href="{{ i.p.lpid }}">{{ i.p.name }}</a></td> |
114 | <td> |
115 | @@ -107,8 +110,9 @@ |
116 | {% for i in output|dictsortreversed:"p.first_upload.timestamp" %} |
117 | {% if 'quantal' in i.p.first_upload.release %} |
118 | <tr class='{{ i.color }}'> |
119 | - <td>{% if i.p.contacted %} |
120 | - <center>✓</center>{% endif %} |
121 | + <td>{% if i.p|recent_contact %} |
122 | + <center>✓</center> |
123 | + {% endif %} |
124 | </td> |
125 | <td><a href="{{ i.p.lpid }}">{{ i.p.name }}</a></td> |
126 | <td> |
127 | @@ -146,8 +150,9 @@ |
128 | {% for i in output|dictsortreversed:"p.first_upload.timestamp" %} |
129 | {% if 'precise' in i.p.first_upload.release %} |
130 | <tr class='{{ i.color }}'> |
131 | - <td>{% if i.p.contacted %} |
132 | - <center>✓</center>{% endif %} |
133 | + <td>{% if i.p|recent_contact %} |
134 | + <center>✓</center> |
135 | + {% endif %} |
136 | </td> |
137 | <td><a href="{{ i.p.lpid }}">{{ i.p.name }}</a></td> |
138 | <td> |
139 | |
140 | === modified file 'overview/templates/lost_contributors.html' |
141 | --- overview/templates/lost_contributors.html 2013-06-19 20:29:36 +0000 |
142 | +++ overview/templates/lost_contributors.html 2013-06-23 19:42:22 +0000 |
143 | @@ -18,7 +18,9 @@ |
144 | </tr> |
145 | {% for p in lost_contributors|dictsortreversed:"last_upload.timestamp" %} |
146 | <tr> |
147 | - <td>{% if p.contacted %}<center>✓</center>{% endif %}</td> |
148 | + <td>{% if p|recent_contact > p.last_upload.timestamp %} |
149 | + <center>✓</center>{% endif %} |
150 | + </td> |
151 | <td> |
152 | <a href="{{ p.lpid }}">{{ p.name }}</a>{% ubu_dev_img p.ubuntu_dev %} |
153 | </td> |
154 | |
155 | === modified file 'overview/templates/person.html' |
156 | --- overview/templates/person.html 2013-06-21 20:24:21 +0000 |
157 | +++ overview/templates/person.html 2013-06-23 19:42:22 +0000 |
158 | @@ -1,5 +1,6 @@ |
159 | {% extends "base.html" %} |
160 | {% load custom_tags %} |
161 | +{% load comments %} |
162 | |
163 | {% block extrahead %} |
164 | |
165 | @@ -46,24 +47,18 @@ |
166 | <li><b>Ubuntu Developer:</b> {{ person.ubuntu_dev|yesno:"Yes,No" }}</li> |
167 | <li><b>Active:</b> {{ person.is_active|yesno:"Yes,No" }}</li> |
168 | <li><b>Last Seen:</b> {{ person.last_upload.timestamp }}</li> |
169 | + <li><b>Last Contact:</b> {{ person|recent_contact }}</li> |
170 | <li><b>Total uploads:</b> {{ person.total_uploads }}</li> |
171 | {% if ppu_candidates %} |
172 | <li><b>PPU Candidates:</b> |
173 | {% for pkg in ppu_candidates %} |
174 | - <a href="https://launchpad.net/ubuntu/+source/{{ pkg }}">{{ pkg }}</a>,</li> |
175 | + <a href="https://launchpad.net/ubuntu/+source/{{ pkg }}">{{ pkg }}</a>, </li> |
176 | {% endfor %} |
177 | {% endif %} |
178 | + |
179 | </ul> |
180 | </div> |
181 | |
182 | -<div id='contacted_form'> |
183 | - <h3>Contacted?</h3> |
184 | - <form action="#" method="post">{% csrf_token %} |
185 | - {{ contacted.checkbox }} |
186 | - <input type="submit" name='update_contacted' value="Save" /> |
187 | - </form> |
188 | -</div> |
189 | - |
190 | <div id='whiteboard'> |
191 | <h2>Whiteboard:</h2> |
192 | |
193 | @@ -73,6 +68,43 @@ |
194 | </form> |
195 | </div> |
196 | |
197 | +<div id='contacts'> |
198 | + |
199 | + <h2>Record contact:</h2> |
200 | + |
201 | + <div id='comment-form'> |
202 | + {% get_comment_form for person as form %} |
203 | + <form action="{% comment_form_target %}" method="post"> |
204 | + {% csrf_token %} |
205 | + {{ form.comment }} |
206 | + {{ form.honeypot }} |
207 | + {{ form.content_type }} |
208 | + {{ form.object_pk }} |
209 | + {{ form.timestamp }} |
210 | + {{ form.security_hash }} |
211 | + <input type="hidden" name="next" value="/contributors/{{ person.lpid }}#" /> |
212 | + <input type="submit" name="submit" value="Record contact"> |
213 | + </form> |
214 | + </div> |
215 | + |
216 | + <h2>Contacts:</h2> |
217 | + |
218 | + {% get_comment_list for person as comment_list %} |
219 | + {% for comment in comment_list reversed %} |
220 | + |
221 | + <div id='comment'> |
222 | + {{ comment.comment|linebreaks }} |
223 | + <h3>#{{ forloop.revcounter }}</h3> |
224 | + </div> |
225 | + |
226 | + <div id='comment-details'> |
227 | + by <a href="/users/{{ comment.user }}">{{ comment.user }}</a> on {{ comment.submit_date }} |
228 | + </div> |
229 | + <br> |
230 | + {% endfor %} |
231 | + |
232 | +</div> |
233 | + |
234 | <div id='uploads_per_release'> |
235 | <h2>Uploads per release:</h2> |
236 | <div id="uploads_per_release_chart"></div> |
237 | |
238 | === modified file 'overview/templates/potential_devs.html' |
239 | --- overview/templates/potential_devs.html 2013-06-19 20:29:36 +0000 |
240 | +++ overview/templates/potential_devs.html 2013-06-23 19:42:22 +0000 |
241 | @@ -1,4 +1,5 @@ |
242 | {% extends "base.html" %} |
243 | +{% load custom_tags %} |
244 | |
245 | {% block content %} |
246 | |
247 | @@ -15,9 +16,12 @@ |
248 | <th>Uploads</th> |
249 | <th>Dates Active</th> |
250 | </tr> |
251 | + |
252 | {% for p in potential_devs|dictsortreversed:"first_upload.timestamp" %} |
253 | <tr> |
254 | - <td>{% if p.contacted %}<center>✓</center>{% endif %}</td> |
255 | + <td>{% if p|recent_contact > p.fortieth %} |
256 | + <center>✓</center>{% endif %} |
257 | + </td> |
258 | <td><a href="{{ p.lpid }}">{{ p.name }}</a></td> |
259 | <td>{{ p.total_uploads }}</td> |
260 | <td>{{ p.first_upload.timestamp|date:"SHORT_DATE_FORMAT" }} to {{ p.last_upload.timestamp|date:"SHORT_DATE_FORMAT" }}</td> |
261 | |
262 | === modified file 'overview/uploads/forms.py' |
263 | --- overview/uploads/forms.py 2013-04-23 18:32:37 +0000 |
264 | +++ overview/uploads/forms.py 2013-06-23 19:42:22 +0000 |
265 | @@ -3,9 +3,6 @@ |
266 | class NotesForm(forms.Form): |
267 | notes = forms.CharField(widget = forms.widgets.Textarea(), required=False) |
268 | |
269 | -class BooleanForm(forms.Form): |
270 | - checkbox = forms.BooleanField(required=False) |
271 | - |
272 | class EditContrib(forms.Form): |
273 | lpid = forms.CharField(label='Launchpad ID: ', required=True) |
274 | email = forms.EmailField(label='Email: ', required=True) |
275 | |
276 | === modified file 'overview/uploads/models.py' |
277 | --- overview/uploads/models.py 2013-06-10 16:42:05 +0000 |
278 | +++ overview/uploads/models.py 2013-06-23 19:42:22 +0000 |
279 | @@ -1,5 +1,7 @@ |
280 | from django.db import models |
281 | from django.contrib.auth.models import User |
282 | +from django.contrib.contenttypes import generic |
283 | +from django.contrib.comments.models import Comment |
284 | |
285 | class UDD(models.Model): |
286 | connection_name='udd' |
287 | @@ -41,7 +43,7 @@ |
288 | last_upload = models.ForeignKey('Uploads', related_name='+') |
289 | ubuntu_dev = models.BooleanField(default=False) |
290 | notes = models.TextField(blank=True) |
291 | - contacted = models.BooleanField(default=False) |
292 | + contacts = generic.GenericRelation(Comment, object_id_field="object_pk") |
293 | |
294 | class Meta: |
295 | db_table = u'people' |
296 | |
297 | === modified file 'overview/uploads/templatetags/custom_tags.py' |
298 | --- overview/uploads/templatetags/custom_tags.py 2013-04-06 22:04:28 +0000 |
299 | +++ overview/uploads/templatetags/custom_tags.py 2013-06-23 19:42:22 +0000 |
300 | @@ -5,3 +5,8 @@ |
301 | @register.inclusion_tag('ubu_dev_flag_img.html') |
302 | def ubu_dev_img(flag): |
303 | return {'flag': flag} |
304 | + |
305 | +@register.filter |
306 | +def recent_contact(person): |
307 | + if person.contacts.all(): |
308 | + return person.contacts.all().reverse()[0].submit_date |
309 | |
310 | === modified file 'overview/uploads/views.py' |
311 | --- overview/uploads/views.py 2013-06-21 20:24:21 +0000 |
312 | +++ overview/uploads/views.py 2013-06-23 19:42:22 +0000 |
313 | @@ -13,13 +13,17 @@ |
314 | from uploads.decorators import group_perm_required |
315 | from uploads.models import Uploads, People, UserProfile |
316 | from django.contrib.auth.models import User |
317 | -from uploads.forms import NotesForm, BooleanForm, EditContrib |
318 | +from uploads.forms import NotesForm, EditContrib |
319 | + |
320 | +from django.dispatch import receiver |
321 | +from django.contrib.comments.signals import comment_was_posted |
322 | |
323 | |
324 | @group_perm_required() |
325 | def first_timers(request): |
326 | output = [] |
327 | - for p in People.objects.all(): |
328 | + for p in People.objects.all().prefetch_related("first_upload" |
329 | + ).prefetch_related("last_upload"): |
330 | if p.total_uploads < 5: |
331 | color = "lt5" |
332 | if p.total_uploads >= 5 and p.total_uploads < 10: |
333 | @@ -41,21 +45,8 @@ |
334 | person = get_object_or_404(People, lpid=lpid) |
335 | uploads = Uploads.objects.filter(lpid_changer=lpid) |
336 | recent_uploads = uploads.order_by('timestamp').reverse()[0:10] |
337 | - uploads_per_release = OrderedDict([]) |
338 | - for d in UbuntuDistroInfo().all: |
339 | - release_uploads = len(Uploads.objects.filter(lpid_changer=lpid).filter(release__icontains=d)) |
340 | - if uploads_per_release or release_uploads > 0: |
341 | - uploads_per_release[d] = release_uploads |
342 | - packages = [] |
343 | - ppu_candidates = [] |
344 | - for ul in uploads: |
345 | - packages += [ul.package] |
346 | - appearances = defaultdict(int) |
347 | - for curr in packages: |
348 | - appearances[curr] += 1 |
349 | - for pkg in appearances: |
350 | - if appearances[pkg] > 5: |
351 | - ppu_candidates += [pkg] |
352 | + uploads_per_release = get_uploads_per_release(lpid) |
353 | + ppu_candidates = get_ppu_candidates(uploads) |
354 | if request.method == 'POST': |
355 | if 'save_notes' in request.POST: |
356 | notes_form = NotesForm(request.POST) |
357 | @@ -67,56 +58,75 @@ |
358 | log_action(person, change_message, request.user.pk) |
359 | messages.success(request, 'Change successfully saved...') |
360 | return HttpResponseRedirect('#') |
361 | - elif 'update_contacted' in request.POST: |
362 | - contacted = BooleanForm(request.POST) |
363 | - notes_form = NotesForm(initial={'notes': person.notes}) |
364 | - if contacted.is_valid(): |
365 | - person.contacted = contacted.cleaned_data['checkbox'] |
366 | - person.save() |
367 | - change_message = "Marked %s as contacted." % person.name |
368 | - log_action(person, change_message, request.user.pk) |
369 | - messages.success(request, 'Change successfully saved...') |
370 | - return HttpResponseRedirect('#') |
371 | else: |
372 | notes_form = NotesForm(initial={'notes': person.notes}) |
373 | - contacted = BooleanForm(initial={'checkbox': person.contacted}) |
374 | return render(request, 'person.html', {'person': person, |
375 | 'recent_uploads': recent_uploads, |
376 | 'ppu_candidates': ppu_candidates, |
377 | 'notes_form': notes_form, |
378 | - 'contacted': contacted, |
379 | - 'uploads_per_release': uploads_per_release}) |
380 | + 'uploads_per_release': |
381 | + uploads_per_release}) |
382 | + |
383 | + |
384 | +def get_ppu_candidates(uploads): |
385 | + """ |
386 | + Takes an Uploads object filtered by lpid_changer and returns |
387 | + a list of package that were uploaded by a contributor more than |
388 | + five times. |
389 | + """ |
390 | + packages = uploads.values_list('package', flat=True) |
391 | + ppu_candidates = [] |
392 | + appearances = defaultdict(int) |
393 | + for curr in packages: |
394 | + appearances[curr] += 1 |
395 | + for pkg in appearances: |
396 | + if appearances[pkg] > 5: |
397 | + ppu_candidates += [pkg] |
398 | + return ppu_candidates |
399 | + |
400 | + |
401 | +def get_uploads_per_release(lpid): |
402 | + """ |
403 | + Takes an lpid and returns an ordered dict of uploads per release. |
404 | + """ |
405 | + uploads_per_release = OrderedDict([]) |
406 | + for d in UbuntuDistroInfo().all: |
407 | + release_uploads = len(Uploads.objects.filter( |
408 | + lpid_changer=lpid).filter(release__icontains=d)) |
409 | + if uploads_per_release or release_uploads > 0: |
410 | + uploads_per_release[d] = release_uploads |
411 | + return uploads_per_release |
412 | |
413 | |
414 | @group_perm_required() |
415 | def edit_person(request, lpid): |
416 | person = get_object_or_404(People, lpid=lpid) |
417 | if request.method == 'POST': |
418 | - if request.method == 'POST': |
419 | - person_form = EditContrib(request.POST) |
420 | - if person_form.is_valid(): |
421 | - new_lpid = person_form.cleaned_data['lpid'] |
422 | - person.email = person_form.cleaned_data['email'] |
423 | - person.lpid = new_lpid |
424 | - person.save() |
425 | - if lpid is not new_lpid: |
426 | - uploads = Uploads.objects.filter(lpid_changer=lpid) |
427 | - uploads.update(lpid_changer = new_lpid) |
428 | - change_message = "Updated %s's details." % person.name |
429 | - log_action(person, change_message, request.user.pk) |
430 | - messages.success(request, 'Change successfully saved...') |
431 | - return HttpResponseRedirect('/contributors/{}'.format(new_lpid)) |
432 | + person_form = EditContrib(request.POST) |
433 | + if person_form.is_valid(): |
434 | + new_lpid = person_form.cleaned_data['lpid'] |
435 | + person.email = person_form.cleaned_data['email'] |
436 | + person.lpid = new_lpid |
437 | + person.save() |
438 | + if lpid is not new_lpid: |
439 | + uploads = Uploads.objects.filter(lpid_changer=lpid) |
440 | + uploads.update(lpid_changer=new_lpid) |
441 | + change_message = "Updated %s's details." % person.name |
442 | + log_action(person, change_message, request.user.pk) |
443 | + messages.success(request, 'Change successfully saved...') |
444 | + return HttpResponseRedirect('/contributors/{}'.format(new_lpid)) |
445 | else: |
446 | person_form = EditContrib(initial={'lpid': lpid, |
447 | 'email': person.email}) |
448 | return render(request, 'edit_person.html', {'person': person, |
449 | 'person_form': person_form}) |
450 | |
451 | + |
452 | @group_perm_required() |
453 | def recent_contributors(request): |
454 | recent_contributors = [] |
455 | - for p in People.objects.all(): |
456 | - cutoff_date = timezone.now() - timedelta(days=2 * 30) |
457 | + cutoff_date = timezone.now() - timedelta(days=2 * 30) |
458 | + for p in People.objects.all().prefetch_related("last_upload"): |
459 | if p.last_upload.timestamp > cutoff_date: |
460 | recent_contributors += [p] |
461 | return render(request, 'recent_contributors.html', |
462 | @@ -126,9 +136,9 @@ |
463 | @group_perm_required() |
464 | def lost_contributors(request): |
465 | lost_contributors = [] |
466 | - for p in People.objects.all(): |
467 | - one_year = timezone.now() - timedelta(days=365) |
468 | - two_months = timezone.now() - timedelta(days=2 * 30) |
469 | + one_year = timezone.now() - timedelta(days=365) |
470 | + two_months = timezone.now() - timedelta(days=2 * 30) |
471 | + for p in People.objects.all().prefetch_related('last_upload'): |
472 | ul_date = p.last_upload.timestamp |
473 | if ul_date > one_year and ul_date < two_months: |
474 | lost_contributors += [p] |
475 | @@ -139,48 +149,63 @@ |
476 | @group_perm_required() |
477 | def potential_devs(request): |
478 | potential_devs = [] |
479 | - for p in People.objects.all(): |
480 | - six_months = timezone.now() - timedelta(days=6 * 30) |
481 | - if ((p.first_upload.timestamp < six_months |
482 | - and p.ubuntu_dev is not True |
483 | - and p.total_uploads >= 40 |
484 | - and p.is_active is True)): |
485 | - potential_devs += [p] |
486 | + cutoff_upload = {} |
487 | + six_months = timezone.now() - timedelta(days=6 * 30) |
488 | + for p in People.objects.filter(ubuntu_dev=False |
489 | + ).filter(total_uploads__gte=40 |
490 | + ).filter(is_active=True |
491 | + ).prefetch_related("first_upload" |
492 | + ).prefetch_related("last_upload" |
493 | + ).filter(first_upload__timestamp__lte=six_months): |
494 | + uploads = Uploads.objects.filter(lpid_changer=p.lpid) |
495 | + p.fortieth = uploads.order_by("timestamp")[39].timestamp |
496 | + potential_devs += [p] |
497 | return render(request, 'potential_devs.html', |
498 | - {'potential_devs': potential_devs}) |
499 | + {'potential_devs': potential_devs, |
500 | + 'cutoff_upload': cutoff_upload}) |
501 | + |
502 | |
503 | def log_action(object, change_message, user): |
504 | LogEntry.objects.log_action( |
505 | - user_id = user, |
506 | - content_type_id = ContentType.objects.get_for_model(object).pk, |
507 | - object_id = object.pk, |
508 | - object_repr = object.lpid, |
509 | - change_message = change_message, |
510 | - action_flag = ADDITION |
511 | + user_id=user, |
512 | + content_type_id=ContentType.objects.get_for_model(object).pk, |
513 | + object_id=object.pk, |
514 | + object_repr=object.lpid, |
515 | + change_message=change_message, |
516 | + action_flag=ADDITION |
517 | ) |
518 | |
519 | + |
520 | @group_perm_required() |
521 | def user_profile(request, user): |
522 | profile = User.objects.get(username=user).profile |
523 | actions = LogEntry.objects.filter(user_id=profile.user_id) |
524 | - edited_contribs = actions.order_by('object_repr').values_list("object_repr", |
525 | - flat=True).distinct() |
526 | - return render(request, 'user_profile.html',{'profile': profile, |
527 | - 'actions': actions, |
528 | - 'edited_contribs': edited_contribs}) |
529 | + edited_contribs = actions.order_by('object_repr' |
530 | + ).values_list("object_repr", |
531 | + flat=True).distinct() |
532 | + return render(request, 'user_profile.html', {'profile': profile, |
533 | + 'actions': actions, |
534 | + 'edited_contribs': |
535 | + edited_contribs}) |
536 | + |
537 | |
538 | def site_logout(request): |
539 | logout(request) |
540 | messages.success(request, 'Logged out successfully...') |
541 | return HttpResponseRedirect('/') |
542 | |
543 | + |
544 | def access_denied(request, redirect): |
545 | - messages.error(request, 'You do not have the correct permissions to view that page...') |
546 | + messages.error(request, """ |
547 | + You do not have the correct permissions to view that page... |
548 | + """) |
549 | return HttpResponseRedirect(redirect) |
550 | |
551 | + |
552 | def index(request): |
553 | return render(request, 'index.html', dashboard()) |
554 | |
555 | + |
556 | def dashboard(): |
557 | first_timers = [] |
558 | experienced = [] |
559 | @@ -189,21 +214,46 @@ |
560 | two_months = timezone.now() - timedelta(days=2 * 30) |
561 | six_months = timezone.now() - timedelta(days=6 * 30) |
562 | one_year = timezone.now() - timedelta(days=365) |
563 | - for p in People.objects.all().order_by('last_upload__timestamp').reverse(): |
564 | - if (len(first_timers) < 20 and p.first_upload.timestamp > three_months |
565 | - and p.contacted is False): |
566 | + people = People.objects.all().prefetch_related("first_upload" |
567 | + ).prefetch_related("last_upload" |
568 | + ).select_related('contacts' |
569 | + ).order_by('last_upload__timestamp').reverse() |
570 | + first_timers_qs = people.filter(first_upload__timestamp__gte=three_months) |
571 | + experienced_qs = people.filter(ubuntu_dev=False |
572 | + ).filter(total_uploads__gte=40 |
573 | + ).filter(is_active=True) |
574 | + inactive_qs = people.filter(last_upload__timestamp__gt=one_year |
575 | + ).filter(last_upload__timestamp__lt=two_months |
576 | + ).filter(total_uploads__gte=5) |
577 | + for p in first_timers_qs: |
578 | + if (len(first_timers) < 20 and not p.contacts.all()): |
579 | first_timers.append(p) |
580 | - if (len(experienced) < 20 and p.first_upload.timestamp < six_months |
581 | - and p.ubuntu_dev is not True |
582 | - and p.total_uploads >= 40 |
583 | - and p.is_active is True |
584 | - and p.contacted is False): |
585 | - experienced.append(p) |
586 | - if len(inactive) < 20: |
587 | - ul_date = p.last_upload.timestamp |
588 | - if (ul_date > one_year and ul_date < two_months |
589 | - and p.contacted is False and p.total_uploads >= 5): |
590 | - inactive.append(p) |
591 | + for p in experienced_qs: |
592 | + if p.contacts.all(): |
593 | + recent_c = p.contacts.all().reverse()[0].submit_date |
594 | + else: |
595 | + recent_c = None |
596 | + if (len(experienced) < 20 and (recent_c is None or |
597 | + recent_c < Uploads.objects.filter(lpid_changer=p.lpid |
598 | + ).order_by("timestamp" |
599 | + )[39].timestamp)): |
600 | + experienced.append(p) |
601 | + for p in inactive_qs: |
602 | + if p.contacts.all(): |
603 | + recent_c = p.contacts.all().reverse()[0].submit_date |
604 | + else: |
605 | + recent_c = None |
606 | + if len(inactive) < 20 and (recent_c is None or |
607 | + recent_c < p.last_upload.timestamp): |
608 | + inactive.append(p) |
609 | return {'first_timers': first_timers, |
610 | 'experienced': experienced, |
611 | 'inactive': inactive} |
612 | + |
613 | + |
614 | +@receiver(comment_was_posted) |
615 | +def on_contact_saved(sender, comment=None, request=None, **kwargs): |
616 | + person = People.objects.get(pk=comment.object_pk) |
617 | + change_message = "Recorded a contact with %s." % person.name |
618 | + log_action(person, change_message, comment.user.pk) |
619 | + messages.success(request, 'Change successfully saved...') |
620 | |
621 | === modified file 'overview/urls.py' |
622 | --- overview/urls.py 2013-06-12 18:37:58 +0000 |
623 | +++ overview/urls.py 2013-06-23 19:42:22 +0000 |
624 | @@ -29,7 +29,8 @@ |
625 | name='potential_devs'), |
626 | url(r'^contributors/(?P<lpid>.+)/edit', views.edit_person, name='edit_person'), |
627 | url(r'^contributors/(?P<lpid>.+)', views.person_detail, name='person_detail'), |
628 | - url(r'^users/(?P<user>.+)', views.user_profile, name='user_profile') |
629 | + url(r'^users/(?P<user>.+)', views.user_profile, name='user_profile'), |
630 | + url(r'^comments/', include('django.contrib.comments.urls')) |
631 | ) |
632 | |
633 | if settings.STATIC_SERVE: |
Works great here! Awesome stuff again!
Thanks Andrew!
Regards
Bhavani