From cbd04a10c8382482b597c1c3c54efff243da9f4e Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Tue, 6 Sep 2011 08:06:59 -0400 Subject: [PATCH] site config, user level, item level --- pandora/annotation/views.py | 5 +++-- pandora/api/views.py | 3 +-- pandora/app/admin.py | 5 ----- pandora/app/models.py | 43 +++++++++++++++++++++++-------------- pandora/archive/models.py | 8 +++---- pandora/archive/views.py | 5 ++--- pandora/item/managers.py | 12 +++++++---- pandora/item/models.py | 41 ++++++++++++++++------------------- pandora/item/views.py | 4 +--- pandora/itemlist/models.py | 2 +- pandora/user/models.py | 13 +++++------ pandora/user/views.py | 3 +-- 12 files changed, 71 insertions(+), 73 deletions(-) diff --git a/pandora/annotation/views.py b/pandora/annotation/views.py index 11056fba..ee87cf51 100644 --- a/pandora/annotation/views.py +++ b/pandora/annotation/views.py @@ -2,13 +2,14 @@ # vi:si:et:sw=4:sts=4:ts=4 from __future__ import division +from django.conf import settings + import ox from ox.utils import json from ox.django.decorators import login_required_json from ox.django.shortcuts import render_to_json_response, get_object_or_404_json, json_response -from app.models import site_config from item.models import Item from api.actions import actions @@ -101,7 +102,7 @@ def addAnnotation(request): text='invalid data')) #FIXME: this should be only called starting up server - models.load_layers(site_config()['layers']) + models.load_layers(settings.CONFIG['layers']) item = get_object_or_404_json(Item, itemId=data['item']) layer = get_object_or_404_json(models.Layer, name=data['layer']) diff --git a/pandora/api/views.py b/pandora/api/views.py index 0817d472..9994a0ff 100644 --- a/pandora/api/views.py +++ b/pandora/api/views.py @@ -14,7 +14,6 @@ from ox.utils import json from user.models import get_user_json from item.models import ItemSort -from app.models import site_config from actions import actions @@ -55,7 +54,7 @@ def init(request): ''' #data = json.loads(request.POST['data']) response = json_response({}) - config = site_config() + config = settings.CONFIG.copy() del config['keys'] #is this needed? #populate max values for percent requests diff --git a/pandora/app/admin.py b/pandora/app/admin.py index 90cbd79f..c3ac69c7 100644 --- a/pandora/app/admin.py +++ b/pandora/app/admin.py @@ -11,8 +11,3 @@ class PageAdmin(admin.ModelAdmin): admin.site.register(models.Page, PageAdmin) - -class SiteSettingsAdmin(admin.ModelAdmin): - search_fields = ['key', 'value'] - -admin.site.register(models.SiteSettings, SiteSettingsAdmin) diff --git a/pandora/app/models.py b/pandora/app/models.py index 8cfe9794..b0c5f8a7 100644 --- a/pandora/app/models.py +++ b/pandora/app/models.py @@ -2,11 +2,15 @@ # vi:si:et:sw=4:sts=4:ts=4 from __future__ import division, with_statement import os +import sys +import time +import thread from django.db import models from django.conf import settings from ox.utils import json +_win = (sys.platform == "win32") class Page(models.Model): created = models.DateTimeField(auto_now_add=True) @@ -17,24 +21,31 @@ class Page(models.Model): def __unicode__(self): return self.name +RUN_RELOADER = True -class SiteSettings(models.Model): - key = models.CharField(max_length=1024, unique=True) - value = models.TextField(blank=True) +def reloader_thread(): + _config_mtime = 0 + while RUN_RELOADER: + stat = os.stat(settings.SITE_CONFIG) + mtime = stat.st_mtime + if _win: + mtime -= stat.st_ctime + if mtime > _config_mtime: + with open(settings.SITE_CONFIG) as f: + config = json.load(f) - def __unicode__(self): - return self.key + config['site']['id'] = settings.SITEID + config['site']['name'] = settings.SITENAME + config['site']['sectionName'] = settings.SITENAME + config['site']['url'] = settings.URL -def site_config(): - with open(settings.SITE_CONFIG) as f: - site_config = json.load(f) + config['keys'] = {} + for key in config['itemKeys']: + config['keys'][key['id']] = key - site_config['site']['id'] = settings.SITEID - site_config['site']['name'] = settings.SITENAME - site_config['site']['sectionName'] = settings.SITENAME - site_config['site']['url'] = settings.URL + settings.CONFIG = config + _config_mtime = mtime + time.sleep(1) + +thread.start_new_thread(reloader_thread, ()) - site_config['keys'] = {} - for key in site_config['itemKeys']: - site_config['keys'][key['id']] = key - return site_config diff --git a/pandora/archive/models.py b/pandora/archive/models.py index 820036cf..7b639370 100644 --- a/pandora/archive/models.py +++ b/pandora/archive/models.py @@ -17,7 +17,6 @@ import ox from ox.normalize import canonicalTitle import chardet -from app.models import site_config from item import utils from person.models import get_name_sort @@ -237,12 +236,11 @@ class File(models.Model): return srt def editable(self, user): - #FIXME: check that user has instance of this file - return True + return self.instances.filter(volume__user=user).count() > 0 def save_chunk(self, chunk, chunk_id=-1, done=False): if not self.available: - config = site_config()['video'] + config = settings.CONFIG['video'] stream, created = Stream.objects.get_or_create( file=self, resolution=config['resolutions'][0], @@ -485,7 +483,7 @@ class Stream(models.Model): return self.file.path(name) def extract_derivatives(self): - config = site_config()['video'] + config = settings.CONFIG['video'] for resolution in config['resolutions']: for f in config['formats']: derivative, created = Stream.objects.get_or_create(file=self.file, diff --git a/pandora/archive/views.py b/pandora/archive/views.py index e74c33ee..4d0ce26a 100644 --- a/pandora/archive/views.py +++ b/pandora/archive/views.py @@ -14,7 +14,6 @@ from ox.django.decorators import login_required_json from ox.django.shortcuts import render_to_json_response, get_object_or_404_json, json_response from ox.django.views import task_status -from app.models import site_config from item import utils from item.models import get_item, Item from item.views import parse_query @@ -114,7 +113,7 @@ actions.register(update, cache=False) @login_required_json def encodingProfile(request): - config = site_config()['video'] + config = settings.CONFIG['video'] profile = "%sp.%s" % (config['resolutions'][0], config['formats'][0]) response = json_response({'profile': profile}) return render_to_json_response(response) @@ -172,7 +171,7 @@ class VideoChunkForm(forms.Form): def firefogg_upload(request): profile = request.GET['profile'] oshash = request.GET['id'] - config = site_config()['video'] + config = settings.CONFIG['video'] video_profile = "%sp.%s" % (config['resolutions'][0], config['formats'][0]) #handle video upload diff --git a/pandora/item/managers.py b/pandora/item/managers.py index ee7412b3..67d7b03a 100644 --- a/pandora/item/managers.py +++ b/pandora/item/managers.py @@ -3,9 +3,11 @@ from datetime import datetime from django.db.models import Q, Manager +from django.conf import settings from itemlist.models import List import models + from ox.django.query import QuerySet def parseCondition(condition): @@ -43,7 +45,7 @@ def parseCondition(condition): else: return q - key_type = models.site_config()['keys'].get(k, {'type':'string'}).get('type') + key_type = settings.config['keys'].get(k, {'type':'string'}).get('type') if isinstance(key_type, list): key_type = key_type[0] key_type = { @@ -245,9 +247,11 @@ class ItemManager(Manager): #anonymous can only see public items if user.is_anonymous(): - qs = qs.filter(public=True) + allowed_level = settings.config['capabilities']['canSeeItem']['guest'] + qs = qs.filter(level__lte=allowed_level) #users can see public items, there own items and items of there groups - elif not user.is_staff: - qs = qs.filter(Q(public=True)|Q(user=user)|Q(groups__in=user.groups.all())) + else: + allowed_level = settings.config['capabilities']['canSeeItem'][user.get_profile().get_level()] + qs = qs.filter(Q(level__lte=allowed_level)|Q(user=user)|Q(groups__in=user.groups.all())) #admins can see all available items return qs diff --git a/pandora/item/models.py b/pandora/item/models.py index 76ff7d2f..361f0452 100644 --- a/pandora/item/models.py +++ b/pandora/item/models.py @@ -37,7 +37,6 @@ from annotation.models import Annotation, Layer import archive.models from person.models import get_name_sort -from app.models import site_config def get_item(info, user=None, async=False): @@ -129,7 +128,7 @@ class Item(models.Model): #while metadata is updated, files are set to rendered=False rendered = models.BooleanField(default=False, db_index=True) - public = models.BooleanField(default=False, db_index=True) + level = models.IntegerField(default=False, db_index=True) itemId = models.CharField(max_length=128, unique=True, blank=True) oxdbId = models.CharField(max_length=42, unique=True, blank=True, null=True) @@ -163,11 +162,11 @@ class Item(models.Model): return default def access(self, user): - #check rights level - if self.public: + allowed_level = settings.CONFIG['capabilities']['canSeeItem'][user.get_profile().get_level()] + if self.level < allowed_level: return True elif user.is_authenticated() and \ - (user.is_staff or self.user == user or \ + (self.user == user or \ self.groups.filter(id__in=user.groups.all()).count() > 0): return True return False @@ -414,7 +413,7 @@ class Item(models.Model): } i.update(self.external_data) i.update(self.data) - for k in site_config()['itemKeys']: + for k in settings.CONFIG['itemKeys']: key = k['id'] if not keys or key in keys: if key not in i: @@ -483,7 +482,7 @@ class Item(models.Model): else: f.delete() - for key in site_config()['itemKeys']: + for key in settings.CONFIG['itemKeys']: if key.get('find'): i = key['id'] if i == 'title': @@ -514,7 +513,7 @@ class Item(models.Model): values = [] for k in map(lambda x: x['id'], filter(lambda x: x.get('sort') == 'person', - config['itemKeys'])): + settings.CONFIG['itemKeys'])): values += self.get(k, []) else: values = self.get(key, '') @@ -566,7 +565,7 @@ class Item(models.Model): 'popularity', ) - for key in filter(lambda k: 'columnWidth' in k, config['itemKeys']): + for key in filter(lambda k: 'columnWidth' in k, settings.CONFIG['itemKeys']): name = key['id'] source = name sort_type = key.get('sort', key['type']) @@ -619,10 +618,9 @@ class Item(models.Model): s.published = self.published # sort values based on data from videos - s.words = 0 #FIXME: get words from all layers or something - s.wordsperminute = 0 + s.words = sum([len(a.value.split()) for a in self.annotations.all()]) + s.clips = 0 #FIXME: get clips from all layers or something - s.popularity = 0 #FIXME: get popularity from somewhere videos = self.files.filter(active=True, is_video=True) if videos.count() > 0: s.duration = sum([v.duration for v in videos]) @@ -656,8 +654,10 @@ class Item(models.Model): s.cuts = len(self.data.get('cuts', [])) if s.duration: s.cutsperminute = s.cuts / (s.duration/60) + s.wordsperminute = s.words / (s.duration / 60) else: s.cutsperminute = None + s.wordsperminute = None s.popularity = self.accessed.aggregate(Sum('accessed'))['accessed__sum'] s.save() @@ -679,7 +679,7 @@ class Item(models.Model): current_values = [] for k in map(lambda x: x['id'], filter(lambda x: x.get('sort') == 'person', - config['itemKeys'])): + settings.CONFIG['itemKeys'])): current_values += self.get(k, []) if not isinstance(current_values, list): current_values = [unicode(current_values)] @@ -852,7 +852,6 @@ class Item(models.Model): file__item=self, file__is_video=True, file__active=True).order_by('file__part') def update_timeline(self, force=False): - config = site_config() streams = self.streams() self.make_timeline() self.data['cuts'] = extract.cuts(self.timeline_prefix) @@ -862,7 +861,7 @@ class Item(models.Model): self.make_local_poster() self.make_poster() self.make_icon() - if config['video']['download']: + if settings.CONFIG['video']['download']: self.make_torrent() self.load_subtitles() self.rendered = streams != [] @@ -999,7 +998,7 @@ class Item(models.Model): if frames and len(frames) > int(self.poster_frame): return frames[int(self.poster_frame)]['path'] else: - size = site_config()['video']['resolutions'][0] + size = settings.CONFIG['video']['resolutions'][0] return self.frame(self.poster_frame, size) if frames: @@ -1068,15 +1067,13 @@ def delete_item(sender, **kwargs): i.delete_files() pre_delete.connect(delete_item, sender=Item) -config = site_config() - Item.facet_keys = [] -for key in config['itemKeys']: +for key in settings.CONFIG['itemKeys']: if 'autocomplete' in key and not 'autocompleteSortKey' in key: Item.facet_keys.append(key['id']) Item.person_keys = [] -for key in config['itemKeys']: +for key in settings.CONFIG['itemKeys']: if 'sort' in key and key['sort'] == 'person': Item.person_keys.append(key['id']) @@ -1098,14 +1095,14 @@ class ItemFind(models.Model): return u"%s=%s" % (self.key, self.value) ''' ItemSort -table constructed based on info in site_config['itemKeys'] +table constructed based on info in settings.CONFIG['itemKeys'] ''' attrs = { '__module__': 'item.models', 'item': models.OneToOneField('Item', related_name='sort', primary_key=True), 'duration': models.FloatField(null=True, blank=True, db_index=True), } -for key in filter(lambda k: 'columnWidth' in k, config['itemKeys']): +for key in filter(lambda k: 'columnWidth' in k, settings.CONFIG['itemKeys']): name = key['id'] name = {'id': 'itemId'}.get(name, name) sort_type = key.get('sort', key['type']) diff --git a/pandora/item/views.py b/pandora/item/views.py index 1912fcf9..38d76d28 100644 --- a/pandora/item/views.py +++ b/pandora/item/views.py @@ -288,8 +288,7 @@ def autocomplete(request): data['range'] = [0, 10] op = data.get('operator', '') - site_config = models.site_config() - key = site_config['keys'][data['key']] + key = settings.CONFIG['keys'][data['key']] order_by = key.get('autocompleteSortKey', False) if order_by: order_by = '-sort__%s' % order_by @@ -452,7 +451,6 @@ def setPosterFrame(request): #parse path and return info data = json.loads(request.POST['data']) item = get_object_or_404_json(models.Item, itemId=data['id']) if item.editable(request.user): - #FIXME: some things need to be updated after changing this item.poster_frame = data['position'] item.save() tasks.update_poster(item.itemId) diff --git a/pandora/itemlist/models.py b/pandora/itemlist/models.py index d55c936f..6c66be98 100644 --- a/pandora/itemlist/models.py +++ b/pandora/itemlist/models.py @@ -25,7 +25,7 @@ class List(models.Model): status = models.CharField(max_length=20, default='private') _status = ['private', 'public', 'featured'] query = DictField(default={"static": True}) - type= models.CharField(max_length=255, default='static') + type = models.CharField(max_length=255, default='static') description = models.TextField(default='') icon = models.ImageField(default=None, blank=True, diff --git a/pandora/user/models.py b/pandora/user/models.py index 5fbe434d..126a12df 100644 --- a/pandora/user/models.py +++ b/pandora/user/models.py @@ -5,17 +5,18 @@ from datetime import datetime from django.contrib.auth.models import User from django.db import models from django.db.models import Max +from django.conf import settings from ox.django.fields import DictField -from app.models import site_config from itemlist.models import List, Position class UserProfile(models.Model): reset_token = models.TextField(blank=True, null=True, unique=True) - user = models.ForeignKey(User, unique=True) + user = models.ForeignKey(User, unique=True, related_name='profile') + level = models.IntegerField(default=1) files_updated = models.DateTimeField(default=datetime.now) newsletter = models.BooleanField(default=True) ui = DictField(default={}) @@ -28,7 +29,7 @@ class UserProfile(models.Model): def get_ui(self): ui = {} - config = site_config() + config = settings.CONFIG.copy() ui.update(config['user']['ui']) def updateUI(ui, new): ''' @@ -82,11 +83,7 @@ class UserProfile(models.Model): return ui def get_level(self): - if self.user.is_superuser: - return 'admin' - elif self.user.is_staff: - return 'staff' - return 'member' + return ['guest', 'member', 'staff', 'admin'][self.level] def user_post_save(sender, instance, **kwargs): profile, new = UserProfile.objects.get_or_create(user=instance) diff --git a/pandora/user/views.py b/pandora/user/views.py index 0f44ad96..827c938e 100644 --- a/pandora/user/views.py +++ b/pandora/user/views.py @@ -18,7 +18,6 @@ import ox import models from api.actions import actions -from app.models import site_config from item.models import Access, Item class SigninForm(forms.Form): @@ -101,7 +100,7 @@ def signout(request): response = json_response(text='logged out') logout(request) - response['data']['user'] = site_config()['user'] + response['data']['user'] = settings.CONFIG['user'] return render_to_json_response(response) actions.register(signout, cache=False)