From 74f777e0d1f4fdd86efb082d8ee01b9f84f31687 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Tue, 18 Oct 2011 22:06:01 +0200 Subject: [PATCH 1/5] show selected/wanted files --- pandora/archive/models.py | 30 ++++++++++----------- pandora/archive/views.py | 30 +++++++++++++-------- pandora/item/models.py | 24 +++++++++++------ pandora/item/views.py | 32 ++++++++++++++++++++++ static/js/pandora/ui/filesView.js | 45 +++++++++++++++++++++++++++---- 5 files changed, 121 insertions(+), 40 deletions(-) diff --git a/pandora/archive/models.py b/pandora/archive/models.py index cee5e8d7..37552ee9 100644 --- a/pandora/archive/models.py +++ b/pandora/archive/models.py @@ -261,28 +261,26 @@ class File(models.Model): if resolution == (0, 0): resolution = None duration = self.duration - if self.get_type() != 'video': + if self.type != 'video': duration = None data = { + 'audioCodec': self.audio_codec, 'available': self.available, 'duration': duration, 'framerate': self.framerate, - #'height': self.height, - #'width': self.width, - 'resolution': resolution, 'id': self.oshash, - 'samplerate': self.samplerate, - 'video_codec': self.video_codec, - 'audio_codec': self.audio_codec, - 'path': self.path, - 'size': self.size, - #'info': self.info, - 'users': list(set([u.username - for u in User.objects.filter(volumes__files__in=self.instances.all())])), 'instances': [i.json() for i in self.instances.all()], - 'type': self.get_type(), - 'part': self.get_part() + 'part': self.part, + 'path': self.path, + 'resolution': resolution, + 'samplerate': self.samplerate, + 'selected': self.selected, + 'size': self.size, + 'type': self.type, + 'videoCodec': self.video_codec, + 'wanted': self.wanted, } + data['users'] = [i['user'] for i in data['instances']] if keys: for k in data.keys(): if k not in keys: @@ -290,7 +288,6 @@ class File(models.Model): return data def get_part(self): - #FIXME: this breaks for sub/idx/srt if os.path.splitext(self.path)[-1] in ('.sub', '.idx', '.srt'): name = os.path.splitext(self.path)[0] if self.language: @@ -388,9 +385,10 @@ class Instance(models.Model): def json(self): return { + 'ignore': self.ignore, + 'path': self.path, 'user': self.volume.user.username, 'volume': self.volume.name, - 'path': self.path } def frame_path(frame, name): diff --git a/pandora/archive/views.py b/pandora/archive/views.py index f8ac0b08..3a475b78 100644 --- a/pandora/archive/views.py +++ b/pandora/archive/views.py @@ -7,7 +7,7 @@ from datetime import datetime from django import forms from django.shortcuts import get_object_or_404, redirect from django.conf import settings -from django.db.models import Count, Sum +from django.db.models import Count import ox from ox.utils import json @@ -288,7 +288,8 @@ def editFile(request): param data { id: hash of file part: - id_extra: boolean + language: + ignore: boolean } return { @@ -297,17 +298,26 @@ def editFile(request): } } ''' - #FIXME: permissions, need to be checked data = json.loads(request.POST['data']) f = get_object_or_404_json(models.File, oshash=data['id']) response = json_response() - if data.keys() != ('id', ): - for key in data: - if key in ('is_extra', 'is_subtitle', 'is_video', 'is_version', - 'part', 'language'): + if f.editable(request.user): + update = False + #FIXME: should all instances be ignored? + if 'ignore' in data: + f.instances.update(ignore=True) + #FIXME: is this to slow to run sync? + f.item.update_selected() + for key in ('part', 'language'): + if key in data: setattr(f, key, data[key]) - f.auto = False - f.save() + f.auto = False + update = True + if update: + f.save() + response = json_response(status=200, text='updated') + else: + response = json_response(status=403, text='permissino denied') return render_to_json_response(response) actions.register(editFile, cache=False) @@ -415,8 +425,6 @@ Positions } ''' data = json.loads(request.POST['data']) - if settings.JSON_DEBUG: - print json.dumps(data, indent=2) query = parse_query(data, request.user) response = json_response({}) diff --git a/pandora/item/models.py b/pandora/item/models.py index 83889e21..e125a159 100644 --- a/pandora/item/models.py +++ b/pandora/item/models.py @@ -59,7 +59,7 @@ def get_id(info): if settings.DATA_SERVICE: r = external_data('getId', info) if r['status']['code'] == 200: - imdbId = r['data']['imdbId'] + imdbId = r['data']['id'] return imdbId return None @@ -542,6 +542,8 @@ class Item(models.Model): def set_value(s, name, value): if not value: value = None + if isinstance(value, basestring): + value = value.lower() setattr(s, name, value) base_keys = ( @@ -553,7 +555,7 @@ class Item(models.Model): 'lightness', 'volume', 'clips', - 'cuts', + 'numberofcuts', 'cutsperminute', 'words', 'wordsperminute', @@ -622,8 +624,8 @@ class Item(models.Model): # sort values based on data from videos s.words = sum([len(a.value.split()) for a in self.annotations.all()]) + s.clips= self.clips.count() - s.clips = 0 #FIXME: get clips from all layers or something videos = self.files.filter(selected=True, is_video=True) if videos.count() > 0: s.duration = sum([v.duration for v in videos]) @@ -657,9 +659,9 @@ class Item(models.Model): s.hue = None s.saturation = None s.brighness = None - s.cuts = len(self.data.get('cuts', [])) + s.numberofcuts = len(self.data.get('cuts', [])) if s.duration: - s.cutsperminute = s.cuts / (s.duration/60) + s.cutsperminute = s.numberofcuts / (s.duration/60) s.wordsperminute = s.words / (s.duration / 60) else: s.cutsperminute = None @@ -667,7 +669,6 @@ class Item(models.Model): s.popularity = self.accessed.aggregate(Sum('accessed'))['accessed__sum'] s.save() - def update_facets(self): #FIXME: what to do with Unkown Director, Year, Country etc. for key in self.facet_keys + ['title']: @@ -735,8 +736,10 @@ class Item(models.Model): return os.path.join(settings.MEDIA_ROOT, self.path(), 'timeline') def get_files(self, user): - #FIXME: limit by user - return [f.json() for f in self.files.all()] + files = self.files.all().select_related() + if user.get_profile().get_level() != 'admin': + files = files.filter(instances__volume__user=user) + return [f.json() for f in files] def users_with_files(self): return User.objects.filter( @@ -764,6 +767,7 @@ class Item(models.Model): for s in self.sets(): if s.filter(Q(is_video=True)|Q(is_audio=True)).filter(available=False).count() == 0: update = False + self.files.exclude(id__in=s).exclude(part=None).update(part=None) deselect = self.files.filter(selected=True).exclude(id__in=s) if deselect.count() > 0: deselect.update(selected=False) @@ -771,6 +775,10 @@ class Item(models.Model): if s.filter(selected=False).count() > 0: s.update(selected=True, wanted=False) update = True + for f in s: + if f.get_part() != f.part: + f.save() + update = True if update: self.rendered = False self.save() diff --git a/pandora/item/views.py b/pandora/item/views.py index 10d27363..745a8e56 100644 --- a/pandora/item/views.py +++ b/pandora/item/views.py @@ -326,6 +326,38 @@ def autocomplete(request): return render_to_json_response(response) actions.register(autocomplete) +def findId(request): + ''' + param data { + 'query': query, + 'sort': array, + 'range': array + } + + ''' + data = json.loads(request.POST['data']) + response = json_response({}) + response['data']['items'] = [] + ''' + FIXME: can not handle query for director [] + query = parse_query(data, request.user) + qs = _order_query(query['qs'], query['sort']) + if qs.count() == 1: + response['data']['items'] = [i.get_json(data['keys']) for i in qs] + elif settings.DATA_SERVICE: + ''' + if settings.DATA_SERVICE: + ''' + info = {} + for c in data['query']['conditions']: + info[c['key']] = c['value'] + r = models.external_data('getId', info) + ''' + r = models.external_data('getId', data) + if r['status']['code'] == 200: + response['data']['items'] = [r['data']] + return render_to_json_response(response) +actions.register(findId) def get(request): ''' diff --git a/static/js/pandora/ui/filesView.js b/static/js/pandora/ui/filesView.js index 16140b9b..bd307b56 100644 --- a/static/js/pandora/ui/filesView.js +++ b/static/js/pandora/ui/filesView.js @@ -45,13 +45,36 @@ pandora.ui.filesView = function(options, self) { self.$filesList = Ox.TextList({ columns: [ + { + format: function(value, data) { + Ox.print('File', value, data.wanted, data); + return $('') + .attr({ + src: data.wanted ? Ox.UI.getImageURL('symbolStar') : + Ox.UI.getImageURL('symbolCheck') + }) + .css({ + width: '10px', + height: '10px', + padding: '3px', + opacity: (value || data.wanted) ? 1 : 0 + }); + }, + id: 'selected', + operator: '-', + title: $('').attr({ + src: Ox.UI.getImageURL('symbolCheck') + }), + visible: true, + width: 16 + }, { align: 'left', id: 'users', operator: '+', title: 'Users', visible: true, - width: 120 + width: 50 }, { align: 'left', @@ -133,11 +156,12 @@ pandora.ui.filesView = function(options, self) { conditions: [{ key: 'id', value: self.options.id, - operator: '=' + operator: '==' }] } }), callback); }, + keys: ['wanted'], scrollbarVisible: true, sort: [{key: 'path', operator: '+'}] }) @@ -202,13 +226,14 @@ pandora.ui.filesView = function(options, self) { change: function(data) { var conditions; if (data.value.length) { + /* if (key == 'id') { - conditions = [{key: 'id', value: data.value, operator: '='}] + conditions = [{key: 'id', value: data.value, operator: '=='}] } else { conditions = Ox.map(['title', 'director', 'year'], function(key) { var value = self['$' + key + 'Input'].options('value') return value.length ? {key: key, value: value, operator: '='} : null; - }) + }); } pandora.api.find({ keys: ['title', 'director', 'year', 'id'], @@ -218,6 +243,15 @@ pandora.ui.filesView = function(options, self) { }, range: [0, 2] }, function(result) { + */ + conditions = {}; + Ox.map(['id', 'title', 'director', 'year'], function(key) { + var value = self['$' + key + 'Input'].options('value'); + if(value.length) { + conditions[key] = value; + } + }); + pandora.api.findId(conditions, function(result) { var length = result.data.items.length; if (length == 0) { if (key != 'id') { @@ -234,7 +268,7 @@ pandora.ui.filesView = function(options, self) { } else { self.$idInput.options({value: ''}); } - }) + }); } } }); @@ -345,6 +379,7 @@ pandora.ui.filesView = function(options, self) { } }); updateForm(); + self.$titleInput.triggerEvent('change', {value: result.data['title']}); }); } From 1c33fea5bb89a3a62d2345606df19d14d667f714 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Tue, 18 Oct 2011 22:30:32 +0200 Subject: [PATCH 2/5] part bug --- pandora/archive/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandora/archive/models.py b/pandora/archive/models.py index 37552ee9..f6199e8e 100644 --- a/pandora/archive/models.py +++ b/pandora/archive/models.py @@ -295,7 +295,7 @@ class File(models.Model): qs = self.item.files.filter(Q(is_video=True)|Q(is_audio=True), selected=True, path__startswith=name) if qs.count()>0: - return qs[0].part + return qs[0].get_part() if self.selected: files = list(self.item.files.filter(type=self.type, language=self.language, selected=self.selected).order_by('sort_path')) From 764e992fcc92cf5c70cdb4b49da32ab087713f3d Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Tue, 18 Oct 2011 23:02:30 +0200 Subject: [PATCH 3/5] status --- static/js/pandora/ui/status.js | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/static/js/pandora/ui/status.js b/static/js/pandora/ui/status.js index 0367e10b..1c80e082 100644 --- a/static/js/pandora/ui/status.js +++ b/static/js/pandora/ui/status.js @@ -1,13 +1,23 @@ // vim: et:ts=4:sw=4:sts=4:ft=javascript pandora.ui.status = function(key, data) { - var that = Ox.toTitleCase(key) + ': ' + [ - Ox.formatNumber(data.items) + ' '+ (data.items != 1 ? pandora.site.itemName.plural : pandora.site.itemName.singular), - Ox.formatDuration(data.runtime, 'short'), - data.files + ' file' + (data.files != 1 ? 's' : ''), - Ox.formatDuration(data.duration), - Ox.formatValue(data.size, 'B'), - Ox.formatValue(data.pixels, 'px') - ].join(', '); - return that; + var itemName = data.items != 1 ? pandora.site.itemName.plural : pandora.site.itemName.singular, + segments = [], + that = Ox.toTitleCase(key) + ': '; + if (!pandora.user.ui.item && pandora.user.ui.listView == 'clip') { + itemName = data.items != 1 ? 'Clips' : 'Clip'; + } + + segments.push(Ox.formatNumber(data.items) + ' '+ itemName); + if (data.runtime) + segments.push(Ox.formatDuration(data.runtime, 'short')); + if (data.files) + segments.push(data.files + ' file' + (data.files != 1 ? 's' : '')); + if (data.duration) + segments.push(Ox.formatDuration(data.duration)); + if (data.size) + segments.push(Ox.formatValue(data.size, 'B')); + if (data.pixels) + segments.push(Ox.formatValue(data.pixels, 'px')); + return that + segments.join(', '); }; From 24f94a092ec50e9f333083a95337f8413be9ac01 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Tue, 18 Oct 2011 23:28:58 +0200 Subject: [PATCH 4/5] email --- pandora/user/models.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pandora/user/models.py b/pandora/user/models.py index c1128eb0..3797c69b 100644 --- a/pandora/user/models.py +++ b/pandora/user/models.py @@ -33,11 +33,6 @@ class UserProfile(models.Model): info = DictField(default={}) notes = models.TextField(default='') - def get_preferences(self): - prefs = self.preferences - prefs['email'] = self.user.email - return prefs - def get_ui(self): return get_ui(self.ui, self.user) @@ -154,7 +149,7 @@ def init_user(user, request=None): result[key] = getattr(user, key) result['level'] = profile.get_level() result['groups'] = [g.name for g in user.groups.all()] - result['preferences'] = profile.get_preferences() + result['email'] = user.email result['ui'] = profile.get_ui() result['volumes'] = [v.json() for v in user.volumes.all()] return result From 45bb18ef9658704f21d310b0e652152c73707ed9 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Tue, 18 Oct 2011 23:41:54 +0200 Subject: [PATCH 5/5] editPreferences --- pandora/user/views.py | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/pandora/user/views.py b/pandora/user/views.py index 524e5e1b..8737a4af 100644 --- a/pandora/user/views.py +++ b/pandora/user/views.py @@ -577,29 +577,34 @@ def getPositionById(list, key): @login_required_json -def setPreferences(request): +def editPreferences(request): ''' param data { - key.subkey: value + key: value } + keys: email, password return ''' data = json.loads(request.POST['data']) - keys = re.sub('([^\\\\])\.', '\\1\n', data.keys()[0]).split('\n') - value = data.values()[0] - profile = request.user.get_profile() - p = profile.preferences - while len(keys)>1: - key = keys.pop(0) - if isinstance(p, list): - p = p[getPositionById(p, key)] - else: - p = p[key] - p[keys[0]] = value - profile.save() + errors = {} + change = False response = json_response() + if 'email' in data: + if models.User.objects.filter( + email=data['email']).exclude(username=request.user.username).count()>0: + errors['email'] = 'Email address already in use' + else: + change = True + request.user.email = data['email'] + if 'password' in data: + change = True + request.user.password = data['password'] + if change: + request.user.save() + if errors: + response = json_response({ 'errors': errors}) return render_to_json_response(response) -actions.register(setPreferences, cache=False) +actions.register(editPreferences, cache=False) def resetUI(request):