# HG changeset patch # User ymh # Date 1358957996 -3600 # Node ID 2e086097cb5db0da76a591ff2a402f05cd10633a # Parent 09c1d515b5627821502ac3bbd90e762cefaaa679# Parent cb83b868164a4795345f7a87ad9291c97725740d Merge with cb83b868164a4795345f7a87ad9291c97725740d diff -r cb83b868164a -r 2e086097cb5d .hgtags --- a/.hgtags Wed Jan 02 17:21:19 2013 +0100 +++ b/.hgtags Wed Jan 23 17:19:56 2013 +0100 @@ -137,3 +137,11 @@ a6a37775a76dd0a1aa56b61172ada2422fd99b14 V01.37 5a9f718115d38140a9dcd4ba8d650a1de13f6aa0 V01.38 0897d4ffdbc96f9cfb4b9c9b6e4f27dbebf8331a V01.39 +7fa1389a1d1da6f78f1509733874baf13647e960 V01.40 +57bb8c9fe1ff60b3a3e5d21a647e724b8cb18a45 V01.41 +726f2cf3f020c6d4dd1075acb6b94de2dbec5685 V01.42 +c4d6ddd5f718d1e55441247aa4c4366a5d7be470 V01.43 +996bb5b1adbc920f8ecb49f9d7b45f51a8aa3c04 V01.44 +62be1eedf90855ab3cef1ab8a9f0c66130638673 V01.45 +e1b6be4d85a47f4cecce2cf6e88ff190301bd8dc V01.46 +86dbc665226d08c082a559b2c218efcd56105c69 V01.47 diff -r cb83b868164a -r 2e086097cb5d .settings/org.eclipse.core.resources.prefs --- a/.settings/org.eclipse.core.resources.prefs Wed Jan 02 17:21:19 2013 +0100 +++ b/.settings/org.eclipse.core.resources.prefs Wed Jan 23 17:19:56 2013 +0100 @@ -1,43 +1,45 @@ -eclipse.preferences.version=1 -encoding//src/ldt/ldt/core/migrations/0001_initial.py=utf-8 -encoding//src/ldt/ldt/core/migrations/0002_auto__del_owner.py=utf-8 -encoding//src/ldt/ldt/indexation/backends/elasticsearch_backend.py=utf-8 -encoding//src/ldt/ldt/indexation/highlighter.py=utf-8 -encoding//src/ldt/ldt/indexation/models.py=utf-8 -encoding//src/ldt/ldt/indexation/query_parser.py=utf-8 -encoding//src/ldt/ldt/indexation/search_indexes.py=utf-8 -encoding//src/ldt/ldt/indexation/tests.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0001_initial.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0002_auto__add_field_media_mimetype_field__chg_field_media_external_src_url.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0003_auto__chg_field_project_owner.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0004_auto__add_field_project_description.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0005_add_permissions.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0006_auto__add_field_media_image.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0007_auto__add_field_content_image__del_field_media_image.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0008_auto__add_field_project_image.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0009_auto__chg_field_content_image__chg_field_project_image.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0010_auto__add_annotationstat.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0011_gen_stat_annotation.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0012_auto__add_field_content_last_annotated.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0013_auto__add_field_content_front_project__chg_field_content_last_annotate.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0014_auto__del_annotationstat__chg_field_content_last_annotated.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0015_auto__add_contentstat__del_field_content_last_annotated__del_field_con.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0016_one_to_one_stat_annotation.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0017_correct_image_path.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0018_auto__chg_field_content_iri_id__chg_field_project_ldt_id__chg_field_au.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0019_recalculate_media_hash_src.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0020_auto__add_field_segment_id_hash__chg_field_segment_iri_id__chg_field_s.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0021_recalculate_segment_id_hash_script.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0022_auto__add_unique_media_src_hash__chg_field_segment_cutting_id__chg_fie.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0023_auto__add_field_segment_audio_src__add_field_segment_audio_href.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0024_auto__chg_field_tag_name.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0025_chg_site_domain.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/migrations/0026_set_relative_ldtproject.py=utf-8 -encoding//src/ldt/ldt/ldt_utils/views/json.py=utf-8 -encoding//src/ldt/ldt/management/utils.py=utf-8 -encoding//src/ldt/ldt/test/test_runner.py=utf-8 -encoding//src/ldt/ldt/text/migrations/0001_initial.py=utf-8 -encoding//src/ldt/ldt/user/migrations/0001_initial.py=utf-8 -encoding//src/ldt/ldt/user/migrations/0008_auto__chg_field_groupprofile_image__chg_field_groupprofile_group__chg_.py=utf-8 -encoding//virtualenv/web/env/guardianenv/Lib/site-packages/guardian/migrations/0001_initial.py=utf-8 -encoding/=UTF-8 +eclipse.preferences.version=1 +encoding//src/ldt/ldt/core/migrations/0001_initial.py=utf-8 +encoding//src/ldt/ldt/core/migrations/0002_auto__del_owner.py=utf-8 +encoding//src/ldt/ldt/indexation/backends/elasticsearch_backend.py=utf-8 +encoding//src/ldt/ldt/indexation/highlighter.py=utf-8 +encoding//src/ldt/ldt/indexation/models.py=utf-8 +encoding//src/ldt/ldt/indexation/query_parser.py=utf-8 +encoding//src/ldt/ldt/indexation/search_indexes.py=utf-8 +encoding//src/ldt/ldt/indexation/tests.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/events.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0001_initial.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0002_auto__add_field_media_mimetype_field__chg_field_media_external_src_url.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0003_auto__chg_field_project_owner.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0004_auto__add_field_project_description.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0005_add_permissions.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0006_auto__add_field_media_image.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0007_auto__add_field_content_image__del_field_media_image.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0008_auto__add_field_project_image.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0009_auto__chg_field_content_image__chg_field_project_image.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0010_auto__add_annotationstat.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0011_gen_stat_annotation.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0012_auto__add_field_content_last_annotated.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0013_auto__add_field_content_front_project__chg_field_content_last_annotate.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0014_auto__del_annotationstat__chg_field_content_last_annotated.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0015_auto__add_contentstat__del_field_content_last_annotated__del_field_con.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0016_one_to_one_stat_annotation.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0017_correct_image_path.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0018_auto__chg_field_content_iri_id__chg_field_project_ldt_id__chg_field_au.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0019_recalculate_media_hash_src.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0020_auto__add_field_segment_id_hash__chg_field_segment_iri_id__chg_field_s.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0021_recalculate_segment_id_hash_script.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0022_auto__add_unique_media_src_hash__chg_field_segment_cutting_id__chg_fie.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0023_auto__add_field_segment_audio_src__add_field_segment_audio_href.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0024_auto__chg_field_tag_name.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0025_chg_site_domain.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/migrations/0026_set_relative_ldtproject.py=utf-8 +encoding//src/ldt/ldt/ldt_utils/views/json.py=utf-8 +encoding//src/ldt/ldt/management/commands/synciri.py=utf-8 +encoding//src/ldt/ldt/management/utils.py=utf-8 +encoding//src/ldt/ldt/test/test_runner.py=utf-8 +encoding//src/ldt/ldt/text/migrations/0001_initial.py=utf-8 +encoding//src/ldt/ldt/user/migrations/0001_initial.py=utf-8 +encoding//src/ldt/ldt/user/migrations/0008_auto__chg_field_groupprofile_image__chg_field_groupprofile_group__chg_.py=utf-8 +encoding//virtualenv/web/env/guardianenv/Lib/site-packages/guardian/migrations/0001_initial.py=utf-8 +encoding/=UTF-8 diff -r cb83b868164a -r 2e086097cb5d src/ldt/ldt/__init__.py --- a/src/ldt/ldt/__init__.py Wed Jan 02 17:21:19 2013 +0100 +++ b/src/ldt/ldt/__init__.py Wed Jan 23 17:19:56 2013 +0100 @@ -1,4 +1,4 @@ -VERSION = (1, 39, 0, "final", 0) +VERSION = (1, 47, 0, "final", 0) def get_version(): diff -r cb83b868164a -r 2e086097cb5d src/ldt/ldt/api/ldt/authentication.py --- a/src/ldt/ldt/api/ldt/authentication.py Wed Jan 02 17:21:19 2013 +0100 +++ b/src/ldt/ldt/api/ldt/authentication.py Wed Jan 23 17:19:56 2013 +0100 @@ -2,6 +2,12 @@ from django.middleware.csrf import _sanitize_token, constant_time_compare from django.utils.http import same_origin from tastypie.authentication import Authentication +from tastypie.http import HttpUnauthorized +from django.contrib.auth.models import User +from django.contrib.auth import login +from ldt.security import set_current_user + + # imported from tastypie's next version 0.9.12 class SessionAuthentication(Authentication): @@ -58,4 +64,138 @@ if request.user: return request.user.username else: - return "anon." \ No newline at end of file + return "anon." + +# imported from tastypie's next version 1.0.0 +class MultiAuthentication(object): + """ + An authentication backend that tries a number of backends in order. + """ + def __init__(self, *backends, **kwargs): + super(MultiAuthentication, self).__init__(**kwargs) + self.backends = backends + + def is_authenticated(self, request, **kwargs): + """ + Identifies if the user is authenticated to continue or not. + + Should return either ``True`` if allowed, ``False`` if not or an + ``HttpResponse`` if you need something custom. + """ + unauthorized = False + + for backend in self.backends: + check = backend.is_authenticated(request, **kwargs) + + if check: + if isinstance(check, HttpUnauthorized): + unauthorized = unauthorized or check + else: + request._authentication_backend = backend + return check + + return unauthorized + + def get_identifier(self, request): + """ + Provides a unique string identifier for the requestor. + + This implementation returns a combination of IP address and hostname. + """ + try: + return request._authentication_backend.get_identifier(request) + except AttributeError: + return 'anon.' + +class ApiKeyAuthentication(Authentication): + """ + Handles API key auth, in which a user provides a username & API key. + + Uses the ``ApiKey`` model that ships with tastypie. If you wish to use + a different model, override the ``get_key`` method to perform the key check + as suits your needs. + """ + def __init__(self, require_active=True): + self.require_active = require_active + + def _unauthorized(self): + return HttpUnauthorized() + + def extract_credentials(self, request): + if request.META.get('HTTP_AUTHORIZATION') and request.META['HTTP_AUTHORIZATION'].lower().startswith('apikey '): + (auth_type, data) = request.META['HTTP_AUTHORIZATION'].split() + + if auth_type.lower() != 'apikey': + raise ValueError("Incorrect authorization header.") + + username, api_key = data.split(':', 1) + else: + username = request.GET.get('username') or request.POST.get('username') + api_key = request.GET.get('api_key') or request.POST.get('api_key') + + return username, api_key + + def is_authenticated(self, request, **kwargs): + """ + Finds the user and checks their API key. + + Should return either ``True`` if allowed, ``False`` if not or an + ``HttpResponse`` if you need something custom. + """ + + try: + username, api_key = self.extract_credentials(request) + except ValueError: + return self._unauthorized() + + if not username or not api_key: + return self._unauthorized() + + try: + user = User.objects.get(username=username) + except (User.DoesNotExist, User.MultipleObjectsReturned): + return self._unauthorized() + + if not self.check_active(user): + return False + user.backend = "django.contrib.auth.backends.ModelBackend" + request.user = user + login(request,user) + set_current_user(user) + return self.get_key(user, api_key) + + def check_active(self, user): + """ + Ensures the user has an active account. + + Optimized for the ``django.contrib.auth.models.User`` case. + """ + if not self.require_active: + # Ignore & move on. + return True + + return user.is_active + + + def get_key(self, user, api_key): + """ + Attempts to find the API key for the user. Uses ``ApiKey`` by default + but can be overridden. + """ + from tastypie.models import ApiKey + + try: + ApiKey.objects.get(user=user, key=api_key) + except ApiKey.DoesNotExist: + return self._unauthorized() + + return True + + def get_identifier(self, request): + """ + Provides a unique string identifier for the requestor. + + This implementation returns the user's username. + """ + username, api_key = self.extract_credentials(request) + return username or 'nouser' \ No newline at end of file diff -r cb83b868164a -r 2e086097cb5d src/ldt/ldt/api/ldt/resources/annotation.py --- a/src/ldt/ldt/api/ldt/resources/annotation.py Wed Jan 02 17:21:19 2013 +0100 +++ b/src/ldt/ldt/api/ldt/resources/annotation.py Wed Jan 23 17:19:56 2013 +0100 @@ -7,14 +7,16 @@ from tastypie.exceptions import NotFound, BadRequest from tastypie.resources import Resource import logging #@UnresolvedImport +from ldt.ldt_utils.contentindexer import add_segment class AnnotationObject(object): - def __init__(self, id="", project = "", type = "", type_title = "", media = "", begin = 0, end = 0, content = {"title":"", "description":""}, tags = [], meta = {"creator":"","created":""}): + def __init__(self, id="", project = "", type = "", type_title = "", ensemble="", media = "", begin = 0, end = 0, content = {"title":"", "description":""}, tags = [], meta = {"creator":"","created":""}): self.id = id self.project = project self.type = type self.type_title = type_title + self.ensemble = ensemble self.media = media self.begin = begin self.end = end @@ -86,25 +88,44 @@ author = meta['creator'] date = meta['created'] # add(media, cutting_id, cutting_title, title, text, tags_list, begin, dur, author, date - type_id, new_id = adder.add(a['media'], a['type'], a['type_title'], a['content']['title'], a['content']['description'], a['tags'], begin, dur, author, date, None, "2194379", audio_src, audio_href) + type_id, new_id, ensemble_id = adder.add(a['media'], a['type'], a['type_title'], a['content']['title'], a['content']['description'], a['tags'], begin, dur, author, date, None, "2194379", audio_src, audio_href) if not new_id: protect_models() raise BadRequest content = project.contents.get(iri_id=a['media']) - add_annotation_to_stat(content, a['begin'], a['end']) # We update the ids a['type'] = type_id + a['ensemble'] = ensemble_id a['id'] = new_id if not a['content'].has_key('audio') : a['content']['audio'] = {'src':audio_src, 'href':audio_href} + + #add segment + add_segment({ + "project" : project, + "content" : content, + "ensemble_id" : ensemble_id, + "cutting_id" : a['type'], + "element_id" : new_id, + "title" : a['content']['title'], + "abstract" : a['content']['description'], + "tags" : ",".join(a['tags']), + "start_ts" : begin, + "duration" : dur, + "author" : author, + "date" : date, + "audio_src" : audio_src, + "audio_href" : audio_href, + "polemics": adder.get_polemic_syntax(a['content']['title']) + }) # We save the added annotation and reprotect the contents and projects - adder.save() + adder.save(must_reindex=False) protect_models() # We update the AnnotationObject for the returned datas to be correct. - bundle.obj = AnnotationObject(id = a["id"], project = a["project"], type = a["type"], type_title = a["type_title"], media = a["media"], begin = a["begin"], end = a["end"], content = a['content'], tags = a['tags'], meta = a['meta']) + bundle.obj = AnnotationObject(id = a["id"], project = a["project"], type = a["type"], type_title = a["type_title"], ensemble=a['ensemble'], media = a["media"], begin = a["begin"], end = a["end"], content = a['content'], tags = a['tags'], meta = a['meta']) return bundle def get_resource_uri(self, bundle_or_obj): diff -r cb83b868164a -r 2e086097cb5d src/ldt/ldt/api/ldt/resources/project.py --- a/src/ldt/ldt/api/ldt/resources/project.py Wed Jan 02 17:21:19 2013 +0100 +++ b/src/ldt/ldt/api/ldt/resources/project.py Wed Jan 23 17:19:56 2013 +0100 @@ -3,7 +3,7 @@ from django.contrib.auth.models import Group from guardian.shortcuts import assign from ldt.ldt_utils.models import Project -from ldt.api.ldt.authentication import SessionAuthentication +from ldt.api.ldt.authentication import SessionAuthentication, MultiAuthentication, ApiKeyAuthentication from ldt.api.ldt.serializers.cinelabserializer import CinelabSerializer from ldt.api.ldt.resources import ContentResource from ldt.api.ldt.resources.user import UserResource @@ -11,21 +11,23 @@ from tastypie.authorization import Authorization from tastypie.resources import Bundle, ModelResource, ALL from tastypie import fields +from tastypie.exceptions import BadRequest class ProjectResource(ModelResource): contents = fields.ManyToManyField(ContentResource, 'contents') owner = fields.ForeignKey(UserResource, 'owner') class Meta: - allowed_methods = ['get', 'post'] + allowed_methods = ['get', 'post', 'put'] authorization = Authorization() # BE CAREFUL WITH THAT, it's unsecure - authentication = SessionAuthentication() + authentication = MultiAuthentication(ApiKeyAuthentication(), SessionAuthentication()) resource_name = 'projects' queryset = Project.objects.all() serializer = CinelabSerializer() filtering = { 'state' : ALL, - 'ldt_id' : ALL + 'ldt_id' : ALL, + 'title' : ALL } # In the future version : # detail_uri_name = 'ldt_id' @@ -62,4 +64,7 @@ assign('ldt_utils.view_project', everyone, bundle.obj) protect_models() return bundle + + def obj_delete_list(self, request=None, **kwargs): + raise BadRequest("PUT with a list of projects is forbidden.") \ No newline at end of file diff -r cb83b868164a -r 2e086097cb5d src/ldt/ldt/api/ldt/resources/tag.py --- a/src/ldt/ldt/api/ldt/resources/tag.py Wed Jan 02 17:21:19 2013 +0100 +++ b/src/ldt/ldt/api/ldt/resources/tag.py Wed Jan 23 17:19:56 2013 +0100 @@ -26,15 +26,21 @@ # Search by content ids is priori content_ids = request.GET.get('contents', '') segment_ids = request.GET.get('segments', '') + # We define the number of steps in weight int + try: + weight_steps = int(request.GET.get('steps', 10)) + except: + weight_steps = 10 tags_cloud = None - if content_ids != "": + if content_ids=="all" or segment_ids=="all": + tags_cloud = Tag.objects.cloud_for_model(Segment, steps=weight_steps) + elif content_ids != "": # We get all the segments for these contents content_ids = content_ids.split(',') - tags_cloud = Tag.objects.cloud_for_model(Segment, filters={"iri_id__in":content_ids}) - if not all_segments and segment_ids != "": + tags_cloud = Tag.objects.cloud_for_model(Segment, filters={"iri_id__in":content_ids}, steps=weight_steps) + elif not all_segments and segment_ids != "": segment_ids = segment_ids.split(',') - tags_cloud = Tag.objects.cloud_for_model(Segment, filters={"element_id__in":segment_ids}) - + tags_cloud = Tag.objects.cloud_for_model(Segment, filters={"element_id__in":segment_ids}, steps=weight_steps) limit = request.GET.get('limit', getattr(settings, 'API_LIMIT_PER_PAGE', 20)) if limit == "0": @@ -52,10 +58,16 @@ bundle = self.build_bundle(obj=tag, request=request) bundle = self.full_dehydrate(bundle) objects.append(bundle) - + object_list = { 'objects': objects, } self.log_throttled_access(request) - return self.create_response(request, object_list) \ No newline at end of file + return self.create_response(request, object_list) + + def dehydrate(self, bundle): + # This function enable to add the weight of a tag in the bundle's datas, which is not in the tag model + if bundle.obj and hasattr(bundle.obj,'font_size'): + bundle.data['weight'] = bundle.obj.font_size + return bundle \ No newline at end of file diff -r cb83b868164a -r 2e086097cb5d src/ldt/ldt/forms/fields.py --- a/src/ldt/ldt/forms/fields.py Wed Jan 02 17:21:19 2013 +0100 +++ b/src/ldt/ldt/forms/fields.py Wed Jan 23 17:19:56 2013 +0100 @@ -4,6 +4,7 @@ from django import forms from django.utils.translation import ugettext_lazy as _ +from django.core.exceptions import ValidationError import logging import time import math @@ -13,16 +14,21 @@ ) class LdtDurationField (forms.TimeField): + """ + A field allowing to enter the duration format (eg: XhMM, XXhMM, HH:MM:SS) + """ + default_error_messages = { - 'invalid': _(u'Enter a valid duration format'), + 'required': _(u'The duration field can not be empty.'), + 'invalid': _(u'Enter a valid duration format;'), } def __init__(self, formats, *args, **kwargs): self.formats = formats super(LdtDurationField, self).__init__(*args, **kwargs) - def clean(self, data): - dur = data + def to_python(self, value): + dur = value for format in self.formats: try: dur = time.strptime(dur, format) @@ -30,5 +36,15 @@ dur = dur*1000 break except: - logging.debug("trying next format") - return dur \ No newline at end of file + pass + return dur + + def validate(self, value): + if value==None or value=="": + raise ValidationError(self.default_error_messages['required']) + else: + try: + int(value) + except (ValueError, TypeError): + raise ValidationError(self.default_error_messages['invalid']) + \ No newline at end of file diff -r cb83b868164a -r 2e086097cb5d src/ldt/ldt/forms/widgets.py --- a/src/ldt/ldt/forms/widgets.py Wed Jan 02 17:21:19 2013 +0100 +++ b/src/ldt/ldt/forms/widgets.py Wed Jan 23 17:19:56 2013 +0100 @@ -18,22 +18,4 @@ def format_output(self, rendered_widgets): return mark_safe(u'
%s
%s
%s
%s
' % \ - (_('Date'), rendered_widgets[0], _('Time'), rendered_widgets[1])) - - -class LdtParseVideoDuration(TimeInput): - """ - A widget allowing to enter the duration format (eg: XhMM, XXhMM, HH:MM:SS) - """ - - def value_from_datadict(self, data, files, name): - dur = data['content-duration'] - for format in self.format: - try: - dur = time.strptime(dur, format) - dur = dur.tm_hour*3600 + dur.tm_min*60 + dur.tm_sec - dur = dur*1000 - break - except: - logging.debug("trying next format") - return dur \ No newline at end of file + (_('Date'), rendered_widgets[0], _('Time'), rendered_widgets[1])) \ No newline at end of file diff -r cb83b868164a -r 2e086097cb5d src/ldt/ldt/ldt_utils/admin.py --- a/src/ldt/ldt/ldt_utils/admin.py Wed Jan 02 17:21:19 2013 +0100 +++ b/src/ldt/ldt/ldt_utils/admin.py Wed Jan 23 17:19:56 2013 +0100 @@ -8,6 +8,10 @@ from ldt.ldt_utils.models import Content, Project, Media, Author from ldt.ldt_utils.stat import update_stat_content from guardian.admin import GuardedModelAdmin +from django.http import HttpResponse +from StringIO import StringIO +from django.core.management import call_command +import logging class ProjectAdmin(GuardedModelAdmin): @@ -95,18 +99,38 @@ form = StatAnnotationForm() return render_to_response('admin/ldt_utils/content/stats_form.html', {'form': form, 'message':message, 'current_app': self.admin_site.name, 'current_action' : 'stats' }, context_instance=RequestContext(request)) - + + + def dumpdata(self, request): + # do we dump the datas ? + dump_str = request.REQUEST.get("dump") + app_str = request.REQUEST.get("app", "") + dump_bool = False + if dump_str: + dump_bool = {'true': True, 'false': False, "0": False, "1": True}.get(dump_str.lower()) + if dump_bool: + content = StringIO() + if app_str=="": + call_command("dumpdata", indent=1, stdout=content) + else: + call_command("dumpdata", app_str, indent=1, stdout=content) + content.seek(0) + out = content.getvalue() + content.close() + res = HttpResponse(out, mimetype='application/json') + res["Content-Disposition"] = "attachment; filename=dumpdata_ldt.json" + return res + return render_to_response('admin/ldt_utils/content/dumpdata.html', {}, context_instance=RequestContext(request)) + def get_urls(self): urls = super(ContentAdmin, self).get_urls() content_urls = patterns('', url(r'^reindex/$', self.admin_site.admin_view(self.reindex), name="ldt_content_reindex"), - # (r'^admin/ldt/content/import/upload/$', 'ldt.ldt_utils.views.uploadFile'), url(r'^import/$', self.admin_site.admin_view(self.import_file), name="ldt_content_import_file"), - url(r'^stats/$', self.admin_site.admin_view(self.stats_annotations), name="ldt_project_compute_stats") - + url(r'^stats/$', self.admin_site.admin_view(self.stats_annotations), name="ldt_project_compute_stats"), + url(r'^dumpdata/$', self.admin_site.admin_view(self.dumpdata), name="ldt_admin_dump_data"), ) - return content_urls + urls diff -r cb83b868164a -r 2e086097cb5d src/ldt/ldt/ldt_utils/contentindexer.py --- a/src/ldt/ldt/ldt_utils/contentindexer.py Wed Jan 02 17:21:19 2013 +0100 +++ b/src/ldt/ldt/ldt_utils/contentindexer.py Wed Jan 23 17:19:56 2013 +0100 @@ -1,8 +1,8 @@ -from django.db.models.signals import post_save from django.dispatch import receiver from ldt import settings from ldt.ldt_utils.models import Segment, Content, Project -from ldt.ldt_utils.stat import update_stat_project +from ldt.ldt_utils.events import post_project_save +from ldt.ldt_utils.stat import update_stat_project, add_annotation_to_stat from ldt.ldt_utils.utils import reduce_text_node from tagging import settings as tagging_settings import logging @@ -71,9 +71,11 @@ if tags is None: tags = u"" - + tags_list = [tag[:tagging_settings.MAX_TAG_LENGTH] for tag in tagging.utils.parse_tag_input(tags)] tags = u",".join(tags_list) + if u"," not in tags: + tags = u"," + tags title = reduce_text_node(elementNode, "title/text()") @@ -175,14 +177,66 @@ for ensemble in content.getchildren(): self.index_ensemble(ensemble, content_obj, project) -@receiver(post_save, sender=Project) -def index_project(sender, **kwargs): - if settings.AUTO_INDEX_AFTER_SAVE: +@receiver(post_project_save) +def index_project(**kwargs): + must_reindex = kwargs.get("must_reindex", True) + if must_reindex and settings.AUTO_INDEX_AFTER_SAVE: instance = kwargs['instance'] - if instance.state != 2: + if instance.state != Project.PUBLISHED: Segment.objects.filter(project_obj__ldt_id=instance.ldt_id).delete() #@UndefinedVariable update_stat_project(instance) else: projectIndexer = ProjectIndexer([instance]) projectIndexer.index_all() update_stat_project(instance) + + + +def add_segment(params): + + project = params.get("project",None) + content = params.get("content",None) + ensemble_id = params.get("ensemble_id", "") + cutting_id = params.get("cutting_id", "") + element_id = params.get("element_id", "") + title = params.get("title", "") + abstract = params.get("abstract", "") + tags_str = params.get("tags", "") + start_ts = params.get("start_ts", 0) + duration = params.get("duration", 0) + author = params.get("author", "") + date_str = params.get("date", "") + audio_src = params.get("audio_src", "") + audio_href = params.get("audio_href", "") + polemics = params.get("polemics", "") + + seg = Segment(content=content, + iri_id=content.iri_id if content is not None else "", + ensemble_id=ensemble_id, + cutting_id=cutting_id, + element_id=element_id, + tags=tags_str, + title=title, + abstract=abstract, + duration=duration, + author=author, + start_ts=start_ts, + date=date_str, + project_obj=project, + project_id=project.ldt_id if project is not None else "", + audio_src=audio_src, + audio_href=audio_href) + seg.polemics = seg.get_polemic(polemics) + seg.save() + add_annotation_to_stat(seg.content, seg.start_ts, seg.start_ts+seg.duration) + + +def delete_segment(project, project_id, iri_id, ensemble_id, cutting_id, element_id): + + # delete Segment + for seg in Segment.objects.filter(project_id=project_id, iri_id=iri_id, ensemble_id=ensemble_id, cutting_id=cutting_id, element_id=element_id): + seg.delete() + add_annotation_to_stat(seg.content, seg.start_ts, seg.start_ts+seg.duration) + + + \ No newline at end of file diff -r cb83b868164a -r 2e086097cb5d src/ldt/ldt/ldt_utils/events.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ldt/ldt/ldt_utils/events.py Wed Jan 23 17:19:56 2013 +0100 @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +''' +Created on Jan 22, 2013 + +@author: ymh +''' +import django.dispatch + +post_project_save = django.dispatch.Signal(["instance","must_reindex"]) \ No newline at end of file diff -r cb83b868164a -r 2e086097cb5d src/ldt/ldt/ldt_utils/models.py --- a/src/ldt/ldt/ldt_utils/models.py Wed Jan 02 17:21:19 2013 +0100 +++ b/src/ldt/ldt/ldt_utils/models.py Wed Jan 23 17:19:56 2013 +0100 @@ -24,7 +24,7 @@ import uuid from shutil import move from django.core.files.storage import default_storage -#from ldt.core.models import Document, Owner +from .events import post_project_save class Author(SafeModel): @@ -571,17 +571,22 @@ return locals() polemics_volume = property(**polemics_volume()) - - -class Project(Document, SafeModel): +class Project(Document, SafeModel): + + EDITION = 1 + PUBLISHED = 2 + MODERATED = 3 + REJECTED = 4 + DELETED = 5 + STATE_CHOICES = ( - (1, 'edition'), - (2, 'published'), - (3, 'moderated'), - (4, 'rejected'), - (5, 'deleted') + (EDITION, 'edition'), + (PUBLISHED, 'published'), + (MODERATED, 'moderated'), + (REJECTED, 'rejected'), + (DELETED, 'deleted') ) ldt_id = models.CharField(max_length=255, unique=True) ldt = models.TextField(null=True) @@ -645,7 +650,15 @@ return locals() stream_mode = property(**stream_mode()) - + + def save(self, *args, **kwargs): + + must_reindex = kwargs.pop("must_reindex", True) + super(Project, self).save(*args, **kwargs) + + post_project_save.send(self, instance=self, must_reindex = must_reindex) + + @staticmethod def create_project(user, title, contents, description='', groups=[], set_icon=True, cuttings=[]): # owner = Owner.objects.get(user=user) #@UndefinedVariable diff -r cb83b868164a -r 2e086097cb5d src/ldt/ldt/ldt_utils/templates/admin/ldt_utils/app_index.html --- a/src/ldt/ldt/ldt_utils/templates/admin/ldt_utils/app_index.html Wed Jan 02 17:21:19 2013 +0100 +++ b/src/ldt/ldt/ldt_utils/templates/admin/ldt_utils/app_index.html Wed Jan 23 17:19:56 2013 +0100 @@ -14,26 +14,32 @@ Import Import - an ldt + an ldt + +   + + + Reindex + +   + + + Compute stats +   - - - Reindex - -   - - - Compute stats - -   - + +
+ + + + + + +
Data
Dump data +  
+
{% endblock %} diff -r cb83b868164a -r 2e086097cb5d src/ldt/ldt/ldt_utils/templates/admin/ldt_utils/content/dumpdata.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ldt/ldt/ldt_utils/templates/admin/ldt_utils/content/dumpdata.html Wed Jan 23 17:19:56 2013 +0100 @@ -0,0 +1,16 @@ +{% extends "admin/ldt_utils/app_action.html" %} +{% load i18n %} +{% load absurl %} +{# DUMP DATA #} +{% block content %} +{% if message %} +
+

{{ message }}

+
+{% endif %} +
+

Click HERE if you want to download the dumpdata's json. It can be long to load. The dumpdata is full and raw, without natural keys.

+
+ +Back to administration page +{% endblock %} diff -r cb83b868164a -r 2e086097cb5d src/ldt/ldt/ldt_utils/templates/ldt/ldt_utils/search_results.html --- a/src/ldt/ldt/ldt_utils/templates/ldt/ldt_utils/search_results.html Wed Jan 02 17:21:19 2013 +0100 +++ b/src/ldt/ldt/ldt_utils/templates/ldt/ldt_utils/search_results.html Wed Jan 23 17:19:56 2013 +0100 @@ -73,7 +73,11 @@