initial round of text section
This commit is contained in:
parent
f8ededaf55
commit
c8af45e7cf
25 changed files with 2243 additions and 984 deletions
|
|
@ -31,6 +31,8 @@
|
|||
"canEditAnnotations": {"staff": true, "admin": true},
|
||||
"canEditEvents": {"staff": true, "admin": true},
|
||||
"canEditFeaturedLists": {"staff": true, "admin": true},
|
||||
"canEditFeaturedTexts": {"staff": true, "admin": true},
|
||||
"canEditFeaturedEdits": {"staff": true, "admin": true},
|
||||
"canEditMetadata": {"staff": true, "admin": true},
|
||||
"canEditPlaces": {"staff": true, "admin": true},
|
||||
"canEditSitePages": {"staff": true, "admin": true},
|
||||
|
|
@ -712,6 +714,8 @@
|
|||
"icons": "posters",
|
||||
"infoIconSize": 256,
|
||||
"item": "",
|
||||
"text": "",
|
||||
"edit": "",
|
||||
"itemFind": "",
|
||||
"itemSort": [{"key": "position", "operator": "+"}],
|
||||
"itemView": "info",
|
||||
|
|
@ -749,6 +753,11 @@
|
|||
"featured": true,
|
||||
"volumes": true
|
||||
}
|
||||
"texts": {
|
||||
"personal": true,
|
||||
"favorite": true,
|
||||
"featured": true
|
||||
}
|
||||
},
|
||||
"showSidebar": true,
|
||||
"showSitePosters": false,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
"canEditAnnotations": {"staff": true, "admin": true},
|
||||
"canEditEvents": {"staff": true, "admin": true},
|
||||
"canEditFeaturedLists": {"staff": true, "admin": true},
|
||||
"canEditFeaturedTexts": {"staff": true, "admin": true},
|
||||
"canEditFeaturedEdits": {"staff": true, "admin": true},
|
||||
"canEditMetadata": {"staff": true, "admin": true},
|
||||
"canEditPlaces": {"staff": true, "admin": true},
|
||||
"canEditSitePages": {"staff": true, "admin": true},
|
||||
|
|
@ -630,6 +632,8 @@
|
|||
"icons": "frames",
|
||||
"infoIconSize": 256,
|
||||
"item": "",
|
||||
"text": "",
|
||||
"edit": "",
|
||||
"itemFind": "",
|
||||
"itemSort": [{"key": "position", "operator": "+"}],
|
||||
"itemView": "info",
|
||||
|
|
@ -670,6 +674,11 @@
|
|||
"favorite": true,
|
||||
"featured": true,
|
||||
"volumes": true
|
||||
},
|
||||
"texts": {
|
||||
"personal": true,
|
||||
"favorite": true,
|
||||
"featured": true
|
||||
}
|
||||
},
|
||||
"showSidebar": true,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
"canEditAnnotations": {"staff": true, "admin": true},
|
||||
"canEditEvents": {"staff": true, "admin": true},
|
||||
"canEditFeaturedLists": {"staff": true, "admin": true},
|
||||
"canEditFeaturedTexts": {"staff": true, "admin": true},
|
||||
"canEditFeaturedEdits": {"staff": true, "admin": true},
|
||||
"canEditMetadata": {"staff": true, "admin": true},
|
||||
"canEditPlaces": {"staff": true, "admin": true},
|
||||
"canEditSitePages": {"staff": true, "admin": true},
|
||||
|
|
@ -549,6 +551,8 @@
|
|||
"icons": "posters",
|
||||
"infoIconSize": 256,
|
||||
"item": "",
|
||||
"text": "",
|
||||
"edit": "",
|
||||
"itemFind": "",
|
||||
"itemSort": [{"key": "position", "operator": "+"}],
|
||||
"itemView": "info",
|
||||
|
|
@ -589,6 +593,11 @@
|
|||
"featured": true,
|
||||
"volumes": true
|
||||
}
|
||||
"texts": {
|
||||
"personal": true,
|
||||
"favorite": true,
|
||||
"featured": true
|
||||
}
|
||||
},
|
||||
"showSidebar": true,
|
||||
"showSitePosters": false,
|
||||
|
|
|
|||
|
|
@ -207,7 +207,9 @@ def addList(request):
|
|||
return {
|
||||
status: {'code': int, 'text': string},
|
||||
data: {
|
||||
list:
|
||||
id:
|
||||
name:
|
||||
...
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
|
|
|||
136
pandora/text/managers.py
Normal file
136
pandora/text/managers.py
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vi:si:et:sw=4:sts=4:ts=4
|
||||
from datetime import datetime
|
||||
|
||||
from django.db.models import Q, Manager
|
||||
|
||||
import models
|
||||
|
||||
|
||||
def parseCondition(condition, user):
|
||||
'''
|
||||
'''
|
||||
k = condition.get('key', 'name')
|
||||
k = {
|
||||
'user': 'user__username',
|
||||
'position': 'position__position',
|
||||
'posterFrames': 'poster_frames',
|
||||
}.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 k == 'id':
|
||||
v = v.split(":")
|
||||
if len(v) >= 2:
|
||||
v = (v[0], ":".join(v[1:]))
|
||||
q = Q(user__username=v[0], name=v[1])
|
||||
else:
|
||||
q = Q(id__in=[])
|
||||
return q
|
||||
if k == 'subscribed':
|
||||
key = 'subscribed_users__username'
|
||||
v = user.username
|
||||
elif isinstance(v, bool): #featured and public flag
|
||||
key = k
|
||||
else:
|
||||
key = "%s%s" % (k, {
|
||||
'==': '__iexact',
|
||||
'^': '__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 TextManager(Manager):
|
||||
|
||||
def get_query_set(self):
|
||||
return super(TextManager, self).get_query_set()
|
||||
|
||||
def find(self, data, user):
|
||||
'''
|
||||
query: {
|
||||
conditions: [
|
||||
{
|
||||
value: "war"
|
||||
}
|
||||
{
|
||||
key: "year",
|
||||
value: "1970-1980,
|
||||
operator: "!="
|
||||
},
|
||||
{
|
||||
key: "country",
|
||||
value: "f",
|
||||
operator: "^"
|
||||
}
|
||||
],
|
||||
operator: "&"
|
||||
}
|
||||
'''
|
||||
|
||||
#join query with operator
|
||||
qs = self.get_query_set()
|
||||
conditions = parseConditions(data['query'].get('conditions', []),
|
||||
data['query'].get('operator', '&'),
|
||||
user)
|
||||
if conditions:
|
||||
qs = qs.filter(conditions)
|
||||
|
||||
if user.is_anonymous():
|
||||
qs = qs.filter(Q(status='public') | Q(status='featured'))
|
||||
else:
|
||||
qs = qs.filter(Q(status='public') | Q(status='featured') | Q(user=user))
|
||||
return qs
|
||||
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
# -*- coding: 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 model 'Image'
|
||||
db.delete_table('text_image')
|
||||
|
||||
# Deleting model 'Attachment'
|
||||
db.delete_table('text_attachment')
|
||||
|
||||
# Adding model 'Position'
|
||||
db.create_table('text_position', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('text', self.gf('django.db.models.fields.related.ForeignKey')(related_name='position', to=orm['text.Text'])),
|
||||
('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='text_position', to=orm['auth.User'])),
|
||||
('section', self.gf('django.db.models.fields.CharField')(max_length='255')),
|
||||
('position', self.gf('django.db.models.fields.IntegerField')(default=0)),
|
||||
))
|
||||
db.send_create_signal('text', ['Position'])
|
||||
|
||||
# Adding unique constraint on 'Position', fields ['user', 'text', 'section']
|
||||
db.create_unique('text_position', ['user_id', 'text_id', 'section'])
|
||||
|
||||
# Deleting field 'Text.public'
|
||||
db.delete_column('text_text', 'public')
|
||||
|
||||
# Deleting field 'Text.slug'
|
||||
db.delete_column('text_text', 'slug')
|
||||
|
||||
# Deleting field 'Text.title'
|
||||
db.delete_column('text_text', 'title')
|
||||
|
||||
# Deleting field 'Text.published'
|
||||
db.delete_column('text_text', 'published')
|
||||
|
||||
# Adding field 'Text.name'
|
||||
db.add_column('text_text', 'name',
|
||||
self.gf('django.db.models.fields.CharField')(default=datetime.datetime(2013, 2, 15, 0, 0), max_length=255),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'Text.status'
|
||||
db.add_column('text_text', 'status',
|
||||
self.gf('django.db.models.fields.CharField')(default='private', max_length=20),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'Text.description'
|
||||
db.add_column('text_text', 'description',
|
||||
self.gf('django.db.models.fields.TextField')(default=''),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'Text.icon'
|
||||
db.add_column('text_text', 'icon',
|
||||
self.gf('django.db.models.fields.files.ImageField')(default='', max_length=100, blank=True),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'Text.poster_frames'
|
||||
db.add_column('text_text', 'poster_frames',
|
||||
self.gf('ox.django.fields.TupleField')(default=[]),
|
||||
keep_default=False)
|
||||
|
||||
# Adding M2M table for field subscribed_users on 'Text'
|
||||
db.create_table('text_text_subscribed_users', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('text', models.ForeignKey(orm['text.text'], null=False)),
|
||||
('user', models.ForeignKey(orm['auth.user'], null=False))
|
||||
))
|
||||
db.create_unique('text_text_subscribed_users', ['text_id', 'user_id'])
|
||||
|
||||
# Adding unique constraint on 'Text', fields ['user', 'name']
|
||||
db.create_unique('text_text', ['user_id', 'name'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Removing unique constraint on 'Text', fields ['user', 'name']
|
||||
db.delete_unique('text_text', ['user_id', 'name'])
|
||||
|
||||
# Removing unique constraint on 'Position', fields ['user', 'text', 'section']
|
||||
db.delete_unique('text_position', ['user_id', 'text_id', 'section'])
|
||||
|
||||
# Adding model 'Image'
|
||||
db.create_table('text_image', (
|
||||
('caption', self.gf('django.db.models.fields.CharField')(default='', max_length=255)),
|
||||
('image', self.gf('django.db.models.fields.files.ImageField')(max_length=100)),
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
))
|
||||
db.send_create_signal('text', ['Image'])
|
||||
|
||||
# Adding model 'Attachment'
|
||||
db.create_table('text_attachment', (
|
||||
('caption', self.gf('django.db.models.fields.CharField')(default='', max_length=255)),
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('file', self.gf('django.db.models.fields.files.FileField')(max_length=100)),
|
||||
))
|
||||
db.send_create_signal('text', ['Attachment'])
|
||||
|
||||
# Deleting model 'Position'
|
||||
db.delete_table('text_position')
|
||||
|
||||
# Adding field 'Text.public'
|
||||
db.add_column('text_text', 'public',
|
||||
self.gf('django.db.models.fields.BooleanField')(default=False),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'Text.slug'
|
||||
db.add_column('text_text', 'slug',
|
||||
self.gf('django.db.models.fields.SlugField')(default='', max_length=50),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'Text.title'
|
||||
db.add_column('text_text', 'title',
|
||||
self.gf('django.db.models.fields.CharField')(max_length=1000, null=True),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'Text.published'
|
||||
db.add_column('text_text', 'published',
|
||||
self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now),
|
||||
keep_default=False)
|
||||
|
||||
# Deleting field 'Text.name'
|
||||
db.delete_column('text_text', 'name')
|
||||
|
||||
# Deleting field 'Text.status'
|
||||
db.delete_column('text_text', 'status')
|
||||
|
||||
# Deleting field 'Text.description'
|
||||
db.delete_column('text_text', 'description')
|
||||
|
||||
# Deleting field 'Text.icon'
|
||||
db.delete_column('text_text', 'icon')
|
||||
|
||||
# Deleting field 'Text.poster_frames'
|
||||
db.delete_column('text_text', 'poster_frames')
|
||||
|
||||
# Removing M2M table for field subscribed_users on 'Text'
|
||||
db.delete_table('text_text_subscribed_users')
|
||||
|
||||
|
||||
models = {
|
||||
'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': '255'}),
|
||||
'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': '255', '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': '255'}),
|
||||
'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': '255'})
|
||||
},
|
||||
'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'})
|
||||
},
|
||||
'text.position': {
|
||||
'Meta': {'unique_together': "(('user', 'text', 'section'),)", 'object_name': 'Position'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'position': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'section': ('django.db.models.fields.CharField', [], {'max_length': "'255'"}),
|
||||
'text': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'position'", 'to': "orm['text.Text']"}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'text_position'", 'to': "orm['auth.User']"})
|
||||
},
|
||||
'text.text': {
|
||||
'Meta': {'unique_together': "(('user', 'name'),)", 'object_name': 'Text'},
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''"}),
|
||||
'icon': ('django.db.models.fields.files.ImageField', [], {'default': 'None', 'max_length': '100', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'poster_frames': ('ox.django.fields.TupleField', [], {'default': '[]'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'private'", 'max_length': '20'}),
|
||||
'subscribed_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribed_texts'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'text': ('django.db.models.fields.TextField', [], {'default': "''"}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'texts'", 'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['text']
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
# -*- coding: 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 'Text.type'
|
||||
db.add_column('text_text', 'type',
|
||||
self.gf('django.db.models.fields.CharField')(default='html', max_length=255),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'Text.links'
|
||||
db.add_column('text_text', 'links',
|
||||
self.gf('ox.django.fields.DictField')(default={}),
|
||||
keep_default=False)
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting field 'Text.type'
|
||||
db.delete_column('text_text', 'type')
|
||||
|
||||
# Deleting field 'Text.links'
|
||||
db.delete_column('text_text', 'links')
|
||||
|
||||
|
||||
models = {
|
||||
'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': '255'}),
|
||||
'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': '255', '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': '255'}),
|
||||
'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': '255'})
|
||||
},
|
||||
'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'})
|
||||
},
|
||||
'text.position': {
|
||||
'Meta': {'unique_together': "(('user', 'text', 'section'),)", 'object_name': 'Position'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'position': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'section': ('django.db.models.fields.CharField', [], {'max_length': "'255'"}),
|
||||
'text': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'position'", 'to': "orm['text.Text']"}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'text_position'", 'to': "orm['auth.User']"})
|
||||
},
|
||||
'text.text': {
|
||||
'Meta': {'unique_together': "(('user', 'name'),)", 'object_name': 'Text'},
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''"}),
|
||||
'icon': ('django.db.models.fields.files.ImageField', [], {'default': 'None', 'max_length': '100', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'links': ('ox.django.fields.DictField', [], {'default': '{}'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'poster_frames': ('ox.django.fields.TupleField', [], {'default': '[]'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'private'", 'max_length': '20'}),
|
||||
'subscribed_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribed_texts'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
|
||||
'text': ('django.db.models.fields.TextField', [], {'default': "''"}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'default': "'html'", 'max_length': '255'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'texts'", 'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['text']
|
||||
|
|
@ -2,40 +2,158 @@
|
|||
# vi:si:et:sw=4:sts=4:ts=4
|
||||
from __future__ import division, with_statement
|
||||
from datetime import datetime
|
||||
import os
|
||||
import subprocess
|
||||
from glob import glob
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django.conf import settings
|
||||
import ox
|
||||
from ox.django.fields import DictField, TupleField
|
||||
|
||||
from archive import extract
|
||||
|
||||
import managers
|
||||
|
||||
|
||||
class Text(models.Model):
|
||||
|
||||
class Meta:
|
||||
unique_together = ("user", "name")
|
||||
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
modified = models.DateTimeField(auto_now=True)
|
||||
published = models.DateTimeField(default=datetime.now, editable=False)
|
||||
public = models.BooleanField(default=False)
|
||||
user = models.ForeignKey(User, related_name='texts')
|
||||
name = models.CharField(max_length=255)
|
||||
status = models.CharField(max_length=20, default='private')
|
||||
_status = ['private', 'public', 'featured']
|
||||
type = models.CharField(max_length=255, default='html')
|
||||
description = models.TextField(default='')
|
||||
|
||||
user = models.ForeignKey(User)
|
||||
slug = models.SlugField()
|
||||
title = models.CharField(null=True, max_length=1000)
|
||||
text = models.TextField(default='')
|
||||
icon = models.ImageField(default=None, blank=True,
|
||||
upload_to=lambda i, x: i.path("icon.jpg"))
|
||||
|
||||
text = models.TextField(default="")
|
||||
links = DictField(default={}, editable=True)
|
||||
|
||||
poster_frames = TupleField(default=[], editable=False)
|
||||
subscribed_users = models.ManyToManyField(User, related_name='subscribed_texts')
|
||||
|
||||
objects = managers.TextManager()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super(Text, self).save(*args, **kwargs)
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s <%s>" % (self.title, self.slug)
|
||||
return self.get_id()
|
||||
|
||||
def get_absolute_url(self):
|
||||
return '/text/%s' % self.slug
|
||||
def get_id(self):
|
||||
return u'%s:%s' % (self.user.username, self.name)
|
||||
|
||||
def accessible(self, user):
|
||||
return self.user == user or self.status in ('public', 'featured')
|
||||
|
||||
class Image(models.Model):
|
||||
image = models.ImageField(upload_to='text/image')
|
||||
caption = models.CharField(max_length=255, default="")
|
||||
def editable(self, user):
|
||||
if user.is_anonymous():
|
||||
return False
|
||||
if self.user == user or \
|
||||
user.is_staff or \
|
||||
user.get_profile().capability('canEditFeaturedTexts') == True:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_absolute_url(self):
|
||||
return self.image.url
|
||||
def json(self, keys=None, user=None):
|
||||
if not keys:
|
||||
keys=['id', 'name', 'user', 'status', 'subscribed', 'posterFrames', 'description', 'text', 'type', 'links']
|
||||
response = {}
|
||||
_map = {
|
||||
'posterFrames': 'poster_frames'
|
||||
}
|
||||
for key in keys:
|
||||
if key == 'id':
|
||||
response[key] = self.get_id()
|
||||
elif key == 'user':
|
||||
response[key] = self.user.username
|
||||
elif key == 'subscribers':
|
||||
response[key] = self.subscribed_users.all().count()
|
||||
elif key == 'subscribed':
|
||||
if user and not user.is_anonymous():
|
||||
response[key] = self.subscribed_users.filter(id=user.id).exists()
|
||||
elif hasattr(self, _map.get(key, key)):
|
||||
response[key] = getattr(self, _map.get(key,key))
|
||||
return response
|
||||
|
||||
def path(self, name=''):
|
||||
h = "%07d" % self.id
|
||||
return os.path.join('texts', h[:2], h[2:4], h[4:6], h[6:], name)
|
||||
|
||||
class Attachment(models.Model):
|
||||
file = models.FileField(upload_to='text/attachment')
|
||||
caption = models.CharField(max_length=255, default="")
|
||||
def update_icon(self):
|
||||
frames = []
|
||||
if not self.poster_frames:
|
||||
items = self.get_items(self.user).filter(rendered=True)
|
||||
if items.count():
|
||||
poster_frames = []
|
||||
for i in range(0, items.count(), max(1, int(items.count()/4))):
|
||||
poster_frames.append({
|
||||
'item': items[int(i)].itemId,
|
||||
'position': items[int(i)].poster_frame
|
||||
})
|
||||
self.poster_frames = tuple(poster_frames)
|
||||
self.save()
|
||||
for i in self.poster_frames:
|
||||
from item.models import Item
|
||||
qs = Item.objects.filter(itemId=i['item'])
|
||||
if qs.count() > 0:
|
||||
frame = qs[0].frame(i['position'])
|
||||
if frame:
|
||||
frames.append(frame)
|
||||
self.icon.name = self.path('icon.jpg')
|
||||
icon = self.icon.path
|
||||
if frames:
|
||||
while len(frames) < 4:
|
||||
frames += frames
|
||||
folder = os.path.dirname(icon)
|
||||
ox.makedirs(folder)
|
||||
for f in glob("%s/icon*.jpg" % folder):
|
||||
os.unlink(f)
|
||||
cmd = [
|
||||
settings.LIST_ICON,
|
||||
'-f', ','.join(frames),
|
||||
'-o', icon
|
||||
]
|
||||
p = subprocess.Popen(cmd)
|
||||
p.wait()
|
||||
self.save()
|
||||
|
||||
def get_icon(self, size=16):
|
||||
path = self.path('icon%d.jpg' % size)
|
||||
path = os.path.join(settings.MEDIA_ROOT, path)
|
||||
if not os.path.exists(path):
|
||||
folder = os.path.dirname(path)
|
||||
ox.makedirs(folder)
|
||||
if self.icon and os.path.exists(self.icon.path):
|
||||
source = self.icon.path
|
||||
max_size = min(self.icon.width, self.icon.height)
|
||||
else:
|
||||
source = os.path.join(settings.STATIC_ROOT, 'jpg/list256.jpg')
|
||||
max_size = 256
|
||||
if size < max_size:
|
||||
extract.resize_image(source, path, size=size)
|
||||
else:
|
||||
path = source
|
||||
return path
|
||||
|
||||
class Position(models.Model):
|
||||
|
||||
class Meta:
|
||||
unique_together = ("user", "text", "section")
|
||||
|
||||
text = models.ForeignKey(Text, related_name='position')
|
||||
user = models.ForeignKey(User, related_name='text_position')
|
||||
section = models.CharField(max_length='255')
|
||||
position = models.IntegerField(default=0)
|
||||
|
||||
def __unicode__(self):
|
||||
return u'%s/%s/%s' % (self.section, self.position, self.text)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return self.file.url
|
||||
|
|
|
|||
|
|
@ -1,27 +1,96 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vi:si:et:sw=4:sts=4:ts=4
|
||||
from __future__ import division
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
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
|
||||
|
||||
import models
|
||||
from ox.django.api import actions
|
||||
from ox.django.decorators import login_required_json
|
||||
from ox.django.http import HttpFileResponse
|
||||
from ox.django.shortcuts import render_to_json_response, get_object_or_404_json, json_response
|
||||
from django.db.models import Count, Q, Sum, Max
|
||||
|
||||
from item import utils
|
||||
import models
|
||||
|
||||
def get_text_or_404_json(id):
|
||||
id = id.split(':')
|
||||
username = id[0]
|
||||
textname = ":".join(id[1:])
|
||||
return get_object_or_404_json(models.Text, user__username=username, name=textname)
|
||||
|
||||
@login_required_json
|
||||
def addText(request):
|
||||
'''
|
||||
param data {
|
||||
name: value,
|
||||
}
|
||||
return {
|
||||
status: {'code': int, 'text': string},
|
||||
data: {
|
||||
id:
|
||||
name:
|
||||
...
|
||||
}
|
||||
}
|
||||
'''
|
||||
data = json.loads(request.POST['data'])
|
||||
data['name'] = re.sub(' \[\d+\]$', '', data['name']).strip()
|
||||
name = data['name']
|
||||
if not name:
|
||||
name = "Untitled"
|
||||
num = 1
|
||||
created = False
|
||||
while not created:
|
||||
text, created = models.Text.objects.get_or_create(name=name, user=request.user)
|
||||
num += 1
|
||||
name = data['name'] + ' [%d]' % num
|
||||
text.save()
|
||||
|
||||
if text.status == 'featured':
|
||||
pos, created = models.Position.objects.get_or_create(text=text,
|
||||
user=request.user, section='featured')
|
||||
qs = models.Position.objects.filter(section='featured')
|
||||
else:
|
||||
pos, created = models.Position.objects.get_or_create(text=text,
|
||||
user=request.user, section='personal')
|
||||
qs = models.Position.objects.filter(user=request.user, section='personal')
|
||||
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
|
||||
pos.save()
|
||||
response = json_response(status=200, text='created')
|
||||
response['data'] = text.json()
|
||||
return render_to_json_response(response)
|
||||
actions.register(addText, cache=False)
|
||||
|
||||
def getText(request):
|
||||
'''
|
||||
param data
|
||||
string id
|
||||
|
||||
return page
|
||||
param data {
|
||||
id: textid
|
||||
}
|
||||
return {
|
||||
id:
|
||||
text:
|
||||
...
|
||||
}
|
||||
'''
|
||||
response = json_response({})
|
||||
itemId = json.loads(request.POST['data'])
|
||||
item = get_object_or_404_json(models.Text, pk=itemId)
|
||||
response['data']['page'] = item.html()
|
||||
response = json_response()
|
||||
data = json.loads(request.POST['data'])
|
||||
public_id = data['id']
|
||||
if public_id == '':
|
||||
qs = models.Text.objects.filter(name='')
|
||||
if qs.count() == 0:
|
||||
text = models.Text()
|
||||
text.name = ''
|
||||
text.text = 'Please put something here'
|
||||
text.user = request.user
|
||||
text.save()
|
||||
else:
|
||||
text = qs[0]
|
||||
else:
|
||||
text = get_text_or_404_json(data['id'])
|
||||
response['data'] = text.json()
|
||||
return render_to_json_response(response)
|
||||
actions.register(getText)
|
||||
|
||||
|
|
@ -29,22 +98,355 @@ actions.register(getText)
|
|||
@login_required_json
|
||||
def editText(request):
|
||||
'''
|
||||
param data
|
||||
string id
|
||||
|
||||
return page
|
||||
param data {
|
||||
id:
|
||||
text:
|
||||
public: boolean
|
||||
}
|
||||
return {
|
||||
id:
|
||||
text:
|
||||
...
|
||||
}
|
||||
'''
|
||||
response = json_response({})
|
||||
itemId = json.loads(request.POST['data'])
|
||||
item = get_object_or_404_json(models.Text, pk=itemId)
|
||||
response['data']['page'] = item.html()
|
||||
response = json_response()
|
||||
data = json.loads(request.POST['data'])
|
||||
if data['id']:
|
||||
public_id = data['id'].split(':')
|
||||
username = public_id[0]
|
||||
name = ":".join(public_id[1:])
|
||||
text, created = models.Text.objects.get_or_create(name=name, user=models.User.objects.get(username=username))
|
||||
if created:
|
||||
text.user = request.user
|
||||
else:
|
||||
qs = models.Text.objects.filter(name='')
|
||||
if qs.count() == 0:
|
||||
if request.user.get_profile().capability('canEditFeaturedTexts'):
|
||||
text = models.Text(name='', user=request.user)
|
||||
text.save()
|
||||
else:
|
||||
response = json_response(status=403, text='permission denied')
|
||||
return render_to_json_response(response)
|
||||
else:
|
||||
text = qs[0]
|
||||
if text.editable(request.user):
|
||||
for key in data:
|
||||
if key == 'status':
|
||||
value = data[key]
|
||||
if value not in text._status:
|
||||
value = text._status[0]
|
||||
if value == 'private':
|
||||
for user in text.subscribed_users.all():
|
||||
text.subscribed_users.remove(user)
|
||||
qs = models.Position.objects.filter(user=request.user,
|
||||
section='section', text=text)
|
||||
if qs.count() > 1:
|
||||
pos = qs[0]
|
||||
pos.section = 'personal'
|
||||
pos.save()
|
||||
elif value == 'featured':
|
||||
if request.user.get_profile().capability('canEditFeaturedTexts'):
|
||||
pos, created = models.Position.objects.get_or_create(text=text, user=request.user,
|
||||
section='featured')
|
||||
if created:
|
||||
qs = models.Position.objects.filter(user=request.user, section='featured')
|
||||
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
|
||||
pos.save()
|
||||
models.Position.objects.filter(text=text).exclude(id=pos.id).delete()
|
||||
else:
|
||||
value = text.status
|
||||
elif text.status == 'featured' and value == 'public':
|
||||
models.Position.objects.filter(text=text).delete()
|
||||
pos, created = models.Position.objects.get_or_create(text=text,
|
||||
user=text.user,section='personal')
|
||||
qs = models.Position.objects.filter(user=text.user,
|
||||
section='personal')
|
||||
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
|
||||
pos.save()
|
||||
for u in text.subscribed_users.all():
|
||||
pos, created = models.Position.objects.get_or_create(text=text, user=u,
|
||||
section='public')
|
||||
qs = models.Position.objects.filter(user=u, section='public')
|
||||
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
|
||||
pos.save()
|
||||
|
||||
text.status = value
|
||||
elif key == 'name':
|
||||
data['name'] = re.sub(' \[\d+\]$', '', data['name']).strip()
|
||||
name = data['name']
|
||||
if not name:
|
||||
name = "Untitled"
|
||||
num = 1
|
||||
while models.Text.objects.filter(name=name, user=text.user).exclude(id=text.id).count()>0:
|
||||
num += 1
|
||||
name = data['name'] + ' [%d]' % num
|
||||
text.name = name
|
||||
elif key == 'description':
|
||||
text.description = ox.sanitize_html(data['description'])
|
||||
elif key == 'text':
|
||||
text.text = ox.sanitize_html(data['text'])
|
||||
|
||||
if 'position' in data:
|
||||
pos, created = models.Position.objects.get_or_create(text=text, user=request.user)
|
||||
pos.position = data['position']
|
||||
pos.section = 'featured'
|
||||
if text.status == 'private':
|
||||
pos.section = 'personal'
|
||||
pos.save()
|
||||
if 'type' in data:
|
||||
if data['type'] == 'pdf':
|
||||
text.type = 'pdf'
|
||||
else:
|
||||
text.type = 'html'
|
||||
if 'posterFrames' in data:
|
||||
text.poster_frames = tuple(data['posterFrames'])
|
||||
text.update_icon()
|
||||
text.save()
|
||||
response['data'] = text.json(user=request.user)
|
||||
else:
|
||||
response = json_response(status=403, text='permission denied')
|
||||
return render_to_json_response(response)
|
||||
actions.register(editText, cache=False)
|
||||
|
||||
|
||||
def findText(request):
|
||||
def _order_query(qs, sort):
|
||||
order_by = []
|
||||
for e in sort:
|
||||
operator = e['operator']
|
||||
if operator != '-':
|
||||
operator = ''
|
||||
key = {
|
||||
'subscribed': 'subscribed_users',
|
||||
'items': 'numberofitems'
|
||||
}.get(e['key'], e['key'])
|
||||
order = '%s%s' % (operator, key)
|
||||
order_by.append(order)
|
||||
if key == 'subscribers':
|
||||
qs = qs.annotate(subscribers=Sum('subscribed_users'))
|
||||
if order_by:
|
||||
qs = qs.order_by(*order_by)
|
||||
qs = qs.distinct()
|
||||
return qs
|
||||
|
||||
def parse_query(data, user):
|
||||
query = {}
|
||||
query['range'] = [0, 100]
|
||||
query['sort'] = [{'key':'user', 'operator':'+'}, {'key':'name', 'operator':'+'}]
|
||||
for key in ('keys', 'group', 'text', 'range', 'position', 'positions', 'sort'):
|
||||
if key in data:
|
||||
query[key] = data[key]
|
||||
print data
|
||||
query['qs'] = models.Text.objects.find(data, user).exclude(name='')
|
||||
print query
|
||||
return query
|
||||
|
||||
|
||||
def findTexts(request):
|
||||
'''
|
||||
param data {
|
||||
query: {
|
||||
conditions: [
|
||||
{
|
||||
key: 'user',
|
||||
value: 'something',
|
||||
operator: '='
|
||||
}
|
||||
]
|
||||
operator: ","
|
||||
},
|
||||
sort: [{key: 'name', operator: '+'}],
|
||||
range: [0, 100]
|
||||
keys: []
|
||||
}
|
||||
|
||||
possible query keys:
|
||||
name, user, featured, subscribed
|
||||
|
||||
possible keys:
|
||||
name, user, featured, subscribed, query
|
||||
|
||||
}
|
||||
return {status: {code: int, text: string},
|
||||
data: {
|
||||
items: [
|
||||
{name:, user:, featured:, public...}
|
||||
]
|
||||
}
|
||||
}
|
||||
'''
|
||||
response = json_response({})
|
||||
data = json.loads(request.POST['data'])
|
||||
query = parse_query(data, request.user)
|
||||
|
||||
#order
|
||||
is_section_request = query['sort'] == [{u'operator': u'+', u'key': u'position'}]
|
||||
def is_featured_condition(x):
|
||||
return x['key'] == 'status' and \
|
||||
x['value'] == 'featured' and \
|
||||
x['operator'] in ('=', '==')
|
||||
is_featured = len(filter(is_featured_condition, data['query'].get('conditions', []))) > 0
|
||||
|
||||
if is_section_request:
|
||||
qs = query['qs']
|
||||
if not is_featured and not request.user.is_anonymous():
|
||||
qs = qs.filter(position__in=models.Position.objects.filter(user=request.user))
|
||||
qs = qs.order_by('position__position')
|
||||
else:
|
||||
qs = _order_query(query['qs'], query['sort'])
|
||||
|
||||
response = json_response()
|
||||
if 'keys' in data:
|
||||
qs = qs[query['range'][0]:query['range'][1]]
|
||||
|
||||
response['data']['items'] = [l.json(data['keys'], request.user) for l in qs]
|
||||
elif 'position' in data:
|
||||
#FIXME: actually implement position requests
|
||||
response['data']['position'] = 0
|
||||
elif 'positions' in data:
|
||||
ids = [i.get_id() for i in qs]
|
||||
response['data']['positions'] = utils.get_positions(ids, query['positions'])
|
||||
else:
|
||||
response['data']['items'] = qs.count()
|
||||
return render_to_json_response(response)
|
||||
actions.register(findText)
|
||||
actions.register(findTexts)
|
||||
|
||||
|
||||
@login_required_json
|
||||
def removeText(request):
|
||||
'''
|
||||
param data {
|
||||
id: testId,
|
||||
}
|
||||
return {
|
||||
status: {'code': int, 'text': string},
|
||||
data: {
|
||||
}
|
||||
}
|
||||
'''
|
||||
data = json.loads(request.POST['data'])
|
||||
text = get_text_or_404_json(data['id'])
|
||||
response = json_response()
|
||||
if text.editable(request.user):
|
||||
text.delete()
|
||||
else:
|
||||
response = json_response(status=403, text='not allowed')
|
||||
return render_to_json_response(response)
|
||||
actions.register(removeText, cache=False)
|
||||
|
||||
|
||||
@login_required_json
|
||||
def subscribeToText(request):
|
||||
'''
|
||||
param data {
|
||||
id: testId,
|
||||
}
|
||||
return {
|
||||
status: {'code': int, 'text': string},
|
||||
data: {
|
||||
}
|
||||
}
|
||||
'''
|
||||
data = json.loads(request.POST['data'])
|
||||
text = get_text_or_404_json(data['id'])
|
||||
user = request.user
|
||||
if text.status == 'public' and \
|
||||
text.subscribed_users.filter(username=user.username).count() == 0:
|
||||
text.subscribed_users.add(user)
|
||||
pos, created = models.Position.objects.get_or_create(text=text, user=user, section='public')
|
||||
if created:
|
||||
qs = models.Position.objects.filter(user=user, section='public')
|
||||
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
|
||||
pos.save()
|
||||
response = json_response()
|
||||
return render_to_json_response(response)
|
||||
actions.register(subscribeToText, cache=False)
|
||||
|
||||
|
||||
@login_required_json
|
||||
def unsubscribeFromText(request):
|
||||
'''
|
||||
param data {
|
||||
id: testId,
|
||||
user: username(only admins)
|
||||
}
|
||||
return {
|
||||
status: {'code': int, 'text': string},
|
||||
data: {
|
||||
}
|
||||
}
|
||||
'''
|
||||
data = json.loads(request.POST['data'])
|
||||
text = get_text_or_404_json(data['id'])
|
||||
user = request.user
|
||||
text.subscribed_users.remove(user)
|
||||
models.Position.objects.filter(text=text, user=user, section='public').delete()
|
||||
response = json_response()
|
||||
return render_to_json_response(response)
|
||||
actions.register(unsubscribeFromText, cache=False)
|
||||
|
||||
|
||||
@login_required_json
|
||||
def sortTexts(request):
|
||||
'''
|
||||
param data {
|
||||
section: 'personal',
|
||||
ids: [1,2,4,3]
|
||||
}
|
||||
known sections: 'personal', 'public', 'featured'
|
||||
featured can only be edited by admins
|
||||
return {
|
||||
status: {'code': int, 'text': string},
|
||||
data: {
|
||||
}
|
||||
}
|
||||
'''
|
||||
data = json.loads(request.POST['data'])
|
||||
position = 0
|
||||
section = data['section']
|
||||
#ids = list(set(data['ids']))
|
||||
ids = data['ids']
|
||||
if section == 'featured' and not request.user.get_profile().capability('canEditFeaturedTexts'):
|
||||
response = json_response(status=403, text='not allowed')
|
||||
else:
|
||||
user = request.user
|
||||
if section == 'featured':
|
||||
for i in ids:
|
||||
l = get_text_or_404_json(i)
|
||||
qs = models.Position.objects.filter(section=section, text=l)
|
||||
if qs.count() > 0:
|
||||
pos = qs[0]
|
||||
else:
|
||||
pos = models.Position(text=l, user=user, section=section)
|
||||
if pos.position != position:
|
||||
pos.position = position
|
||||
pos.save()
|
||||
position += 1
|
||||
models.Position.objects.filter(section=section, text=l).exclude(id=pos.id).delete()
|
||||
else:
|
||||
for i in ids:
|
||||
l = get_text_or_404_json(i)
|
||||
pos, created = models.Position.objects.get_or_create(text=l,
|
||||
user=request.user, section=section)
|
||||
if pos.position != position:
|
||||
pos.position = position
|
||||
pos.save()
|
||||
position += 1
|
||||
|
||||
response = json_response()
|
||||
return render_to_json_response(response)
|
||||
actions.register(sortTexts, cache=False)
|
||||
|
||||
|
||||
def icon(request, id, size=16):
|
||||
if not size:
|
||||
size = 16
|
||||
|
||||
id = id.split(':')
|
||||
username = id[0]
|
||||
textname = ":".join(id[1:])
|
||||
qs = models.Text.objects.filter(user__username=username, name=textname)
|
||||
if qs.count() == 1 and qs[0].accessible(request.user):
|
||||
text = qs[0]
|
||||
icon = text.get_icon(int(size))
|
||||
else:
|
||||
icon = os.path.join(settings.STATIC_ROOT, 'jpg/list256.jpg')
|
||||
return HttpFileResponse(icon, content_type='image/jpeg')
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ urlpatterns = patterns('',
|
|||
(r'^api/?$', include(ox.django.api.urls)),
|
||||
(r'^resetUI$', 'user.views.reset_ui'),
|
||||
(r'^list/(?P<id>.*?)/icon(?P<size>\d*).jpg$', 'itemlist.views.icon'),
|
||||
(r'^text/(?P<id>.*?)/icon(?P<size>\d*).jpg$', 'text.views.icon'),
|
||||
(r'^robots.txt$', serve_static_file, {'location': os.path.join(settings.STATIC_ROOT, 'robots.txt'), 'content_type': 'text/plain'}),
|
||||
(r'^favicon.ico$', serve_static_file, {'location': os.path.join(settings.STATIC_ROOT, 'png/icon.16.png'), 'content_type': 'image/x-icon'}),
|
||||
(r'^opensearch.xml$', 'app.views.opensearch_xml'),
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from ox.django.fields import DictField
|
|||
from ox.utils import json
|
||||
|
||||
from itemlist.models import List, Position
|
||||
import text
|
||||
|
||||
import managers
|
||||
import tasks
|
||||
|
|
@ -261,6 +262,29 @@ def get_ui(user_ui, user=None):
|
|||
'''
|
||||
ids.append(id)
|
||||
return ids
|
||||
|
||||
def add_texts(texts, section):
|
||||
P = text.models.Position
|
||||
ids = []
|
||||
for t in texts:
|
||||
qs = P.objects.filter(section=section)
|
||||
if section == 'featured':
|
||||
try:
|
||||
pos = P.objects.get(text=t, section=section)
|
||||
created = False
|
||||
except P.DoesNotExist:
|
||||
pos = P(text=t, section=section, user=l.user)
|
||||
pos.save()
|
||||
created = True
|
||||
else:
|
||||
pos, created = P.objects.get_or_create(text=t, user=user, section=section)
|
||||
qs = qs.filter(user=user)
|
||||
if created:
|
||||
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
|
||||
pos.save()
|
||||
ids.append(t.get_id())
|
||||
return ids
|
||||
|
||||
|
||||
ids = ['']
|
||||
if user:
|
||||
|
|
@ -270,6 +294,11 @@ def get_ui(user_ui, user=None):
|
|||
for i in ui['lists'].keys():
|
||||
if i not in ids:
|
||||
del ui['lists'][i]
|
||||
tids = ['']
|
||||
if user:
|
||||
tids += add_texts(user.texts.exclude(status="featured"), 'personal')
|
||||
tids += add_texts(user.subscribed_texts.filter(status='public'), 'public')
|
||||
tids += add_texts(text.models.Text.objects.filter(status='featured'), 'featured')
|
||||
return ui
|
||||
|
||||
def init_user(user, request=None):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue