migrate to django 1.9

This commit is contained in:
j 2016-03-06 16:05:46 +05:30
parent f7855147ce
commit e5dd8aaab7
48 changed files with 659 additions and 848 deletions

1
.gitignore vendored
View file

@ -14,3 +14,4 @@ build
*.pyc
*~
*.swp
local

View file

@ -20,7 +20,8 @@ end script
exec start-stop-daemon \
--pidfile /var/run/oxdata/oxdata.pid \
--start -c $USER -d $VENV/oxdata \
--exec $VENV/bin/gunicorn_django -- \
--exec $VENV/bin/gunicorn -- \
wsgi:application \
--bind 127.0.0.1:8087 \
--workers 5 \
--max-requests 1000 \

View file

@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4

View file

@ -1,10 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>{{sitename}} API</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="text/javascript" src="/static/oxjs/build/Ox.js"></script>
<script type="text/javascript" src="/static/js/pandora.api.js"></script>
</head>
<body></body>
</html>

View file

@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from django.conf.urls.defaults import *
urlpatterns = patterns("api.views",
(r'^$', 'api'),
)

View file

@ -5,10 +5,7 @@ from __future__ import division
import os.path
import hashlib
from django.conf import settings
from django.db import models
from django.db.models import Q
from django.contrib.auth.models import User
from django.core.files.base import ContentFile
from lookup.models import MovieId
@ -43,6 +40,9 @@ def cover_path(url, filename):
name = "%s.%s" % (h, ext)
return os.path.join('covers', h[:2], h[2:4], h[4:6], name)
def covercache_image_path(i, f):
return cover_path(i.url.encode('utf-8'), f)
class CoverCache(models.Model):
class Meta:
unique_together = ("isbn", "url")
@ -54,7 +54,7 @@ class CoverCache(models.Model):
url = models.CharField(max_length=1024)
site = models.CharField(max_length=255)
site_id = models.CharField(max_length=42)
image = models.ImageField(max_length=255, upload_to=lambda i, f: cover_path(i.url.encode('utf-8'), f))
image = models.ImageField(max_length=255, upload_to=covercache_image_path)
status = models.CharField(max_length=1024, default='200')
failed = models.BooleanField(default=False)
@ -89,10 +89,13 @@ class CoverCache(models.Model):
self.image.delete()
return self.image
def cover_image_path(i, f):
return cover_path('upload/%s' % i.id, f)
class Cover(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
isbn = models.ForeignKey(MovieId, related_name='cover')
cover = models.ImageField(max_length=255, upload_to=lambda i, f: cover_path('upload/%s' % i.id, f))
cover = models.ImageField(max_length=255, upload_to=cover_image_path)

View file

@ -1,6 +1,8 @@
from django.conf.urls.defaults import *
from django.conf.urls import url
urlpatterns = patterns('oxdata.cover.views',
(r'^$', 'cover'),
)
import views
urlpatterns = [
url(r'^$', views.cover),
]

View file

@ -1,13 +1,7 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
import os.path
from django.db import models
from django.db.models import Q
from django.contrib.auth.models import User
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404
from django.template import RequestContext
from ox.django.shortcuts import render_to_json_response
from oxdjango.shortcuts import render_to_json_response
import models

View file

@ -1,15 +1,12 @@
# -*- coding: UTF-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
import os
from django.conf import settings
from ox import find_re
import ox.web.criterion
import ox.web.imdb
import ox.web.impawards
import models
from oxdata.poster.models import PosterCache
from poster.models import PosterCache
import modules
def addPoster(m, url, site, site_id):

View file

@ -1,78 +1,38 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-03-06 10:11
from __future__ import unicode_literals
from south.db import db
from django.db import models
from oxdata.lookup.models import *
class Migration:
def forwards(self, orm):
# Adding model 'MovieId'
db.create_table('lookup_movieid', (
('id', orm['lookup.MovieId:id']),
('created', orm['lookup.MovieId:created']),
('modified', orm['lookup.MovieId:modified']),
('title', orm['lookup.MovieId:title']),
('year', orm['lookup.MovieId:year']),
('director', orm['lookup.MovieId:director']),
('series_title', orm['lookup.MovieId:series_title']),
('episode_title', orm['lookup.MovieId:episode_title']),
('season', orm['lookup.MovieId:season']),
('episode', orm['lookup.MovieId:episode']),
('oxdb_id', orm['lookup.MovieId:oxdb_id']),
('imdb_id', orm['lookup.MovieId:imdb_id']),
('amg_id', orm['lookup.MovieId:amg_id']),
('wikipedia_id', orm['lookup.MovieId:wikipedia_id']),
('criterion_id', orm['lookup.MovieId:criterion_id']),
('impawards_id', orm['lookup.MovieId:impawards_id']),
))
db.send_create_signal('lookup', ['MovieId'])
# Adding model 'Karagarga'
db.create_table('lookup_karagarga', (
('id', orm['lookup.Karagarga:id']),
('movie_id', orm['lookup.Karagarga:movie_id']),
('karagarga_id', orm['lookup.Karagarga:karagarga_id']),
))
db.send_create_signal('lookup', ['Karagarga'])
from django.db import migrations, models
class Migration(migrations.Migration):
def backwards(self, orm):
initial = True
# Deleting model 'MovieId'
db.delete_table('lookup_movieid')
dependencies = [
]
# Deleting model 'Karagarga'
db.delete_table('lookup_karagarga')
models = {
'lookup.karagarga': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'karagarga_id': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'karagarga_ids'", 'to': "orm['lookup.MovieId']"})
},
'lookup.movieid': {
'amg_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'criterion_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'director': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'episode': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'episode_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'imdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '7', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'impawards_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'oxdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '42', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'season': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'series_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'wikipedia_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'year': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4', 'blank': 'True'})
}
}
complete_apps = ['lookup']
operations = [
migrations.CreateModel(
name='MovieId',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(auto_now_add=True)),
('modified', models.DateTimeField(auto_now=True)),
('title', models.CharField(blank=True, default=b'', max_length=1000)),
('year', models.CharField(blank=True, default=b'', max_length=4)),
('director', models.CharField(blank=True, default=b'', max_length=1000)),
('series_title', models.CharField(blank=True, default=b'', max_length=1000)),
('episode_title', models.CharField(blank=True, default=b'', max_length=1000)),
('season', models.IntegerField(default=-1)),
('episode', models.IntegerField(default=-1)),
('oxdb_id', models.CharField(blank=True, default=None, max_length=42, null=True, unique=True)),
('imdb_id', models.CharField(blank=True, default=None, max_length=7, null=True, unique=True)),
('amg_id', models.IntegerField(blank=True, default=None, null=True, unique=True)),
('archiveorg_id', models.CharField(blank=True, default=None, max_length=255, null=True, unique=True)),
('wikipedia_id', models.CharField(blank=True, default=None, max_length=255, null=True, unique=True)),
('criterion_id', models.IntegerField(blank=True, default=None, null=True, unique=True)),
('impawards_id', models.CharField(blank=True, default=None, max_length=255, null=True, unique=True)),
],
),
]

