Skip to content

Commit

Permalink
Merge pull request ofri#48
Browse files Browse the repository at this point in the history
  • Loading branch information
MeirKriheli committed Dec 30, 2012
2 parents 85558bf + a748dc7 commit 41ec02a
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 83 deletions.
37 changes: 0 additions & 37 deletions apis/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,43 +390,6 @@ def read(self, request, **kwargs):
def members(cls,party):
return party.members.values_list('id',flat=True)

class TagHandler(BaseHandler):
fields = ('id', 'name', 'number_of_items')
allowed_methods = ('GET',)
model = Tag

def read(self, request, **kwargs):
id = None
if 'id' in kwargs:
id = kwargs['id']
if id:
try:
return Tag.objects.get(pk=id)
except Tag.DoesNotExist:
return rc.NOT_FOUND
object_id = None
ctype = None
if 'object_id' in kwargs and 'object_type' in kwargs:
object_id = kwargs['object_id']
try:
ctype = ContentType.objects.get_by_natural_key(kwargs['app_label'], kwargs['object_type'])
except ContentType.DoesNotExist:
pass
if object_id and ctype:
tags_ids = TaggedItem.objects.filter(object_id=object_id).filter(content_type=ctype).values_list('tag', flat=True)
return Tag.objects.filter(id__in=tags_ids)

vote_tags = Tag.objects.usage_for_model(Vote)
bill_tags = Tag.objects.usage_for_model(Bill)
cm_tags = Tag.objects.usage_for_model(CommitteeMeeting)
all_tags = list(set(vote_tags).union(bill_tags).union(cm_tags))
all_tags.sort(key=attrgetter('name'))
return all_tags

@classmethod
def number_of_items(self, tag):
return tag.items.count()

class AgendaHandler(BaseHandler):
# TODO: Once we have user authentication over the API,
# need to expose not only public agendas.
Expand Down
3 changes: 2 additions & 1 deletion apis/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from laws.api import BillResource, LawResource, VoteResource
from agendas.api import AgendaResource, AgendaTodoResource
from committees.api import CommitteeResource, CommitteeMeetingResource, ProtocolPartResource
from auxiliary.api import PostResource
from auxiliary.api import PostResource, TagResource

v2_api = Api(api_name='v2')

Expand All @@ -28,3 +28,4 @@
v2_api.register(CommitteeMeetingResource())
v2_api.register(ProtocolPartResource())
v2_api.register(PostResource())
v2_api.register(TagResource())
31 changes: 0 additions & 31 deletions apis/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,6 @@ def setUp(self):
mk = Member.objects.create(name='mk %d' % i,current_party=self.party_1)
self.mks.append(mk)
self.voteactions.append(VoteAction.objects.create(member=mk,type='for',vote=self.vote_1))
self.tags = []
self.tags.append(Tag.objects.create(name = 'tag1'))
self.tags.append(Tag.objects.create(name = 'tag2'))
ctype = ContentType.objects.get_for_model(Vote)
TaggedItem._default_manager.get_or_create(tag=self.tags[0], content_type=ctype, object_id=self.vote_1.id)
TaggedItem._default_manager.get_or_create(tag=self.tags[1], content_type=ctype, object_id=self.vote_1.id)
self.agenda = Agenda.objects.create(name="agenda 1 (public)", public_owner_name="owner", is_public=True)
self.private_agenda = Agenda.objects.create(name="agenda 2 (private)", public_owner_name="owner")
self.law_1 = Law.objects.create(title='law 1')
Expand Down Expand Up @@ -179,31 +173,6 @@ def test_api_bill_list_popular_with_type(self):
res_json = json.loads(res.content)
self.assertEqual(len(res_json), 0)

def test_api_tag_list(self):
res = self.client.get(reverse('tag-handler'))
self.assertEqual(res.status_code, 200)
res_json = json.loads(res.content)
self.assertEqual(len(res_json), 2)
self.assertEqual(set([x['name'] for x in res_json]), set(Tag.objects.values_list('name',flat=True)))

