Merge lp:~daker/loco-team-portal/fix.profiles into lp:loco-team-portal
- fix.profiles
- Merge into 0.2
Proposed by
Adnane Belmadiaf
Status: | Merged | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Approved by: | Adnane Belmadiaf | ||||||||||||||||
Approved revision: | 561 | ||||||||||||||||
Merged at revision: | 563 | ||||||||||||||||
Proposed branch: | lp:~daker/loco-team-portal/fix.profiles | ||||||||||||||||
Merge into: | lp:loco-team-portal | ||||||||||||||||
Diff against target: |
916 lines (+447/-220) 14 files modified
loco_directory/common/launchpad.py (+4/-9) loco_directory/media/css/styles.css (+193/-36) loco_directory/teams/models.py (+9/-9) loco_directory/teams/urls.py (+1/-1) loco_directory/teams/views.py (+0/-10) loco_directory/templates/base.html (+0/-2) loco_directory/templates/profiles/details.html (+98/-0) loco_directory/templates/teams/my_teams.html (+0/-103) loco_directory/urls.py (+1/-0) loco_directory/userprofiles/management/commands/update-profiles.py (+26/-32) loco_directory/userprofiles/models.py (+45/-18) loco_directory/userprofiles/tests.py (+30/-0) loco_directory/userprofiles/urls.py (+10/-0) loco_directory/userprofiles/views.py (+30/-0) |
||||||||||||||||
To merge this branch: | bzr merge lp:~daker/loco-team-portal/fix.profiles | ||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
LoCo Team Portal Developers | Pending | ||
Review via email: mp+135014@code.launchpad.net |
Commit message
Added Profile page
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'loco_directory/common/launchpad.py' |
2 | --- loco_directory/common/launchpad.py 2012-09-13 00:55:39 +0000 |
3 | +++ loco_directory/common/launchpad.py 2012-11-19 23:09:20 +0000 |
4 | @@ -1,9 +1,6 @@ |
5 | # -*- coding: utf-8 -*- |
6 | - |
7 | from launchpadlib.launchpad import Launchpad |
8 | from launchpadlib.errors import HTTPError |
9 | - |
10 | -from teams.models import * |
11 | from django.conf import settings |
12 | |
13 | import os |
14 | @@ -75,18 +72,17 @@ |
15 | timezone = 'UTC' |
16 | if username is None: |
17 | return timezone |
18 | - |
19 | - if not lp: |
20 | + if not lp: |
21 | lp = lp_login() |
22 | if not lp: |
23 | return timezone |
24 | - try: |
25 | + try: |
26 | lp_user = lp.people[username] |
27 | timezone = lp_user.timezone |
28 | except: |
29 | pass |
30 | return timezone |
31 | - |
32 | + |
33 | |
34 | def get_permanent_openid_from_username(username): |
35 | import urllib |
36 | @@ -118,10 +114,9 @@ |
37 | claimed_by.delete() |
38 | else: |
39 | return False |
40 | - |
41 | + |
42 | openid_assoc.claimed_id = openid.local_id |
43 | openid_assoc.display_id = openid.local_id |
44 | openid_assoc.save() |
45 | return True |
46 | return False |
47 | - |
48 | |
49 | === modified file 'loco_directory/media/css/styles.css' |
50 | --- loco_directory/media/css/styles.css 2012-11-12 20:25:25 +0000 |
51 | +++ loco_directory/media/css/styles.css 2012-11-19 23:09:20 +0000 |
52 | @@ -816,6 +816,198 @@ |
53 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); |
54 | } |
55 | |
56 | + |
57 | +.profil-teams-wrapper { |
58 | + display: block; |
59 | + overflow: auto; |
60 | +} |
61 | + |
62 | +.profil-teams-wrapper h2.title |
63 | +{ |
64 | + padding: 20px; |
65 | + padding-top: 10px; |
66 | + padding-bottom: 10px; |
67 | + margin-bottom: 0; |
68 | + border-bottom: 1px solid #DFDFDF; |
69 | + -webkit-box-shadow: 0 1px 0 #F8F8F8; |
70 | + -moz-box-shadow: 0 1px 0 #f8f8f8; |
71 | + box-shadow: 0 1px 0 #F8F8F8; |
72 | + -webkit-box-shadow: 0px 1px 2px 0 1px 0 #F8F8F8; |
73 | + -moz-box-shadow: 0px 1px 2px 0 1px 0 #f8f8f8; |
74 | + box-shadow: 0px 1px 2px 0 1px 0 #F8F8F8; |
75 | +} |
76 | + |
77 | +.profil-team-wrapper |
78 | +{ |
79 | + overflow: auto; |
80 | + padding-left: 20px; |
81 | + padding-bottom: 10px; |
82 | + padding-top: 10px; |
83 | + border-bottom: 1px solid #D8D8D8; |
84 | + -webkit-box-shadow: 0 1px 0 #F8F8F8; |
85 | + -moz-box-shadow: 0 1px 0 #f8f8f8; |
86 | + box-shadow: 0 1px 0 #F8F8F8; |
87 | + -webkit-box-shadow: 0px 1px 2px 0 1px 0 #F8F8F8; |
88 | + -moz-box-shadow: 0px 1px 2px 0 1px 0 #f8f8f8; |
89 | + box-shadow: 0px 1px 2px 0 1px 0 #F8F8F8; |
90 | +} |
91 | + |
92 | +.profil-team-wrapper .mugshot-wrapper::after { |
93 | + content: ""; |
94 | + display: block; |
95 | + height: 140px; |
96 | + width: 1px; |
97 | + background-color: white; |
98 | + background-repeat: repeat-x; |
99 | + background-image: -khtml-gradient(linear, left top, left bottom, from(#DDD), to(white)); |
100 | + background-image: -moz-linear-gradient(top, #DDD, white); |
101 | + background-image: -ms-linear-gradient(top, #DDD, white); |
102 | + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #DDD), color-stop(100%, white)); |
103 | + background-image: -webkit-linear-gradient(top, #DDD, white); |
104 | + background-image: -o-linear-gradient(top, #DDD, white); |
105 | + background-image: linear-gradient(top, #DDD, white); |
106 | + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#dddddd', endColorstr='#ffffff', GradientType=0); |
107 | + position: relative; |
108 | + left: 110px; |
109 | + top: -105px; |
110 | +} |
111 | + |
112 | +.profil-team-wrapper .mugshot-wrapper { |
113 | + float: left; |
114 | + height: 140px; |
115 | +} |
116 | +.profil-team-wrapper img.mugshot |
117 | +{ |
118 | + width: 96px; |
119 | + height: 96px; |
120 | + margin-right: 10px; |
121 | + -webkit-border-radius: 3px; |
122 | + -moz-border-radius: 3px; |
123 | + border-radius: 3px; |
124 | + display: block; |
125 | +} |
126 | + |
127 | +.profil-team-wrapper a.link2 |
128 | +{ |
129 | + font-size: 1.4em; |
130 | + font-weight: normal; |
131 | + line-height: 1.8; |
132 | + overflow: auto; |
133 | +} |
134 | + |
135 | +.profil-team-meeting-wrapper { |
136 | + float: left; |
137 | + display: block; |
138 | + overflow: auto; |
139 | + width: 535px; |
140 | + margin-left: 20px; |
141 | +} |
142 | + |
143 | +.profil-team-meeting-wrapper h4.title { |
144 | + font-size: 16px; |
145 | + font-style: italic; |
146 | +} |
147 | + |
148 | +ul.indent { |
149 | + list-style: none; |
150 | + padding: 0; |
151 | + margin: 0; |
152 | + border: 1px solid #D2D3D3; |
153 | + border-bottom-color: #B9BABC; |
154 | + border-top-color: #DFDFDF; |
155 | + border-bottom: 1px solid #D8D8D8; |
156 | + -webkit-box-shadow: 0px 1px 2px 0 1px 0 #F8F8F8; |
157 | + -moz-box-shadow: 0px 1px 2px 0 1px 0 #f8f8f8; |
158 | + box-shadow: 0px 1px 2px 0 1px 0 #F8F8F8; |
159 | + background: white; |
160 | + border-radius: 3px; |
161 | + -moz-border-radius: 3px; |
162 | + -webkit-border-radius: 3px; |
163 | + margin-bottom: 5px; |
164 | +} |
165 | + |
166 | +ul.indent li { |
167 | + margin: 0; |
168 | + line-height: 18px; |
169 | + color: #59636D; |
170 | + border-bottom: 1px dotted #DDD; |
171 | +} |
172 | + |
173 | +ul.indent li.nothing { |
174 | + font-style: italic; |
175 | + padding: 10px; |
176 | +} |
177 | + |
178 | +ul.indent li:first-child { |
179 | + border-top: 0; |
180 | +} |
181 | + |
182 | +ul.indent li:last-child { |
183 | + border-bottom: 0; |
184 | +} |
185 | + |
186 | +ul.indent li:first-child a{ |
187 | + border-radius: 3px 3px 0 0; |
188 | + -moz-border-radius: 3px 3px 0 0; |
189 | + -webkit-border-radius: 3px 3px 0 0; |
190 | +} |
191 | + |
192 | +ul.indent li:last-child a{ |
193 | + border-radius: 0 0 3px 3px; |
194 | + -moz-border-radius: 0 0 3px 3px; |
195 | + -webkit-border-radius: 0 0 3px 3px; |
196 | +} |
197 | + |
198 | +ul.indent li a { |
199 | + display: block; |
200 | + padding: 10px; |
201 | + color: #333; |
202 | +} |
203 | + |
204 | +ul.indent li a:hover { |
205 | + background-color: #FBFBFB; |
206 | +} |
207 | + |
208 | +div.profil-inner img.mugshot { |
209 | + display: block; |
210 | + width: 200px; |
211 | + height: 200px; |
212 | +} |
213 | + |
214 | +div.profil-inner h2 { |
215 | + display: block; |
216 | + margin: 0; |
217 | + margin-top: 5px; |
218 | +} |
219 | + |
220 | +.new { |
221 | + background: transparent url(../images/bg_btn.png) repeat-x top left; |
222 | + -webkit-border-radius: 4px; |
223 | + -moz-border-radius: 4px; |
224 | + border-radius: 4px; |
225 | + font-size: 11px; |
226 | + font-weight: bold; |
227 | + text-align: center; |
228 | + white-space: nowrap; |
229 | + margin: 0; |
230 | + margin-left: 16px; |
231 | + height: 27px; |
232 | + line-height: 27px; |
233 | + outline: 0; |
234 | + padding: 0 10px; |
235 | + color: white!important; |
236 | + text-shadow: 0 1px rgba(0, 0, 0, 0.1); |
237 | + position: relative; |
238 | + display: inline-block; |
239 | + text-transform: uppercase; |
240 | + top: -4px; |
241 | +} |
242 | + |
243 | +.new:active { |
244 | + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); |
245 | + -moz-box-shadow: inset 0 1px 2px rgba(0,0,0,0.3); |
246 | + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); |
247 | +} |
248 | /* My Teams style */ |
249 | h2.dynamic-width { |
250 | display: inline-block; |
251 | @@ -841,32 +1033,6 @@ |
252 | width: 75px; |
253 | } |
254 | |
255 | -.main-content-split { |
256 | - width:450px; |
257 | - margin-top: 15px; |
258 | -} |
259 | - |
260 | -.main-content-split.left { |
261 | - float: left; |
262 | -} |
263 | - |
264 | -.main-content-split.right { |
265 | - float: right; |
266 | -} |
267 | - |
268 | -.main-content-split.left .title { |
269 | - font-size: 0.875em; |
270 | -} |
271 | - |
272 | -.main-content-split.left .new { |
273 | - float: right; |
274 | - font-size: 0.75em; |
275 | -} |
276 | - |
277 | -.event-summary { |
278 | - margin-top:15px; |
279 | -} |
280 | - |
281 | hr.no-top { |
282 | margin: 0 0; |
283 | } |
284 | @@ -875,16 +1041,6 @@ |
285 | vertical-align: bottom; |
286 | } |
287 | |
288 | -ul.indent { |
289 | - list-style: none; |
290 | - background-color: #F7F7F7; |
291 | - padding: 2px 2px 2px 15px; |
292 | -} |
293 | - |
294 | -ul.indent li { |
295 | - line-height:1.2em; |
296 | - margin: 0.5em 0; |
297 | -} |
298 | |
299 | .teams-legend { |
300 | width:200px; |
301 | @@ -1335,6 +1491,7 @@ |
302 | .ml:after { content: "%";} |
303 | .forums:after { content: "9";} |
304 | .ical:before { content: "P"; } |
305 | +.website:after { content: "5"; margin-top: 10px;} |
306 | |
307 | .action { |
308 | top: 3px!important; |
309 | |
310 | === modified file 'loco_directory/teams/models.py' |
311 | --- loco_directory/teams/models.py 2011-10-27 14:00:26 +0000 |
312 | +++ loco_directory/teams/models.py 2012-11-19 23:09:20 +0000 |
313 | @@ -47,14 +47,14 @@ |
314 | |
315 | class Meta: |
316 | ordering = ('name',) |
317 | - |
318 | + |
319 | def __unicode__(self): |
320 | return u'%s' % (self.name) |
321 | |
322 | @property |
323 | def related_teams(self): |
324 | return self.team_set.all() |
325 | - |
326 | + |
327 | @property |
328 | def related_venues(self): |
329 | return self.venue_set.all() |
330 | @@ -65,7 +65,7 @@ |
331 | return self.name.replace(',', '').replace(' ', '_') |
332 | else: |
333 | return 'no_country' |
334 | - |
335 | + |
336 | def countries_without_continent(): |
337 | return Country.objects.filter(continents__isnull=True) |
338 | |
339 | @@ -116,16 +116,16 @@ |
340 | microbloghashtag = models.CharField(max_length=50, help_text=_('Hash Tag used for microbloggers to mention this team'), verbose_name=_('Microblogging Hash Tag'), null=True, blank=True) |
341 | active = models.BooleanField(_("Active Team"), default=True) |
342 | tz = models.CharField(max_length=32, verbose_name=_('Default Timezone'), default='UTC', choices=[(tz, tz) for tz in pytz.all_timezones], blank=False, null=False, help_text=_('The most commonly used timezone for this Team.')) |
343 | - |
344 | + |
345 | objects = TeamManager() |
346 | - |
347 | + |
348 | class Meta: |
349 | db_table = 'teams' |
350 | ordering = ('approved', 'name',) |
351 | - |
352 | + |
353 | def __unicode__(self): |
354 | return self.lp_name |
355 | - |
356 | + |
357 | @property |
358 | def display_name(self): |
359 | return self.override_name or self.name |
360 | @@ -133,7 +133,7 @@ |
361 | @models.permalink |
362 | def get_absolute_url(self): |
363 | return ('team-detail', [str(self.lp_name)]) |
364 | - |
365 | + |
366 | def next_5_events_and_meetings(self): |
367 | """ a list with all upcoming team meetings """ |
368 | events_and_meetings = [] |
369 | @@ -149,6 +149,6 @@ |
370 | if len(events_and_meetings) > 5: |
371 | events_and_meetings = events_and_meetings[:5] |
372 | return events_and_meetings |
373 | - |
374 | + |
375 | def teams_without_country(): |
376 | return Team.objects.filter(countries__isnull=True) |
377 | |
378 | === modified file 'loco_directory/teams/urls.py' |
379 | --- loco_directory/teams/urls.py 2011-02-26 02:09:43 +0000 |
380 | +++ loco_directory/teams/urls.py 2012-11-19 23:09:20 +0000 |
381 | @@ -2,7 +2,7 @@ |
382 | |
383 | urlpatterns = patterns('', |
384 | url(r'^$', 'teams.views.team_list', name='team-list'), |
385 | - url(r'^me$', 'teams.views.my_teams', name='my-teams'), |
386 | + #url(r'^me$', 'teams.views.my_teams', name='my-teams'), |
387 | url(r'(?P<team_slug>[a-zA-Z0-9\-\.\+?]+)/edit$', 'teams.views.team_edit', name='team-edit'), |
388 | url(r'(?P<team_slug>[a-zA-Z0-9\-\.\+?]+)/merge/(?P<other_team_slug>[a-zA-Z0-9\-\.\+?]+)/$', 'teams.views.team_merge', name='team-merge'), |
389 | url(r'(?P<team_slug>[a-zA-Z0-9\-\.\+?]+)/merge', 'teams.views.select_other_team', name='select-other-team'), |
390 | |
391 | === modified file 'loco_directory/teams/views.py' |
392 | --- loco_directory/teams/views.py 2012-11-12 20:47:10 +0000 |
393 | +++ loco_directory/teams/views.py 2012-11-19 23:09:20 +0000 |
394 | @@ -83,16 +83,6 @@ |
395 | return render_to_response('teams/team_list.html', context, |
396 | RequestContext(request)) |
397 | |
398 | -@login_required |
399 | -def my_teams(request): |
400 | - teams = Team.objects.filter(lp_name__in=[group.name for group in request.user.groups.all()]) |
401 | - context = { |
402 | - 'teams': teams, |
403 | - } |
404 | - return render_to_response('teams/my_teams.html', context, |
405 | - RequestContext(request)) |
406 | - |
407 | - |
408 | def team_ical(request, team_slug): |
409 | """ |
410 | Return a ical list with the events and meetings in ical format. |
411 | |
412 | === modified file 'loco_directory/templates/base.html' |
413 | --- loco_directory/templates/base.html 2012-11-16 21:13:18 +0000 |
414 | +++ loco_directory/templates/base.html 2012-11-19 23:09:20 +0000 |
415 | @@ -28,8 +28,6 @@ |
416 | {% trans "Welcome" %}&nbps; |
417 | <a class="top-login-item" href="http://launchpad.net/~{{ user.username }}">{{ user.username }}</a> |
418 | <span class="top-login-separator">|</span> |
419 | - <a class="top-login-item" href="{% url my-teams %}">{% trans "My Teams" %}</a> |
420 | - <span class="top-login-separator">|</span> |
421 | {% if user.is_staff %} |
422 | <a class="top-login-item" href="/admin" title="Admin">{% trans "Admin" %}</a> |
423 | <span class="top-login-separator">|</span> |
424 | |
425 | === added directory 'loco_directory/templates/profiles' |
426 | === added file 'loco_directory/templates/profiles/details.html' |
427 | --- loco_directory/templates/profiles/details.html 1970-01-01 00:00:00 +0000 |
428 | +++ loco_directory/templates/profiles/details.html 2012-11-19 23:09:20 +0000 |
429 | @@ -0,0 +1,98 @@ |
430 | +{% extends "base.html" %} |
431 | +{% load i18n smart_if %} |
432 | + |
433 | +{% block title %}Profile for {{ profile.realname }}{% endblock %} |
434 | + |
435 | +{% block content %} |
436 | +<div class="row"> |
437 | + <section class="span-9"> |
438 | + <div class="box_content"> |
439 | + <div class="profil-teams-wrapper"> |
440 | + <h2 class="title">{% if user == profile.user %}{% trans "Your Teams" %}{% else %}{% trans "Teams" %}{% endif %}</h2> |
441 | + {% for team in teams %} |
442 | + <div class="profil-team-wrapper"> |
443 | + <div class="mugshot-wrapper"> |
444 | + <img src="{{ team.mugshot_url }}" alt="{{ team.name }}" class="mugshot" /> |
445 | + </div> |
446 | + <div class="profil-team-meeting-wrapper"> |
447 | + <a href="{% url team-detail team_slug=team.lp_name %}" title="{{ team.name }}" class="link2"> |
448 | + {{ team.name }} |
449 | + </a> |
450 | + <a href="{% url team-meeting-new team_slug=team.lp_name %}" title="{% trans "Schedule a meeting" %}" class="new">{% trans "Schedule a meeting" %}</a> |
451 | + <a href="{% url team-event-new team_slug=team.lp_name %}" title="{% trans "Create an event" %}" class="new">{% trans "Create an event" %}</a> |
452 | + <h4 class="title">{% trans "Meetings" %}</h4> |
453 | + <ul class="indent"> |
454 | + {% if team.teammeeting_set.next_3_meetings %} |
455 | + {% for team_event in team.teammeeting_set.next_3_meetings %} |
456 | + <li> |
457 | + <a title="{{team_event.date_begin|date:"M d"}}" href="{% url team-meeting-detail team_event.first_team.lp_name team_event.id %}">{{ team_event.name }} {% trans "on" %} {{ team_event.local_date_begin|date:"l, d N Y" }} {% trans "at " %}{{ team_event.local_date_begin|date:"H:i T" }}</a> |
458 | + </li> |
459 | + {% endfor %} |
460 | + {% else %} |
461 | + <li class="nothing">{% trans "There are currently no upcoming meeting :(" %}</li> |
462 | + {% endif %} |
463 | + </ul> |
464 | + <h4 class="title">{% trans "Events" %}</h4> |
465 | + |
466 | + <ul class="indent"> |
467 | + {% if team.teamevent_set.next_3_events %} |
468 | + {% for team_event in team.teamevent_set.next_3_events %} |
469 | + <li> |
470 | + <a title="{% if team_event.venue %}{% else %}{{team_event.date_begin|date:"M d"}}{% endif %}" href="{% url team-event-detail team_event.first_team.lp_name team_event.id %}">{{ team_event.name }} {% trans "on" %} {{ team_event.local_date_begin|date:"l, d N Y" }} {% trans "at " %}{{ team_event.local_date_begin|date:"H:i T" }}</a> |
471 | + </li> |
472 | + {% endfor %} |
473 | + {% else %} |
474 | + <li class="nothing">{% trans "There are currently no upcoming events :(" %}</li> |
475 | + {% endif %} |
476 | + </ul> |
477 | + </div> |
478 | + </div> |
479 | + {% endfor %} |
480 | + |
481 | + {% if user == profile.user %} |
482 | + <h2 class="title">{% trans "Events you will be attending" %}</h2> |
483 | + {% for event in my_events %} |
484 | + <a href="{% url team-event-detail event.first_team.lp_name event.id %}" title="{% if event.venue %}{% else %}{{event.date_begin|date:"M d"}}{% endif %}" class="event-meetings"> |
485 | + <span class="title">{{ event.name }}</span> |
486 | + <small>{{ event.local_date_begin|date:"l, d N Y" }} {% trans "at " %}{{ event.local_date_begin|date:"H:i T" }}</small> |
487 | + <p>{{ event.description }}</p> |
488 | + </a> |
489 | + {% endfor %} |
490 | + {% endif %} |
491 | + </div> |
492 | + </div> |
493 | + </section> |
494 | + <section class="span-3 box_content last"> |
495 | + <div class="sidebar-inner"> |
496 | + <div class="profil-inner"> |
497 | + <img src="{{ profile.mugshot }}" class="mugshot"alt="{{ profile.realname }}" title="{{ profile.realname }}" /> |
498 | + <h2>{{ profile.realname }}</a></h2> |
499 | + <div style="margin-bottom: 10px;"> |
500 | + <a style="font-style: italic;" title="Launchpad" href="https://launchpad.net/~{{ profile.user.username }}">{{ profile.user.username }}</a> |
501 | + </div> |
502 | + |
503 | + <div> |
504 | + <span class="pictogram calendar" title="{% trans "Timezone" %}"></span> |
505 | + <span class="pictogram-l">{{ profile.tz }}</span> |
506 | + </div> |
507 | + {% if profile.irc %} |
508 | + <div> |
509 | + <span class="pictogram forums" title="{% trans "IRC" %}"></span> |
510 | + <span class="pictogram-l">{{ profile.irc }}</span> |
511 | + </div> |
512 | + {% endif %} |
513 | + {% if profile.blog or profile.twitter %} |
514 | + <div> |
515 | + <span class="pictogram website" title="{% trans "Social Media" %}"></span> |
516 | + {% if profile.blog %} |
517 | + <a title="{{ profile.blog }}" href="{{ profile.blog }}">{% trans "Blog" %}</a> |
518 | + {% endif %}{% if profile.blog and profile.twitter %}/{% endif %}{% if profile.twitter %} |
519 | + <a title="{{ profile.twitter }}" href="https://twitter.com/{{ profile.twitter }}">{% trans "Twitter" %}</a> |
520 | + {% endif %} |
521 | + </div> |
522 | + {% endif %} |
523 | + </div> |
524 | + </div> |
525 | + </section> |
526 | +</div> |
527 | +{% endblock %} |
528 | \ No newline at end of file |
529 | |
530 | === removed file 'loco_directory/templates/teams/my_teams.html' |
531 | --- loco_directory/templates/teams/my_teams.html 2012-06-02 11:50:27 +0000 |
532 | +++ loco_directory/templates/teams/my_teams.html 1970-01-01 00:00:00 +0000 |
533 | @@ -1,103 +0,0 @@ |
534 | -{% extends "base.html" %} |
535 | -{% load i18n %} |
536 | - |
537 | -{% block page_name %}{% trans "My Teams" %}{% endblock %} |
538 | - |
539 | -{% block extrahead %}{{ block.super }} |
540 | - <link rel="stylesheet" type="text/css" href="{{MEDIA_URL}}/css/twidenash.css" /> |
541 | - <script type="text/javascript" src="{{MEDIA_URL}}jquery/jquery.js"></script> |
542 | - <script type="text/javascript" src="{{MEDIA_URL}}js/jquery.lightbox-0.5.min.js"></script> |
543 | - <link rel="stylesheet" href="{{MEDIA_URL}}css/jquery.lightbox-0.5.css" type="text/css" media="screen" /> |
544 | - <script type="text/javascript" src="{{MEDIA_URL}}js/jquery-flickr.js"></script> |
545 | - <script src="{{ MEDIA_URL }}js/twidenash/jquery-twidenash.js" type="text/javascript"></script> |
546 | - <script type="text/javascript"> |
547 | - //<![CDATA[ |
548 | - $(function () { |
549 | - $('.twidenash').twidenash({ amount: 3 }); |
550 | - {% for team in teams %} |
551 | - $('#flickr-{{ team.lp_name }}').flickr({ key: "{{ flickr_api_key }}", id: "{{ team.flickr_id }}", amount: 10 }); |
552 | - {% endfor %} |
553 | - }); |
554 | - //]]> |
555 | - </script> |
556 | - {# <!-- TODO: this shpuld be rss of events AND meetings --> #} |
557 | - {% for team in teams %} |
558 | - <link type="application/rss+xml" rel="alternate" title="{% trans "Team Events (RSS)" %}" href="{% url team-events-rss team_slug=team.lp_name %}" /> |
559 | - {% endfor %} |
560 | -{% endblock %} |
561 | - |
562 | -{% block sub_nav_links %} |
563 | - <li><a class="sub-nav-item" href="{% url my-teams %}" title="{% trans 'My Teams' %}">{% trans "My Teams" %}</a></li> |
564 | - <li><a class="sub-nav-item" href="{% url team-list %}" title="{% trans 'All Teams' %}">{% trans "All Teams" %}</a></li> |
565 | - {% comment %} |
566 | - <!-- TODO: Need to create those pages --> |
567 | - <li><a class="sub-nav-item" href="" title="{% trans 'Join a Team' %}">{% trans "Join a Team" %}</a></li> |
568 | - <li><a class="sub-nav-item" href="" title="{% trans 'Create a Team' %}">{% trans "Create a Team" %}</a></li> |
569 | - {% endcomment %} |
570 | -{% endblock %} |
571 | - |
572 | -{% block content %} |
573 | - {% for team in teams %} |
574 | -<div class="row"> |
575 | -<section class="span-12"> |
576 | - <h2 class="dynamic-width"> |
577 | - <a href="{% url team-detail team_slug=team.lp_name %}" class="team-title" title="{{ team.name }}">{{ team.name }}</a> |
578 | - {% comment %} |
579 | - <a href="{% url team-calendar team_slug=team.lp_name %}" title="{% trans "Team Calendar (ICAL)" %}"><img class="bottom" src="{{ MEDIA_URL }}img/ical.png" /></a> |
580 | - {# <!-- TODO: this shpuld be rss of events AND meetings --> #} |
581 | - {# <!-- TODO: Change icon to RSS icon --> #} |
582 | - <a href="{% url team-events-rss team_slug=team.lp_name %}" title="{% trans "Team Feed (RSS)" %}"><img class="bottom" src="{{ MEDIA_URL }}img/rss.png" /></a> |
583 | - {% endcomment %} |
584 | - </h2> |
585 | - <aside class="resources"> |
586 | - <span>{% trans "Resources: " %}</span> |
587 | - {% if team.web_url %}<a href="{{ team.web_url }}">{% trans "Website" %}</a>{% endif %} |
588 | - {% if team.wiki_url %}<a href="{{ team.wiki_url }}">{% trans "Wiki" %}</a>{% endif %} |
589 | - {% if team.forum_url %}<a href="{{ team.forum_url }}">{% trans "Forums" %}</a>{% endif %} |
590 | - {% if team.ml_url %}<a href="{{ team.ml_url }}">{% trans "Mailing List" %}</a>{% endif %} |
591 | - {% if team.irc_chan %}<a href="{% url team-detail team_slug=team.lp_name %}#chat">{% trans "IRC Channel" %}</a>{% endif %} |
592 | - </aside> |
593 | - <hr class="no-top" /> |
594 | - <section class="main-content-split left"> |
595 | - <section class="meeting-summary"> |
596 | - <a href="{% url team-meeting-list team_slug=team.lp_name %}" class="title">{% trans "Meetings" %}</a> |
597 | - <a href="{% url team-meeting-new team_slug=team.lp_name %}" class="new">{% trans "+ new meeting" %}</a> |
598 | - <hr class="no-top" /> |
599 | - <ul class="indent"> |
600 | - {% if team.teammeeting_set.next_3_meetings %} |
601 | - {% for team_event in team.teammeeting_set.next_3_meetings %} |
602 | - {% include 'meetings/team_meeting_li.inc.html' %} |
603 | - {% endfor %} |
604 | - {% else %} |
605 | - <li>{% trans "There are no schedules meetings for this team" %}</li> |
606 | - {% endif %} |
607 | - </ul> |
608 | - </section> |
609 | - <section class="event-summary"> |
610 | - <a href="{% url team-event-list team_slug=team.lp_name %}" class="title">{% trans "Events" %}</a> |
611 | - <a href="{% url team-event-new team_slug=team.lp_name %}" class="new">{% trans "+ new event" %}</a> |
612 | - <hr class="no-top" /> |
613 | - <ul class="indent"> |
614 | - {% if team.teamevent_set.next_3_events %} |
615 | - {% for team_event in team.teamevent_set.next_3_events %} |
616 | - {% include 'events/team_event_li.inc.html' %} |
617 | - {% endfor %} |
618 | - {% else %} |
619 | - <li>{% trans "There are no schedules events for this team" %}</li> |
620 | - {% endif %} |
621 | - </ul> |
622 | - </section> |
623 | - </section> |
624 | - <section class="main-content-split right"> |
625 | - {% if team.microbloghashtag %} |
626 | - <div class="twidenash" id="{{ team.microbloghashtag }}"></div> |
627 | - {% else %} |
628 | - {% if team.flickr_id %} {# or team.picasa_id or team.pixie_id %}#} |
629 | - <div class="photo" id="flickr-{{ team.lp_name }}"></div> |
630 | - {% endif %} |
631 | - {% endif %} |
632 | - </section> |
633 | - </section> |
634 | - </div> |
635 | - {% endfor %} |
636 | -{% endblock %} |
637 | |
638 | === modified file 'loco_directory/urls.py' |
639 | --- loco_directory/urls.py 2011-11-13 14:49:25 +0000 |
640 | +++ loco_directory/urls.py 2012-11-19 23:09:20 +0000 |
641 | @@ -27,6 +27,7 @@ |
642 | url(r'^jsi18n', 'django.views.i18n.javascript_catalog', name='jsi18n'), |
643 | url(r'^services/', include('services.urls')), |
644 | url(r'^search/', 'common.views.site_search', name='site_search'), |
645 | + url(r'', include('userprofiles.urls')), |
646 | ) |
647 | |
648 | urlpatterns += patterns('django_openid_auth.views', |
649 | |
650 | === modified file 'loco_directory/userprofiles/management/commands/update-profiles.py' |
651 | --- loco_directory/userprofiles/management/commands/update-profiles.py 2011-07-24 16:30:57 +0000 |
652 | +++ loco_directory/userprofiles/management/commands/update-profiles.py 2012-11-19 23:09:20 +0000 |
653 | @@ -1,37 +1,31 @@ |
654 | +# -*- coding: utf-8 -*- |
655 | #!/usr/bin/python |
656 | -# -*- coding: utf-8 -*- |
657 | - |
658 | -from django.core.management.base import NoArgsCommand |
659 | - |
660 | -from common import launchpad |
661 | -from django.contrib.auth.models import User, Group |
662 | -from userprofiles.models import UserProfile, create_profile |
663 | - |
664 | + |
665 | +from django.core.management.base import BaseCommand |
666 | +from django.contrib.auth.models import User |
667 | + |
668 | +from userprofiles.models import create_userprofile |
669 | + |
670 | +from optparse import make_option |
671 | from datetime import datetime |
672 | import sys |
673 | |
674 | -class Command(NoArgsCommand): |
675 | +class Command(BaseCommand): |
676 | help = "Updates user profiles with information from Launchpad." |
677 | - |
678 | - def handle_noargs(self, **options): |
679 | - lp = launchpad.lp_login() |
680 | - if not lp: |
681 | - sys.exit(1) |
682 | - USER_BLACKLIST = (u"root", u"admin") |
683 | - |
684 | - ld_users = User.objects.all() |
685 | - |
686 | - for ld_user in ld_users: |
687 | - if not ld_user.username in USER_BLACKLIST: |
688 | - profile, created = UserProfile.objects.get_or_create(user=ld_user) |
689 | - try: |
690 | - print "updating %s" % ld_user |
691 | - lp_user = lp.people[ld_user.username] |
692 | - profile.tz = lp_user.time_zone or "UTC" |
693 | - profile.realname = lp_user.display_name or user.username |
694 | - profile.mugshot = launchpad.get_mugshot_url(lp_user.logo_link) |
695 | - profile.save() |
696 | - except Exception, e: |
697 | - print "Error updating %s" % ld_user |
698 | - print e |
699 | - pass |
700 | + option_list = BaseCommand.option_list + ( |
701 | + make_option("-u", "--user", dest='username', |
702 | + help="Supply a user to setup the openid identity url from launchpad."), |
703 | + ) |
704 | + |
705 | + def handle(self, *args, **options): |
706 | + username = options['username'] |
707 | + if not username: |
708 | + ld_users = User.objects.all() |
709 | + for ld_user in ld_users: |
710 | + create_userprofile(sender=User, instance=ld_user, need_update=True) |
711 | + else: |
712 | + try: |
713 | + ld_user = User.objects.get(username=username) |
714 | + except User.DoesNotExist: |
715 | + sys.exit('Seems that this user does not exist') |
716 | + create_userprofile(sender=User, instance=ld_user, need_update=True) |
717 | |
718 | === modified file 'loco_directory/userprofiles/models.py' |
719 | --- loco_directory/userprofiles/models.py 2011-03-04 18:16:03 +0000 |
720 | +++ loco_directory/userprofiles/models.py 2012-11-19 23:09:20 +0000 |
721 | @@ -1,10 +1,22 @@ |
722 | +# -*- coding: utf-8 -*- |
723 | from django.db import models |
724 | from django.utils.translation import ugettext_lazy as _ |
725 | from django.contrib.auth import models as auth_models |
726 | -# Create your models here. |
727 | +from django.db.models.signals import post_save |
728 | +from common.launchpad import (get_user_timezone, lp_login, get_mugshot_url, set_user_openid) |
729 | |
730 | import pytz |
731 | |
732 | +import logging |
733 | +import sys |
734 | +st_handler = logging.StreamHandler(sys.stderr) |
735 | +formatter = logging.Formatter("[%(asctime)s] - %(levelname)s - %(module)s - %(message)s") |
736 | +st_handler.setFormatter(formatter) |
737 | + |
738 | +log = logging.getLogger(__name__) |
739 | +log.addHandler(st_handler) |
740 | +log.setLevel(logging.DEBUG) |
741 | + |
742 | class UserProfile(models.Model): |
743 | " Store profile information about a user " |
744 | |
745 | @@ -25,7 +37,7 @@ |
746 | |
747 | class Meta: |
748 | ordering = ('user__username',) |
749 | - |
750 | + |
751 | def __unicode__(self): |
752 | try: |
753 | if self.realname: |
754 | @@ -40,7 +52,7 @@ |
755 | except: |
756 | return pytz.utc |
757 | timezone = property(get_timezone) |
758 | - |
759 | + |
760 | def tolocaltime(self, dt): |
761 | as_utc = pytz.utc.localize(dt) |
762 | return as_utc.astimezone(self.timezone) |
763 | @@ -48,36 +60,51 @@ |
764 | def fromlocaltime(self, dt): |
765 | local = self.timezone.localize(dt) |
766 | return local.astimezone(pytz.utc) |
767 | - |
768 | + |
769 | def _getUserProfile(self): |
770 | if not self.is_authenticated(): |
771 | return UserProfile() |
772 | - |
773 | + |
774 | profile, created = UserProfile.objects.get_or_create(user=self) |
775 | - |
776 | + |
777 | if created: |
778 | - from common.launchpad import get_user_timezone |
779 | profile.tz = get_user_timezone(self.username) |
780 | profile.save() |
781 | - |
782 | + |
783 | return profile |
784 | |
785 | def _getAnonProfile(self): |
786 | return UserProfile() |
787 | - |
788 | + |
789 | auth_models.User.profile = property(_getUserProfile) |
790 | auth_models.AnonymousUser.profile = property(_getAnonProfile) |
791 | |
792 | +def create_userprofile(sender, instance, lp=None, USER_BLACKLIST=(u"root", u"admin"), need_update=False, **kwargs): |
793 | + profile, created = UserProfile.objects.get_or_create(user=instance) |
794 | + if instance.username in USER_BLACKLIST: |
795 | + log.error('%s tried to create a userprofile, but exists in USER_BLACKLIST' % instance) |
796 | + return profile |
797 | + |
798 | + if need_update or created: |
799 | + if not lp: |
800 | + lp = lp_login() |
801 | + if lp: |
802 | + try: |
803 | + log.debug("Updating %s" % instance) |
804 | + lp_user = lp.people[instance.username] |
805 | + profile.tz = lp_user.time_zone or "UTC" |
806 | + profile.realname = lp_user.display_name or user.username |
807 | + profile.mugshot = get_mugshot_url(lp_user.mugshot_link) |
808 | + profile.save() |
809 | + except Exception, e: |
810 | + log.error("Error updating %s" % instance) |
811 | + return profile |
812 | + |
813 | +post_save.connect(create_userprofile, sender=auth_models.User, dispatch_uid=__name__) |
814 | + |
815 | def create_profile(username): |
816 | user, created = auth_models.User.objects.get_or_create(username=username) |
817 | if created: |
818 | user.save() |
819 | - from common import launchpad |
820 | - launchpad.set_user_openid(user, force=True) |
821 | - profile, created = UserProfile.objects.get_or_create(user=user) |
822 | - if created: |
823 | - # set real name as username for now, |
824 | - # we get the name later on via cronjob |
825 | - profile.realname = username |
826 | - profile.save() |
827 | - return profile |
828 | + set_user_openid(user, force=True) |
829 | + return user.get_profile() |
830 | |
831 | === added file 'loco_directory/userprofiles/tests.py' |
832 | --- loco_directory/userprofiles/tests.py 1970-01-01 00:00:00 +0000 |
833 | +++ loco_directory/userprofiles/tests.py 2012-11-19 23:09:20 +0000 |
834 | @@ -0,0 +1,30 @@ |
835 | +# -*- coding: utf-8 -*- |
836 | +from django.test import TestCase |
837 | +from django.contrib.auth.models import User |
838 | +from django.db.models import signals |
839 | + |
840 | +from userprofiles.models import UserProfile |
841 | + |
842 | +class SignalTest(TestCase): |
843 | + ''' |
844 | + Tests that signals fire properly |
845 | + ''' |
846 | + |
847 | + def test_signals(self): |
848 | + global received |
849 | + received = False |
850 | + |
851 | + def handle_post_save(**kwargs): |
852 | + global received |
853 | + received = True |
854 | + |
855 | + signals.post_save.connect(handle_post_save, sender=User) |
856 | + self.user = User.objects.create(username='bob') |
857 | + self.user.set_password('bob') |
858 | + self.user.save() |
859 | + self.assertTrue(received) |
860 | + |
861 | + def test_profile_creation(self): |
862 | + self.user = User.objects.create(username='bob', password='bob') |
863 | + self.user.save() |
864 | + self.assertEqual(UserProfile.objects.all().count(), 1) |
865 | \ No newline at end of file |
866 | |
867 | === added file 'loco_directory/userprofiles/urls.py' |
868 | --- loco_directory/userprofiles/urls.py 1970-01-01 00:00:00 +0000 |
869 | +++ loco_directory/userprofiles/urls.py 2012-11-19 23:09:20 +0000 |
870 | @@ -0,0 +1,10 @@ |
871 | +# -*- coding: utf-8 -*- |
872 | +from django.conf.urls.defaults import * |
873 | + |
874 | +urlpatterns = patterns('userprofiles.views', |
875 | + url(r'^(?P<username>[-.\w]+)/$', |
876 | + view='profile_detail', |
877 | + name='profile_detail', |
878 | + ), |
879 | + |
880 | +) |
881 | \ No newline at end of file |
882 | |
883 | === added file 'loco_directory/userprofiles/views.py' |
884 | --- loco_directory/userprofiles/views.py 1970-01-01 00:00:00 +0000 |
885 | +++ loco_directory/userprofiles/views.py 2012-11-19 23:09:20 +0000 |
886 | @@ -0,0 +1,30 @@ |
887 | +# -*- coding: utf-8 -*- |
888 | +from django.shortcuts import render_to_response, get_object_or_404 |
889 | +from django.template import RequestContext |
890 | +from django.http import Http404 |
891 | +from django.contrib.auth.models import User |
892 | + |
893 | +from django.db.models import Count |
894 | + |
895 | +from userprofiles.models import UserProfile |
896 | +from teams.models import Team |
897 | +from events.models import Attendee, TeamEvent |
898 | + |
899 | +def profile_detail(request, username): |
900 | + user = get_object_or_404(User, username__iexact=username) |
901 | + teams = Team.objects.filter(lp_name__in=[group.name for group in user.groups.all()]) |
902 | + |
903 | + if request.user == user: |
904 | + profile = request.user.get_profile() |
905 | + my_events = TeamEvent.objects.next_events().annotate(attendees=Count('attendee')).filter(attendee__attendee_profile=profile) |
906 | + else: |
907 | + profile = UserProfile.objects.get(user=user) |
908 | + my_events = {} |
909 | + |
910 | + context = { |
911 | + 'profile': profile, |
912 | + 'teams': teams, |
913 | + 'my_events': my_events, |
914 | + } |
915 | + |
916 | + return render_to_response('profiles/details.html', context, context_instance=RequestContext(request)) |