Compare commits

..

No commits in common. "769f0b7fd2dda5cdf0331a5f415c38ee329fd643" and "2d25c60606004a02297e521211f3d08e823cd8df" have entirely different histories.

160 changed files with 783 additions and 812 deletions

View file

@ -1,13 +1,13 @@
# pan.do/ra - open media archive
for more information about pan.do/ra visit our website at https://pan.do/ra
for more information on pan.do/ra visit our website at https://pan.do/ra
## Installing pan.do/ra
We recommend to run pan.do/ra inside of LXD or LXC or dedicated VM or server.
we recommend to run pan.do/ra inside of LXD or LXC or dedicated VM or server.
You will need at least 2GB of free disk space
pan.do/ra is known to work with Ubuntu 18.04, 20.04 and Debian/10 (buster),
pan.do/ra is known to work with Ubuntu 18.04 and Debian/10 (buster),
other distributions might also work, let us know if it works for you.
Use the following commands as root to install pan.do/ra and all dependencies:
@ -16,7 +16,6 @@
cd /root
curl -sL https://pan.do/ra-install > pandora_install.sh
chmod +x pandora_install.sh
export BRANCH=stable # change to 'master' to get current developement version
./pandora_install.sh 2>&1 | tee pandora_install.log
```

38
ctl
View file

@ -1,18 +1,13 @@
#!/bin/sh
SERVICES="pandora pandora-tasks pandora-encoding pandora-cron pandora-websocketd"
if [ -z "$1" ]; then
echo "Usage: $0 (start|stop|restart|reload|status)"
echo "Usage: $0 (start|stop|restart|reload)"
exit 1
else
action="$1"
fi
self=`readlink "$0"`
if [ -z $self ]; then
self="$0"
fi
if [ "$action" = "init" ]; then
cd "`dirname "$self"`"
cd "`dirname "$0"`"
BASE=`pwd`
SUDO=""
PANDORA_USER=`ls -l update.py | cut -f3 -d" "`
@ -48,27 +43,6 @@ if [ "$action" = "init" ]; then
fi
exit 0
fi
if [ "$action" = "manage" ]; then
cmd="pandora/manage.py"
fi
if [ "$action" = "update" ]; then
cmd="update.py"
fi
if [ ! -z $cmd ]; then
cd "`dirname "$self"`"
BASE=`pwd`
SUDO=""
PANDORA_USER=`ls -l update.py | cut -f3 -d" "`
if [ `whoami` != $PANDORA_USER ]; then
SUDO="sudo -H -u $PANDORA_USER"
fi
shift
$SUDO "$BASE/$cmd" $@
exit $?
fi
if [ `whoami` != 'root' ]; then
echo you have to be root or run $0 with sudo
exit 1
@ -93,7 +67,6 @@ if [ "$action" = "install" ]; then
systemctl enable ${service}.service
done
fi
test -e /usr/local/bin/pandoractl || ln -s /srv/pandora/ctl /usr/local/bin/pandoractl
else
if [ -d /etc/init ]; then
cp $BASE/etc/init/* /etc/init/
@ -101,13 +74,6 @@ if [ "$action" = "install" ]; then
fi
exit 0
fi
if [ "status" = "$action" ]; then
export SYSTEMD_PAGER=
fi
for service in $SERVICES; do
if [ -x /bin/systemctl ]; then
/bin/systemctl $action $service
else
service $service $action
fi
done

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from django.contrib import admin

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.conf import settings
from django.contrib.auth import get_user_model

View file

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import unicodedata
from six import string_types
from django.db.models import Q, Manager
from oxdjango.query import QuerySet
@ -67,7 +68,7 @@ def parseCondition(condition, user):
else:
key = k + get_operator(op, 'istr' if k in case_insensitive_keys else 'str')
key = str(key)
if isinstance(v, str):
if isinstance(v, string_types):
v = unicodedata.normalize('NFKD', v)
if k not in case_sensitive_keys:
v = v.lower()
@ -157,7 +158,7 @@ class AnnotationManager(Manager):
#anonymous can only see public items
public_layers = self.model.public_layers()
if user.is_anonymous:
if user.is_anonymous():
qs = qs.filter(layer__in=public_layers)
#users can see public and own
else:

View file

@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import re
import unicodedata
from django.utils.encoding import python_2_unicode_compatible
from django.db import models, transaction
from django.db.models import Q
from django.contrib.auth import get_user_model
@ -81,15 +83,16 @@ def get_matches(obj, model, layer_type, qs=None):
matches = [-1]
return Annotation.objects.filter(id__in=matches)
@python_2_unicode_compatible
class Annotation(models.Model):
objects = managers.AnnotationManager()
#FIXME: here having a item,start index would be good
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, related_name='annotations', on_delete=models.CASCADE)
item = models.ForeignKey('item.Item', related_name='annotations', on_delete=models.CASCADE)
clip = models.ForeignKey('clip.Clip', null=True, related_name='annotations', on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='annotations')
item = models.ForeignKey('item.Item', related_name='annotations')
clip = models.ForeignKey('clip.Clip', null=True, related_name='annotations')
public_id = models.CharField(max_length=128, unique=True)
#seconds
@ -104,7 +107,7 @@ class Annotation(models.Model):
languages = models.CharField(max_length=255, null=True, blank=True)
def editable(self, user):
if user.is_authenticated:
if user.is_authenticated():
if user.profile.capability('canEditAnnotations') or \
self.user == user or \
user.groups.filter(id__in=self.item.groups.all()).count() > 0:
@ -397,7 +400,7 @@ class Annotation(models.Model):
return j
def __str__(self):
return "%s %s-%s" % (self.public_id, self.start, self.end)
return u"%s %s-%s" % (self.public_id, self.start, self.end)
def cleanup_related(sender, **kwargs):
kwargs['instance'].cleanup_undefined_relations()

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from django.conf import settings
from django.contrib.auth import get_user_model

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from django.conf import settings
from django.db.models import Count, Sum, F, Value

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from django.contrib import admin

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import codecs
import os
@ -9,8 +10,8 @@ import sys
import time
from os.path import dirname, exists, join
from glob import glob
import _thread as thread
from six.moves import _thread as thread
from django.conf import settings
from django.contrib.auth import get_user_model
@ -28,16 +29,20 @@ RUN_RELOADER = True
NOTIFIER = None
def get_version():
info = join(dirname(dirname(dirname(__file__))), '.bzr', 'branch', 'last-revision')
git_dir = join(dirname(dirname(dirname(__file__))), '.git')
if exists(git_dir):
env = {'GIT_DIR': git_dir}
cmd = ['git', 'rev-list', 'HEAD', '--count']
version = subprocess.check_output(cmd, env=env).strip().decode('utf-8')
if settings.VERSION_EPOCH:
version = settings.VERSION_EPOCH + version
return version
return subprocess.check_output(cmd, env=env).strip().decode('utf-8')
elif exists(info):
f = open(info)
rev = int(f.read().split()[0])
f.close()
if rev:
return u'%s' % rev
else:
return 'unknown'
return u'unknown'
def load_config(init=False):
with open(settings.SITE_CONFIG) as f:
@ -394,7 +399,8 @@ def update_static():
def update_geoip(force=False):
path = os.path.join(settings.GEOIP_PATH, 'GeoLite2-City.mmdb')
if not os.path.exists(path) or force:
index = ox.net.read_url('https://db-ip.com/db/download/ip-to-city-lite').decode()
url = 'http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz'
index = ox.net.read_url('https://db-ip.com/db/download/ip-to-country-lite').decode()
match = re.compile('href=[\'"](http.*.mmdb.gz)').findall(index)
if match:
url = match[0]
@ -404,7 +410,7 @@ def update_geoip(force=False):
os.unlink(path)
os.system('gunzip "%s.gz"' % path)
else:
print('failed to download GeoLite2-City.mmdb')
print('failed to download dbip-country-lite-2020-03.mmdb.gz')
def init():
if not settings.RELOADER_RUNNING:

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
import re
import ox.jsonc

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand
from django.conf import settings

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand
from django.db import connection

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand
from django.conf import settings
from ... import documentation

View file

@ -1,13 +1,16 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import json
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from . import monkey_patch
from . import tasks
@python_2_unicode_compatible
class Page(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
@ -17,6 +20,7 @@ class Page(models.Model):
def __str__(self):
return self.name
@python_2_unicode_compatible
class Settings(models.Model):
created = models.DateTimeField(auto_now_add=True)

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
@ -13,17 +14,10 @@ config.init()
NEW_LENGTH = {
'username': 255,
'email': 254,
'email': 255,
'password': 255,
}
def monkey_patch_groupname():
f = Group._meta.get_field('name')
f.max_length = 255
for v in f.validators:
if isinstance(v, MaxLengthValidator):
v.limit_value = 255
def monkey_patch_username():
for field in NEW_LENGTH:
f = User._meta.get_field(field)
@ -31,18 +25,22 @@ def monkey_patch_username():
for v in f.validators:
if isinstance(v, MaxLengthValidator):
v.limit_value = NEW_LENGTH[field]
monkey_patch_groupname()
f = Group._meta.get_field('name')
f.max_length = 255
for v in f.validators:
if isinstance(v, MaxLengthValidator):
v.limit_value = 255
def apply_patch():
from django.db import connection, transaction
cursor = connection.cursor()
table = connection.introspection.get_table_description(cursor, Group._meta.db_table)
table = connection.introspection.get_table_description(cursor, User._meta.db_table)
sql = []
for row in table:
if row.name == 'name' and row.internal_size != 255:
sql.append('ALTER TABLE "%s" ALTER "%s" TYPE varchar(%d)' % (
Group._meta.db_table, row.name, 255)
)
if row.name in NEW_LENGTH and row.internal_size != NEW_LENGTH[row.name]:
sql.append('ALTER TABLE "%s" ALTER "%s" TYPE varchar(%d)' % (User._meta.db_table, row.name, NEW_LENGTH[row.name]))
for q in sql:
cursor.execute(q)
if sql:

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import datetime

View file

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import division, with_statement
import time
from .models import Settings

View file

@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import copy
from datetime import datetime
from six import string_types
from django.shortcuts import render, redirect
from django.conf import settings
from django.http import HttpResponse
@ -112,7 +114,7 @@ def getPage(request, data):
}
see: editPage
'''
if isinstance(data, str):
if isinstance(data, string_types):
name = data
else:
name = data['name']

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from django.contrib import admin

View file

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import division, with_statement
import os
import ox

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import json
import subprocess

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import os
from os.path import exists
@ -12,6 +13,7 @@ import shutil
from distutils.spawn import find_executable
from glob import glob
from six import string_types
import numpy as np
import ox
import ox.image
@ -462,7 +464,7 @@ def timeline(video, prefix, modes=None, size=None):
modes = ['antialias', 'slitscan', 'keyframes', 'audio', 'data']
if size is None:
size = [64, 16]
if isinstance(video, str):
if isinstance(video, string_types):
video = [video]
cmd = ['../bin/oxtimelines',
'-s', ','.join(map(str, reversed(sorted(size)))),

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand
from django.conf import settings

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
import os
import re

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand
from django.conf import settings

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import json
import os.path
@ -6,10 +7,12 @@ import shutil
import tempfile
import time
from six import string_types, PY2
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models
from django.db.models.signals import pre_delete
from django.utils.encoding import python_2_unicode_compatible
from oxdjango.fields import JSONField
from oxdjango import fields
@ -27,9 +30,13 @@ from . import managers
User = get_user_model()
if not PY2:
unicode = str
def data_path(f, x):
return f.get_path('data.bin')
@python_2_unicode_compatible
class File(models.Model):
AV_INFO = (
'duration', 'video', 'audio', 'oshash', 'size',
@ -48,7 +55,7 @@ class File(models.Model):
modified = models.DateTimeField(auto_now=True)
oshash = models.CharField(max_length=16, unique=True)
item = models.ForeignKey("item.Item", related_name='files', null=True, on_delete=models.CASCADE)
item = models.ForeignKey("item.Item", related_name='files', null=True)
path = models.CharField(max_length=2048, default="") # canoncial path/file
sort_path = models.CharField(max_length=2048, default="") # sort name
@ -161,7 +168,7 @@ class File(models.Model):
if self.item:
for key in self.ITEM_INFO:
data[key] = self.item.get(key)
if isinstance(data[key], str):
if isinstance(data[key], string_types):
data[key] = ox.decode_html(data[key])
elif isinstance(data[key], list):
data[key] = [ox.decode_html(e) for e in data[key]]
@ -255,8 +262,8 @@ class File(models.Model):
data = self.get_path_info()
self.extension = data.get('extension')
self.language = data.get('language')
self.part = ox.sort_string(str(data.get('part') or ''))
self.part_title = ox.sort_string(str(data.get('partTitle')) or '')
self.part = ox.sort_string(unicode(data.get('part') or ''))
self.part_title = ox.sort_string(unicode(data.get('partTitle')) or '')
self.type = data.get('type') or 'unknown'
self.version = data.get('version')
@ -476,7 +483,7 @@ class File(models.Model):
if k not in keys:
del data[k]
can_see_media = False
if user and not user.is_anonymous:
if user and not user.is_anonymous():
can_see_media = user.profile.capability('canSeeMedia') or \
user.is_staff or \
self.item.user == user or \
@ -591,15 +598,15 @@ class File(models.Model):
status = {}
if self.encoding:
for s in self.streams.all():
status[s.name()] = 'done' if s.available else 'encoding'
status[s.name()] = u'done' if s.available else u'encoding'
config = settings.CONFIG['video']
max_resolution = self.streams.get(source=None).resolution
for resolution in sorted(config['resolutions'], reverse=True):
if resolution <= max_resolution:
for f in config['formats']:
name = '%sp.%s' % (resolution, f)
name = u'%sp.%s' % (resolution, f)
if name not in status:
status[name] = 'queued'
status[name] = u'queued'
return status
def delete_frames(self):
@ -620,6 +627,7 @@ def delete_file(sender, **kwargs):
f.delete_files()
pre_delete.connect(delete_file, sender=File)
@python_2_unicode_compatible
class Volume(models.Model):
class Meta:
@ -628,11 +636,11 @@ class Volume(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, related_name='volumes', on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='volumes')
name = models.CharField(max_length=1024)
def __str__(self):
return "%s's %s" % (self.user, self.name)
return u"%s's %s" % (self.user, self.name)
def json(self):
return {
@ -644,6 +652,7 @@ class Volume(models.Model):
def inttime():
return int(time.time())
@python_2_unicode_compatible
class Instance(models.Model):
class Meta:
@ -659,11 +668,11 @@ class Instance(models.Model):
path = models.CharField(max_length=2048)
ignore = models.BooleanField(default=False)
file = models.ForeignKey(File, related_name='instances', on_delete=models.CASCADE)
volume = models.ForeignKey(Volume, related_name='files', on_delete=models.CASCADE)
file = models.ForeignKey(File, related_name='instances')
volume = models.ForeignKey(Volume, related_name='files')
def __str__(self):
return "%s's %s <%s>" % (self.volume.user, self.path, self.file.oshash)
return u"%s's %s <%s>" % (self.volume.user, self.path, self.file.oshash)
@property
def public_id(self):
@ -682,13 +691,14 @@ def frame_path(frame, name):
name = "%s%s" % (frame.position, ext)
return frame.file.get_path(name)
@python_2_unicode_compatible
class Frame(models.Model):
class Meta:
unique_together = ("file", "position")
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
file = models.ForeignKey(File, related_name="frames", on_delete=models.CASCADE)
file = models.ForeignKey(File, related_name="frames")
position = models.FloatField()
frame = models.ImageField(default=None, null=True, upload_to=frame_path)
width = models.IntegerField(default=0)
@ -701,7 +711,7 @@ class Frame(models.Model):
super(Frame, self).save(*args, **kwargs)
def __str__(self):
return '%s/%s' % (self.file, self.position)
return u'%s/%s' % (self.file, self.position)
def delete_frame(sender, **kwargs):
f = kwargs['instance']
@ -712,17 +722,18 @@ pre_delete.connect(delete_frame, sender=Frame)
def stream_path(f, x):
return f.path(x)
@python_2_unicode_compatible
class Stream(models.Model):
class Meta:
unique_together = ("file", "resolution", "format")
file = models.ForeignKey(File, related_name='streams', on_delete=models.CASCADE)
file = models.ForeignKey(File, related_name='streams')
resolution = models.IntegerField(default=96)
format = models.CharField(max_length=255, default='webm')
media = models.FileField(default=None, blank=True, upload_to=stream_path)
source = models.ForeignKey('Stream', related_name='derivatives', default=None, null=True, on_delete=models.CASCADE)
source = models.ForeignKey('Stream', related_name='derivatives', default=None, null=True)
available = models.BooleanField(default=False)
oshash = models.CharField(max_length=16, null=True, db_index=True)
info = JSONField(default=dict, editable=False)
@ -742,10 +753,10 @@ class Stream(models.Model):
return os.path.join(settings.MEDIA_ROOT, self.path(), 'timeline')
def name(self):
return "%sp.%s" % (self.resolution, self.format)
return u"%sp.%s" % (self.resolution, self.format)
def __str__(self):
return "%s/%s" % (self.file, self.name())
return u"%s/%s" % (self.file, self.name())
def get(self, resolution, format):
streams = []
@ -803,11 +814,7 @@ class Stream(models.Model):
# file could have been moved while encoding
# get current version from db and update
try:
self.refresh_from_db()
except archive.models.DoesNotExist:
pass
else:
self.update_status(ok, error)
def get_index(self):

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function
from datetime import datetime
from time import time

View file

@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from glob import glob
from six import string_types
from celery.task import task
from django.conf import settings
from django.db.models import Q
@ -218,7 +220,7 @@ def move_media(data, user):
data['public_id'] = data.pop('item').strip()
if not is_imdb_id(data['public_id']):
del data['public_id']
if 'director' in data and isinstance(data['director'], str):
if 'director' in data and isinstance(data['director'], string_types):
if data['director'] == '':
data['director'] = []
else:

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import os.path
from datetime import datetime
@ -7,6 +8,7 @@ from django.shortcuts import get_object_or_404, redirect, render
from django.conf import settings
from django.db.models import Count, Q
from six import string_types
from celery.utils import get_full_cls_name
from celery._state import current_app
import ox
@ -554,7 +556,7 @@ def getPath(request, data):
'''
response = json_response()
ids = data['id']
if isinstance(ids, str):
if isinstance(ids, string_types):
ids = [ids]
for f in models.File.objects.filter(oshash__in=ids).values('path', 'oshash').order_by('sort_path'):
response['data'][f['oshash']] = f['path']

View file

@ -1,9 +1,11 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from datetime import datetime
from django.contrib.auth import get_user_model
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from oxdjango.fields import JSONField
import ox
@ -17,13 +19,14 @@ User = get_user_model()
'''
FIXME: remove this table more migrate to new ChangeLog
'''
@python_2_unicode_compatible
class Changelog(models.Model):
created = models.DateTimeField(auto_now_add=True)
type = models.CharField(max_length=255, db_index=True)
value = JSONField(default=dict, editable=False)
def __str__(self):
return '%s %s' % (self.type, self.created)
return u'%s %s' % (self.type, self.created)
def json(self):
return self.value
@ -47,18 +50,19 @@ def add_changelog(request, data, id=None):
'user': c.user.username,
})
@python_2_unicode_compatible
class Log(models.Model):
action = models.CharField(max_length=255, db_index=True)
data = JSONField(default=dict, editable=False)
created = models.DateTimeField(db_index=True)
user = models.ForeignKey(User, null=True, related_name='changelog', on_delete=models.CASCADE)
user = models.ForeignKey(User, null=True, related_name='changelog')
changeid = models.TextField()
objects = managers.LogManager()
def __str__(self):
return '%s %s %s' % (self.created, self.action, self.changeid)
return u'%s %s %s' % (self.created, self.action, self.changeid)
def get_id(self):
return ox.toAZ(self.id)

View file

@ -1,3 +1,4 @@
from __future__ import print_function
import models
import item.models
@ -17,33 +18,33 @@ def recover_item(id):
created = old.value['created']
i.user = user.models.User.objects.get(username=i.data['user'])
for key in [
'rendered',
'random',
'cuts',
'duration',
'id',
'size',
'posterFrame',
'parts',
'cutsperminute',
'hue',
'numberofcuts',
'durations',
'volume',
'user',
'words',
'videoRatio',
'aspectratio',
'bitrate',
'pixels',
'created',
'numberoffiles',
'modified',
'timesaccessed',
'accessed',
'resolution',
'wordsperminute',
'posterRatio'
u'rendered',
u'random',
u'cuts',
u'duration',
u'id',
u'size',
u'posterFrame',
u'parts',
u'cutsperminute',
u'hue',
u'numberofcuts',
u'durations',
u'volume',
u'user',
u'words',
u'videoRatio',
u'aspectratio',
u'bitrate',
u'pixels',
u'created',
u'numberoffiles',
u'modified',
u'timesaccessed',
u'accessed',
u'resolution',
u'wordsperminute',
u'posterRatio'
]:
if key in i.data:
del i.data[key]

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import ox

View file

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import unicodedata
from six import string_types
from django.db.models import Q, Manager
from django.conf import settings
@ -77,7 +78,7 @@ def parseCondition(condition, user):
else:
key = k + get_operator(op, 'istr' if k in case_insensitive_keys else 'str')
key = str(key)
if isinstance(v, str) and op != '===':
if isinstance(v, string_types) and op != '===':
v = unicodedata.normalize('NFKD', v).lower()
if exclude:
q = ~Q(**{key: v})
@ -154,7 +155,7 @@ class ClipManager(Manager):
def parse(condition):
key = 'findvalue' + get_operator(condition.get('operator', ''))
v = condition['value']
if isinstance(v, str):
if isinstance(v, string_types):
v = unicodedata.normalize('NFKD', v).lower()
q = Q(**{key: v})
if condition['key'] in layer_ids:
@ -214,7 +215,7 @@ class ClipManager(Manager):
for l in list(filter(lambda k: k in layer_ids, data['keys'])):
qs = qs.filter(**{l: True})
#anonymous can only see public clips
if not user or user.is_anonymous:
if not user or user.is_anonymous():
allowed_level = settings.CONFIG['capabilities']['canSeeItem']['guest']
qs = qs.filter(sort__rightslevel__lte=allowed_level)
#users can see public clips, there own clips and clips of there groups

View file

@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from django.db import models
from django.conf import settings
from django.utils.encoding import python_2_unicode_compatible
import ox
@ -13,7 +15,7 @@ from . import managers
def get_layers(item, interval=None, user=None):
from annotation.models import Annotation
if user and user.is_anonymous:
if user and user.is_anonymous():
user = None
layers = {}
@ -43,6 +45,7 @@ def get_layers(item, interval=None, user=None):
return layers
@python_2_unicode_compatible
class MetaClip(object):
def update_calculated_values(self):
start = self.start
@ -181,7 +184,7 @@ class MetaClip(object):
@property
def public_id(self):
return "%s/%0.03f-%0.03f" % (self.item.public_id, float(self.start), float(self.end))
return u"%s/%0.03f-%0.03f" % (self.item.public_id, float(self.start), float(self.end))
def __str__(self):
return self.public_id
@ -197,8 +200,8 @@ attrs = {
'modified': models.DateTimeField(auto_now=True),
'aspect_ratio': models.FloatField(default=0),
'item': models.ForeignKey('item.Item', related_name='clips', on_delete=models.CASCADE),
'sort': models.ForeignKey('item.ItemSort', related_name='matching_clips', on_delete=models.CASCADE),
'item': models.ForeignKey('item.Item', related_name='clips'),
'sort': models.ForeignKey('item.ItemSort', related_name='matching_clips'),
'user': models.IntegerField(db_index=True, null=True),
#seconds
@ -223,4 +226,4 @@ Clip = type('Clip', (MetaClip, models.Model), attrs)
class ClipRandom(models.Model):
id = models.BigIntegerField(primary_key=True)
clip = models.OneToOneField(Clip, on_delete=models.CASCADE)
clip = models.OneToOneField(Clip)

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from django.conf import settings
import ox
@ -153,7 +154,7 @@ def findClips(request, data):
add_annotations(layer, aqs)
elif 'position' in query:
qs = order_query(qs, query['sort'])
ids = ['%s/%0.03f-%0.03f' % (c['item__public_id'], c['start'], c['end'])
ids = [u'%s/%0.03f-%0.03f' % (c['item__public_id'], c['start'], c['end'])
for c in qs.values('item__public_id', 'start', 'end')]
data['conditions'] = data['conditions'] + {
'value': data['position'],
@ -166,7 +167,7 @@ def findClips(request, data):
response['data']['position'] = utils.get_positions(ids, [qs[0].public_id])[0]
elif 'positions' in data:
qs = order_query(qs, query['sort'])
ids = ['%s/%0.03f-%0.03f' % (c['item__public_id'], c['start'], c['end'])
ids = [u'%s/%0.03f-%0.03f' % (c['item__public_id'], c['start'], c['end'])
for c in qs.values('item__public_id', 'start', 'end')]
response['data']['positions'] = utils.get_positions(ids, data['positions'])
else:

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand
from django.db import connection, transaction

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand
from django.db import connection, transaction

View file

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import unicodedata
from six import string_types
from django.db.models import Q, Manager
from django.conf import settings
@ -131,8 +132,6 @@ def buildCondition(k, op, v, user, exclude=False, owner=None):
q = Q(id__in=l.documents.all())
else:
q = Q(id=0)
if exclude:
q = ~q
return q
elif key_config.get('fulltext'):
qs = models.Document.find_fulltext_ids(v)
@ -151,7 +150,7 @@ def buildCondition(k, op, v, user, exclude=False, owner=None):
value_key = 'find__value'
else:
value_key = k
if isinstance(v, str):
if isinstance(v, string_types):
v = unicodedata.normalize('NFKD', v).lower()
if k in facet_keys:
in_find = False
@ -282,7 +281,7 @@ class DocumentManager(Manager):
qs = qs.distinct()
#anonymous can only see public items
if not user or user.is_anonymous:
if not user or user.is_anonymous():
level = 'guest'
allowed_level = settings.CONFIG['capabilities']['canSeeDocument'][level]
qs = qs.filter(rightslevel__lte=allowed_level)

View file

@ -1,16 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from glob import glob
from urllib.parse import quote, unquote
import os
import re
from glob import glob
import unicodedata
from six import PY2, string_types
from six.moves.urllib.parse import quote, unquote
from django.db import models, transaction
from django.db.models import Q, Sum, Max
from django.contrib.auth import get_user_model
from django.db.models.signals import pre_delete
from django.conf import settings
from django.utils.encoding import python_2_unicode_compatible
from oxdjango.fields import JSONField
from PIL import Image
@ -24,7 +27,6 @@ from annotation.models import Annotation
from archive.extract import resize_image
from archive.chunk import save_chunk
from user.models import Group
from user.utils import update_groups
from . import managers
from . import utils
@ -33,15 +35,19 @@ from .fulltext import FulltextMixin
User = get_user_model()
if not PY2:
unicode = str
def get_path(f, x):
return f.path(x)
@python_2_unicode_compatible
class Document(models.Model, FulltextMixin):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, related_name='documents', on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='documents')
groups = models.ManyToManyField(Group, blank=True, related_name='documents')
extension = models.CharField(max_length=255)
@ -67,7 +73,7 @@ class Document(models.Model, FulltextMixin):
data = JSONField(default=dict, editable=False)
def update_access(self, user):
if not user.is_authenticated:
if not user.is_authenticated():
user = None
access, created = Access.objects.get_or_create(document=self, user=user)
if not created:
@ -84,7 +90,7 @@ class Document(models.Model, FulltextMixin):
if not current_values:
current_values = []
else:
current_values = [str(current_values)]
current_values = [unicode(current_values)]
filter_map = utils.get_by_id(settings.CONFIG['documentKeys'], key).get('filterMap')
if filter_map:
@ -135,7 +141,7 @@ class Document(models.Model, FulltextMixin):
f, created = Find.objects.get_or_create(document=self, key=key)
if isinstance(value, bool):
value = value and 'true' or 'false'
if isinstance(value, str):
if isinstance(value, string_types):
value = ox.decode_html(ox.strip_tags(value.strip()))
value = unicodedata.normalize('NFKD', value).lower()
f.value = value
@ -154,7 +160,7 @@ class Document(models.Model, FulltextMixin):
elif i not in ('*', 'dimensions') and i not in self.facet_keys:
value = data.get(i)
if isinstance(value, list):
value = '\n'.join(value)
value = u'\n'.join(value)
save(i, value)
base_keys = ('id', 'size', 'dimensions', 'extension', 'matches')
@ -185,15 +191,15 @@ class Document(models.Model, FulltextMixin):
s.dimensions = ox.sort_string('%d' % prefix) + ox.sort_string('%d' % value)
def sortNames(values):
sort_value = ''
sort_value = u''
if values:
sort_value = '; '.join([get_name_sort(name) for name in values])
sort_value = u'; '.join([get_name_sort(name) for name in values])
if not sort_value:
sort_value = ''
sort_value = u''
return sort_value.lower()
def set_value(s, name, value):
if isinstance(value, str):
if isinstance(value, string_types):
value = ox.decode_html(value.lower())
if not value:
value = None
@ -222,7 +228,7 @@ class Document(models.Model, FulltextMixin):
if isinstance(sort_type, list):
sort_type = sort_type[0]
if sort_type == 'title':
value = self.get_value(source, 'Untitled')
value = self.get_value(source, u'Untitled')
value = utils.sort_title(value)[:955]
set_value(s, name, value)
elif sort_type == 'person':
@ -230,9 +236,9 @@ class Document(models.Model, FulltextMixin):
value = utils.sort_string(value)[:955]
set_value(s, name, value)
elif sort_type == 'string':
value = self.get_value(source, '')
value = self.get_value(source, u'')
if isinstance(value, list):
value = ','.join(value)
value = u','.join(value)
if not isinstance(value, str):
value = str(value)
value = utils.sort_string(value)[:955]
@ -255,7 +261,7 @@ class Document(models.Model, FulltextMixin):
set_value(s, name, value)
elif sort_type == 'date':
value = self.get_value(source)
if isinstance(value, str):
if isinstance(value, string_types):
value = datetime_safe.datetime.strptime(value, '%Y-%m-%d')
set_value(s, name, value)
s.save()
@ -312,7 +318,7 @@ class Document(models.Model, FulltextMixin):
return ox.toAZ(self.id)
def access(self, user):
if user.is_anonymous:
if user.is_anonymous():
level = 'guest'
else:
level = user.profile.get_level()
@ -325,10 +331,9 @@ class Document(models.Model, FulltextMixin):
return False
def editable(self, user, item=None):
if not user or user.is_anonymous:
if not user or user.is_anonymous():
return False
if self.user == user or \
self.groups.filter(id__in=user.groups.all()).count() > 0 or \
user.is_staff or \
user.profile.capability('canEditDocuments') is True or \
(item and item.editable(user)):
@ -342,9 +347,6 @@ class Document(models.Model, FulltextMixin):
p.description = ox.sanitize_html(data['description'])
p.save()
else:
if 'groups' in data:
groups = data.pop('groups')
update_groups(self, groups)
for key in data:
k = list(filter(lambda i: i['id'] == key, settings.CONFIG['documentKeys']))
ktype = k and k[0].get('type') or ''
@ -366,11 +368,11 @@ class Document(models.Model, FulltextMixin):
self.data[key] = [ox.sanitize_html(t) for t in data[key]]
elif ktype == '[string]':
self.data[key] = [ox.escape_html(t) for t in data[key]]
elif isinstance(data[key], str):
elif isinstance(data[key], string_types):
self.data[key] = ox.escape_html(data[key])
elif isinstance(data[key], list):
def cleanup(i):
if isinstance(i, str):
if isinstance(i, string_types):
i = ox.escape_html(i)
return i
self.data[key] = [cleanup(i) for i in data[key]]
@ -434,7 +436,6 @@ class Document(models.Model, FulltextMixin):
'matches',
'size',
'user',
'groups',
'referenced',
]
if self.extension in ('html', 'txt'):
@ -454,8 +455,6 @@ class Document(models.Model, FulltextMixin):
response[key] = self.editable(user)
elif key == 'user':
response[key] = self.user.username
elif key == 'groups':
response[key] = [g.name for g in self.groups.all()]
elif key == 'accessed':
response[key] = self.accessed.aggregate(Max('access'))['access__max']
elif key == 'timesaccessed':
@ -476,7 +475,7 @@ class Document(models.Model, FulltextMixin):
if self.extension == 'html':
response['text'] = self.data.get('text', '')
if item:
if isinstance(item, str):
if isinstance(item, string_types):
item = Item.objects.get(public_id=item)
d = self.descriptions.filter(item=item)
if d.exists():
@ -686,8 +685,8 @@ class ItemProperties(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
document = models.ForeignKey(Document, related_name='descriptions', on_delete=models.CASCADE)
item = models.ForeignKey(Item)
document = models.ForeignKey(Document, related_name='descriptions')
description = models.TextField(default="")
index = models.IntegerField(default=0)
@ -702,13 +701,14 @@ class ItemProperties(models.Model):
super(ItemProperties, self).save(*args, **kwargs)
@python_2_unicode_compatible
class Access(models.Model):
class Meta:
unique_together = ("document", "user")
access = models.DateTimeField(auto_now=True)
document = models.ForeignKey(Document, related_name='accessed', on_delete=models.CASCADE)
user = models.ForeignKey(User, null=True, related_name='accessed_documents', on_delete=models.CASCADE)
document = models.ForeignKey(Document, related_name='accessed')
user = models.ForeignKey(User, null=True, related_name='accessed_documents')
accessed = models.IntegerField(default=0)
def save(self, *args, **kwargs):
@ -721,9 +721,10 @@ class Access(models.Model):
def __str__(self):
if self.user:
return "%s/%s/%s" % (self.user, self.document, self.access)
return "%s/%s" % (self.item, self.access)
return u"%s/%s/%s" % (self.user, self.document, self.access)
return u"%s/%s" % (self.item, self.access)
@python_2_unicode_compatible
class Facet(models.Model):
'''
used for keys that can have multiple values like people, languages etc.
@ -734,13 +735,13 @@ class Facet(models.Model):
class Meta:
unique_together = ("document", "key", "value")
document = models.ForeignKey('Document', related_name='facets', on_delete=models.CASCADE)
document = models.ForeignKey('Document', related_name='facets')
key = models.CharField(max_length=200, db_index=True)
value = models.CharField(max_length=1000, db_index=True)
sortvalue = models.CharField(max_length=1000, db_index=True)
def __str__(self):
return "%s=%s" % (self.key, self.value)
return u"%s=%s" % (self.key, self.value)
def save(self, *args, **kwargs):
if not self.sortvalue:
@ -759,17 +760,18 @@ for key in settings.CONFIG['itemKeys']:
if key.get('sortType') == 'person':
Document.person_keys.append(key['id'])
@python_2_unicode_compatible
class Find(models.Model):
class Meta:
unique_together = ('document', 'key')
document = models.ForeignKey('Document', related_name='find', db_index=True, on_delete=models.CASCADE)
document = models.ForeignKey('Document', related_name='find', db_index=True)
key = models.CharField(max_length=200, db_index=True)
value = models.TextField(blank=True, db_index=settings.DB_GIN_TRGM)
def __str__(self):
return '%s=%s' % (self.key, self.value)
return u'%s=%s' % (self.key, self.value)
'''
Sort
@ -777,7 +779,7 @@ table constructed based on info in settings.CONFIG['documentKeys']
'''
attrs = {
'__module__': 'document.models',
'document': models.OneToOneField('Document', related_name='sort', primary_key=True, on_delete=models.CASCADE),
'document': models.OneToOneField('Document', related_name='sort', primary_key=True),
'created': models.DateTimeField(null=True, blank=True, db_index=True),
}
for key in list(filter(lambda k: k.get('sort', False) or k['type'] in ('integer', 'time', 'float', 'date', 'enum'), settings.CONFIG['documentKeys'])):

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand
from django.db import connection, transaction

View file

@ -1,10 +1,12 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import os
import re
from glob import glob
import unicodedata
from six import string_types
import ox
from ox.utils import json
from oxdjango.api import actions
@ -69,7 +71,7 @@ def addDocument(request, data):
else:
ids = [data['id']]
if 'item' in data:
if isinstance(data['item'], str):
if isinstance(data['item'], string_types):
item = Item.objects.get(public_id=data['item'])
if item.editable(request.user):
for id in ids:
@ -86,7 +88,7 @@ def addDocument(request, data):
document.add(item)
add_changelog(request, data, data['item'])
elif 'entity' in data:
if isinstance(data['entity'], str):
if isinstance(data['entity'], string_types):
entity = Entity.get(data['entity'])
if entity.editable(request.user):
for id in ids:

View file

@ -124,7 +124,7 @@ class CollectionManager(Manager):
if conditions:
qs = qs.filter(conditions)
if user.is_anonymous:
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))

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import os
import re
@ -9,6 +10,7 @@ from django.db import models
from django.db.models import Max
from django.contrib.auth import get_user_model
from django.conf import settings
from django.utils.encoding import python_2_unicode_compatible
from oxdjango.fields import JSONField
import ox
@ -34,6 +36,7 @@ def get_collectionview():
def get_collectionsort():
return tuple(settings.CONFIG['user']['ui']['collectionSort'])
@python_2_unicode_compatible
class Collection(models.Model):
class Meta:
@ -41,7 +44,7 @@ class Collection(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, related_name='collections', on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='collections')
groups = models.ManyToManyField(Group, blank=True, related_name='collections')
name = models.CharField(max_length=255)
status = models.CharField(max_length=20, default='private')
@ -55,7 +58,7 @@ class Collection(models.Model):
view = models.TextField(default=get_collectionview)
sort = JSONField(default=get_collectionsort, editable=False)
poster_frames = JSONField(default=list, editable=False)
poster_frames = JSONField(default=[], editable=False)
#is through table still required?
documents = models.ManyToManyField('document.Document', related_name='collections',
@ -114,13 +117,13 @@ class Collection(models.Model):
return self.get_id()
def get_id(self):
return '%s:%s' % (self.user.username, self.name)
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 not user or user.is_anonymous:
if not user or user.is_anonymous():
return False
if self.user == user or \
self.groups.filter(id__in=user.groups.all()).count() > 0 or \
@ -248,7 +251,7 @@ class Collection(models.Model):
elif key == 'subscribers':
response[key] = self.subscribed_users.all().count()
elif key == 'subscribed':
if user and not user.is_anonymous:
if user and not user.is_anonymous():
response[key] = self.subscribed_users.filter(id=user.id).exists()
else:
response[key] = getattr(self, {
@ -315,26 +318,28 @@ class Collection(models.Model):
path = source
return path
@python_2_unicode_compatible
class CollectionDocument(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
collection = models.ForeignKey(Collection, on_delete=models.CASCADE)
collection = models.ForeignKey(Collection)
index = models.IntegerField(default=0)
document = models.ForeignKey('document.Document', on_delete=models.CASCADE)
document = models.ForeignKey('document.Document')
def __str__(self):
return '%s in %s' % (self.document, self.collection)
return u'%s in %s' % (self.document, self.collection)
@python_2_unicode_compatible
class Position(models.Model):
class Meta:
unique_together = ("user", "collection", "section")
collection = models.ForeignKey(Collection, related_name='position', on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='collection_positions', on_delete=models.CASCADE)
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 __str__(self):
return '%s/%s/%s' % (self.section, self.position, self.collection)
return u'%s/%s/%s' % (self.section, self.position, self.collection)

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import os
import re
@ -74,7 +75,7 @@ def findCollections(request, data):
query = parse_query(data, request.user)
#order
is_section_request = query['sort'] == [{'operator': '+', 'key': 'position'}]
is_section_request = query['sort'] == [{u'operator': u'+', u'key': u'position'}]
def is_featured_condition(x):
return x['key'] == 'status' and \
@ -88,7 +89,7 @@ def findCollections(request, data):
if is_section_request:
qs = query['qs']
if not is_featured and not request.user.is_anonymous:
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:

View file

@ -124,7 +124,7 @@ class EditManager(Manager):
if conditions:
qs = qs.filter(conditions)
if user.is_anonymous:
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))

View file

@ -1,19 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from glob import glob
from urllib.parse import quote
import os
import re
import os
import shutil
from glob import glob
import subprocess
import tempfile
from six.moves.urllib.parse import quote
import ox
from django.conf import settings
from django.db import models, transaction
from django.db.models import Max
from django.contrib.auth import get_user_model
from django.utils.encoding import python_2_unicode_compatible
from oxdjango.fields import JSONField
from annotation.models import Annotation
@ -33,6 +35,7 @@ User = get_user_model()
def get_path(f, x): return f.path(x)
def get_icon_path(f, x): return get_path(f, 'icon.jpg')
@python_2_unicode_compatible
class Edit(models.Model):
class Meta:
@ -42,7 +45,7 @@ class Edit(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, related_name='edits', on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='edits')
groups = models.ManyToManyField(Group, blank=True, related_name='edits')
name = models.CharField(max_length=255)
@ -56,11 +59,11 @@ class Edit(models.Model):
icon = models.ImageField(default=None, blank=True, null=True, upload_to=get_icon_path)
poster_frames = JSONField(default=list, editable=False)
poster_frames = JSONField(default=[], editable=False)
subscribed_users = models.ManyToManyField(User, related_name='subscribed_edits')
def __str__(self):
return '%s (%s)' % (self.name, self.user)
return u'%s (%s)' % (self.name, self.user)
@classmethod
def get(cls, id):
@ -70,7 +73,7 @@ class Edit(models.Model):
return cls.objects.get(user__username=username, name=name)
def get_id(self):
return '%s:%s' % (self.user.username, self.name)
return u'%s:%s' % (self.user.username, self.name)
def get_absolute_url(self):
return ('/edits/%s' % quote(self.get_id())).replace('%3A', ':')
@ -134,7 +137,7 @@ class Edit(models.Model):
return self.user == user or self.status in ('public', 'featured')
def editable(self, user):
if not user or user.is_anonymous:
if not user or user.is_anonymous():
return False
if self.user == user or \
self.groups.filter(id__in=user.groups.all()).count() > 0 or \
@ -400,7 +403,7 @@ class Edit(models.Model):
elif key == 'subscribers':
response[key] = self.subscribed_users.all().count()
elif key == 'subscribed':
if user and not user.is_anonymous:
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))
@ -427,14 +430,15 @@ class Edit(models.Model):
#p.wait()
shutil.rmtree(tmp)
@python_2_unicode_compatible
class Clip(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
edit = models.ForeignKey(Edit, related_name='clips', on_delete=models.CASCADE)
edit = models.ForeignKey(Edit, related_name='clips')
index = models.IntegerField(default=0)
item = models.ForeignKey(Item, null=True, default=None, related_name='editclip', on_delete=models.CASCADE)
annotation = models.ForeignKey(Annotation, null=True, default=None, related_name='editclip', on_delete=models.CASCADE)
item = models.ForeignKey(Item, null=True, default=None, related_name='editclip')
annotation = models.ForeignKey(Annotation, null=True, default=None, related_name='editclip')
start = models.FloatField(default=0)
end = models.FloatField(default=0)
duration = models.FloatField(default=0)
@ -450,8 +454,8 @@ class Clip(models.Model):
def __str__(self):
if self.annotation:
return '%s' % self.annotation.public_id
return '%s/%0.3f-%0.3f' % (self.item.public_id, self.start, self.end)
return u'%s' % self.annotation.public_id
return u'%s/%0.3f-%0.3f' % (self.item.public_id, self.start, self.end)
def get_id(self):
return ox.toAZ(self.id)
@ -537,16 +541,17 @@ class Clip(models.Model):
return clip.models.get_layers(item=item, interval=(start, end), user=user)
@python_2_unicode_compatible
class Position(models.Model):
class Meta:
unique_together = ("user", "edit", "section")
edit = models.ForeignKey(Edit, related_name='position', on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='edit_position', on_delete=models.CASCADE)
edit = models.ForeignKey(Edit, related_name='position')
user = models.ForeignKey(User, related_name='edit_position')
section = models.CharField(max_length=255)
position = models.IntegerField(default=0)
def __str__(self):
return '%s/%s/%s' % (self.section, self.position, self.edit)
return u'%s/%s/%s' % (self.section, self.position, self.edit)

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import os
import re
@ -403,8 +404,7 @@ def findEdits(request, data):
query = parse_query(data, request.user)
#order
is_section_request = query['sort'] == [{'operator': '+', 'key': 'position'}]
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 \
@ -414,7 +414,7 @@ def findEdits(request, data):
if is_section_request:
qs = query['qs']
if not is_featured and not request.user.is_anonymous:
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:

View file

@ -1,17 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from glob import glob
from urllib.parse import quote, unquote
import os
import re
from glob import glob
import unicodedata
from six import string_types
from six.moves.urllib.parse import quote, unquote
from django.db import models, transaction
from django.db.models import Max
from django.contrib.auth import get_user_model
from django.db.models.signals import pre_delete, post_init
from django.conf import settings
from django.utils.encoding import python_2_unicode_compatible
from oxdjango.fields import JSONField
import ox
@ -25,6 +28,7 @@ from . import managers
User = get_user_model()
@python_2_unicode_compatible
class Entity(models.Model):
class ValueError(ValueError):
'''Raised if a field name or value is invalid (based on the "entities"
@ -34,7 +38,7 @@ class Entity(models.Model):
class Meta:
unique_together = ("type", "name")
user = models.ForeignKey(User, related_name='entities', null=True, default=None, on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='entities', null=True, default=None)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
@ -60,7 +64,7 @@ class Entity(models.Model):
self.name = self.name.decode('utf-8')
self.name_sort = get_name_sort(self.name)[:255].lower()
else:
self.name_sort = ox.sort_string(self.name or '')[:255].lower() or None
self.name_sort = ox.sort_string(self.name or u'')[:255].lower() or None
self.name_find = '||' + '||'.join((self.name,) + self.alternativeNames) + '||'
self.name_find = self.name_find.lower()
super(Entity, self).save(*args, **kwargs)
@ -84,11 +88,11 @@ class Entity(models.Model):
@classmethod
def get_by_name(cls, name, type):
return cls.objects.get(name_find__contains='|%s|' % name.lower(), type=type)
return cls.objects.get(name_find__contains=u'|%s|' % name.lower(), type=type)
@classmethod
def get_or_create(model, name):
qs = model.objects.filter(name_find__contains='|%s|' % name.lower())
qs = model.objects.filter(name_find__contains=u'|%s|' % name.lower())
if qs.count() == 0:
instance = model(name=name)
instance.save()
@ -113,7 +117,7 @@ class Entity(models.Model):
DocumentProperties.objects.filter(document=document, entity=self).delete()
def editable(self, user, item=None):
if not user or user.is_anonymous:
if not user or user.is_anonymous():
return False
if user.is_staff or \
user.profile.capability('canEditEntities') == True or \
@ -136,7 +140,7 @@ class Entity(models.Model):
data['name'] = "Unnamed"
name = data['name']
n = 1
while Entity.objects.filter(name_find__contains='|%s|' % name.lower()).exclude(id=self.id).count() > 0:
while Entity.objects.filter(name_find__contains=u'|%s|' % name.lower()).exclude(id=self.id).count() > 0:
n += 1
name = data['name'] + ' [%d]' % n
self.name = name
@ -151,7 +155,7 @@ class Entity(models.Model):
name_ = name
n = 1
while name in used_names or \
Entity.objects.filter(name_find__contains='|%s|' % name.lower()).exclude(id=self.id).count() > 0:
Entity.objects.filter(name_find__contains=u'|%s|' % name.lower()).exclude(id=self.id).count() > 0:
n += 1
name = name_ + ' [%d]' % n
names.append(name)
@ -187,7 +191,7 @@ class Entity(models.Model):
.delete()
else:
#FIXME: more data validation
if isinstance(data[key], str):
if isinstance(data[key], string_types):
self.data[key] = ox.sanitize_html(data[key])
else:
self.data[key] = data[key]
@ -264,7 +268,7 @@ class Entity(models.Model):
return response
def annotation_value(self):
#return '<a href="/entities/%s">%s</a>' % (self.get_id(), ox.escape_html(self.name))
#return u'<a href="/entities/%s">%s</a>' % (self.get_id(), ox.escape_html(self.name))
return ox.escape_html(self.name)
def update_find(self):
@ -274,7 +278,7 @@ class Entity(models.Model):
f, created = Find.objects.get_or_create(entity=self, key=key)
if isinstance(value, bool):
value = value and 'true' or 'false'
if isinstance(value, str):
if isinstance(value, string_types):
value = ox.decode_html(ox.strip_tags(value.strip()))
value = unicodedata.normalize('NFKD', value).lower()
f.value = value
@ -288,10 +292,10 @@ class Entity(models.Model):
for key in entity['keys']:
value = self.data.get(key['id'])
if isinstance(value, list):
value = '\n'.join(value)
value = u'\n'.join(value)
save(key['id'], value)
ids.append(key['id'])
save('name', '\n'.join([self.name] + list(self.alternativeNames)))
save('name', u'\n'.join([self.name] + list(self.alternativeNames)))
self.find.exclude(key__in=ids).delete()
def update_matches(self):
@ -340,6 +344,7 @@ post_init.connect(
)
@python_2_unicode_compatible
class DocumentProperties(models.Model):
class Meta:
@ -348,40 +353,42 @@ class DocumentProperties(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
document = models.ForeignKey(Document, related_name='documentproperties', on_delete=models.CASCADE)
entity = models.ForeignKey(Entity, related_name='documentproperties', on_delete=models.CASCADE)
document = models.ForeignKey(Document, related_name='documentproperties')
entity = models.ForeignKey(Entity, related_name='documentproperties')
index = models.IntegerField(default=0)
data = JSONField(default=dict, editable=False)
def __str__(self):
return "%r-%r" % (self.document, self.entity)
return u"%r-%r" % (self.document, self.entity)
def save(self, *args, **kwargs):
super(DocumentProperties, self).save(*args, **kwargs)
@python_2_unicode_compatible
class Find(models.Model):
class Meta:
unique_together = ("entity", "key")
entity = models.ForeignKey('Entity', related_name='find', db_index=True, on_delete=models.CASCADE)
entity = models.ForeignKey('Entity', related_name='find', db_index=True)
key = models.CharField(max_length=200, db_index=True)
value = models.TextField(blank=True, db_index=settings.DB_GIN_TRGM)
def __str__(self):
return "%s=%s" % (self.key, self.value)
return u"%s=%s" % (self.key, self.value)
@python_2_unicode_compatible
class Link(models.Model):
'''Models entity fields of type "entity".'''
class Meta:
unique_together = ("source", "key", "target")
source = models.ForeignKey(Entity, related_name='links', on_delete=models.CASCADE)
source = models.ForeignKey(Entity, related_name='links')
key = models.CharField(max_length=200)
target = models.ForeignKey(Entity, related_name='backlinks', on_delete=models.CASCADE)
target = models.ForeignKey(Entity, related_name='backlinks')
def __str__(self):
return "%s-[%s]->%s" % (self.source, self.key, self.target)
return u"%s-[%s]->%s" % (self.source, self.key, self.target)

View file

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from six import string_types
import ox
from ox.utils import json
from oxdjango.api import actions
@ -58,7 +60,7 @@ def addEntity(request, data):
for name in names:
name = ox.decode_html(name)
if models.Entity.objects.filter(type=data['type'],
name_find__icontains='|%s|'%name).count() != 0:
name_find__icontains=u'|%s|'%name).count() != 0:
exists = True
existing_names.append(name)
if not exists:
@ -68,7 +70,7 @@ def addEntity(request, data):
for key in ('type', 'alternativeNames'):
if key in data and data[key]:
value = data[key]
if isinstance(value, str):
if isinstance(value, string_types):
value = ox.escape_html(value)
if key == 'alternativeNames':
value = tuple([ox.escape_html(v) for v in value])
@ -85,7 +87,7 @@ def addEntity(request, data):
type = data['type']
name = 'Unnamed'
num = 1
while models.Entity.objects.filter(name_find__icontains='|%s|'%name).count() > 0:
while models.Entity.objects.filter(name_find__icontains=u'|%s|'%name).count() > 0:
num += 1
name = 'Unnamed [%d]' % num
entity = models.Entity(name=name, type=type)

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from django.contrib import admin

View file

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import unicodedata
from six import string_types
from django.db.models import Q, Manager
from oxdjango.query import QuerySet
@ -29,7 +30,7 @@ def parseCondition(condition, user):
key = k + get_operator(op, 'istr')
key = str(key)
if isinstance(v, str):
if isinstance(v, string_types):
v = unicodedata.normalize('NFKD', v).lower()
if exclude:
q = ~Q(**{k: v})

View file

@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from django.db import models, transaction
from django.contrib.auth import get_user_model
from django.utils.encoding import python_2_unicode_compatible
import ox
from oxdjango import fields
@ -17,6 +19,7 @@ from . import managers
User = get_user_model()
@python_2_unicode_compatible
class Event(models.Model):
'''
Events are events in time that can be once or recurring,
@ -30,7 +33,7 @@ class Event(models.Model):
modified = models.DateTimeField(auto_now=True)
defined = models.BooleanField(default=False)
user = models.ForeignKey(User, null=True, related_name='events', on_delete=models.CASCADE)
user = models.ForeignKey(User, null=True, related_name='events')
name = models.CharField(null=True, max_length=255, unique=True)
name_sort = models.CharField(null=True, max_length=255, db_index=True)
@ -63,7 +66,7 @@ class Event(models.Model):
@classmethod
def get_or_create(model, name):
qs = model.objects.filter(name_find__contains='|%s|' % name.lower())
qs = model.objects.filter(name_find__contains=u'|%s|' % name.lower())
if qs.count() == 0:
instance = model(name=name)
instance.save()
@ -72,7 +75,7 @@ class Event(models.Model):
return instance
def editable(self, user):
if user and not user.is_anonymous \
if user and not user.is_anonymous() \
and (not self.user or \
self.user == user or \
user.profile.capability('canEditEvents')):

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from celery.task import task

View file

@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from django.db.models import Count
from django.conf import settings
from six import string_types
import ox
from ox.utils import json
@ -35,7 +37,7 @@ def addEvent(request, data):
for name in names:
name = ox.decode_html(name)
if models.Event.objects.filter(defined=True,
name_find__icontains='|%s|'%name).count() != 0:
name_find__icontains=u'|%s|'%name).count() != 0:
exists = True
existing_names.append(name)
if not exists:
@ -46,7 +48,7 @@ def addEvent(request, data):
'type', 'alternativeNames'):
if key in data and data[key]:
value = data[key]
if isinstance(value, str):
if isinstance(value, string_types):
value = ox.escape_html(value)
if key == 'alternativeNames':
value = tuple([ox.escape_html(v) for v in value])
@ -91,7 +93,7 @@ def editEvent(request, data):
names = [data.get('name', event.name)] + data.get('alternativeNames', [])
for name in names:
if models.Event.objects.filter(defined=True,
name_find__icontains='|%s|'%name).exclude(id=event.id).count() != 0:
name_find__icontains=u'|%s|'%name).exclude(id=event.id).count() != 0:
conflict = True
conflict_names.append(name)
if not conflict:
@ -100,7 +102,7 @@ def editEvent(request, data):
'type', 'alternativeNames'):
if key in data:
value = data[key]
if isinstance(value, str):
if isinstance(value, string_types):
value = ox.escape_html(value)
if key == 'alternativeNames':
value = tuple([ox.escape_html(v) for v in value])

View file

@ -1,3 +1,5 @@
from __future__ import unicode_literals
from django.apps import AppConfig

View file

@ -1,10 +1,13 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from urllib.parse import quote
from six import string_types
from six.moves.urllib.parse import quote
from django.db import models
from django.db.models import Max
from django.db.models.signals import pre_delete
from django.utils.encoding import python_2_unicode_compatible
from oxdjango.fields import JSONField
import ox
@ -14,6 +17,7 @@ from edit.models import Edit
from documentcollection.models import Collection
@python_2_unicode_compatible
class Item(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
@ -23,7 +27,7 @@ class Item(models.Model):
data = JSONField(default=dict, editable=False)
def editable(self, user):
return user.is_authenticated and user.profile.capability("canManageHome")
return user.is_authenticated() and user.profile.capability("canManageHome")
def edit(self, data):
changed = False
@ -42,7 +46,7 @@ class Item(models.Model):
len([d for d in data[key] if isinstance(d, int)]) == 4):
return False
else:
if not isinstance(data[key], str):
if not isinstance(data[key], string_types):
return False
self.data[key] = data[key]
if key == 'contentid' and self.data[key]:
@ -149,7 +153,7 @@ class Item(models.Model):
return j
def __str__(self):
return "%s" % (self.get_id())
return u"%s" % (self.get_id())
def delete_item(type, contentid):
for home in Item.objects.all():

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from django.contrib import admin

View file

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import division, with_statement
import ox
from django.conf import settings

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand
from django.conf import settings

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand
from django.db import connection, transaction

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand
from django.db import connection, transaction

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
import os
from glob import glob

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
import time

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand
@ -43,12 +44,7 @@ class Command(BaseCommand):
(document.models.Find._meta.db_table, 'value'), # Document Find
):
cursor = connection.cursor()
contraints = connection.introspection.get_constraints(cursor, table)
indexes = {
','.join(c['columns']): {'primary_key': c['primary_key'], 'unique': c['unique']}
for k, c in contraints.items()
if c['index'] or c['primary_key'] or c['unique']
}
indexes = connection.introspection.get_indexes(cursor, table)
drop = []
if column in indexes:
for sql in (
@ -67,12 +63,7 @@ class Command(BaseCommand):
if options['debug']:
print(sql)
cursor.execute(sql)
contraints = connection.introspection.get_constraints(cursor, table)
indexes = {
','.join(c['columns']): {'primary_key': c['primary_key'], 'unique': c['unique']}
for k, c in contraints.items()
if c['index'] or c['primary_key'] or c['unique']
}
indexes = connection.introspection.get_indexes(cursor, table)
if column not in indexes:
create_index("%s_%s_idx" % (table, column), table, column)
transaction.commit()

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand
from django.db import connection, transaction

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from django.core.management.base import BaseCommand

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
import os
@ -37,10 +38,10 @@ class Command(BaseCommand):
versions = os.path.join(prefix, os.path.dirname(path), 'Versions')
s = f.streams.filter(source=None)[0]
basename = os.path.basename(path).rsplit('.', 1)[0]
target = os.path.join(versions, '%s.%s' % (basename, s.format))
target = os.path.join(versions, u'%s.%s' % (basename, s.format))
link(s.media.path, target)
else:
s = f.streams.filter(source=None)[0]
basename = path.rsplit('.', 1)[0]
target = os.path.join(prefix, '%s.%s' % (basename, s.format))
target = os.path.join(prefix, u'%s.%s' % (basename, s.format))
link(s.media.path, target)

View file

@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from datetime import datetime
import unicodedata
from six import string_types
from django.db.models import Q, Manager
from django.conf import settings
@ -79,7 +81,7 @@ def parseCondition(condition, user, owner=None):
if (not exclude and op == '=' or op in ('$', '^')) and v == '':
return Q()
elif k == 'filename' and (user.is_anonymous or not user.profile.capability('canSeeMedia')):
elif k == 'filename' and (user.is_anonymous() or not user.profile.capability('canSeeMedia')):
return Q(id=0)
elif k == 'oshash':
return Q(files__oshash=v)
@ -98,7 +100,7 @@ def parseCondition(condition, user, owner=None):
q = ~q
return q
elif k in ('canplayvideo', 'canplayclips'):
level = user.is_anonymous and 'guest' or user.profile.get_level()
level = user.is_anonymous() and 'guest' or user.profile.get_level()
allowed_level = settings.CONFIG['capabilities'][{
'canplayvideo': 'canPlayVideo',
'canplayclips': 'canPlayClips'
@ -122,7 +124,7 @@ def parseCondition(condition, user, owner=None):
else:
value_key = k
if not k.startswith('public_id'):
if isinstance(v, str):
if isinstance(v, string_types):
v = unicodedata.normalize('NFKD', v).lower()
if k in facet_keys:
in_find = False
@ -247,7 +249,7 @@ class ItemManager(Manager):
if l != "*":
l = l.split(":")
only_public = True
if not user.is_anonymous:
if not user.is_anonymous():
if len(l) == 1:
l = [user.username] + l
if user.username == l[0]:
@ -303,7 +305,7 @@ class ItemManager(Manager):
qs = qs.distinct()
#anonymous can only see public items
if not user or user.is_anonymous:
if not user or user.is_anonymous():
level = 'guest'
allowed_level = settings.CONFIG['capabilities']['canSeeItem'][level]
qs = qs.filter(level__lte=allowed_level)

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import json
import os
@ -10,7 +11,9 @@ import unicodedata
import uuid
from datetime import datetime
from glob import glob
from urllib.parse import quote
from six import PY2, string_types
from six.moves.urllib.parse import quote
from django.conf import settings
from django.contrib.auth import get_user_model
@ -18,6 +21,7 @@ from django.core.files.temp import NamedTemporaryFile
from django.db import models, transaction, connection
from django.db.models import Q, Sum, Max
from django.db.models.signals import pre_delete
from django.utils.encoding import python_2_unicode_compatible
from django.utils import datetime_safe
import ox
@ -44,6 +48,8 @@ import archive.models
User = get_user_model()
if not PY2:
unicode = str
def get_id(info):
q = Item.objects.all()
@ -158,11 +164,12 @@ def get_poster_path(f, x):
def get_torrent_path(f, x):
return get_path(f, 'torrent.torrent')
@python_2_unicode_compatible
class Item(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, null=True, related_name='items', on_delete=models.CASCADE)
user = models.ForeignKey(User, null=True, related_name='items')
groups = models.ManyToManyField(Group, blank=True, related_name='items')
# while metadata is updated, files are set to rendered=False
@ -214,7 +221,7 @@ class Item(models.Model):
return default
def access(self, user):
if user.is_anonymous:
if user.is_anonymous():
level = 'guest'
else:
level = user.profile.get_level()
@ -229,7 +236,7 @@ class Item(models.Model):
return False
def editable(self, user):
if user.is_anonymous:
if user.is_anonymous():
return False
if user.profile.capability('canEditMetadata') or \
user.is_staff or \
@ -280,11 +287,11 @@ class Item(models.Model):
self.data[key] = [ox.escape_html(t) for t in data[key]]
elif key in ('episodeTitle', 'seriesTitle', 'episodeDirector', 'seriesYear'):
self.data[key] = ox.escape_html(data[key])
elif isinstance(data[key], str):
elif isinstance(data[key], string_types):
self.data[key] = ox.escape_html(data[key])
elif isinstance(data[key], list):
def cleanup(i):
if isinstance(i, str):
if isinstance(i, string_types):
i = ox.escape_html(i)
return i
self.data[key] = [cleanup(i) for i in data[key]]
@ -325,7 +332,7 @@ class Item(models.Model):
if c:
for t in list(c):
if c[t]:
if isinstance(c[t][0], str):
if isinstance(c[t][0], string_types):
c[t] = [{'id': i, 'title': None} for i in c[t]]
ids = [i['id'] for i in c[t]]
known = {}
@ -343,10 +350,10 @@ class Item(models.Model):
def __str__(self):
year = self.get('year')
if year:
string = '%s (%s)' % (ox.decode_html(self.get('title', 'Untitled')), self.get('year'))
string = u'%s (%s)' % (ox.decode_html(self.get('title', 'Untitled')), self.get('year'))
else:
string = self.get('title', 'Untitled')
return '[%s] %s' % (self.public_id, string)
string = self.get('title', u'Untitled')
return u'[%s] %s' % (self.public_id, string)
def get_absolute_url(self):
return '/%s' % self.public_id
@ -393,7 +400,7 @@ class Item(models.Model):
title = self.get(key, 'Untitled')
while q.count() != 0:
n += 1
self.data[key] = '%s [%d]' % (title, n)
self.data[key] = u'%s [%d]' % (title, n)
oxdbId = self.oxdb_id()
q = Item.objects.filter(oxdbId=oxdbId).exclude(id=self.id)
self.oxdbId = oxdbId
@ -622,7 +629,7 @@ class Item(models.Model):
if value:
i[key] = value
if 'cast' in i and isinstance(i['cast'][0], str):
if 'cast' in i and isinstance(i['cast'][0], string_types):
i['cast'] = [i['cast']]
if 'cast' in i and isinstance(i['cast'][0], list):
i['cast'] = [{'actor': x[0], 'character': x[1]} for x in i['cast']]
@ -793,7 +800,7 @@ class Item(models.Model):
f, created = ItemFind.objects.get_or_create(item=self, key=key)
if isinstance(value, bool):
value = value and 'true' or 'false'
if isinstance(value, str):
if isinstance(value, string_types):
value = ox.decode_html(ox.strip_tags(value.strip()))
value = unicodedata.normalize('NFKD', value).lower()
f.value = value
@ -814,7 +821,7 @@ class Item(models.Model):
for key in settings.CONFIG['itemKeys']:
i = key['id']
if i == 'title':
save(i, '\n'.join(get_titles()))
save(i, u'\n'.join(get_titles()))
elif i == 'rightslevel':
save(i, self.level)
elif i == 'filename':
@ -823,17 +830,17 @@ class Item(models.Model):
qs = Annotation.objects.filter(item=self)
qs = qs.filter(layer__in=Annotation.public_layers()).exclude(findvalue=None)
qs = qs.order_by('start')
save(i, '\n'.join([l.findvalue for l in qs]))
save(i, u'\n'.join([l.findvalue for l in qs]))
elif key['type'] == 'layer':
qs = Annotation.objects.filter(item=self).exclude(findvalue=None)
qs = qs.filter(layer=i)
qs = qs.order_by('start')
save(i, '\n'.join(list(filter(None, [l.findvalue for l in qs]))))
save(i, u'\n'.join(list(filter(None, [l.findvalue for l in qs]))))
layer_keys.append(i)
elif i != '*' and i not in self.facet_keys:
value = self.get(i)
if isinstance(value, list):
value = '\n'.join(value)
value = u'\n'.join(value)
save(i, value)
for key in self.facet_keys:
@ -904,15 +911,15 @@ class Item(models.Model):
s = ItemSort(item=self)
def sortNames(values):
sort_value = ''
sort_value = u''
if values:
sort_value = '; '.join([get_name_sort(name) for name in values])
sort_value = u'; '.join([get_name_sort(name) for name in values])
if not sort_value:
sort_value = ''
sort_value = u''
return sort_value.lower()
def set_value(s, name, value):
if isinstance(value, str):
if isinstance(value, string_types):
value = ox.decode_html(value.lower())
if not value:
value = None
@ -1012,7 +1019,7 @@ class Item(models.Model):
sort_type = sort_type[0]
if name not in self.base_keys:
if sort_type == 'title':
value = get_title_sort(self.get(source, 'Untitled'))
value = get_title_sort(self.get(source, u'Untitled'))
value = utils.sort_title(value)[:955]
set_value(s, name, value)
elif sort_type == 'person':
@ -1020,9 +1027,9 @@ class Item(models.Model):
value = utils.sort_string(value)[:955]
set_value(s, name, value)
elif sort_type == 'string':
value = self.get(source, '')
value = self.get(source, u'')
if isinstance(value, list):
value = ','.join(value)
value = u','.join(value)
value = utils.sort_string(value)[:955]
set_value(s, name, value)
elif sort_type == 'words':
@ -1048,7 +1055,7 @@ class Item(models.Model):
set_value(s, name, value)
elif sort_type == 'date':
value = value_ = self.get(source)
if isinstance(value, str):
if isinstance(value, string_types):
value_ = None
for fmt in ('%Y-%m-%d', '%Y-%m', '%Y'):
try:
@ -1087,7 +1094,7 @@ class Item(models.Model):
if not current_values:
current_values = []
else:
current_values = [str(current_values)]
current_values = [unicode(current_values)]
filter_map = utils.get_by_id(settings.CONFIG['itemKeys'], key).get('filterMap')
if filter_map:
@ -1777,6 +1784,7 @@ for key in settings.CONFIG['itemKeys']:
if key.get('sortType') == 'person':
Item.person_keys.append(key['id'])
@python_2_unicode_compatible
class ItemFind(models.Model):
"""
used to find items,
@ -1787,19 +1795,19 @@ class ItemFind(models.Model):
class Meta:
unique_together = ("item", "key")
item = models.ForeignKey('Item', related_name='find', db_index=True, on_delete=models.CASCADE)
item = models.ForeignKey('Item', related_name='find', db_index=True)
key = models.CharField(max_length=200, db_index=True)
value = models.TextField(blank=True, db_index=settings.DB_GIN_TRGM)
def __str__(self):
return "%s=%s" % (self.key, self.value)
return u"%s=%s" % (self.key, self.value)
'''
ItemSort
table constructed based on info in settings.CONFIG['itemKeys']
'''
attrs = {
'__module__': 'item.models',
'item': models.OneToOneField('Item', related_name='sort', primary_key=True, on_delete=models.CASCADE),
'item': models.OneToOneField('Item', related_name='sort', primary_key=True),
'duration': models.FloatField(null=True, blank=True, db_index=True),
'width': models.BigIntegerField(null=True, blank=True, db_index=True),
'height': models.BigIntegerField(null=True, blank=True, db_index=True),
@ -1818,13 +1826,14 @@ for key in list(filter(lambda k: k.get('sort', False) or k['type'] in ('integer'
ItemSort = type('ItemSort', (models.Model,), attrs)
ItemSort.fields = [f.name for f in ItemSort._meta.fields]
@python_2_unicode_compatible
class Access(models.Model):
class Meta:
unique_together = ("item", "user")
access = models.DateTimeField(auto_now=True)
item = models.ForeignKey(Item, related_name='accessed', on_delete=models.CASCADE)
user = models.ForeignKey(User, null=True, related_name='accessed_items', on_delete=models.CASCADE)
item = models.ForeignKey(Item, related_name='accessed')
user = models.ForeignKey(User, null=True, related_name='accessed_items')
accessed = models.IntegerField(default=0)
def save(self, *args, **kwargs):
@ -1837,9 +1846,10 @@ class Access(models.Model):
def __str__(self):
if self.user:
return "%s/%s/%s" % (self.user, self.item, self.access)
return "%s/%s" % (self.item, self.access)
return u"%s/%s/%s" % (self.user, self.item, self.access)
return u"%s/%s" % (self.item, self.access)
@python_2_unicode_compatible
class Facet(models.Model):
'''
used for keys that can have multiple values like people, languages etc.
@ -1850,13 +1860,13 @@ class Facet(models.Model):
class Meta:
unique_together = ("item", "key", "value")
item = models.ForeignKey('Item', related_name='facets', on_delete=models.CASCADE)
item = models.ForeignKey('Item', related_name='facets')
key = models.CharField(max_length=200, db_index=True)
value = models.CharField(max_length=1000, db_index=True)
sortvalue = models.CharField(max_length=1000, db_index=True)
def __str__(self):
return "%s=%s" % (self.key, self.value)
return u"%s=%s" % (self.key, self.value)
def save(self, *args, **kwargs):
if not self.sortvalue:
@ -1876,7 +1886,7 @@ class Description(models.Model):
class AnnotationSequence(models.Model):
item = models.OneToOneField('Item', related_name='_annotation_sequence', on_delete=models.CASCADE)
item = models.OneToOneField('Item', related_name='_annotation_sequence')
value = models.BigIntegerField(default=1)
@classmethod

View file

@ -1,51 +0,0 @@
# -*- coding: utf-8 -*-
from django.urls import path, re_path
from . import views
urls = [
[
#frames
re_path(r'^(?P<id>[A-Z0-9].*)/(?P<size>\d+)p(?P<position>[\d\.]*)\.jpg$', views.frame),
#timelines
re_path(r'^(?P<id>[A-Z0-9].*)/timeline(?P<mode>[a-z]*)(?P<size>\d+)p(?P<position>\d+)\.(?P<format>png|jpg)$', views.timeline),
re_path(r'^(?P<id>[A-Z0-9].*)/timeline(?P<mode>[a-z]*)(?P<size>\d+)p\.(?P<format>png|jpg)$', views.timeline),
#download
re_path(r'^(?P<id>[A-Z0-9].*)/download$', views.download),
re_path(r'^(?P<id>[A-Z0-9].*)/download/$', views.download),
re_path(r'^(?P<id>[A-Z0-9].*)/download/source/(?P<part>\d+)?$', views.download_source),
re_path(r'^(?P<id>[A-Z0-9].*)/download/(?P<resolution>\d+)p(?P<part>\d+)\.(?P<format>webm|ogv|mp4)$', views.download),
re_path(r'^(?P<id>[A-Z0-9].*)/download/(?P<resolution>\d+)p\.(?P<format>webm|ogv|mp4)$', views.download),
#video
re_path(r'^(?P<id>[A-Z0-9].*)/(?P<resolution>\d+)p(?P<index>\d*)\.(?P<format>webm|ogv|mp4)$', views.video),
re_path(r'^(?P<id>[A-Z0-9].*)/(?P<resolution>\d+)p(?P<index>\d*)\.(?P<track>.+)\.(?P<format>webm|ogv|mp4)$', views.video),
#torrent
re_path(r'^(?P<id>[A-Z0-9].*)/torrent$', views.torrent),
re_path(r'^(?P<id>[A-Z0-9].*)/torrent/(?P<filename>.*?)$', views.torrent),
#export
re_path(r'^(?P<id>[A-Z0-9].*)/json$', views.item_json),
re_path(r'^(?P<id>[A-Z0-9].*)/xml$', views.item_xml),
#srt export
re_path(r'^(?P<id>[A-Z0-9].*)/(?P<layer>.+)\.(?:(?P<language>.{2})\.)?(?P<ext>srt|vtt)$', views.srt),
#icon
re_path(r'^(?P<id>[A-Z0-9].*)/icon(?P<size>\d*)\.jpg$', views.icon),
#poster
re_path(r'^(?P<id>[A-Z0-9].*)/posterframe(?P<position>\d+).jpg$', views.poster_frame),
re_path(r'^(?P<id>[A-Z0-9].*)/poster(?P<size>\d+)\.jpg$', views.poster),
re_path(r'^(?P<id>[A-Z0-9].*)/siteposter(?P<size>\d*)\.jpg$', views.siteposter),
re_path(r'^(?P<id>[A-Z0-9].*)/poster\.jpg$', views.siteposter),
re_path(r'^random$', views.random_annotation),
],
'item',
'item',
]

View file

@ -1,11 +1,12 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from datetime import timedelta, datetime
from urllib.parse import quote
import gzip
import os
from datetime import timedelta, datetime
import gzip
import random
from six.moves.urllib.parse import quote
from celery.task import task, periodic_task
from django.conf import settings
from django.db import connection, transaction

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, with_statement, print_function
import math
import os

47
pandora/item/urls.py Normal file
View file

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
from django.conf.urls import url
from . import views
urlpatterns = [
#frames
url(r'^(?P<id>[A-Z0-9].*)/(?P<size>\d+)p(?P<position>[\d\.]*)\.jpg$', views.frame),
#timelines
url(r'^(?P<id>[A-Z0-9].*)/timeline(?P<mode>[a-z]*)(?P<size>\d+)p(?P<position>\d+)\.(?P<format>png|jpg)$', views.timeline),
url(r'^(?P<id>[A-Z0-9].*)/timeline(?P<mode>[a-z]*)(?P<size>\d+)p\.(?P<format>png|jpg)$', views.timeline),
#download
url(r'^(?P<id>[A-Z0-9].*)/download$', views.download),
url(r'^(?P<id>[A-Z0-9].*)/download/$', views.download),
url(r'^(?P<id>[A-Z0-9].*)/download/source/(?P<part>\d+)?$', views.download_source),
url(r'^(?P<id>[A-Z0-9].*)/download/(?P<resolution>\d+)p(?P<part>\d+)\.(?P<format>webm|ogv|mp4)$', views.download),
url(r'^(?P<id>[A-Z0-9].*)/download/(?P<resolution>\d+)p\.(?P<format>webm|ogv|mp4)$', views.download),
#video
url(r'^(?P<id>[A-Z0-9].*)/(?P<resolution>\d+)p(?P<index>\d*)\.(?P<format>webm|ogv|mp4)$', views.video),
url(r'^(?P<id>[A-Z0-9].*)/(?P<resolution>\d+)p(?P<index>\d*)\.(?P<track>.+)\.(?P<format>webm|ogv|mp4)$', views.video),
#torrent
url(r'^(?P<id>[A-Z0-9].*)/torrent$', views.torrent),
url(r'^(?P<id>[A-Z0-9].*)/torrent/(?P<filename>.*?)$', views.torrent),
#export
url(r'^(?P<id>[A-Z0-9].*)/json$', views.item_json),
url(r'^(?P<id>[A-Z0-9].*)/xml$', views.item_xml),
#srt export
url(r'^(?P<id>[A-Z0-9].*)/(?P<layer>.+)\.(?:(?P<language>.{2})\.)?(?P<ext>srt|vtt)$', views.srt),
#icon
url(r'^(?P<id>[A-Z0-9].*)/icon(?P<size>\d*)\.jpg$', views.icon),
#poster
url(r'^(?P<id>[A-Z0-9].*)/posterframe(?P<position>\d+).jpg$', views.poster_frame),
url(r'^(?P<id>[A-Z0-9].*)/poster(?P<size>\d+)\.jpg$', views.poster),
url(r'^(?P<id>[A-Z0-9].*)/siteposter(?P<size>\d*)\.jpg$', views.siteposter),
url(r'^(?P<id>[A-Z0-9].*)/poster\.jpg$', views.siteposter),
url(r'^random$', views.random_annotation),
]

View file

@ -6,6 +6,7 @@ import unicodedata
import ox
from ox import sort_string
from six import PY2
def safe_filename(filename):
@ -54,14 +55,13 @@ def plural_key(term):
def sort_title(title):
title = title.replace('Æ', 'Ae')
title = title.replace(u'Æ', 'Ae')
if isinstance(title, bytes):
title = title.decode('utf-8')
title = ox.decode_html(title)
title = sort_string(title)
#title
title = re.sub('[\'!¿¡,\.;\-"\:\*\[\]]', '', title)
title = re.sub(u'[\'!¿¡,\.;\-"\:\*\[\]]', '', title)
return title.strip()
def get_positions(ids, pos, decode_id=False):
@ -91,7 +91,11 @@ def get_by_id(objects, id):
return get_by_key(objects, 'id', id)
def normalize_dict(encoding, data):
if isinstance(data, str):
if PY2:
string_type = unicode
else:
string_type = str
if isinstance(data, string_type):
data = unicodedata.normalize(encoding, data)
elif isinstance(data, dict):
for key in data:

View file

@ -1,12 +1,14 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from datetime import datetime, timedelta
from urllib.parse import quote, urlparse
import mimetypes
import os.path
import mimetypes
import random
import time
from datetime import datetime, timedelta
from six import PY2
from six.moves.urllib.parse import quote, urlparse
from PIL import Image
from django.db.models import Count, Sum
from django.http import HttpResponse, HttpResponseForbidden, Http404
@ -34,6 +36,8 @@ from changelog.models import add_changelog
from oxdjango.api import actions
if not PY2:
unicode = str
def _order_query(qs, sort, prefix='sort__'):
order_by = []
@ -140,7 +144,7 @@ def get_positions(request, query):
return utils.get_positions(ids, query['positions'])
def is_editable(request, item):
if request.user.is_anonymous:
if request.user.is_anonymous():
return False
if not hasattr(request, 'user_group_names'):
request.user_group_names = {g.name for g in request.user.groups.all()}
@ -1093,7 +1097,7 @@ def video(request, id, resolution, format, index=None, track=None):
ext = '.%s' % format
duration = stream.info['duration']
filename = "Clip of %s - %s-%s - %s %s%s" % (
filename = u"Clip of %s - %s-%s - %s %s%s" % (
item.get('title'),
ox.format_duration(t[0] * 1000).replace(':', '.')[:-4],
ox.format_duration(t[1] * 1000).replace(':', '.')[:-4],
@ -1162,9 +1166,9 @@ def srt(request, id, layer, language=None, index=None, ext='srt'):
content_type, encoder = _subtitle_formats[ext]
response = HttpResponse()
if language:
filename = "%s.%s.%s" % (item.get('title'), language, ext)
filename = u"%s.%s.%s" % (item.get('title'), language, ext)
else:
filename = "%s.%s" % (item.get('title'), ext)
filename = u"%s.%s" % (item.get('title'), ext)
response['Content-Disposition'] = "attachment; filename*=UTF-8''%s" % quote(filename.encode('utf-8'))
response['Content-Type'] = content_type
response.write(item.srt(layer, language, encoder=encoder))
@ -1202,7 +1206,7 @@ def atom_xml(request):
el.text = atom_link
level = settings.CONFIG['capabilities']['canSeeItem']['guest']
if not request.user.is_anonymous:
if not request.user.is_anonymous():
level = request.user.profile.level
for item in models.Item.objects.filter(level__lte=level, rendered=True).order_by('-created')[:7]:
if add_updated:
@ -1228,7 +1232,7 @@ def atom_xml(request):
if item.get('director'):
el = ET.SubElement(entry, "author")
name = ET.SubElement(el, "name")
name.text = ox.decode_html(', '.join(item.get('director')))
name.text = ox.decode_html(u', '.join(item.get('director')))
elif item.user:
el = ET.SubElement(entry, "author")
name = ET.SubElement(el, "name")
@ -1277,9 +1281,9 @@ def atom_xml(request):
}.get(key, key))
if value and value != -1:
el = ET.SubElement(format, key)
el.text = str(value)
el.text = unicode(value)
el = ET.SubElement(format, 'pixel_aspect_ratio')
el.text = "1:1"
el.text = u"1:1"
if has_capability(request.user, 'canDownloadVideo'):
if item.torrent:
@ -1354,7 +1358,7 @@ def oembed(request):
oxml = ET.Element('oembed')
for key in oembed:
e = ET.SubElement(oxml, key)
e.text = str(oembed[key])
e.text = unicode(oembed[key])
return HttpResponse(
'<?xml version="1.0" encoding="utf-8" standalone="yes"?>\n' + ET.tostring(oxml).decode(),
'application/xml'
@ -1382,7 +1386,7 @@ def sitemap_part_xml(request, part):
def item_json(request, id):
level = settings.CONFIG['capabilities']['canSeeItem']['guest']
if not request.user.is_anonymous:
if not request.user.is_anonymous():
level = request.user.profile.level
qs = models.Item.objects.filter(public_id=id, level__lte=level)
if qs.count() == 0:
@ -1395,7 +1399,7 @@ def item_json(request, id):
def item_xml(request, id):
level = settings.CONFIG['capabilities']['canSeeItem']['guest']
if not request.user.is_anonymous:
if not request.user.is_anonymous():
level = request.user.profile.level
qs = models.Item.objects.filter(public_id=id, level__lte=level)
if qs.count() == 0:
@ -1420,7 +1424,7 @@ def item_xml(request, id):
xmltree(root, k, data[k])
else:
e = ET.SubElement(root, key)
e.text = str(data)
e.text = unicode(data)
oxml = ET.Element('item')
xmltree(oxml, 'item', j)
@ -1435,7 +1439,7 @@ def item(request, id):
view = None
template = 'index.html'
level = settings.CONFIG['capabilities']['canSeeItem']['guest']
if not request.user.is_anonymous:
if not request.user.is_anonymous():
level = request.user.profile.level
qs = models.Item.objects.filter(public_id=id, level__lte=level)
if qs.count() == 0:
@ -1480,7 +1484,7 @@ def item(request, id):
else:
title = key['title'] if key else k.capitalize()
if isinstance(value, list):
value = value = ', '.join([str(v) for v in value])
value = value = u', '.join([unicode(v) for v in value])
elif key and key.get('type') == 'float':
value = '%0.3f' % value
elif key and key.get('type') == 'time':
@ -1489,7 +1493,7 @@ def item(request, id):
clips = []
clip = {'in': 0, 'annotations': []}
# logged in users should have javascript. not adding annotations makes load faster
if not settings.USE_IMDB and request.user.is_anonymous:
if not settings.USE_IMDB and request.user.is_anonymous():
for a in item.annotations.exclude(
layer='subtitles'
).exclude(
@ -1509,13 +1513,13 @@ def item(request, id):
head_title = item.get('title', '')
title = item.get('title', '')
if item.get('director'):
head_title += ' (%s)' % ', '.join(item.get('director', []))
head_title += u' (%s)' % u', '.join(item.get('director', []))
if item.get('year'):
head_title += ' %s' % item.get('year')
title += ' (%s)' % item.get('year')
head_title += u' %s' % item.get('year')
title += u' (%s)' % item.get('year')
if view:
head_title += ' %s' % view
head_title += ' %s' % settings.SITENAME
head_title += u' %s' % view
head_title += u' %s' % settings.SITENAME
head_title = ox.decode_html(head_title)
title = ox.decode_html(title)
ctx = {

View file

@ -124,7 +124,7 @@ class ListManager(Manager):
if conditions:
qs = qs.filter(conditions)
if user.is_anonymous:
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))

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import os
import re
@ -9,6 +10,7 @@ from django.db import models
from django.db.models import Max
from django.contrib.auth import get_user_model
from django.conf import settings
from django.utils.encoding import python_2_unicode_compatible
from oxdjango.fields import JSONField
import ox
@ -26,6 +28,7 @@ def get_icon_path(f, x): return get_path(f, 'icon.jpg')
def get_listview(): return settings.CONFIG['user']['ui']['listView']
def get_listsort(): return tuple(settings.CONFIG['user']['ui']['listSort'])
@python_2_unicode_compatible
class List(models.Model):
class Meta:
@ -33,7 +36,7 @@ class List(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, related_name='lists', on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='lists')
groups = models.ManyToManyField(Group, blank=True, related_name='lists')
name = models.CharField(max_length=255)
status = models.CharField(max_length=20, default='private')
@ -47,7 +50,7 @@ class List(models.Model):
view = models.TextField(default=get_listview)
sort = JSONField(default=get_listsort, editable=False)
poster_frames = JSONField(default=list, editable=False)
poster_frames = JSONField(default=[], editable=False)
#is through table still required?
items = models.ManyToManyField('item.Item', related_name='lists',
@ -107,13 +110,13 @@ class List(models.Model):
return self.get_id()
def get_id(self):
return '%s:%s' % (self.user.username, self.name)
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 not user or user.is_anonymous:
if not user or user.is_anonymous():
return False
if self.user == user or \
self.groups.filter(id__in=user.groups.all()).count() > 0 or \
@ -241,7 +244,7 @@ class List(models.Model):
elif key == 'subscribers':
response[key] = self.subscribed_users.all().count()
elif key == 'subscribed':
if user and not user.is_anonymous:
if user and not user.is_anonymous():
response[key] = self.subscribed_users.filter(id=user.id).exists()
else:
response[key] = getattr(self, {
@ -311,27 +314,29 @@ class List(models.Model):
path = source
return path
@python_2_unicode_compatible
class ListItem(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
list = models.ForeignKey(List, on_delete=models.CASCADE)
list = models.ForeignKey(List)
index = models.IntegerField(default=0)
item = models.ForeignKey('item.Item', on_delete=models.CASCADE)
item = models.ForeignKey('item.Item')
def __str__(self):
return '%s in %s' % (self.item, self.list)
return u'%s in %s' % (self.item, self.list)
@python_2_unicode_compatible
class Position(models.Model):
class Meta:
unique_together = ("user", "list", "section")
list = models.ForeignKey(List, related_name='position', on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
list = models.ForeignKey(List, related_name='position')
user = models.ForeignKey(User)
section = models.CharField(max_length=255)
position = models.IntegerField(default=0)
def __str__(self):
return '%s/%s/%s' % (self.section, self.position, self.list)
return u'%s/%s/%s' % (self.section, self.position, self.list)

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import os
import re
@ -74,7 +75,7 @@ def findLists(request, data):
query = parse_query(data, request.user)
#order
is_section_request = query['sort'] == [{'operator': '+', 'key': 'position'}]
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 \
@ -86,7 +87,7 @@ def findLists(request, data):
if is_section_request:
qs = query['qs']
if not is_featured and not request.user.is_anonymous:
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:

View file

@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from django.db import models
from django.contrib.auth import get_user_model
from django.utils.encoding import python_2_unicode_compatible
import ox
@ -10,10 +12,11 @@ from . import managers
User = get_user_model()
@python_2_unicode_compatible
class Log(models.Model):
created = models.DateTimeField(auto_now_add=True, db_index=True)
modified = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, default=None, blank=True, null=True, on_delete=models.CASCADE)
user = models.ForeignKey(User, default=None, blank=True, null=True)
url = models.CharField(max_length=1000, default='')
line = models.IntegerField(default=0)
text = models.TextField(blank=True)
@ -21,7 +24,7 @@ class Log(models.Model):
objects = managers.LogManager()
def __str__(self):
return "%s" % self.id
return u"%s" % self.id
def json(self, keys=None):
j = {

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from datetime import timedelta, datetime

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import logging
import sys
@ -33,7 +34,7 @@ class ErrorHandler(logging.Handler):
request = record.request
request_repr = repr(request)
if request.user.is_authenticated:
if request.user.is_authenticated():
user = request.user
url = request.META.get('PATH_INFO', '')
except:

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import ox
from ox.utils import json
@ -24,7 +25,7 @@ def logError(request, data):
returns {}
see: findErrorLogs, removeErrorLogs
'''
if request.user.is_authenticated:
if request.user.is_authenticated():
user = request.user
else:
user = None

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from django.contrib import admin

View file

@ -1,11 +1,14 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
import ox
from . import managers
@python_2_unicode_compatible
class News(models.Model):
objects = managers.NewsManager()
@ -17,7 +20,7 @@ class News(models.Model):
text = models.TextField()
def editable(self, user):
return user.is_authenticated and user.profile.capability("canEditSitePages")
return user.is_authenticated() and user.profile.capability("canEditSitePages")
def save(self, *args, **kwargs):
super(News, self).save(*args, **kwargs)
@ -39,5 +42,5 @@ class News(models.Model):
return j
def __str__(self):
return "%s/%s" % (self.date, self.title)
return u"%s/%s" % (self.date, self.title)

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import ox
from ox.utils import json

View file

@ -1 +1,3 @@
from __future__ import absolute_import
from .actions import actions

View file

@ -1,7 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import division, absolute_import
import inspect
import sys
from six import PY2
from django.conf import settings
from ..shortcuts import render_to_json_response, json_response
@ -106,8 +109,12 @@ class ApiActions(dict):
if name != 'api' and hasattr(f, 'func_closure') and f.func_closure:
fc = list(filter(lambda c: hasattr(c.cell_contents, '__call__'), f.func_closure))
f = fc[len(fc)-1].cell_contents
if PY2:
info = f.func_code.co_filename[len(settings.PROJECT_ROOT)+1:]
info = u'%s:%s' % (info, f.func_code.co_firstlineno)
else:
info = f.__code__.co_filename[len(settings.PROJECT_ROOT)+1:]
info = '%s:%s' % (info, f.__code__.co_firstlineno)
info = u'%s:%s' % (info, f.__code__.co_firstlineno)
return info, trim(inspect.getsource(f))
def register(self, method, action=None, cache=True, version=None):

View file

@ -1,15 +0,0 @@
# -*- coding: utf-8 -*-
from django.urls import path
from . import views
from . import actions
actions.autodiscover()
urls = [
[
path(r'', views.api),
],
'api',
'api'
]

View file

@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from django.conf.urls import url
from . import views
from . import actions
actions.autodiscover()
urlpatterns = [
url(r'^$', views.api),
]

View file

@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import division, absolute_import
import json
from django.shortcuts import render
from django.shortcuts import render_to_response
from django.conf import settings
from ..shortcuts import render_to_json_response, json_response, HttpErrorJson
@ -29,7 +31,7 @@ def api(request):
'settings': settings,
'sitename': settings.SITENAME
}
response = render(request, 'api.html', context)
response = render_to_response('api.html', context)
response['Access-Control-Allow-Origin'] = '*'
return response
if request.META.get('CONTENT_TYPE') == 'application/json':

View file

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from functools import wraps
from .shortcuts import render_to_json_response
@ -10,7 +12,7 @@ def login_required_json(function=None):
"""
def _wrapped_view(request, *args, **kwargs):
if request.user.is_authenticated:
if request.user.is_authenticated():
return function(request, *args, **kwargs)
return render_to_json_response({'status': {'code': 401, 'text': 'login required'}})
return wraps(function)(_wrapped_view)
@ -22,7 +24,7 @@ def admin_required_json(function=None):
"""
def _wrapped_view(request, *args, **kwargs):
if request.user.is_authenticated and request.user.profile.get_level() == 'admin':
if request.user.is_authenticated() and request.user.profile.get_level() == 'admin':
return function(request, *args, **kwargs)
return render_to_json_response({'status': {'code': 403, 'text': 'permission denied'}})
return wraps(function)(_wrapped_view)

View file

@ -8,6 +8,8 @@ from django.utils import datetime_safe
import django.contrib.postgres.fields
from django.core.serializers.json import DjangoJSONEncoder
from six import string_types
from ox.utils import json
class JSONField(django.contrib.postgres.fields.JSONField):
@ -62,7 +64,7 @@ class DictField(models.TextField):
def dumps(cls, obj):
return json.dumps(obj, default=to_json, ensure_ascii=False)
def from_db_value(self, value, expression, connection, context=None):
def from_db_value(self, value, expression, connection, context):
if value is None:
return value
if isinstance(value, self._type):
@ -72,7 +74,7 @@ class DictField(models.TextField):
except:
raise Exception('failed to parse value: %s' % value)
if value is not None:
if isinstance(value, str):
if isinstance(value, string_types):
value = json.loads(value)
assert isinstance(value, self._type)
return value
@ -81,7 +83,7 @@ class DictField(models.TextField):
if isinstance(value, self._type):
value = self.dumps(value)
if value is not None:
assert isinstance(value, str)
assert isinstance(value, string_types)
value = models.TextField.get_prep_value(self, value)
return value

View file

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from datetime import datetime, timedelta
from urllib.parse import quote
import mimetypes
import os
import mimetypes
from datetime import datetime, timedelta
from six.moves.urllib.parse import quote
from django.http import HttpResponse, Http404
from django.conf import settings

View file

@ -1,17 +1,14 @@
# -*- coding: utf-8 -*-
from django.utils.deprecation import MiddlewareMixin
from .shortcuts import HttpErrorJson, render_to_json_response
class ExceptionMiddleware(MiddlewareMixin):
class ExceptionMiddleware(object):
def process_exception(self, request, exception):
if isinstance(exception, HttpErrorJson):
return render_to_json_response(exception.response)
return None
class ChromeFrameMiddleware(MiddlewareMixin):
class ChromeFrameMiddleware(object):
def process_response(self, request, response):
response['X-UA-Compatible'] = 'chrome=1'
return response

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
import datetime
from django.utils import datetime_safe
from django.http import HttpResponse, Http404
@ -22,7 +23,7 @@ def _to_json(python_object):
return python_object.strftime('%Y-%m-%dT%H:%M:%SZ')
if isinstance(python_object, datetime_safe.datetime):
return python_object.strftime('%Y-%m-%dT%H:%M:%SZ')
raise TypeError('%s %s is not JSON serializable' % (repr(python_object), type(python_object)))
raise TypeError(u'%s %s is not JSON serializable' % (repr(python_object), type(python_object)))
def json_dump(data, fp, indent=4):
return json.dump(data, fp, indent=indent, default=_to_json, ensure_ascii=False)

View file

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import unicodedata
from six import string_types
from django.db.models import Q, Manager
from item.utils import decode_id
@ -55,7 +56,7 @@ def parseCondition(condition, user):
else:
key = k + get_operator(op, 'istr')
key = str(key)
if isinstance(v, str):
if isinstance(v, string_types):
v = unicodedata.normalize('NFKD', v).lower()
if exclude:
q = ~Q(**{key: v})

View file

@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import
import unicodedata
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from oxdjango import fields
import ox
@ -22,9 +24,10 @@ def get_name_sort(name, sortname=None):
person.save()
sortname = unicodedata.normalize('NFKD', person.sortname)
else:
sortname = ''
sortname = u''
return sortname
@python_2_unicode_compatible
class Person(models.Model):
name = models.CharField(max_length=200, unique=True)
sortname = models.CharField(max_length=200)

Some files were not shown because too many files have changed in this diff Show more