def test_api_tag(self):
res = self.client.get(reverse('tag-handler', args=[self.tags[0].id]))
self.assertEqual(res.status_code, 200)
res_json = json.loads(res.content)
self.assertEqual(res_json['name'], self.tags[0].name)

def test_api_tag_not_found(self):
res = self.client.get(reverse('tag-handler', args=[123456]))
self.assertEqual(res.status_code, 404)

def test_api_tag_for_vote(self):
res = self.client.get(reverse('tag-handler',
args=['laws', 'vote',
self.vote_1.id]))
self.assertEqual(res.status_code, 200)
res_json = json.loads(res.content)
self.assertEqual(len(res_json), 2)

def test_api_agenda_list(self):
res = self.client.get(reverse('agenda-handler'))
self.assertEqual(res.status_code, 200)
Expand Down
4 changes: 0 additions & 4 deletions apis/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
bill_handler = cache_page(Resource(BillHandler), 60*15)
member_handler = cache_page(Resource(MemberHandler), 60*15)
party_handler = cache_page(Resource(PartyHandler), 60*15)
tag_handler = cache_page(Resource(TagHandler), 60*15)
agenda_handler = cache_page(Resource(AgendaHandler), 60*15)
committee_handler = cache_page(Resource(CommitteeHandler), 60*15)
committee_meeting_handler = cache_page(Resource(CommitteeMeetingHandler), 60*15)
Expand All @@ -26,9 +25,6 @@
url(r'^member/(?P<id>[0-9]+)/$', member_handler, name='member-handler'),
url(r'^party/$', party_handler, name='party-handler'),
url(r'^party/(?P<id>[0-9]+)/$', party_handler, name='party-handler'),
url(r'^tag/$', tag_handler, name='tag-handler'),
url(r'^tag/(?P<id>[0-9]+)/$', tag_handler, name='tag-handler'),
url(r'^tag/(?P<app_label>\w+)/(?P<object_type>\w+)/(?P<object_id>[0-9]+)/$', tag_handler, name='tag-handler'),
url(r'^agenda/$', agenda_handler, name='agenda-handler'),
url(r'^agenda/(?P<id>[0-9]+)/$', agenda_handler, name='agenda-handler'),
url(r'^agenda/(?P<app_label>\w+)/(?P<object_type>\w+)/(?P<object_id>[0-9]+)/$', agenda_handler, name='agenda-handler'),
Expand Down
77 changes: 76 additions & 1 deletion auxiliary/api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'''
Api for planet
Api for planet and tags
'''

from tastypie.exceptions import InvalidFilterError
Expand All @@ -8,6 +8,16 @@
from planet.models import Feed, Post
from mks.models import Member
from links.models import Link
from tagging.models import Tag, TaggedItem
from django.contrib.contenttypes.models import ContentType
from django.conf.urls.defaults import url
from django.http import Http404
from django.shortcuts import get_object_or_404

from laws.models import Vote, Bill
from committees.models import CommitteeMeeting

from operator import attrgetter


class PostResource(BaseResource):
Expand Down Expand Up @@ -40,3 +50,68 @@ def build_filters(self, filters=None):
orm_filters["feed__in"] = feeds

return orm_filters


class TagResource(BaseResource):
''' Tagging API
'''
class Meta:
queryset = Tag.objects.all().order_by('name')
allowed_methods = ['get']
list_fields = [ 'id', 'name' ]

TAGGED_MODELS = ( Vote, Bill, CommitteeMeeting )

def obj_get_list(self, filters=None, **kwargs):
all_tags = list(set().union(*[Tag.objects.usage_for_model(model) for model in self.TAGGED_MODELS]))
all_tags.sort(key=attrgetter('name'))
return all_tags

def dehydrate(self, bundle):
bundle.data['number_of_items'] = bundle.obj.items.count()
return bundle

def override_urls(self):
return [
url(r'^(?P<resource_name>%s)/(?P<app_label>\w+)/(?P<object_type>\w+)/(?P<object_id>[0-9]+)/$' % self._meta.resource_name, self.wrap_view('get_object_tags'), name='tags-for-object'),
url(r'^(?P<resource_name>%s)/(?P<app_label>\w+)/(?P<object_type>\w+)/(?P<object_id>[0-9]+)/(?P<related_name>[_a-zA-Z]\w*)/$' % self._meta.resource_name, self.wrap_view('get_related_tags'), name='related-tags'),
]