View file

@ -1,47 +0,0 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Deleting model 'karagarga'
db.delete_table('lookup_karagarga')
def backwards(self, orm):
# Adding model 'karagarga'
db.create_table('lookup_karagarga', (
('movie_id', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='karagarga_ids', to=orm['lookup.MovieId'])),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('karagarga_id', self.gf('django.db.models.fields.IntegerField')(unique=True)),
))
db.send_create_signal('lookup', ['karagarga'])
models = {
'lookup.movieid': {
'Meta': {'object_name': 'MovieId'},
'amg_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'criterion_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'director': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'episode': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'episode_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'imdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '7', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'impawards_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'oxdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '42', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'season': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'series_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'wikipedia_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'year': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4', 'blank': 'True'})
}
}
complete_apps = ['lookup']

View file

@ -1,16 +1,12 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
import os
import hashlib
from urllib import quote
from django.db import models
from django.db.models import Q, Max
from django.contrib.auth.models import User
import ox
from ox.normalize import canonical_name, normalize_path, strip_accents
from ox import strip_tags
from ox.normalize import canonical_name
import ox.web.archive
import ox.web.imdb
import ox.web.wikipedia

View file

@ -1,7 +1,8 @@
from django.conf.urls.defaults import *
from django.conf.urls import url
urlpatterns = patterns('oxdata.lookup.views',
(r'^$', 'ids'),
(r'^urls$', 'urls'),
)
import views
urlpatterns = [
url(r'^$', views.ids),
url(r'^urls$', views.urls),
]

View file

@ -1,13 +1,8 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
import os.path
from django.db import models
from django.db.models import Q
from django.contrib.auth.models import User
from oxdjango.shortcuts import render_to_json_response, json_response
from oxdjango.api import actions
from ox.django.shortcuts import render_to_json_response, json_response
from ox.utils import json
from api.actions import actions
import models

View file

@ -1,5 +1,6 @@
#!/usr/bin/env python
import os
import sys
root_dir = os.path.normpath(os.path.abspath(os.path.dirname(__file__)))
os.chdir(root_dir)
@ -8,13 +9,8 @@ os.chdir(root_dir)
activate_this = os.path.join(root_dir, '..', 'bin', 'activate_this.py')
execfile(activate_this, dict(__file__=activate_this))
from django.core.management import execute_manager
try:
import settings # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
sys.exit(1)
if __name__ == "__main__":
execute_manager(settings)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)

View file

@ -11,7 +11,7 @@ import base64
from django.db import models
from django.conf import settings
import ox
from ox.django.fields import DictField
from oxdjango.fields import DictField
from lookup.models import get_movie_id
from poster.models import getPosters
@ -238,9 +238,10 @@ def get_new_ids(timeout=-1):
ids = re.compile('<loc>http://www.imdb.com/title/tt(\d{7})/combined</loc>').findall(s)
added = 0
for i in frozenset(ids) - known_ids:
m = Imdb(imdb=i)
m, created = Imdb.objects.get_or_create(imdb=i)
m.update()
print m
if created:
added += 1
if added:
print url, added

View file

@ -2,12 +2,11 @@
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division
import re
from ox.django.shortcuts import render_to_json_response, json_response
from oxdjango.shortcuts import render_to_json_response, json_response
import ox.web.imdb
from api.actions import actions
from oxdjango.api import actions
import models
def getId(request, data):

View file

@ -0,0 +1 @@
from actions import actions

View file

