new documents section

This commit is contained in:
j 2016-10-05 00:00:03 +02:00
commit e1f35b1ec8
74 changed files with 6737 additions and 631 deletions

View file

View file

@ -0,0 +1,132 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from django.db.models import Q, Manager
from oxdjango.managers import get_operator
from oxdjango.query import QuerySet
keymap = {
'user': 'user__username',
}
default_key = 'name'
def parseCondition(condition, user):
'''
'''
k = condition.get('key', default_key)
k = keymap.get(k, k)
if not k:
k = default_key
v = condition.get('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):
key = k
else:
key = k + get_operator(op, 'istr')
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 CollectionManager(Manager):
def get_query_set(self):
return QuerySet(self.model)
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()
query = data.get('query', {})
conditions = parseConditions(query.get('conditions', []),
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

View file

@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-10-08 12:34
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import documentcollection.models
import oxdjango.fields
class Migration(migrations.Migration):
initial = True
dependencies = [
('document', '0003_new_fields'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Collection',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(auto_now_add=True)),
('modified', models.DateTimeField(auto_now=True)),
('name', models.CharField(max_length=255)),
('status', models.CharField(default=b'private', max_length=20)),
('query', oxdjango.fields.DictField(default={b'static': True})),
('type', models.CharField(default=b'static', max_length=255)),
('description', models.TextField(default=b'')),
('icon', models.ImageField(blank=True, default=None, upload_to=documentcollection.models.get_icon_path)),
('view', models.TextField(default=documentcollection.models.get_collectionview)),
('sort', oxdjango.fields.TupleField(default=documentcollection.models.get_collectionsort, editable=False)),
('poster_frames', oxdjango.fields.TupleField(default=[], editable=False)),
('numberofdocuments', models.IntegerField(default=0)),
],
),
migrations.CreateModel(
name='CollectionDocument',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(auto_now_add=True)),
('modified', models.DateTimeField(auto_now=True)),
('index', models.IntegerField(default=0)),
('collection', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='documentcollection.Collection')),
('document', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='document.Document')),
],
),
migrations.CreateModel(
name='Position',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('section', models.CharField(max_length=255)),
('position', models.IntegerField(default=0)),
('collection', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='position', to='documentcollection.Collection')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='collection_positions', to=settings.AUTH_USER_MODEL)),
],
),
migrations.AddField(
model_name='collection',
name='documents',
field=models.ManyToManyField(related_name='collections', through='documentcollection.CollectionDocument', to='document.Document'),
),
migrations.AddField(
model_name='collection',
name='subscribed_users',
field=models.ManyToManyField(related_name='subscribed_collections', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='collection',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='collections', to=settings.AUTH_USER_MODEL),
),
migrations.AlterUniqueTogether(
name='position',
unique_together=set([('user', 'collection', 'section')]),
),
migrations.AlterUniqueTogether(
name='collection',
unique_together=set([('user', 'name')]),
),
]

View file

