From 9b60e7f1207cfa0a79bd79ac254ecad273107f99 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Fri, 7 Oct 2011 10:47:19 +0200 Subject: [PATCH] add news backend --- pandora/news/__init__.py | 0 pandora/news/admin.py | 12 +++ pandora/news/managers.py | 119 ++++++++++++++++++++++++ pandora/news/models.py | 50 ++++++++++ pandora/news/views.py | 192 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 373 insertions(+) create mode 100644 pandora/news/__init__.py create mode 100644 pandora/news/admin.py create mode 100644 pandora/news/managers.py create mode 100644 pandora/news/models.py create mode 100644 pandora/news/views.py diff --git a/pandora/news/__init__.py b/pandora/news/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pandora/news/admin.py b/pandora/news/admin.py new file mode 100644 index 000000000..d30e91e0c --- /dev/null +++ b/pandora/news/admin.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +# vi:si:et:sw=4:sts=4:ts=4 + +from django.contrib import admin + +import models + + +class NewsAdmin(admin.ModelAdmin): + search_fields = ['name', 'title'] +admin.site.register(models.News, NewsAdmin) + diff --git a/pandora/news/managers.py b/pandora/news/managers.py new file mode 100644 index 000000000..e98a1b976 --- /dev/null +++ b/pandora/news/managers.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- +# vi:si:et:sw=4:sts=4:ts=4 +from django.db.models import Q, Manager +from ox.django.query import QuerySet +import ox + +def parseCondition(condition, user): + k = condition.get('key', 'name') + k = { + 'user': 'user__username', + }.get(k, k) + if not k: + k = 'name' + v = condition['value'] + op = condition.get('operator') + if not op: + op = '' + if op.startswith('!'): + op = op[1:] + exclude = True + else: + exclude = False + if op == '-': + q = parseCondition({'key': k, 'value': v[0], 'operator': '>='}, user) \ + & parseCondition({'key': k, 'value': v[1], 'operator': '<'}, user) + if exclude: + return ~q + else: + return q + if k == 'id': + v = ox.from26(v) + if isinstance(v, bool): #featured and public flag + key = k + elif k in ('id',): + key = "%s%s" % (k, { + '>': '__gt', + '>=': '__gte', + '<': '__lt', + '<=': '__lte', + }.get(op, '')) + else: + key = "%s%s" % (k, { + '>': '__gt', + '>=': '__gte', + '<': '__lt', + '<=': '__lte', + '==': '__iexact', + '=': '__icontains', + '^': '__istartswith', + '$': '__iendswith', + }.get(op, '__icontains')) + + key = str(key) + if exclude: + q = ~Q(**{key: v}) + else: + q = Q(**{key: v}) + return q + +def parseConditions(conditions, operator, user): + ''' + conditions: [ + { + value: "war" + } + { + key: "year", + value: "1970-1980, + operator: "!=" + }, + { + key: "country", + value: "f", + operator: "^" + } + ], + operator: "&" + ''' + conn = [] + for condition in conditions: + if 'conditions' in condition: + q = parseConditions(condition['conditions'], + condition.get('operator', '&'), user) + if q: + conn.append(q) + pass + else: + conn.append(parseCondition(condition, user)) + if conn: + q = conn[0] + for c in conn[1:]: + if operator == '|': + q = q | c + else: + q = q & c + return q + return None + + +class NewsManager(Manager): + + def get_query_set(self): + return QuerySet(self.model) + + def find(self, data, user): + #join query with operator + qs = self.get_query_set() + + conditions = parseConditions(data.get('query', {}).get('conditions', []), + data.get('query', {}).get('operator', '&'), + user) + if conditions: + qs = qs.filter(conditions) + if user: + if not user.get_profile().get_level() in ('staff', 'admin'): + qs = qs.filter(Q(public=True)|Q(user=user)) + else: + qs = qs.filter(public=True) + return qs diff --git a/pandora/news/models.py b/pandora/news/models.py new file mode 100644 index 000000000..cb054190b --- /dev/null +++ b/pandora/news/models.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# vi:si:et:sw=4:sts=4:ts=4 +from __future__ import division, with_statement + +from django.db import models +from django.contrib.auth.models import User +import ox + +import managers + + +class News(models.Model): + objects = managers.NewsManager() + + created = models.DateTimeField(auto_now_add=True) + modified = models.DateTimeField(auto_now=True) + user = models.ForeignKey(User) + + title = models.TextField() + content = models.TextField() + + def editable(self, user): + if user.is_authenticated(): + if user.get_profile().get_level() in ('staff', 'admin') or \ + self.user == user or \ + user.groups.filter(id__in=self.groups.all()).count() > 0: + return True + return False + + ''' + def save(self, *args, **kwargs): + super(News, self).save(*args, **kwargs) + ''' + + def json(self, keys=None): + j = { + 'user': self.user.username, + 'id': ox.to26(self.id), + 'title': self.title, + 'content': self.content, + } + if keys: + for key in j.keys(): + if key not in keys: + del j[key] + return j + + def __unicode__(self): + return u"%s/%s" %(self.created, self.title) + diff --git a/pandora/news/views.py b/pandora/news/views.py new file mode 100644 index 000000000..c6dc36ccf --- /dev/null +++ b/pandora/news/views.py @@ -0,0 +1,192 @@ +# -*- coding: utf-8 -*- +# vi:si:et:sw=4:sts=4:ts=4 +from __future__ import division + +from django.conf import settings + +import ox +from ox.utils import json +from ox.django.decorators import login_required_json +from ox.django.shortcuts import render_to_json_response, get_object_or_404_json, json_response + + +from item.models import Item +from api.actions import actions + +from item import utils +from item.models import Item + +import models + + +def parse_query(data, user): + query = {} + query['range'] = [0, 100] + query['sort'] = [{'key':'in', 'operator':'+'}] + for key in ('keys', 'group', 'range', 'sort', 'query'): + if key in data: + query[key] = data[key] + query['qs'] = models.News.objects.find(query, user) + if 'itemQuery' in data: + item_query = Item.objects.find({'query': data['itemQuery']}, user) + query['qs'] = query['qs'].filter(item__in=item_query) + return query + +def news_sort_key(key): + return { + 'text': 'value', + 'position': 'start', + }.get(key, key) + +def order_query(qs, sort): + order_by = [] + print sort + for e in sort: + operator = e['operator'] + if operator != '-': + operator = '' + key = { + 'duration': 'clip__duration', + 'in': 'start', + 'lightness': 'clip__lightness', + 'out': 'end', + 'saturation': 'clip__saturation', + 'volume': 'clip__volume', + }.get(e['key'], e['key']) + if key.startswith('clip:'): + key = news_sort_key(e['key'][len('clip:'):]) + elif key not in ('start', 'end', 'value') and not key.startswith('clip__'): + #key mgith need to be changed, see order_sort in item/views.py + key = "item__sort__%s" % key + order = '%s%s' % (operator, key) + order_by.append(order) + if order_by: + qs = qs.order_by(*order_by, nulls_last=True) + return qs + +def findNews(request): + ''' + param data { + query: ... + itemQuery: ... + } + + return { + 'status': {'code': int, 'text': string} + 'data': { + newss = [{..}, {...}, ...] + } + } + ''' + data = json.loads(request.POST['data']) + response = json_response() + + query = parse_query(data, request.user) + qs = order_query(query['qs'], query['sort']) + if 'keys' in data: + qs = qs[query['range'][0]:query['range'][1]] + response['data']['items'] = [p.json(keys=data['keys']) for p in qs] + elif 'position' in query: + ids = [ox.to26(i.id) for i in qs] + data['conditions'] = data['conditions'] + { + 'value': data['position'], + 'key': query['sort'][0]['key'], + 'operator': '^' + } + query = parse_query(data, request.user) + qs = order_query(query['qs'], query['sort']) + if qs.count() > 0: + response['data']['position'] = utils.get_positions(ids, [qs[0].itemId])[0] + elif 'positions' in data: + ids = [ox.to26(i.id) for i in qs] + response['data']['positions'] = utils.get_positions(ids, data['positions']) + else: + response['data']['items'] = qs.count() + return render_to_json_response(response) +actions.register(findNews) + + +@login_required_json +def addNews(request): + ''' + param data { + title: string, + content: text, + public: boolean + } + return {'status': {'code': int, 'text': string}, + 'data': { + id: 123, + ... + } + } + ''' + data = json.loads(request.POST['data']) + + news = models.News( + user=request.user, + title=data['title'], + content=data['content'], + public=data['content']) + news.save() + response = json_response(news.json()) + return render_to_json_response(response) +actions.register(addNews, cache=False) + + +@login_required_json +def removeNews(request): + ''' + param data { + ids: [] + } + return {'status': {'code': int, 'text': string}, + 'data': { + } + } + ''' + response = json_response({}) + data = json.loads(request.POST['data']) + failed = [] + ids = [ox.from26(i) for i in data['ids']] + for a in models.News.objects.filter(id__in=ids): + if a.editable(request.user): + a.delete() + else: + failed.append(a.id) + if failed: + response = json_response(status=403, text='permission denied') + response['data']['ids'] = [ox.to26(i) for i in failed] + return render_to_json_response(response) +actions.register(removeNews, cache=False) + + +@login_required_json +def editNews(request): + ''' + param data { + id:, + title: + content: + public: + } + return {'status': {'code': int, 'text': string}, + 'data': { + id: + ... + } + } + ''' + response = json_response({}) + data = json.loads(request.POST['data']) + n = get_object_or_404_json(models.News, id=ox.from26(data['id'])) + if n.editable(request.user): + for key in ('title', 'content', 'public'): + if key in data: + setattr(n, key, data[key]) + n.save() + response['data'] = n.json() + else: + response = json_response(status=403, text='permission denied') + return render_to_json_response(response) +actions.register(editNews, cache=False)