@ -1,17 +1,16 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
import sys
from __future__ import division, with_statement
import inspect
import sys
from django.conf import settings
from ox.django.shortcuts import render_to_json_response, json_response
from ox.utils import json
from ..shortcuts import render_to_json_response, json_response
def autodiscover():
#register api actions from all installed apps
from django.utils.importlib import import_module
# Register api actions from all installed apps
from importlib import import_module
from django.utils.module_loading import module_has_submodule
for app in settings.INSTALLED_APPS:
if app != 'api':
@ -50,61 +49,74 @@ def trim(docstring):
class ApiActions(dict):
properties = {}
versions = {}
def __init__(self):
def api(request, data):
'''
returns list of all known api actions
param data {
docs: bool
Returns a list of all api actions
takes {
code: boolean, // if true, return source code (optional)
docs: boolean // if true, return doc strings (optional)
}
if docs is true, action properties contain docstrings
return {
status: {'code': int, 'text': string},
data: {
returns {
actions: {
'api': {
cache: true,
doc: 'recursion'
name: {
cache: boolean, // if false, don't cache results
code: string, // source code
doc: string // doc strings
},
'hello': {
cache: true,
..
}
...
}
... // more actions
}
}
'''
docs = data.get('docs', False)
code = data.get('code', False)
version = getattr(request, 'version', None)
if version:
_actions = self.versions.get(version, {}).keys()
_actions = list(set(_actions + self.keys()))
else:
_actions = self.keys()
_actions.sort()
actions = {}
for a in _actions:
actions[a] = self.properties[a]
if docs:
actions[a]['doc'] = self.doc(a)
actions[a]['doc'] = self.doc(a, version)
if code:
actions[a]['code'] = self.code(a)
actions[a]['code'] = self.code(a, version)
response = json_response({'actions': actions})
return render_to_json_response(response)
self.register(api)
def doc(self, f):
return trim(self[f].__doc__)
def doc(self, name, version=None):
if version:
f = self.versions[version].get(name, self.get(name))
else:
f = self[name]
return trim(f.__doc__)
def code(self, name):
def code(self, name, version=None):
if version:
f = self.versions[version].get(name, self.get(name))
else:
f = self[name]
if name != 'api' and hasattr(f, 'func_closure') and f.func_closure:
f = f.func_closure[0].cell_contents
fc = filter(lambda c: hasattr(c.cell_contents, '__call__'), f.func_closure)
f = fc[len(fc)-1].cell_contents
info = f.func_code.co_filename[len(settings.PROJECT_ROOT)+1:]
info = u'%s:%s' % (info, f.func_code.co_firstlineno)
return info, trim(inspect.getsource(f))
def register(self, method, action=None, cache=True):
def register(self, method, action=None, cache=True, version=None):
if not action:
action = method.func_name
if version:
if not version in self.versions:
self.versions[version] = {}
self.versions[version][action] = method
else:
self[action] = method
self.properties[action] = {'cache': cache}
@ -114,3 +126,10 @@ class ApiActions(dict):
actions = ApiActions()
def error(request, data):
'''
This action is used to test API error codes. It should return a 503 error.
'''
success = error_is_success
return render_to_json_response({})
actions.register(error)

View file

@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from django.conf.urls import url
import views
import actions
actions.autodiscover()
urlpatterns = [
url(r'^$', views.api),
]

View file

