Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #254 from readevalprint/atomic_service_page

[fix bug 753398] service tab with API key generator
  • Loading branch information...
commit 2e5fe2f226b9ccef5bcd838dc76c5a8097693adc 2 parents c604621 + 031c3d0
@readevalprint readevalprint authored
View
66 apps/phonebook/templates/phonebook/edit_profile.html
@@ -1,15 +1,23 @@
{% extends "base.html" %}
+{% block site_js %}
+ {{ super() }}
+ {{ js('edit_profile') }}
+{% endblock %}
+
+{% block site_css %}
+ {{ super() }}
+ {{ css('edit_profile') }}
+{% endblock %}
+
{% block page_title %}{{ _('Edit Your Profile') }}{% endblock %}
{% block body_id %}edit-profile{% endblock %}
{% block body_classes %}box-content{% endblock %}
-{% block page_js %}
- {{ js('edit_profile') }}
-{% endblock %}
{% block main_content %}
- <form action="{{ edit_form_action }}"
- method="POST" enctype="multipart/form-data"
+ <form action="{{ url('profile.edit') }}"
+ method="POST"
+ enctype="multipart/form-data"
class="form-horizontal edit-profile">
{{ csrf() }}
<h1>{{ _('Edit Your Profile') }}</h1>
@@ -19,6 +27,7 @@
<li><a href="#skills" data-toggle="tab">{{ _('Skills & Groups') }}</a></li>
<li><a href="#vouches" data-toggle="tab">{{ _('Vouches & Invites') }}</a></li>
<li><a href="#account" data-toggle="tab">{{ _('Account') }}</a></li>
+ <li><a href="#services" data-toggle="tab">{{ _('Services') }}</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="1">
@@ -42,22 +51,22 @@
</div>
<div class="tab-pane" id="skills">
<h2>{{ _('Groups') }}</h2>
- <p class="field_description">
- {% trans %}
- Groups are a community of Mozillians with some relation to each
- other. This can be an interest, team, project, product or
- sub-community.
- {% endtrans %}
- </p>
+ <p class="field_description">
+ {% trans %}
+ Groups are a community of Mozillians with some relation to each
+ other. This can be an interest, team, project, product or
+ sub-community.
+ {% endtrans %}
+ </p>
{{ form.groups.label_tag() }}
{{ form.groups }}
<h2>{{ _('Skills') }}</h2>
- <p class="field_description">
- {% trans %}
- A skill is the learned capacity to carry out pre-determined
- results often with the minimum outlay of time, energy, or both.
- {% endtrans %}
- </p>
+ <p class="field_description">
+ {% trans %}
+ A skill is the learned capacity to carry out pre-determined
+ results often with the minimum outlay of time, energy, or both.
+ {% endtrans %}
+ </p>
{{ form.skills.label_tag() }}
{{ form.skills }}
</div>
@@ -135,6 +144,27 @@
</div>
</div>
</div>
+ <div class="tab-pane" id="services">
+ <div class="control-group">
+ <h2>{{ _("API") }}</h2>
+ <p class="field_description">
+ {% trans %}
+ The Mozillians' Phonebook offers an API to Vouched Mozillians to help share profile data to other tools and sites
+ {% endtrans %}
+ </p>
+ <label class="control-label">{{ _("Api Key") }}</label>
+ <div class="controls">
+ <span class="label-text">
+ <div class="input-append">
+ <input id="api-key" type="text" class="span4" autocomplete="off" data-value="{{ profile.get_api_key() }}" value="{{ profile.get_api_key() }}">
+ <button type="submit" name="reset_api_key" class="btn btn-mini btn-danger">
+ {{ _("Generate new API Key") }}
+ </button>
+ </div>
+ </span>
+ </div>
+ </div>
+ </div>
</div>
</div>
<div id="edit_controls">
View
26 apps/phonebook/tests/test_views.py
@@ -276,6 +276,32 @@ def test_replace_photo(self):
new_photo = doc('#profile-photo').attr('src')
assert new_photo != old_photo
+ def test_api_key(self):
+ """Assert that the Api key will be created and displayed"""
+ client = self.mozillian_client
+ r = client.get(reverse('profile.edit'), follow=True)
+
+ doc = pq(r.content)
+ api_key = doc('#api-key').attr('value')
+
+ p = self.mozillian.get_profile()
+ assert p.get_api_key() == api_key
+
+ def test_reset_api_key(self):
+ """Assert that resetingthe aPI key changes it."""
+ client = self.mozillian_client
+ r = client.get(reverse('profile.edit'), follow=True)
+
+ doc = pq(r.content)
+ original_api_key = doc('#api-key').attr('value')
+
+ data = {'reset_api_key': True}
+ r = client.post(reverse('profile.edit'), data, follow=True)
+
+ doc = pq(r.content)
+ new_api_key = doc('#api-key').attr('value')
+ assert original_api_key != new_api_key
+
class TestVouch(TestCase):
"""
View
46 apps/phonebook/views.py
@@ -13,6 +13,8 @@
import commonware.log
from funfactory.urlresolvers import reverse
from product_details import product_details
+from funfactory.helpers import urlparams
+from tastypie.models import ApiKey
from tower import ugettext as _
from groups.helpers import stringify_groups
@@ -72,6 +74,15 @@ def edit_profile(request):
instance=profile,
)
form.fields['region'].choices = COUNTRIES
+
+ if 'reset_api_key' in request.POST:
+ # The rest of the form is irrelevant.
+ try:
+ request.user.api_key.delete()
+ except ApiKey.DoesNotExist:
+ pass
+ return redirect(urlparams(reverse('profile.edit'), 'services'))
+
if form.is_valid():
old_username = request.user.username
form.save(request)
@@ -84,24 +95,24 @@ def edit_profile(request):
'changed.'))
return redirect(reverse('profile', args=[request.user.username]))
- else:
- initial = dict(first_name=request.user.first_name,
- last_name=request.user.last_name,
- bio=profile.bio,
- website=profile.website,
- irc_nickname=profile.ircname,
- groups=user_groups,
- skills=user_skills)
+ else:
+ initial = dict(first_name=request.user.first_name,
+ last_name=request.user.last_name,
+ bio=profile.bio,
+ website=profile.website,
+ irc_nickname=profile.ircname,
+ groups=user_groups,
+ skills=user_skills)
+
+ form = forms.ProfileForm(
+ instance=profile,
+ initial=initial,
+ )
+ form.fields['country'].choices = COUNTRIES
if not request.user.username.startswith('u/'):
initial.update(username=request.user.username)
- form = forms.ProfileForm(
- instance=profile,
- initial=initial,
- )
- form.fields['country'].choices = COUNTRIES
-
# When changing this keep in mind that the same view is used for
# user.register.
d = dict(form=form,
@@ -152,7 +163,9 @@ def search(request):
# If nothing has been entered don't load any searches.
if not (not query and vouched is None and profilepic is None):
- profiles = UserProfile.search(query, vouched=vouched, photo=profilepic)
+ profiles = UserProfile.search(query,
+ vouched=vouched,
+ photo=profilepic)
paginator = Paginator(profiles, limit)
@@ -164,7 +177,8 @@ def search(request):
people = paginator.page(paginator.num_pages)
if len(profiles) == 1:
- return redirect(reverse('profile', args=[people[0].user.username]))
+ return redirect(reverse('profile',
+ args=[people[0].user.username]))
if paginator.count > forms.PAGINATION_LIMIT:
show_pagination = True
View
5 apps/users/models.py
@@ -14,6 +14,7 @@
from PIL import Image, ImageOps
from product_details import product_details
from sorl.thumbnail import ImageField
+from tastypie.models import ApiKey
from tower import ugettext as _, ugettext_lazy as _lazy
from groups.models import Group, Skill
@@ -156,6 +157,10 @@ def vouch(self, vouched_by, system=True, commit=True):
# Email the user and tell them they were vouched.
self._email_now_vouched()
+ def get_api_key(self):
+ api_key, created = ApiKey.objects.get_or_create(user=self.user)
+ return api_key.key
+
def _email_now_vouched(self):
"""Email this user, letting them know they are now vouched."""
subject = _(u'You are now vouched on Mozillians!')
View
15 apps/users/tests.py
@@ -338,7 +338,7 @@ class TestUser(TestCase):
"""Test User functionality"""
def test_userprofile(self):
- u = User.objects.create(username='tmp', email='tmp@domain.com')
+ u = user()
UserProfile.objects.all().delete()
@@ -354,6 +354,19 @@ def test_userprofile(self):
# Good to go
assert u.get_profile()
+ def test_apikey(self):
+ """Test that get_api_key() will create a key if missing."""
+ # A new user will not have a key created.
+ u = user()
+ p = u.get_profile()
+ from tastypie.models import ApiKey
+
+ # A new key is not generated automatically on a user.
+ self.assertRaises(ApiKey.DoesNotExist, lambda: u.api_key)
+
+ # get_api_key will always return a key, creating one if needed.
+ eq_(p.get_api_key(), u.api_key.key)
+
class TestMigrateRegistration(TestCase):
"""Test funky behavior of flee ldap"""
View
4 media/css/user.css
@@ -0,0 +1,4 @@
+.control-group h2 {
+ border-bottom: 1px solid black;
+ margin-bottom: 10px;
+}
View
4 settings/default.py
@@ -69,6 +69,9 @@
'test': (
'css/qunit.css',
),
+ 'edit_profile': (
+ 'css/user.css',
+ ),
},
'js': {
'common': (
@@ -149,6 +152,7 @@
'cronjobs',
'elasticutils',
'sorl.thumbnail',
+ 'tastypie',
'django.contrib.admin',
'django.contrib.auth',
Please sign in to comment.
Something went wrong with that request. Please try again.