| # Copyright 2008 Google Inc. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """Django template library for Gerrit.""" |
| |
| import cgi |
| import logging |
| |
| from google.appengine.api import memcache |
| from google.appengine.api import users |
| |
| import django.template |
| import django.utils.safestring |
| from django.utils.safestring import mark_safe |
| from django.utils.timesince import timesince |
| |
| from memcache import CachedDict |
| import models |
| import view_util |
| |
| register = django.template.Library() |
| |
| class _CachedUser(object): |
| """Important data about an Account, pickled into memcache for |
| faster access when rendering pages to clients. |
| """ |
| email = None |
| real_name = None |
| exists = False |
| |
| def _store_users(emails): |
| def _cache(pair): |
| email, account = pair |
| r = _CachedUser() |
| if account: |
| r.email = account.email |
| r.real_name = account.real_name |
| r.exists = account.real_name_entered |
| else: |
| r.email = email |
| r.real_name = email |
| if '@' in r.real_name: |
| r.real_name = r.real_name.split('@', 1)[0] |
| if r.real_name is None: |
| r.real_name = 'Unknown Person (%s)' % r.email |
| return r |
| all = zip(emails, models.Account.get_accounts_for_emails(emails)) |
| return map(_cache, all) |
| _user_cache = CachedDict(prefix = 'CachedUser:', |
| compute_multi = _store_users, |
| timeout = 300) |
| |
| def _to_email(u): |
| if isinstance(u, users.User): |
| return u.email() |
| return u |
| |
| def prefetch_names(emails): |
| _user_cache.prefetch(map(_to_email, emails)) |
| |
| |
| @register.filter |
| def real_name(email, arg=None): |
| """Render an email address or a User object as a real_name. |
| |
| If the input is a user object that equals the current user, |
| 'me' is returned, unless the filter argument is non-empty. |
| Example: |
| {{foo|real_name}} may render 'me'; |
| {{foo|real_name:"x"}} will never render 'me'. |
| """ |
| return real_names([email], arg) |
| |
| @register.filter |
| def real_names(email_list, arg=None): |
| """Render a list of email addresses or User objects as real_names. |
| |
| Each list item is first formatter via the real_name() filter above, |
| and then the resulting strings are separated by commas. |
| The filter argument is the same as for real_name() above. |
| """ |
| if arg: |
| user = None |
| else: |
| user = users.get_current_user() |
| |
| email_list = map(_to_email, email_list) |
| all = _user_cache.get_multi(email_list) |
| |
| names = [] |
| for email in email_list: |
| if user and user.email() == email: |
| names.append('me') |
| else: |
| names.append(all[email].real_name) |
| return ', '.join(names) |
| |
| |
| @register.filter |
| def show_user(email, arg=None): |
| """Render a link to the user's dashboard, with text being |
| the real_name. |
| """ |
| return show_users([email], arg) |
| |
| @register.filter |
| def show_users(email_list, arg=None): |
| """Render list of links to each user's dashboard, with text |
| being the real_name. |
| """ |
| if arg: |
| user = None |
| else: |
| user = users.get_current_user() |
| |
| email_list = map(_to_email, email_list) |
| all = _user_cache.get_multi(email_list) |
| |
| names = [] |
| for email in email_list: |
| if user and user.email() == email: |
| names.append('me') |
| else: |
| u = all[email] |
| if u.exists: |
| names.append( |
| '<a href="/user/%(link)s"' |
| ' onMouseOver="M_showUserInfoPopup(this)">' |
| '%(name)s</a>' |
| % {'link': cgi.escape(u.email.replace('@',',,')), |
| 'name': cgi.escape(u.real_name)} |
| ) |
| else: |
| names.append(cgi.escape(u.real_name)) |
| return mark_safe(', '.join(names)) |
| |
| |
| def _init_lgtm_text(): |
| r = {} |
| for key, value in models.LGTM_CHOICES: |
| r[key] = value |
| return r |
| _lgtm_text = _init_lgtm_text() |
| |
| @register.filter |
| def review_status_text(status, arg=None): |
| try: |
| return _lgtm_text[status] |
| except KeyError: |
| return '' |
| |
| |
| _lgtm_icon = { |
| 'lgtm': mark_safe('<img src="/static/check.png" />'), |
| 'yes': mark_safe('<font color="#08a400">+1</font>'), |
| 'abstain': '', |
| 'no': mark_safe('<font color="#d10000"><b>-1</b></font>'), |
| 'reject': mark_safe('<img src="/static/x.png" />'), |
| } |
| |
| @register.filter |
| def review_status_icons(status, arg=None): |
| try: |
| return _lgtm_icon[status] |
| except KeyError: |
| return '' |
| |
| |
| @register.filter |
| def form_xsrf(url, arg=None): |
| x = view_util.xsrf_for(url) |
| return mark_safe('<input type="hidden" name="xsrf" value="%s" />' % x) |
| |
| @register.filter |
| def bare_xsrf(url, arg=None): |
| return mark_safe(view_util.xsrf_for(url)) |
| |
| _abbrev_units = { |
| 'year': 'y', 'years': 'y', |
| 'month': 'mo', 'months': 'm', |
| 'week': 'w', 'weeks': 'w', |
| 'day': 'd', 'days': 'd', |
| 'hour': 'h', 'hours': 'h', |
| 'minute': 'min', 'minutes': 'mins', |
| } |
| |
| @register.filter |
| def abbrevtimesince(d, arg=None): |
| r = [] |
| for p in timesince(d).split(', '): |
| cnt, unit = p.split(' ', 2) |
| try: |
| r.append('%s %s' % (cnt, _abbrev_units[unit])) |
| except KeyError: |
| r.append(p) |
| return ', '.join(r) |