@ -2,20 +2,16 @@
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division, with_statement
import os
import copy
import json
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.conf import settings
from django.db.models import Max, Sum
from ox.django.shortcuts import render_to_json_response, json_response
from ox.utils import json
from ..shortcuts import render_to_json_response, json_response
from actions import actions
def api(request):
if request.META['REQUEST_METHOD'] == "OPTIONS":
response = render_to_json_response({'status': {'code': 200,
@ -30,8 +26,11 @@ def api(request):
for f in sorted(methods):
api.append({'name': f,
'doc': actions.doc(f).replace('\n', '<br>\n')})
context = RequestContext(request, {'api': api,
'sitename': settings.SITENAME})
context = RequestContext(request, {
'api': api,
'settings': settings,
'sitename': settings.SITENAME
})
return render_to_response('api.html', context)
if request.META.get('CONTENT_TYPE') == 'application/json':
r = json.loads(request.body)
@ -40,7 +39,10 @@ def api(request):
else:
action = request.POST['action']
data = json.loads(request.POST.get('data', '{}'))
version = getattr(request, 'version', None)
if version:
f = actions.versions.get(version, {}).get(action, actions.get(action))
else:
f = actions.get(action)
if f:
response = f(request, data)
@ -50,14 +52,3 @@ def api(request):
response['Access-Control-Allow-Origin'] = '*'
return response
def init(request, data):
return render_to_json_response(json_response())
actions.register(init)
def error(request, data):
'''
this action is used to test api error codes, it should return a 503 error
'''
success = error_is_success
return render_to_json_response({})
actions.register(error)

View file

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
try:
from django.contrib.auth.decorators import wraps
except:
from django.utils.functional import wraps
from shortcuts import render_to_json_response
def login_required_json(function=None):
"""
Decorator for views that checks that the user is logged in
return json error if not logged in.
"""
def _wrapped_view(request, *args, **kwargs):
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)
def admin_required_json(function=None):
"""
Decorator for views that checks that the user is logged in
return json error if not logged in.
"""
def _wrapped_view(request, *args, **kwargs):
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)

99
oxdata/oxdjango/fields.py Normal file
View file

@ -0,0 +1,99 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
import time
import datetime
import copy
from django.db import models
from django.utils import datetime_safe
from six import string_types
from ox.utils import json
def to_json(python_object):
if isinstance(python_object, datetime.datetime):
if python_object.year < 1900:
tt = python_object.timetuple()
value = '%d-%02d-%02dT%02d:%02d%02dZ' % tuple(list(tt)[:6])
else:
value = python_object.strftime('%Y-%m-%dT%H:%M:%SZ')
return {'__class__': 'datetime.datetime',
'__value__': value}
if isinstance(python_object, datetime_safe.datetime):
return {'__class__': 'datetime.datetime',
'__value__': python_object.strftime('%Y-%m-%dT%H:%M:%SZ')}
if isinstance(python_object, time.struct_time):
return {'__class__': 'time.asctime',
'__value__': time.asctime(python_object)}
try:
if isinstance(python_object, bytes):
return {'__class__': 'bytes',
'__value__': list(python_object)}
except:
pass
raise TypeError(repr(python_object) + ' is not JSON serializable')
def from_json(json_object):
if '__class__' in json_object:
if json_object['__class__'] == 'bytes':
return bytes(json_object['__value__'])
if json_object['__class__'] == 'datetime_safe.datetime' \
or json_object['__class__'] == 'datetime.datetime':
return datetime_safe.datetime.strptime(json_object['__value__'], '%Y-%m-%dT%H:%M:%SZ')
if json_object['__class__'] == 'time.asctime':
return time.strptime(json_object['__value__'])
return json_object
class DictField(models.TextField):
_type = dict
def loads(self, value):
return json.loads(value, object_hook=from_json)
def dumps(self, obj):
return json.dumps(obj, default=to_json, ensure_ascii=False)
def from_db_value(self, value, expression, connection, context):
if value is None:
return value
if isinstance(value, self._type):
return value
try:
value = self.loads(value)
except:
raise Exception('failed to parse value: %s' % value)
if value is not None:
assert isinstance(value, self._type)
return value
def get_prep_value(self, value):
if isinstance(value, self._type):
value = self.dumps(value)
if value is not None:
assert isinstance(value, string_types)
value = models.TextField.get_prep_value(self, value)
return value
def get_default(self):
if self.has_default():
if callable(self.default):
return self.default()
return copy.deepcopy(self.default)
return super(DictField, self).get_default()
class TupleField(DictField):
_type = (tuple, list)
def loads(self, value):
value = DictField.loads(self, value)
if isinstance(value, list):
value = tuple(value)
return value
try:
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^oxdjango\.fields\.DictField"])
add_introspection_rules([], ["^oxdjango\.fields\.TupleField"])
except:
pass

58
oxdata/oxdjango/http.py Normal file
View file

@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
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
def HttpFileResponse(path, content_type=None, filename=None):
if not os.path.exists(path):
raise Http404
if not content_type:
content_type = mimetypes.guess_type(path)[0]
if not content_type:
content_type = 'application/octet-stream'
if getattr(settings, 'XACCELREDIRECT', False):
response = HttpResponse()
response['Content-Length'] = os.stat(path).st_size
for PREFIX in ('STATIC', 'MEDIA'):
root = getattr(settings, PREFIX+'_ROOT', '')
url = getattr(settings, PREFIX+'_URL', '')
if root and path.startswith(root):
path = url + path[len(root)+1:]
if not isinstance(path, bytes):
path = path.encode('utf-8')
response['X-Accel-Redirect'] = path
if content_type:
response['Content-Type'] = content_type
elif getattr(settings, 'XSENDFILE', False):
response = HttpResponse()
if not isinstance(path, bytes):
path = path.encode('utf-8')
response['X-Sendfile'] = path
if content_type:
response['Content-Type'] = content_type
response['Content-Length'] = os.stat(path).st_size
else:
response = HttpResponse(open(path), content_type=content_type)
if filename:
if not isinstance(filename, bytes):
filename = filename.encode('utf-8')
response['Content-Disposition'] = "attachment; filename*=UTF=8''%s" % quote(filename)
response['Expires'] = datetime.strftime(datetime.utcnow() + timedelta(days=1), "%a, %d-%b-%Y %H:%M:%S GMT")
def allow_access():
for key in ('X-Accel-Redirect', 'X-Sendfile'):
if key in response:
del response[key]
response['Access-Control-Allow-Origin'] = '*'
response.allow_access = allow_access
return response

View file

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from .shortcuts import HttpErrorJson, render_to_json_response
class ExceptionMiddleware(object):
def process_exception(self, request, exception):
if isinstance(exception, HttpErrorJson):
return render_to_json_response(exception.response)
return None
class ChromeFrameMiddleware(object):
def process_response(self, request, response):
response['X-UA-Compatible'] = 'chrome=1'
return response

58
oxdata/oxdjango/query.py Normal file
View file

@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from django.db.models.sql import Query
from django.db.models.sql.compiler import SQLCompiler
from django.db import connections
import django.db.models.query
'''
models.py:
-----------------------------------
from oxdjango.query import QuerySet
class Manager(models.Manager):
def get_query_set(self):
return QuerySet(self.model)
class Model(models.Model):
...
objects = Manager()
'''
class NullLastSQLCompiler(SQLCompiler):
def get_order_by(self):
result = super(NullLastSQLCompiler, self).get_order_by()
if self.query.nulls_last and result \
and self.connection.vendor == 'postgresql':
return [(expr, (sql + ' NULLS LAST', params, is_ref))
for (expr, (sql, params, is_ref)) in result]
return result
class NullsLastQuery(Query):
nulls_last = False
def clone(self, *args, **kwargs):
obj = super(NullsLastQuery, self).clone(*args, **kwargs)
obj.nulls_last = self.nulls_last
return obj
def get_compiler(self, using=None, connection=None):
if using is None and connection is None:
raise ValueError("Need either using or connection")
if using:
connection = connections[using]
return NullLastSQLCompiler(self, connection, using)
class QuerySet(django.db.models.query.QuerySet):
def __init__(self, model=None, query=None, using=None, **kwargs):
super(QuerySet, self).__init__(model=model, query=query, using=None, **kwargs)
self.query = query or NullsLastQuery(self.model)
def order_by(self, *args, **kwargs):
nulls_last = kwargs.pop('nulls_last', False)
obj = super(QuerySet, self).order_by(*args, **kwargs)
obj.query.nulls_last = nulls_last
return obj

View file

@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import print_function
import datetime
from django.utils import datetime_safe
from django.http import HttpResponse, Http404
import json
from django.conf import settings
class HttpErrorJson(Http404):
def __init__(self, response):
self.response = response
def json_response(data=None, status=200, text='ok'):
if not data:
data = {}
return {'status': {'code': status, 'text': text}, 'data': data}
def _to_json(python_object):
if isinstance(python_object, datetime.datetime):
if python_object.year < 1900:
tt = python_object.timetuple()
return '%d-%02d-%02dT%02d:%02d%02dZ' % tuple(list(tt)[:6])
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(u'%s %s is not JSON serializable' % (repr(python_object), type(python_object)))
def render_to_json_response(dictionary, content_type="text/json", status=200):
indent=None
if settings.DEBUG:
content_type = "text/javascript"
indent = 2
if getattr(settings, 'JSON_DEBUG', False):
print(json.dumps(dictionary, indent=2, default=_to_json, ensure_ascii=False).encode('utf-8'))
return HttpResponse(json.dumps(dictionary, indent=indent, default=_to_json,
ensure_ascii=False).encode('utf-8'), content_type=content_type, status=status)
def get_object_or_404_json(klass, *args, **kwargs):
from django.shortcuts import _get_queryset
queryset = _get_queryset(klass)
try:
return queryset.get(*args, **kwargs)
except queryset.model.DoesNotExist:
response = {'status': {'code': 404,
'text': '%s not found' % queryset.model._meta.object_name}}
raise HttpErrorJson(response)

47
oxdata/oxdjango/utils.py Normal file
View file

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from django.http import HttpResponse,Http404
from django.core.servers.basehttp import FileWrapper
from django.conf import settings
import mimetypes
import os
def basic_sendfile(fname,download_name=None):
if not os.path.exists(fname):
raise Http404
wrapper = FileWrapper(open(fname,"r"))
content_type = mimetypes.guess_type(fname)[0]
response = HttpResponse(wrapper, content_type=content_type)
response['Content-Length'] = os.path.getsize(fname)
if download_name:
response['Content-Disposition'] = "attachment; filename=%s"%download_name
return response
def x_sendfile(fname,download_name=None):
if not os.path.exists(fname):
raise Http404
content_type = mimetypes.guess_type(fname)[0]
response = HttpResponse('', content_type=content_type)
response['Content-Length'] = os.path.getsize(fname)
response['X-Sendfile'] = fname
if download_name:
response['Content-Disposition'] = "attachment; filename=%s"%download_name
return response
try:
__sendfile = getattr(settings,'SENDFILE',False) == 'x_sendfile'
except:
__sendfile = False
if __sendfile == 'x_sendfile':
sendfile = x_sendfile
else:
sendfile = basic_sendfile

View file

@ -1,90 +1,38 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-03-06 10:11
from __future__ import unicode_literals
from south.db import db
from django.db import models
from oxdata.poster.models import *
class Migration:
def forwards(self, orm):
# Adding model 'PosterCache'
db.create_table('poster_postercache', (
('id', orm['poster.PosterCache:id']),
('created', orm['poster.PosterCache:created']),
('modified', orm['poster.PosterCache:modified']),
('movie_id', orm['poster.PosterCache:movie_id']),
('url', orm['poster.PosterCache:url']),
('site', orm['poster.PosterCache:site']),
('site_id', orm['poster.PosterCache:site_id']),
('image', orm['poster.PosterCache:image']),
('failed', orm['poster.PosterCache:failed']),
))
db.send_create_signal('poster', ['PosterCache'])
# Adding model 'Poster'
db.create_table('poster_poster', (
('id', orm['poster.Poster:id']),
('created', orm['poster.Poster:created']),
('modified', orm['poster.Poster:modified']),
('movie_id', orm['poster.Poster:movie_id']),
('poster', orm['poster.Poster:poster']),
('upload', orm['poster.Poster:upload']),
('oxdb', orm['poster.Poster:oxdb']),
))
db.send_create_signal('poster', ['Poster'])
from django.db import migrations, models
import django.db.models.deletion
import poster.models
class Migration(migrations.Migration):
def backwards(self, orm):
initial = True
# Deleting model 'PosterCache'
db.delete_table('poster_postercache')
dependencies = [
('lookup', '0001_initial'),
]
# Deleting model 'Poster'
db.delete_table('poster_poster')
models = {
'lookup.movieid': {
'amg_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'criterion_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'director': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'episode': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'episode_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'imdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '7', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'impawards_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'oxdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '42', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'season': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'series_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'wikipedia_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'year': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4', 'blank': 'True'})
},
'poster.poster': {
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'poster'", 'to': "orm['lookup.MovieId']"}),
'oxdb': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'}),
'poster': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['poster.PosterCache']", 'blank': 'True'}),
'upload': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'})
},
'poster.postercache': {
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postercache'", 'to': "orm['lookup.MovieId']"}),
'site': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'site_id': ('django.db.models.fields.CharField', [], {'max_length': '42'}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
}
}
complete_apps = ['poster']
operations = [
migrations.CreateModel(
name='PosterCache',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(auto_now_add=True)),
('modified', models.DateTimeField(auto_now=True)),
('url', models.CharField(max_length=1024)),
('site', models.CharField(max_length=255)),
('site_id', models.CharField(max_length=1024)),
('image', models.ImageField(max_length=255, upload_to=poster.models.postercache_path)),
('status', models.CharField(default=b'200', max_length=1024)),
('failed', models.BooleanField(default=False)),
('movie_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='postercache', to='lookup.MovieId')),
],
),
migrations.AlterUniqueTogether(
name='postercache',
unique_together=set([('movie_id', 'url')]),
),
]

View file

@ -1,92 +0,0 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'PosterCache.status'
db.add_column('poster_postercache', 'status', self.gf('django.db.models.fields.CharField')(default='200', max_length=1024), keep_default=False)
# Deleting field 'poster.upload'
db.delete_column('poster_poster', 'upload')
# Deleting field 'poster.oxdb'
db.delete_column('poster_poster', 'oxdb')
# Renaming column for 'Poster.poster' to match new field type.
db.rename_column('poster_poster', 'poster_id', 'poster')
# Changing field 'Poster.poster'
db.add_column('poster_poster', 'poster', self.gf('django.db.models.fields.files.ImageField')(max_length=255))
# Removing index on 'poster', fields ['poster']
db.delete_index('poster_poster', ['poster_id'])
def backwards(self, orm):
# Deleting field 'PosterCache.status'
db.delete_column('poster_postercache', 'status')
# Adding field 'poster.upload'
db.add_column('poster_poster', 'upload', self.gf('django.db.models.fields.files.ImageField')(default=None, max_length=255), keep_default=False)
# Adding field 'poster.oxdb'
db.add_column('poster_poster', 'oxdb', self.gf('django.db.models.fields.files.ImageField')(default=None, max_length=255), keep_default=False)
# Renaming column for 'Poster.poster' to match new field type.
db.rename_column('poster_poster', 'poster', 'poster_id')
# Changing field 'Poster.poster'
db.alter_column('poster_poster', 'poster_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['poster.PosterCache'], blank=True))
# Adding index on 'poster', fields ['poster']
db.create_index('poster_poster', ['poster_id'])
models = {
'lookup.movieid': {
'Meta': {'object_name': 'MovieId'},
'amg_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'criterion_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'director': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'episode': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'episode_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'imdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '7', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'impawards_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'oxdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '42', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'season': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'series_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'wikipedia_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'year': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4', 'blank': 'True'})
},
'poster.poster': {
'Meta': {'object_name': 'Poster'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'poster'", 'to': "orm['lookup.MovieId']"}),
'poster': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'})
},
'poster.postercache': {
'Meta': {'object_name': 'PosterCache'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postercache'", 'to': "orm['lookup.MovieId']"}),
'site': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'site_id': ('django.db.models.fields.CharField', [], {'max_length': '42'}),
'status': ('django.db.models.fields.CharField', [], {'default': "'200'", 'max_length': '1024'}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
}
}
complete_apps = ['poster']

View file

@ -1,64 +0,0 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding unique constraint on 'PosterCache', fields ['url']
db.create_unique('poster_postercache', ['url'])
def backwards(self, orm):
# Removing unique constraint on 'PosterCache', fields ['url']
db.delete_unique('poster_postercache', ['url'])
models = {
'lookup.movieid': {
'Meta': {'object_name': 'MovieId'},
'amg_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'criterion_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'director': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'episode': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'episode_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'imdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '7', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'impawards_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'oxdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '42', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'season': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'series_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'wikipedia_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'year': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4', 'blank': 'True'})
},
'poster.poster': {
'Meta': {'object_name': 'Poster'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'poster'", 'to': "orm['lookup.MovieId']"}),
'poster': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'})
},
'poster.postercache': {
'Meta': {'object_name': 'PosterCache'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postercache'", 'to': "orm['lookup.MovieId']"}),
'site': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'site_id': ('django.db.models.fields.CharField', [], {'max_length': '42'}),
'status': ('django.db.models.fields.CharField', [], {'default': "'200'", 'max_length': '1024'}),
'url': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '1024'})
}
}
complete_apps = ['poster']

View file

@ -1,70 +0,0 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Removing unique constraint on 'PosterCache', fields ['url']
db.delete_unique('poster_postercache', ['url'])
# Adding unique constraint on 'PosterCache', fields ['url', 'movie_id']
db.create_unique('poster_postercache', ['url', 'movie_id_id'])
def backwards(self, orm):
# Adding unique constraint on 'PosterCache', fields ['url']
db.create_unique('poster_postercache', ['url'])
# Removing unique constraint on 'PosterCache', fields ['url', 'movie_id']
db.delete_unique('poster_postercache', ['url', 'movie_id_id'])
models = {
'lookup.movieid': {
'Meta': {'object_name': 'MovieId'},
'amg_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'criterion_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'director': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'episode': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'episode_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'imdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '7', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'impawards_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'oxdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '42', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'season': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'series_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'wikipedia_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'year': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4', 'blank': 'True'})
},
'poster.poster': {
'Meta': {'object_name': 'Poster'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'poster'", 'to': "orm['lookup.MovieId']"}),
'poster': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'})
},
'poster.postercache': {
'Meta': {'unique_together': "(('movie_id', 'url'),)", 'object_name': 'PosterCache'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postercache'", 'to': "orm['lookup.MovieId']"}),
'site': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'site_id': ('django.db.models.fields.CharField', [], {'max_length': '42'}),
'status': ('django.db.models.fields.CharField', [], {'default': "'200'", 'max_length': '1024'}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
}
}
complete_apps = ['poster']

View file

@ -7,11 +7,7 @@ import hashlib
import socket
import urllib2
from django.conf import settings
from django.db import models
from django.db.models import Q
from django.contrib.auth.models import User
from django.core.files.base import ContentFile
import ox
import ox.web.criterion
@ -21,7 +17,7 @@ import ox.web.impawards
import ox.web.apple
import ox.web.piratecinema
from oxdata.lookup.models import MovieId
from lookup.models import MovieId
def getPosters(movie_id, url_prefix='', limit=lambda x, y: 0.3 < x/y < 1):
if not movie_id:
@ -55,6 +51,9 @@ def poster_path(url, filename):
name = "%s.%s" % (h, ext)
return os.path.join('posters', h[:2], h[2:4], h[4:6], name)
def postercache_path(i, f):
return poster_path(i.url.encode('utf-8'), f)
class PosterCache(models.Model):
class Meta:
unique_together = ("movie_id", "url")
@ -66,7 +65,7 @@ class PosterCache(models.Model):
url = models.CharField(max_length=1024)
site = models.CharField(max_length=255)
site_id = models.CharField(max_length=1024)
image = models.ImageField(max_length=255, upload_to=lambda i, f: poster_path(i.url.encode('utf-8'), f))
image = models.ImageField(max_length=255, upload_to=postercache_path)
status = models.CharField(max_length=1024, default='200')
failed = models.BooleanField(default=False)

View file

@ -1,6 +1,8 @@
from django.conf.urls.defaults import *
from django.conf.urls import url
urlpatterns = patterns('oxdata.poster.views',
(r'^$', 'poster'),
)
import views
urlpatterns = [
url(r'^$', views.poster),
]

View file

@ -1,19 +1,12 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
import os.path
from django.db import models
from django.db.models import Q
from django.contrib.auth.models import User
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404
from django.template import RequestContext
from oxdjango.shortcuts import render_to_json_response
from ox.django.shortcuts import render_to_json_response
from oxdata.lookup.models import MovieId
from oxdata.lookup.views import get_movie_id
from lookup.views import get_movie_id
import models
def poster(request):
movie_id = get_movie_id(request)
json = models.getPosters(movie_id, request.build_absolute_uri('/'))

View file

@ -2,11 +2,13 @@
# vi:si:et:sw=4:sts=4:ts=4
# Django settings for oxdata project.
import os
from os.path import join
from os.path import join, normpath, dirname
import djcelery
djcelery.setup_loader()
SITENAME = 'oxdata'
PROJECT_ROOT = os.path.normpath(os.path.dirname(__file__))
BASE_DIR = PROJECT_ROOT = normpath(dirname(__file__))
DEBUG = False
TEMPLATE_DEBUG = DEBUG
@ -30,7 +32,7 @@ DATABASES = {
# although not all choices may be available on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'Europe/Berlin'
TIME_ZONE = 'UTC'
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
@ -58,6 +60,23 @@ STATIC_ROOT = join(PROJECT_ROOT, 'static')
DATA_ROOT = join(PROJECT_ROOT, 'data')
CACHE_ROOT = join(PROJECT_ROOT, 'cache')
STATIC_URL = '/static/'
# Additional locations of static files
STATICFILES_DIRS = (
# Put strings here, like "/home/html/static" or "C:/www/django/static".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
# List of finder classes that know how to find static files in
# various locations.
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
#'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
os.environ['oxCACHE'] = 'fs:' + CACHE_ROOT
@ -71,38 +90,45 @@ MEDIA_URL = '/media/'
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/admin/media/'
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
'django.template.loaders.eggs.Loader',
)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
join(PROJECT_ROOT, 'templates'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
ROOT_URLCONF = 'oxdata.urls'
TEMPLATE_DIRS = (
join(PROJECT_ROOT, 'templates'),
)
ROOT_URLCONF = 'urls'
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.admin',
'django.contrib.humanize',
'south',
'django_extensions',
'djcelery',
'api',
'lookup',
'movie',
'poster',
@ -112,12 +138,12 @@ INSTALLED_APPS = (
LOGIN_REDIRECT_URL='/'
CELERY_RESULT_BACKEND = "database"
BROKER_HOST = "127.0.0.1"
BROKER_PORT = 5672
BROKER_USER = "oxdata"
BROKER_PASSWORD = "ox"
BROKER_VHOST = "/oxdata"
CELERY_RESULT_BACKEND = 'database'
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_ACCEPT_CONTENT = ['json']
BROKER_URL = 'amqp://oxdata:ox@localhost:5672//odata'
#Movie related settings
REVIEW_WHITELIST = {

File diff suppressed because one or more lines are too long

View file

@ -1,157 +0,0 @@
/***
Pandora API
***/
Ox.load('UI', {
hideScreen: false,
showScreen: true,
theme: 'classic'
}, function() {
var app = new Ox.App({
apiURL: '/api/',
}).bindEvent('load', function(data) {
app.default_info = '<div class="OxSelectable"><h2>Pan.do/ra API Overview</h2>use this api in the browser with <a href="/static/oxjs/demos/doc2/index.html#Ox.App">Ox.app</a> or use <a href="http://code.0x2620.org/pandora_client">pandora_client</a> it in python. Further description of the api can be found <a href="https://wiki.0x2620.org/wiki/pandora/API">on the wiki</a></div>';
app.$body = $('body');
app.$document = $(document);
app.$window = $(window);
//app.$body.html('');
Ox.UI.hideLoadingScreen();
app.$ui = {};
app.$ui.actionList = constructList();
app.$ui.actionInfo = Ox.Container().css({padding: '16px'}).html(app.default_info);
app.api.api({docs: true, code: true}, function(results) {
app.actions = results.data.actions;
if(document.location.hash) {
app.$ui.actionList.triggerEvent('select', {ids: document.location.hash.substring(1).split(',')});
}
});
var $left = new Ox.SplitPanel({
elements: [
{
element: new Ox.Element().append(new Ox.Element()
.html('API').css({
'padding': '4px',
})).css({
'background-color': '#ddd',
'font-weight': 'bold',
}),
size: 24
},
{
element: app.$ui.actionList
}
],
orientation: 'vertical'
});
var $main = new Ox.SplitPanel({
elements: [
{
element: $left,
size: 160
},
{
element: app.$ui.actionInfo,
}
],
orientation: 'horizontal'
});
$main.appendTo(app.$body);
});
function constructList() {
return new Ox.TextList({
columns: [
{
align: "left",
id: "name",
operator: "+",
title: "Name",
unique: true,
visible: true,
width: 140
},
],
columnsMovable: false,
columnsRemovable: false,
id: 'actionList',
items: function(data, callback) {
function _sort(a, b) {
if(a.name > b.name)
return 1;
else if(a.name == b.name)
return 0;
return -1;
}
if (!data.keys) {
app.api.api(function(results) {
var items = [];
Ox.forEach(results.data.actions, function(v, k) {
items.push({'name': k})
});
items.sort(_sort);
var result = {'data': {'items': items.length}};
callback(result);
});
} else {
app.api.api(function(results) {
var items = [];
Ox.forEach(results.data.actions, function(v, k) {
items.push({'name': k})
});
items.sort(_sort);
var result = {'data': {'items': items}};
callback(result);
});
}
},
scrollbarVisible: true,
sort: [
{
key: "name",
operator: "+"
}
]
}).bindEvent({
select: function(data) {
var info = $('<div>').addClass('OxSelectable'),
hash = '#';
if(data.ids.length)
data.ids.forEach(function(id) {
info.append($("<h2>").html(id));
var $doc =$('<pre>')
.html(app.actions[id].doc.replace('/\n/<br>\n/g'))
.appendTo(info);
var $code = $('<code class="python">')
.html(app.actions[id].code[1].replace('/\n/<br>\n/g'))
.hide();
var $button = new Ox.Button({
title: [
{id: "one", title: "right"},
{id: "two", title: "down"},
],
type: "image"
})
.addClass("margin")
.click(function() { $code.toggle()})
.appendTo(info)
var f = app.actions[id].code[0];
$('<span>').html(' View Source ('+f+')').appendTo(info)
$('<pre>').append($code).appendTo(info)
hash += id + ','
});
else
info.html(app.default_info);
document.location.hash = hash.substring(0, hash.length-1);
app.$ui.actionInfo.html(info);
}
});
}
});

View file

@ -0,0 +1 @@
404 not found

View file

@ -0,0 +1 @@
api

View file

@ -2,49 +2,50 @@
# vi:si:et:sw=4:sts=4:ts=4
import os
from django.conf.urls.defaults import *
from ox.django.http import HttpFileResponse
from django.conf.urls import url, include
from oxdjango.http import HttpFileResponse
from django.conf import settings
import django.views.static
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
from api import actions
actions.autodiscover()
import oxdjango.api.urls
import views
import poster.urls
import lookup.urls
def serve_static_file(path, location, content_type):
return HttpFileResponse(location, content_type=content_type)
urlpatterns = patterns('',
(r'^$', 'oxdata.views.index'),
(r'^api/$', include('api.urls')),
(r'^poster/', include('oxdata.poster.urls')),
(r'^still/$', 'oxdata.poster.views.still'),
(r'^id/', include('oxdata.lookup.urls')),
(r'^get/', include('oxdata.lookup.urls')),
(r'^robots.txt$', serve_static_file, {
urlpatterns = [
url(r'^$', views.index),
url(r'^api/?', include(oxdjango.api.urls)),
url(r'^poster/', include(poster.urls)),
url(r'^still/$', poster.views.still),
url(r'^id/', include(lookup.urls)),
url(r'^get/', include(lookup.urls)),
url(r'^robots.txt$', serve_static_file, {
'location': os.path.join(settings.STATIC_ROOT, 'robots.txt'),
'content_type': 'text/plain'
}),
(r'^favicon.ico$', serve_static_file, {
url(r'^favicon.ico$', serve_static_file, {
'location': os.path.join(settings.STATIC_ROOT, 'favicon.ico'),
'content_type': 'image/x-icon'}),
# Uncomment the next line to enable the admin:
(r'^admin/', include(admin.site.urls)),
)
url(r'^admin/', include(admin.site.urls)),
]
if settings.DEBUG:
urlpatterns += patterns('',
(r'^media/(?P<path>.*)$', 'django.views.static.serve',
urlpatterns += [
url(r'^media/(?P<path>.*)$', django.views.static.serve,
{'document_root': settings.MEDIA_ROOT}),
(r'^static/(?P<path>.*)$', 'django.views.static.serve',
url(r'^static/(?P<path>.*)$', django.views.static.serve,
{'document_root': settings.STATIC_ROOT}),
)
]
#load local urls if present
try:

View file

@ -1,10 +1,7 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404
from django.template import RequestContext
from django.shortcuts import render
def index(request):
context = RequestContext(request, {})
return render_to_response('index.html', context)
return render(request, 'index.html', {})

16
oxdata/wsgi.py Normal file
View file

@ -0,0 +1,16 @@
"""
WSGI config for fixme project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
application = get_wsgi_application()

View file

@ -1,7 +1,6 @@
Django>=1.3.0,<1.4
South
-e bzr+http://code.0x2620.org/python-ox/#egg=python-ox
chardet
django-celery
gunicorn
-e git://github.com/bit/django-extensions.git#egg=django_extensions
Django==1.9.4
celery==3.1.20
django-celery==3.1.17
django-extensions==1.6.1
gunicorn==19.4.5
-e git+http://git.0x2620.org/python-ox.git#egg=python-ox

View file

@ -1,28 +0,0 @@
# django.wsgi
import os
import sys
import site
project_module = 'oxdata'
root_dir = os.path.normpath(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
#using virtualenv's activate_this.py to reorder sys.path
activate_this = os.path.join(root_dir, 'bin', 'activate_this.py')
execfile(activate_this, dict(__file__=activate_this))
sys.path.append(root_dir)
sys.path.append(os.path.join(root_dir, project_module))
#reload if this django.wsgi gets touched
from oxdjango import monitor
monitor.start(interval=1.0)
monitor.track(os.path.abspath(os.path.dirname(__file__)))
os.environ['DJANGO_SETTINGS_MODULE'] = project_module + '.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()