Skip to content
This repository has been archived by the owner on Jan 19, 2021. It is now read-only.

Commit

Permalink
Implement API methods, add admin panel controls and more data.
Browse files Browse the repository at this point in the history
[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
glogiotatidis committed Oct 30, 2012
1 parent 57c907e commit d690ebd
Show file tree
Hide file tree
Showing 28 changed files with 1,097 additions and 211 deletions.
Empty file added apps/api/__init__.py
Empty file.
11 changes: 11 additions & 0 deletions apps/api/admin.py
@@ -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)
16 changes: 16 additions & 0 deletions apps/api/authenticators.py
@@ -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())

24 changes: 24 additions & 0 deletions apps/api/authorisers.py
@@ -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
81 changes: 81 additions & 0 deletions apps/api/migrations/0001_initial.py
@@ -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']
72 changes: 72 additions & 0 deletions apps/api/migrations/0003_auto__add_field_apiapp_is_active.py
@@ -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']
Empty file added apps/api/migrations/__init__.py
Empty file.
36 changes: 36 additions & 0 deletions apps/api/models.py
@@ -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()
2 changes: 1 addition & 1 deletion templates/api.html → apps/api/templates/api.html
Expand Up @@ -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 %}
Expand Down
12 changes: 12 additions & 0 deletions apps/api/urls.py
@@ -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)),
)
18 changes: 0 additions & 18 deletions apps/common/api.py

This file was deleted.

4 changes: 1 addition & 3 deletions apps/common/tests.py
@@ -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
Expand All @@ -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."""
Expand Down
2 changes: 1 addition & 1 deletion apps/phonebook/forms.py
Expand Up @@ -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):
Expand Down

0 comments on commit d690ebd

Please sign in to comment.