@ -0,0 +1,321 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division, print_function, absolute_import
import os
import re
import subprocess
from glob import glob
from django.db import models
from django.db.models import Max
from django.contrib.auth.models import User
from django.conf import settings
import ox
from oxdjango.fields import DictField, TupleField
from archive import extract
from . import managers
def get_path(f, x):
return f.path(x)
def get_icon_path(f, x):
return get_path(f, 'icon.jpg')
def get_collectionview():
return settings.CONFIG['user']['ui']['collectionView']
def get_collectionsort():
return tuple(settings.CONFIG['user']['ui']['collectionSort'])
class Collection(models.Model):
class Meta:
unique_together = ("user", "name")
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, related_name='collections')
name = models.CharField(max_length=255)
status = models.CharField(max_length=20, default='private')
_status = ['private', 'public', 'featured']
query = DictField(default={"static": True})
type = models.CharField(max_length=255, default='static')
description = models.TextField(default='')
icon = models.ImageField(default=None, blank=True, upload_to=get_icon_path)
view = models.TextField(default=get_collectionview)
sort = TupleField(default=get_collectionsort, editable=False)
poster_frames = TupleField(default=[], editable=False)
#is through table still required?
documents = models.ManyToManyField('document.Document', related_name='collections',
through='CollectionDocument')
numberofdocuments = models.IntegerField(default=0)
subscribed_users = models.ManyToManyField(User, related_name='subscribed_collections')
objects = managers.CollectionManager()
def save(self, *args, **kwargs):
if self.query.get('static', False):
self.type = 'static'
else:
self.type = 'smart'
if self.id:
self.numberofdocuments = self.get_numberofdocuments(self.user)
super(Collection, self).save(*args, **kwargs)
@classmethod
def get(cls, id):
id = id.split(':')
username = id[0]
collectionname = ":".join(id[1:])
return cls.objects.get(user__username=username, name=collectionname)
def get_documents(self, user=None):
if self.query.get('static', False):
return self.documents
from document.models import Document
return Document.objects.find({'query': self.query}, user)
def get_numberofdocuments(self, user=None):
return self.get_documents(user).count()
def add(self, document):
q = self.documents.filter(id=document.id)
if q.count() == 0:
l = CollectionDocument()
l.collection = self
l.document = document
l.index = CollectionDocument.objects.filter(collection=self).aggregate(Max('index'))['index__max']
if l.index is None:
l.index = 0
else:
l.index += 1
l.save()
def remove(self, document=None, documents=None):
if document:
CollectionDocument.objects.all().filter(document=document, collection=self).delete()
if documents:
CollectionDocument.objects.all().filter(document__id__in=documents, collection=self).delete()
def __unicode__(self):
return self.get_id()
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')
def editable(self, user):
if user.is_anonymous():
return False
if self.user == user or \
user.is_staff or \
user.profile.capability('canEditFeaturedCollections') is True:
return True
return False
def edit(self, data, user):
for key in data:
if key == 'query' and not data['query']:
setattr(self, key, {"static": True})
elif key == 'query' and isinstance(data[key], dict):
setattr(self, key, data[key])
elif key == 'type':
if data[key] == 'static':
self.query = {"static": True}
self.type = 'static'
else:
self.type = 'smart'
if self.query.get('static', False):
self.query = {}
elif key == 'status':
value = data[key]
if value not in self._status:
value = self._status[0]
if value == 'private':
for user in self.subscribed_users.all():
self.subscribed_users.remove(user)
qs = Position.objects.filter(user=user, collection=self)
if qs.count() > 1:
pos = qs[0]
pos.section = 'personal'
pos.save()
elif value == 'featured':
if user.profile.capability('canEditFeaturedCollections'):
pos, created = Position.objects.get_or_create(collection=self, user=user,
section='featured')
if created:
qs = Position.objects.filter(user=user, section='featured')
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
pos.save()
Position.objects.filter(collection=self).exclude(id=pos.id).delete()
else:
value = self.status
elif self.status == 'featured' and value == 'public':
Position.objects.filter(collection=self).delete()
pos, created = Position.objects.get_or_create(collection=self,
user=self.user, section='personal')
qs = Position.objects.filter(user=self.user, section='personal')
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
pos.save()
for u in self.subscribed_users.all():
pos, created = Position.objects.get_or_create(collection=self, user=u,
section='public')
qs = Position.objects.filter(user=u, section='public')
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
pos.save()
self.status = value
elif key == 'name':
data['name'] = re.sub(' \[\d+\]$', '', data['name']).strip()
if not data['name']:
data['name'] = "Untitled"
name = data['name']
num = 1
while Collection.objects.filter(name=name, user=self.user).exclude(id=self.id).count() > 0:
num += 1
name = data['name'] + ' [%d]' % num
self.name = name
elif key == 'description':
self.description = ox.sanitize_html(data['description'])
if 'position' in data:
pos, created = Position.objects.get_or_create(collection=self, user=user)
pos.position = data['position']
pos.section = 'featured'
if self.status == 'private':
pos.section = 'personal'
pos.save()
if 'posterFrames' in data:
self.poster_frames = tuple(data['posterFrames'])
if 'view' in data:
self.view = data['view']
if 'sort' in data:
self.sort = tuple(data['sort'])
self.save()
if 'posterFrames' in data:
self.update_icon()
def json(self, keys=None, user=None):
if not keys:
keys = ['id', 'name', 'user', 'type', 'query', 'status', 'subscribed', 'posterFrames', 'description', 'view']
response = {}
for key in keys:
if key in ('items', 'documents'):
response[key] = self.get_numberofdocuments(user)
elif key == 'id':
response[key] = self.get_id()
elif key == 'user':
response[key] = self.user.username
elif key == 'query':
if not self.query.get('static', False):
response[key] = self.query
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()
else:
response[key] = getattr(self, {
'posterFrames': 'poster_frames'
}.get(key, key))
return response
def path(self, name=''):
h = "%07d" % self.id
return os.path.join('collections', h[:2], h[2:4], h[4:6], h[6:], name)
def update_icon(self):
frames = []
#fixme
'''
if not self.poster_frames:
documents = self.get_documents(self.user)
if documents.count():
poster_frames = []
for i in range(0, documents.count(), max(1, int(documents.count()/4))):
poster_frames.append({
'document': documents[int(i)].id,
'position': documents[int(i)].poster_frame
})
self.poster_frames = tuple(poster_frames)
self.save()
for i in self.poster_frames:
from document.models import Document
qs = Document.objects.filter(id=i['document'])
if qs.count() > 0:
if i.get('position'):
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.collection_ICON,
'-f', ','.join(frames),
'-o', icon
]
p = subprocess.Popen(cmd, close_fds=True)
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 CollectionDocument(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
collection = models.ForeignKey(Collection)
index = models.IntegerField(default=0)
document = models.ForeignKey('document.Document')
def __unicode__(self):
return u'%s in %s' % (self.document, self.collection)
class Position(models.Model):
class Meta:
unique_together = ("user", "collection", "section")
collection = models.ForeignKey(Collection, related_name='position')
user = models.ForeignKey(User, related_name='collection_positions')
section = models.CharField(max_length=255)
position = models.IntegerField(default=0)
def __unicode__(self):
return u'%s/%s/%s' % (self.section, self.position, self.collection)

View file

@ -0,0 +1,448 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division, print_function, absolute_import
import os
import re
import json
from django.db.models import Max, Sum
from django.db import transaction
from django.conf import settings
from oxdjango.decorators import login_required_json
from oxdjango.shortcuts import render_to_json_response, get_object_or_404_json, json_response
from oxdjango.http import HttpFileResponse
import ox
from . import models
from oxdjango.api import actions
from item import utils
from document.models import Document
from user.tasks import update_numberofcollections
from changelog.models import add_changelog
def get_collection_or_404_json(id):
id = id.split(':')
username = id[0]
collectionname = ":".join(id[1:])
return get_object_or_404_json(models.Collection, user__username=username, name=collectionname)
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, nulls_last=True)
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', 'collection', 'range', 'position', 'positions', 'sort'):
if key in data:
query[key] = data[key]
query['qs'] = models.Collection.objects.find(data, user)
return query
def findCollections(request, data):
'''
Finds collections for a given query
takes {
query: object, // query object, see `find`
sort: [], // collection of sort objects, see `find`
range: [int, int], // range of results to return
keys: [string] // collection of properties to return
}
returns {
items: [object] // collection of collection objects
}
notes: Possible query keys are 'featured', 'name', 'subscribed' and 'user',
possible keys are 'featured', 'name', 'query', 'subscribed' and 'user'.
see: addCollection, editCollection, find, getCollection, removeCollection, sortCollections
'''
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 = any(
is_featured_condition(x)
for x in data.get('query', {}).get('conditions', [])
)
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(findCollections)
def getCollection(request, data):
'''
Gets a collection by id
takes {
id: string // collection id
}
returns {
id: string, // collection id
section: string, // collections section (like 'personal')
... // more key/value pairs
}
see: addCollection, editCollection, findCollections, removeCollection, sortCollections
'''
if 'id' in data:
response = json_response()
collection = get_collection_or_404_json(data['id'])
if collection.accessible(request.user):
response['data'] = collection.json(user=request.user)
else:
response = json_response(status=403, text='not allowed')
else:
response = json_response(status=404, text='not found')
return render_to_json_response(response)
actions.register(getCollection)
@login_required_json
def addCollectionItems(request, data):
'''
Adds one or more items to a static collection
takes {
collection: string, // collection id
items: [string], // either collection of item ids
query: object // or query object, see `find`
}
returns {}
see: find, orderCollectionItems, removeCollectionItems
'''
collection = get_collection_or_404_json(data['collection'])
if 'items' in data:
if collection.editable(request.user):
with transaction.atomic():
items = [ox.fromAZ(id) for id in data['items']]
for item in Document.objects.filter(id__in=items):
collection.add(item)
response = json_response(status=200, text='items added')
add_changelog(request, data, data['collection'])
else:
response = json_response(status=403, text='not allowed')
elif 'query' in data:
response = json_response(status=501, text='not implemented')
else:
response = json_response(status=501, text='not implemented')
return render_to_json_response(response)
actions.register(addCollectionItems, cache=False)
@login_required_json
def removeCollectionItems(request, data):
'''
Removes one or more items from a static collection
takes {
collection: string, // collection id
items: [itemId], // either collection of item ids
query: object // or query object, see `find`
}
returns {}
see: addCollectionItems, find, orderCollectionItems
'''
collection = get_collection_or_404_json(data['collection'])
if 'items' in data:
if collection.editable(request.user):
items = [ox.fromAZ(id) for id in data['items']]
collection.remove(documents=items)
response = json_response(status=200, text='items removed')
add_changelog(request, data, data['collection'])
else:
response = json_response(status=403, text='not allowed')
elif 'query' in data:
response = json_response(status=501, text='not implemented')
else:
response = json_response(status=501, text='not implemented')
return render_to_json_response(response)
actions.register(removeCollectionItems, cache=False)
@login_required_json
def orderCollectionItems(request, data):
'''
Sets the manual ordering of items in a given collection
takes {
collection: string, // collection id
ids: [string] // ordered collection of item ids
}
returns {}
notes: There is no UI for this yet.
see: addCollectionItems, removeCollectionItems
'''
collection = get_collection_or_404_json(data['collection'])
response = json_response()
if collection.editable(request.user) and collection.type == 'static':
index = 0
with transaction.atomic():
for i in data['ids']:
models.CollectionItem.objects.filter(collection=collection, item__public_id=i).update(index=index)
index += 1
else:
response = json_response(status=403, text='permission denied')
return render_to_json_response(response)
actions.register(orderCollectionItems, cache=False)
@login_required_json
def addCollection(request, data):
'''
Adds a new collection
takes {
name: value, // collection name (optional)
... // more key/value pairs
}
returns {
id: string, // collection id
name: string, // collection name
... // more key/value pairs
}
notes: Possible keys are 'description', 'items', 'name', 'query', 'sort',
'type' and 'view'.
see: editCollection, findCollections, getCollection, removeCollection, sortCollections
'''
data['name'] = re.sub(' \[\d+\]$', '', data.get('name', 'Untitled')).strip()
name = data['name']
if not name:
name = "Untitled"
num = 1
created = False
while not created:
collection, created = models.Collection.objects.get_or_create(name=name, user=request.user)
num += 1
name = data['name'] + ' [%d]' % num
del data['name']
if data:
collection.edit(data, request.user)
else:
collection.save()
update_numberofcollections.delay(request.user.username)
if 'items' in data:
items = [ox.fromAZ(id) for id in data['items']]
for item in Document.objects.filter(id__in=items):
collection.add(item)
if collection.status == 'featured':
pos, created = models.Position.objects.get_or_create(collection=collection,
user=request.user, section='featured')
qs = models.Position.objects.filter(section='featured')
else:
pos, created = models.Position.objects.get_or_create(collection=collection,
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'] = collection.json()
add_changelog(request, data, collection.get_id())
return render_to_json_response(response)
actions.register(addCollection, cache=False)
@login_required_json
def editCollection(request, data):
'''
Edits a collection
takes {
id: string, // collection id
key: value, // property id and new value
... // more key/value pairs
}
returns {
id: string, // collection id
... // more key/value pairs
}
notes: Possible keys are 'name', 'position', 'posterFrames', 'query' and
'status'. 'posterFrames' is an array of {item, position}. If you change
'status', you have to pass 'position' (the position of the collection in its new
collection folder).
see: addCollection, findCollections, getCollection, removeCollection, sortCollections
'''
collection = get_collection_or_404_json(data['id'])
if collection.editable(request.user):
response = json_response()
collection.edit(data, request.user)
response['data'] = collection.json(user=request.user)
add_changelog(request, data)
else:
response = json_response(status=403, text='not allowed')
return render_to_json_response(response)
actions.register(editCollection, cache=False)
@login_required_json
def removeCollection(request, data):
'''
Removes a collection
takes {
id: string // collection id
}
returns {}
see: addCollection, editCollection, findCollections, getCollection, sortCollections
'''
collection = get_collection_or_404_json(data['id'])
response = json_response()
if collection.editable(request.user):
add_changelog(request, data)
collection.delete()
update_numberofcollections.delay(request.user.username)
else:
response = json_response(status=403, text='not allowed')
return render_to_json_response(response)
actions.register(removeCollection, cache=False)
@login_required_json
def subscribeToCollection(request, data):
'''
Adds a collection to favorites
takes {
id: string, // collection id
user: string // username (admin-only)
}
returns {}
see: unsubscribeFromCollection
'''
collection = get_collection_or_404_json(data['id'])
user = request.user
if collection.status == 'public' and \
collection.subscribed_users.filter(username=user.username).count() == 0:
collection.subscribed_users.add(user)
pos, created = models.Position.objects.get_or_create(collection=collection, 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()
add_changelog(request, data)
response = json_response()
return render_to_json_response(response)
actions.register(subscribeToCollection, cache=False)
@login_required_json
def unsubscribeFromCollection(request, data):
'''
Removes a collection from favorites
takes {
id: string, // collection id
user: string // username (admin-only)
}
returns {}
see: subscribeToCollection
'''
collection = get_collection_or_404_json(data['id'])
user = request.user
collection.subscribed_users.remove(user)
models.Position.objects.filter(collection=collection, user=user, section='public').delete()
response = json_response()
add_changelog(request, data)
return render_to_json_response(response)
actions.register(unsubscribeFromCollection, cache=False)
@login_required_json
def sortCollections(request, data):
'''
Sets the order of collections in a given section
takes {
section: string, // collections section
ids: [string] // ordered collection of collections
}
returns {}
notes: Possible sections are 'personal', 'favorite' and 'featured'. Setting
the order of featured collections requires the appropriate capability.
see: addCollection, editCollection, findCollections, getCollection, removeCollection
'''
position = 0
section = data['section']
section = {
'favorite': 'public'
}.get(section, section)
#ids = collection(set(data['ids']))
ids = data['ids']
if section == 'featured' and not request.user.profile.capability('canEditFeaturedCollections'):
response = json_response(status=403, text='not allowed')
else:
user = request.user
if section == 'featured':
for i in ids:
l = get_collection_or_404_json(i)
qs = models.Position.objects.filter(section=section, collection=l)
if qs.count() > 0:
pos = qs[0]
else:
pos = models.Position(collection=l, user=user, section=section)
if pos.position != position:
pos.position = position
pos.save()
position += 1
models.Position.objects.filter(section=section, collection=l).exclude(id=pos.id).delete()
else:
for i in ids:
l = get_collection_or_404_json(i)
pos, created = models.Position.objects.get_or_create(collection=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(sortCollections, cache=False)
def icon(request, id, size=16):
if not size:
size = 16
id = id.split(':')
username = id[0]
collectionname = ":".join(id[1:])
qs = models.Collection.objects.filter(user__username=username, name=collectionname)
if qs.count() == 1 and qs[0].accessible(request.user):
collection = qs[0]
icon = collection.get_icon(int(size))
else:
icon = os.path.join(settings.STATIC_ROOT, 'jpg/list256.jpg')
return HttpFileResponse(icon, content_type='image/jpeg')