Permalink
Browse files

Implement API methods, add admin panel controls and more data.

[fix bug 795385] Add API controls to Admin panel.
[fix bug 769070] Include more data in API.
[bug 769069] Implement API methods.

[fix bug 763717] Add search functionality to API.

Search for groups, skills, languages, username, ircname, country,
region, city, last_name, first_name, is_vouched.

[fix bug 795380] Add API privacy controls.
  • Loading branch information...
1 parent 57c907e commit d690ebdcf9b6732361719143be71de79206e4346 @glogiotatidis glogiotatidis committed with glogiotatidis Sep 4, 2012
View
No changes.
View
@@ -0,0 +1,11 @@
+from django.contrib import admin
+
+from models import APIApp
+
+
+class APIAppAdmin(admin.ModelAdmin):
+ """APIApp Admin."""
+ list_display = ['name', 'key', 'owner', 'is_mozilla_app', 'is_active']
+ list_filter = ['is_mozilla_app', 'is_active']
+
+admin.site.register(APIApp, APIAppAdmin)
View
@@ -0,0 +1,16 @@
+from tastypie.authentication import Authentication
+
+from models import APIApp
+
+
+class AppAuthentication(Authentication):
+ """App Authentication."""
+
+ def is_authenticated(self, request, **kwargs):
+ """Authenticate App."""
+ app_key = request.GET.get('app_key', None)
+ app_name = request.GET.get('app_name', None)
+
+ return (APIApp.objects.filter(name__iexact=app_name, key=app_key,
+ is_active=True).exists())
+
View
@@ -0,0 +1,24 @@
+from tastypie.authorization import ReadOnlyAuthorization
+
+from models import APIApp
+
+
+class MozillaOfficialAuthorization(ReadOnlyAuthorization):
+ """Authorize an App as official Mozilla or Community."""
+
+ def is_authorized(self, request, object=None):
+ """Authorize App.
+
+ Always authorize Apps. Community Apps get a 'restricted' URL
+ parameter.
+
+ """
+ app_name = request.GET.get('app_name', None)
+ app_key = request.GET.get('app_key', None)
+ app = APIApp.objects.get(name=app_name, key=app_key)
+
+ if not app.is_mozilla_app:
+ data = request.GET.copy()
+ data['restricted'] = True
+ request.GET = data
+ return True
@@ -0,0 +1,81 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model 'APIApp'
+ db.create_table('api_apiapp', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=100)),
+ ('description', self.gf('django.db.models.fields.TextField')()),
+ ('url', self.gf('django.db.models.fields.URLField')(default='', max_length=300, blank=True)),
+ ('owner', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ('key', self.gf('django.db.models.fields.CharField')(default='', max_length=256, blank=True)),
+ ('is_superapp', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+ ))
+ db.send_create_signal('api', ['APIApp'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'APIApp'
+ db.delete_table('api_apiapp')
+
+
+ models = {
+ 'api.apiapp': {
+ 'Meta': {'object_name': 'APIApp'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_superapp': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'key': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '256', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['api']
@@ -0,0 +1,77 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Deleting field 'APIApp.is_superapp'
+ db.delete_column('api_apiapp', 'is_superapp')
+
+ # Adding field 'APIApp.is_mozilla_app'
+ db.add_column('api_apiapp', 'is_mozilla_app', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Adding field 'APIApp.is_superapp'
+ db.add_column('api_apiapp', 'is_superapp', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False)
+
+ # Deleting field 'APIApp.is_mozilla_app'
+ db.delete_column('api_apiapp', 'is_mozilla_app')
+
+
+ models = {
+ 'api.apiapp': {
+ 'Meta': {'object_name': 'APIApp'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_mozilla_app': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'key': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '256', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['api']
@@ -0,0 +1,72 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding field 'APIApp.is_active'
+ db.add_column('api_apiapp', 'is_active', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Deleting field 'APIApp.is_active'
+ db.delete_column('api_apiapp', 'is_active')
+
+
+ models = {
+ 'api.apiapp': {
+ 'Meta': {'object_name': 'APIApp'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_mozilla_app': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'key': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '256', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['api']
No changes.
View
@@ -0,0 +1,36 @@
+import hmac
+import uuid
+from hashlib import sha1
+
+from django.contrib.auth.models import User
+from django.db import models
+
+
+class APIApp(models.Model):
+ """APIApp Model."""
+ name = models.CharField(max_length=100, unique=True)
+ description = models.TextField()
+ url = models.URLField(max_length=300, blank=True, default='')
+ owner = models.ForeignKey(User)
+ key = models.CharField(
+ help_text='Leave this field empty to generate a new API key.',
+ max_length=256, blank=True, default='')
+ is_mozilla_app = models.BooleanField(blank=True, default=False)
+ is_active = models.BooleanField(blank=True, default=False)
+ created = models.DateTimeField(auto_now_add=True)
+
+ def __unicode__(self):
+ """Return unicode representation of object."""
+ return "%s for %s" % (self.name, self.owner)
+
+ def save(self, *args, **kwargs):
+ """Generates a key if none and saves object."""
+ if not self.key:
+ self.key = self.generate_key()
+
+ return super(APIApp, self).save(*args, **kwargs)
+
+ def generate_key(self):
+ """Return a key."""
+ new_uuid = uuid.uuid4()
+ return hmac.new(str(new_uuid), digestmod=sha1).hexdigest()
@@ -10,7 +10,7 @@
</head>
<body>
{% block content %}
- <a id="json_url" href=""></a>
+ <a id="json_url" href=""></a>
<pre id="json" class="prettyprint">
</pre>
{% endblock %}
View
@@ -0,0 +1,12 @@
+from django.conf.urls.defaults import include, patterns, url
+
+from tastypie.api import Api
+
+import apps.users.api
+
+v1_api = Api(api_name='v1')
+v1_api.register(apps.users.api.UserResource())
+
+urlpatterns = patterns('',
+ url(r'', include(v1_api.urls)),
+)
View
@@ -1,18 +0,0 @@
-from django.template.loader import render_to_string
-
-from tastypie.serializers import Serializer
-
-
-class HTMLSerializer(Serializer):
- """HTML Serializer for django-tastypie."""
- formats = ['json', 'jsonp', 'xml', 'html']
- content_types = {
- 'json': 'application/json',
- 'jsonp': 'text/javascript',
- 'xml': 'application/xml',
- 'html': 'text/html',
- }
-
- def to_html(self, data, options=None):
- """Return /data/ to html."""
- return render_to_string('api.html', locals())
View
@@ -1,8 +1,6 @@
import random
from string import letters
-import pyes.exceptions
-
from django import test
from django.conf import settings
from django.contrib.auth.models import User
@@ -13,7 +11,7 @@
from elasticutils.contrib.django import get_es
from apps.users.cron import index_all_profiles
-from apps.users.models import UserProfile
+
class TestCase(test_utils.TestCase):
"""Tests for common package."""
View
@@ -120,7 +120,7 @@ class Meta:
# Model form stuff
model = UserProfile
fields = ('ircname', 'website', 'bio', 'photo', 'country', 'region',
- 'city')
+ 'city', 'allows_community_sites', 'allows_mozilla_sites')
widgets = {'bio': forms.Textarea()}
def clean_groups(self):
Oops, something went wrong.

0 comments on commit d690ebd

Please sign in to comment.