def _create_response(self, request, objects):
bundles = []
for result in objects:
bundle = self.build_bundle(obj=result, request=request)
bundle = self.full_dehydrate(bundle)
bundles.append(bundle)

return self.create_response(request, {'objects': bundles})

def get_related_tags(self, request, **kwargs):
""" Can be used to get all tags used by all CommitteeMeetings of a specific committee
"""
try:
ctype = ContentType.objects.get_by_natural_key(kwargs['app_label'], kwargs['object_type'])
except ContentType.DoesNotExist:
raise Http404('Object type not found.')

model = ctype.model_class()
container = get_object_or_404(model, pk=kwargs['object_id'])
try:
related_objects = getattr(container, kwargs['related_name']).all()
except AttributeError:
raise Http404('Related name not found.')

tags = Tag.objects.usage_for_queryset(related_objects)

return self._create_response(request, tags)

def get_object_tags(self, request, **kwargs):
ctype = None
try:
ctype = ContentType.objects.get_by_natural_key(kwargs['app_label'], kwargs['object_type'])
except ContentType.DoesNotExist:
pass

tags_ids = TaggedItem.objects.filter(object_id=kwargs['object_id']).filter(content_type=ctype).values_list('tag', flat=True)
tags = Tag.objects.filter(id__in=tags_ids)
return self._create_response(request, tags)
65 changes: 64 additions & 1 deletion auxiliary/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,75 @@
from django.utils import translation
from django.conf import settings
from tagging.models import Tag,TaggedItem
from laws.models import Vote, VoteAction, Bill
from laws.models import Vote, VoteAction, Bill, Law
from mks.models import Member,Party,WeeklyPresence
from agendas.models import Agenda
from knesset.sitemap import sitemaps
from django.utils import simplejson as json
from auxiliary.views import CsvView
from django.core import cache

class TagResourceTest(TestCase):

def setUp(self):
cache.cache.clear()
self.tags = []
self.tags.append(Tag.objects.create(name = 'tag1'))
self.tags.append(Tag.objects.create(name = 'tag2'))
self.tags.append(Tag.objects.create(name = 'tag3'))

self.vote = Vote.objects.create(title="vote 1", time=datetime.datetime.now())
ctype = ContentType.objects.get_for_model(Vote)
TaggedItem._default_manager.get_or_create(tag=self.tags[0], content_type=ctype, object_id=self.vote.id)
TaggedItem._default_manager.get_or_create(tag=self.tags[1], content_type=ctype, object_id=self.vote.id)
self.law = Law.objects.create(title='law 1')
self.bill = Bill.objects.create(stage='1',
stage_date=datetime.date.today(),
title='bill 1',
law=self.law)
self.bill2 = Bill.objects.create(stage='2',
stage_date=datetime.date.today(),
title='bill 2',
law=self.law)
Tag.objects.add_tag(self.bill, 'tag1')
Tag.objects.add_tag(self.bill2, 'tag3')

def _reverse_api(self, name, **args):
args.update(dict(api_name='v2', resource_name='tag'))
return reverse(name, kwargs=args)

def test_api_tag_list(self):
res = self.client.get(self._reverse_api('api_dispatch_list'))
self.assertEqual(res.status_code, 200)
res_json = json.loads(res.content)['objects']
self.assertEqual(len(res_json), 3)
self.assertEqual(set([x['name'] for x in res_json]), set(Tag.objects.values_list('name',flat=True)))

def test_api_tag(self):
res = self.client.get(self._reverse_api('api_dispatch_detail', pk = self.tags[0].id))
self.assertEqual(res.status_code, 200)
res_json = json.loads(res.content)
self.assertEqual(res_json['name'], self.tags[0].name)

def test_api_tag_not_found(self):
res = self.client.get(self._reverse_api('api_dispatch_detail', pk = 12345))
self.assertEqual(res.status_code, 404)

def test_api_tag_for_vote(self):
res = self.client.get(self._reverse_api('tags-for-object', app_label='laws',
object_type='vote', object_id=self.vote.id))
self.assertEqual(res.status_code, 200)
res_json = json.loads(res.content)['objects']
self.assertEqual(len(res_json), 2)

def test_api_related_tags(self):
res = self.client.get(self._reverse_api('related-tags', app_label='laws',
object_type='law', object_id=self.law.id, related_name='bills'))
self.assertEqual(res.status_code, 200)
res_json = json.loads(res.content)['objects']
self.assertEqual(len(res_json), 2)
received_tags = set(Tag.objects.get(pk=x) for x in (res_json[0]['id'], res_json[1]['id']))
self.assertEqual(received_tags, set([self.tags[0], self.tags[2]]))

class InternalLinksTest(TestCase):

Expand Down
25 changes: 19 additions & 6 deletions static/js/tagging.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,30 @@ var current_id = "";
var current_object_type = "";
var current_app = "";

function get_tags_list() {
$("#possible_tags").html('');
$.ajax({url: '/api/tag/', success: get_tags_list_callback, cache: false});
function get_tags_list(url) {
if (typeof(url) === 'undefined') {
url = '/api/v2/tag/?format=json&limit=100'
}
$.ajax({url: url, success: get_tags_list_callback, cache: false});
}

function add_nav_button(text, url) {
if (url !== null) {
$('<a>').attr('href', "javascript:get_tags_list('"+encodeURIComponent(url)+"')").html(text).appendTo("#possible_tags");
}
}

function get_tags_list_callback(data) {
$.each(data, function(i,item){
$("#possible_tags").html('<br/>');
$.each(data['objects'], function(i,item){
var href = "javascript:toggle_tag("+item.id+");";
$('<a class="tag">').attr("id", "possible_tag_"+item.id).attr("href", href).html(item.name).appendTo("#possible_tags");
$("#possible_tags").append(document.createTextNode(" "));
});
meta = data['meta'];
$("#possible_tags").append('<br/>');
add_nav_button(gettext('previous'), meta['previous']);
add_nav_button(gettext('next'), meta['next']);
current_app = $('input[name="app_label"]').val();
current_object_type = $('input[name="object_type"]').val();
current_id = $('input[name="id"]').val();
Expand All @@ -22,7 +35,7 @@ function get_tags_list_callback(data) {
current_object_type = 'committeemeeting';
current_id = window.location.pathname.split('/')[3];
}
var url = '/api/tag/'+current_app+'/'+current_object_type+'/'+current_id+'/';
var url = '/api/v2/tag/'+current_app+'/'+current_object_type+'/'+current_id+'/';
$.ajax({url: url, success: mark_selected_tags, cache: false});
$('#create_tag').show();
$('#create_tag_form').submit(function(){
Expand All @@ -35,7 +48,7 @@ function get_tags_list_callback(data) {
}

function mark_selected_tags(data){
$.each(data, function(i,item){
$.each(data['objects'], function(i,item){
$("#possible_tag_"+item.id).addClass("selected");
selected_tags[item.id]=1;
});
Expand Down
4 changes: 2 additions & 2 deletions templates/committees/committeemeeting_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ <h2>{% trans "Tags" %}</h2>
</div>
<div id="add_tags">
<span>{% trans "Edit Tags" %}</span>
<span id="possible_tags"><a href="javascript:get_tags_list();">{% trans "Click here" %}</a>
</span>
<span id="possible_tags"></span><br>
<a href="javascript:get_tags_list('{% url related-tags resource_name='tag' api_name='v2' app_label='committees' object_type='committee' object_id=object.committee.id related_name='meetings' %}');">{% trans "Click here for tags related to this committee" %}</a><br><a href="javascript:get_tags_list();">{% trans "Click here to see all available tags" %}</a>
<div id="create_tag" style='display:none'>
{% if perms.tagging.add_tag %}
<form id="create_tag_form" action="#">{% csrf_token %}
Expand Down

0 comments on commit 41ec02a

Please sign in to comment.