source: telemeta/web/base.py @ d511f9f

cremcrem2devdev2diademsfeature/breadcrumbsfeature/ts-0.5feature/ts-0.5.4feature/writecacheformagenericinstru_searchlamlam2mapsv3mergenlivemultiproductionrelease/1.4.4sabiodsecurityserversocialstoragetelecastertestvideo
Last change on this file since d511f9f was d511f9f, checked in by yomguy <yomguy@…>, 3 years ago

transcode flag only from source streaming, cleanup

  • Property mode set to 100644
File size: 57.6 KB
Line 
1# -*- coding: utf-8 -*-
2# Copyright (C) 2007-2010 Samalyse SARL
3# Copyright (C) 2010-2011 Parisson SARL
4
5# This software is a computer program whose purpose is to backup, analyse,
6# transcode and stream any audio content with its metadata over a web frontend.
7
8# This software is governed by the CeCILL  license under French law and
9# abiding by the rules of distribution of free software.  You can  use,
10# modify and/ or redistribute the software under the terms of the CeCILL
11# license as circulated by CEA, CNRS and INRIA at the following URL
12# "http://www.cecill.info".
13
14# As a counterpart to the access to the source code and  rights to copy,
15# modify and redistribute granted by the license, users are provided only
16# with a limited warranty  and the software's author,  the holder of the
17# economic rights,  and the successive licensors  have only  limited
18# liability.
19
20# In this respect, the user's attention is drawn to the risks associated
21# with loading,  using,  modifying and/or developing or reproducing the
22# software by the user in light of its specific status of free software,
23# that may mean  that it is complicated to manipulate,  and  that  also
24# therefore means  that it is reserved for developers  and  experienced
25# professionals having in-depth computer knowledge. Users are therefore
26# encouraged to load and test the software's suitability as regards their
27# requirements in conditions enabling the security of their systems and/or
28# data to be ensured and,  more generally, to use and operate it in the
29# same conditions as regards security.
30
31# The fact that you are presently reading this means that you have had
32# knowledge of the CeCILL license and that you accept its terms.
33
34# Authors: Olivier Guilyardi <olivier@samalyse.com>
35#          Guillaume Pellerin <yomguy@parisson.com>
36
37import re
38import os
39import sys
40import csv
41import time
42import random
43import datetime
44import timeside
45
46from jsonrpc import jsonrpc_method
47
48from django.utils.decorators import method_decorator
49from django.contrib.auth import authenticate, login
50from django.template import RequestContext, loader
51from django import template
52from django.http import HttpResponse, HttpResponseRedirect
53from django.http import Http404
54from django.shortcuts import render_to_response, redirect
55from django.views.generic import list_detail
56from django.conf import settings
57from django.contrib import auth
58from django.contrib import messages
59from django.contrib.auth.decorators import login_required, permission_required
60from django.core.context_processors import csrf
61from django.forms.models import modelformset_factory, inlineformset_factory
62from django.contrib.auth.models import User
63from django.utils.translation import ugettext
64from django.contrib.auth.forms import UserChangeForm
65from django.core.exceptions import ObjectDoesNotExist
66from django.contrib.syndication.views import Feed
67
68from telemeta.models import *
69import telemeta.models
70import telemeta.interop.oai as oai
71from telemeta.interop.oaidatasource import TelemetaOAIDataSource
72from telemeta.util.unaccent import unaccent
73from telemeta.util.unaccent import unaccent_icmp
74from telemeta.util.logger import Logger
75from telemeta.util.unicode import UnicodeWriter
76from telemeta.cache import TelemetaCache
77import telemeta.web.pages as pages
78from telemeta.forms import *
79
80
81def render(request, template, data = None, mimetype = None):
82    return render_to_response(template, data, context_instance=RequestContext(request),
83                              mimetype=mimetype)
84
85def stream_from_processor(__decoder, __processor, __flag, metadata=None):
86    while True:
87        __frames, __eodproc = __processor.process(*__decoder.process())
88        if __eodproc or not len(__frames):
89            if metadata:
90                __processor.set_metadata(metadata)
91                __processor.write_metadata()
92            __flag.value = True
93            __flag.save()
94            break
95        yield __processor.chunk
96
97def stream_from_file(__file):
98    chunk_size = 0x10000
99    f = open(__file, 'r')
100    while True:
101        __chunk = f.read(chunk_size)
102        if not len(__chunk):
103            f.close()
104            break
105        yield __chunk
106
107def get_public_access(access, year_from=None, year_to=None):
108    # Rolling publishing date : public access is given when time between recorded year
109    # and current year is over the settings value PUBLIC_ACCESS_PERIOD
110    if year_from and not year_from == 0:
111        year = year_from
112    elif year_to and not year_to == 0:
113        year = year_to
114    else:
115        year = 0
116    if access == 'full':
117        public_access = True
118    else:
119        public_access = False
120        if year and not year == 'None':
121            year_now = datetime.datetime.now().strftime("%Y")
122            if int(year_now) - int(year) >= settings.TELEMETA_PUBLIC_ACCESS_PERIOD:
123                public_access = True
124        else:
125            public_access = False
126    return public_access
127
128def get_revisions(nb):
129    last_revisions = Revision.objects.order_by('-time')[0:nb]
130    revisions = []
131    for revision in last_revisions:
132        if revision.element_type == 'item':
133            try:
134                element = MediaItem.objects.get(pk=revision.element_id)
135            except:
136                element = None
137        if revision.element_type == 'collection':
138            try:
139                element = MediaCollection.objects.get(pk=revision.element_id)
140            except:
141                element = None
142        if revision.element_type == 'marker':
143            try:
144                element = MediaItemMarker.objects.get(pk=revision.element_id)
145            except:
146                element = None
147        if not element == None:
148            revisions.append({'revision': revision, 'element': element})
149    return revisions
150
151def get_playlists(request, user=None):
152    if not user:
153        user = request.user
154    playlists = []
155    if user.is_authenticated():
156        user_playlists = Playlist.objects.filter(author=user)
157        for playlist in user_playlists:
158            playlist_resources = PlaylistResource.objects.filter(playlist=playlist)
159            resources = []
160            for resource in playlist_resources:
161                try:
162                    if resource.resource_type == 'item':
163                        element = MediaItem.objects.get(id=resource.resource_id)
164                    if resource.resource_type == 'collection':
165                        element = MediaCollection.objects.get(id=resource.resource_id)
166                    if resource.resource_type == 'marker':
167                        element = MediaItemMarker.objects.get(id=resource.resource_id)
168                except:
169                    element = None
170                resources.append({'element': element, 'type': resource.resource_type, 'public_id': resource.public_id })
171            playlists.append({'playlist': playlist, 'resources': resources})
172    return playlists
173
174
175class GeneralView(object):
176    """Provide general web UI methods"""
177
178    def index(self, request):
179        """Render the homepage"""
180        if not request.user.is_authenticated():
181            template = loader.get_template('telemeta/index.html')
182
183            sound_items = MediaItem.objects.sound()
184            _sound_pub_items = []
185            for item in sound_items:
186                if get_public_access(item.public_access,  str(item.recorded_from_date).split('-')[0],
187                                                str(item.recorded_to_date).split('-')[0]):
188                    _sound_pub_items.append(item)
189
190            random.shuffle(_sound_pub_items)
191            if len(_sound_pub_items) != 0:
192                sound_pub_item = _sound_pub_items[0]
193            else:
194                sound_pub_item = None
195            if len(_sound_pub_items) == 2:
196                sound_pub_items = [_sound_pub_items[1]]
197            elif len(_sound_pub_items) > 2:
198                sound_pub_items = _sound_pub_items[1:3]
199            else:
200                sound_pub_items = None
201
202            revisions = get_revisions(4)
203            context = RequestContext(request, {
204                        'page_content': pages.get_page_content(request, 'home', ignore_slash_issue=True),
205                        'revisions': revisions,  'sound_pub_items': sound_pub_items,
206                        'sound_pub_item': sound_pub_item })
207            return HttpResponse(template.render(context))
208        else:
209            template='telemeta/home.html'
210            playlists = get_playlists(request)
211            revisions = get_revisions(15)
212            searches = Search.objects.filter(username=request.user)
213            return render(request, template, {'playlists': playlists, 'searches': searches,
214                                              'revisions': revisions,})
215
216    def edit_search(self, request, criteria=None):
217        year_min, year_max = MediaCollection.objects.all().recording_year_range()
218        rec_years = year_min and year_max and range(year_min, year_max + 1) or []
219        year_min, year_max = MediaCollection.objects.all().publishing_year_range()
220        pub_years = year_min and year_max and range(year_min, year_max + 1) or []
221        return render(request, 'telemeta/search_criteria.html', {
222            'rec_years': rec_years,
223            'pub_years': pub_years,
224            'ethnic_groups': MediaItem.objects.all().ethnic_groups(),
225            'criteria': criteria
226        })
227
228    def handle_oai_request(self, request):
229        host = request.META['HTTP_HOST']
230        datasource  = TelemetaOAIDataSource()
231        repository_name = settings.TELEMETA_ORGANIZATION
232        url         = 'http://' + host + request.path
233        admin       = settings.ADMINS[0][1]
234        provider    = oai.DataProvider(datasource, repository_name, url, admin)
235        args        = request.GET.copy()
236        args.update(request.POST)
237        return HttpResponse(provider.handle(args), mimetype='text/xml')
238
239    def render_flatpage(self, request, path):
240        try:
241            content = pages.get_page_content(request, path)
242        except pages.MalformedPagePath:
243            return redirect(request.path + '/')
244
245        if isinstance(content, pages.PageAttachment):
246            return HttpResponse(content, content.mimetype())
247        else:
248            return render(request, 'telemeta/flatpage.html', {'page_content': content })
249
250    def logout(self, request):
251        auth.logout(request)
252        return redirect('telemeta-home')
253
254    def search(self, request, type = None):
255        """Perform a search through collections and items metadata"""
256        collections = MediaCollection.objects.enriched()
257        items = MediaItem.objects.enriched()
258        input = request.REQUEST
259        criteria = {}
260
261        switch = {
262            'pattern': lambda value: (
263                collections.quick_search(value),
264                items.quick_search(value)),
265            'title': lambda value: (
266                collections.word_search('title', value),
267                items.by_title(value)),
268            'location': lambda value: (
269                collections.by_location(Location.objects.get(name=value)),
270                items.by_location(Location.objects.get(name=value))),
271            'continent': lambda value: (
272                collections.by_continent(value),
273                items.filter(continent = value)),
274            'ethnic_group': lambda value: (
275                collections.by_ethnic_group(value),
276                items.filter(ethnic_group = value),
277                EthnicGroup.objects.get(pk=value)),
278            'creator': lambda value: (
279                collections.word_search('creator', value),
280                items.word_search('collection__creator', value)),
281            'collector': lambda value: (
282                collections.by_fuzzy_collector(value),
283                items.by_fuzzy_collector(value)),
284            'rec_year_from': lambda value: (
285                collections.by_recording_year(int(value), int(input.get('rec_year_to', value))),
286                items.by_recording_date(datetime.date(int(value), 1, 1),
287                                        datetime.date(int(input.get('rec_year_to', value)), 12, 31))),
288            'rec_year_to': lambda value: (collections, items),
289            'pub_year_from': lambda value: (
290                collections.by_publish_year(int(value), int(input.get('pub_year_to', value))),
291                items.by_publish_year(int(value), int(input.get('pub_year_to', value)))),
292            'pub_year_to': lambda value: (collections, items),
293            'sound': lambda value: (
294                collections.sound(),
295                items.sound()),
296        }
297
298        for key, value in input.items():
299            func = switch.get(key)
300            if func and value and value != "0":
301                try:
302                    res = func(value)
303                    if len(res)  > 2:
304                        collections, items, value = res
305                    else:
306                        collections, items = res
307                except ObjectDoesNotExist:
308                    collections = collections.none()
309                    items = items.none()
310
311                criteria[key] = value
312
313        if type is None:
314            if collections.count():
315                type = 'collections'
316            else:
317                type = 'items'
318
319        if type == 'items':
320            objects = items
321        else:
322            objects = collections
323
324        return list_detail.object_list(request, objects,
325            template_name='telemeta/search_results.html', paginate_by=20,
326            extra_context={'criteria': criteria, 'collections_num': collections.count(),
327                'items_num': items.count(), 'type' : type})
328
329    def complete_location(self, request, with_items=True):
330        input = request.REQUEST
331
332        token = input['q']
333        limit = int(input['limit'])
334        if with_items:
335            locations = MediaItem.objects.all().locations()
336        else:
337            locations = Location.objects.all()
338
339        locations = locations.filter(name__istartswith=token).order_by('name')[:limit]
340        data = [unicode(l) + " (%d items)" % l.items().count() for l in locations]
341
342        return HttpResponse("\n".join(data))
343
344    def users(self, request):
345        users = User.objects.all()
346        return render(request, 'telemeta/users.html', {'users': users})
347
348class CollectionView(object):
349    """Provide Collections web UI methods"""
350
351    def collection_detail(self, request, public_id, template='telemeta/collection_detail.html'):
352        collection = MediaCollection.objects.get(public_id=public_id)
353        items = collection.items.enriched()
354        items = items.order_by('code', 'old_code')
355
356        if collection.public_access == 'none' and not (request.user.is_staff or request.user.is_superuser):
357            mess = ugettext('Access not allowed')
358            title = ugettext('Collection') + ' : ' + public_id + ' : ' + mess
359            description = ugettext('Please login or contact the website administator to get a private access.')
360            messages.error(request, title)
361            return render(request, 'telemeta/messages.html', {'description' : description})
362
363        public_access = get_public_access(collection.public_access, collection.recorded_from_year,
364                                                collection.recorded_to_year)
365        playlists = get_playlists(request)
366
367        related_media = MediaCollectionRelated.objects.filter(collection=collection)
368        for media in related_media:
369            if not media.mime_type:
370                media.set_mime_type()
371                media.save()
372            if not media.title and media.url:
373                try:
374                    from lxml import etree
375                    parser = etree.HTMLParser()
376                    tree = etree.parse(media.url, parser)
377                    title = tree.find(".//title").text
378                    title = title.replace('\n', '').strip()
379                    media.title = title
380                except:
381                    media.title = media.url
382                media.save()
383
384        return render(request, template, {'collection': collection, 'playlists': playlists, 'public_access': public_access, 'items': items, 'related_media': related_media})
385
386    @method_decorator(permission_required('telemeta.change_mediacollection'))
387    def collection_edit(self, request, public_id, template='telemeta/collection_edit.html'):
388        collection = MediaCollection.objects.get(public_id=public_id)
389        if request.method == 'POST':
390            form = MediaCollectionForm(data=request.POST, files=request.FILES, instance=collection)
391            if form.is_valid():
392                code = form.cleaned_data['code']
393                if not code:
394                    code = public_id
395                form.save()
396                collection.set_revision(request.user)
397                return HttpResponseRedirect('/collections/'+code)
398        else:
399            form = MediaCollectionForm(instance=collection)
400
401        return render(request, template, {'collection': collection, "form": form,})
402
403    @method_decorator(permission_required('telemeta.add_mediacollection'))
404    def collection_add(self, request, template='telemeta/collection_add.html'):
405        collection = MediaCollection()
406        if request.method == 'POST':
407            form = MediaCollectionForm(data=request.POST, files=request.FILES, instance=collection)
408            if form.is_valid():
409                code = form.cleaned_data['code']
410                if not code:
411                    code = public_id
412                form.save()
413                collection.set_revision(request.user)
414                return HttpResponseRedirect('/collections/'+code)
415        else:
416            form = MediaCollectionForm(instance=collection)
417
418        return render(request, template, {'collection': collection, "form": form,})
419
420    @method_decorator(permission_required('telemeta.add_mediacollection'))
421    def collection_copy(self, request, public_id, template='telemeta/collection_edit.html'):
422        if request.method == 'POST':
423            collection = MediaCollection()
424            form = MediaCollectionForm(data=request.POST, files=request.FILES, instance=collection)
425            if form.is_valid():
426                code = form.cleaned_data['code']
427                if not code:
428                    code = public_id
429                form.save()
430                collection.set_revision(request.user)
431                return HttpResponseRedirect('/collections/'+code)
432        else:
433            collection = MediaCollection.objects.get(public_id=public_id)
434            form = MediaCollectionForm(instance=collection)
435
436        return render(request, template, {'collection': collection, "form": form,})
437
438    def collection_playlist(self, request, public_id, template, mimetype):
439        try:
440            collection = MediaCollection.objects.get(public_id=public_id)
441        except ObjectDoesNotExist:
442            raise Http404
443
444        template = loader.get_template(template)
445        context = RequestContext(request, {'collection': collection, 'host': request.META['HTTP_HOST']})
446        return HttpResponse(template.render(context), mimetype=mimetype)
447
448    @method_decorator(permission_required('telemeta.delete_mediacollection'))
449    def collection_delete(self, request, public_id):
450        """Delete a given collection"""
451        collection = MediaCollection.objects.get(public_id=public_id)
452        collection.delete()
453        return HttpResponseRedirect('/collections/')
454
455    def related_media_collection_stream(self, request, collection_public_id, media_id):
456        collection = MediaCollection.objects.get(public_id=collection_public_id)
457        media = MediaCollectionRelated.objects.get(collection=collection, id=media_id)
458        response = HttpResponse(stream_from_file(media.file.path), mimetype=media.mime_type)
459#        response['Content-Disposition'] = 'attachment'
460        return response
461
462    @method_decorator(permission_required('telemeta.change_mediacollection'))
463    def related_media_edit(self, request, public_id, template):
464        collection = MediaCollection.objects.get(public_id=public_id)
465        MediaCollectionRelatedFormSet = inlineformset_factory(MediaCollection, MediaCollectionRelated, form=MediaCollectionRelatedForm)
466        if request.method == 'POST':
467            formset = MediaCollectionRelatedFormSet(data=request.POST, files=request.FILES, instance=collection)
468            if formset.is_valid():
469                formset.save()
470                collection.set_revision(request.user)
471                return HttpResponseRedirect('/collections/'+public_id)
472        else:
473            formset = MediaCollectionRelatedFormSet(instance=collection)
474
475        return render(request, template, {'collection': collection, 'formset': formset,})
476
477class ItemView(object):
478    """Provide Collections web UI methods"""
479
480    graphers = timeside.core.processors(timeside.api.IGrapher)
481    decoders = timeside.core.processors(timeside.api.IDecoder)
482    encoders = timeside.core.processors(timeside.api.IEncoder)
483    analyzers = timeside.core.processors(timeside.api.IAnalyzer)
484    cache_data = TelemetaCache(settings.TELEMETA_DATA_CACHE_DIR)
485    cache_export = TelemetaCache(settings.TELEMETA_EXPORT_CACHE_DIR)
486
487    def item_previous_next(self, item):
488        # Get previous and next items
489        pks = []
490        items = MediaItem.objects.filter(collection=item.collection)
491        items = items.order_by('code', 'old_code')
492
493        if len(items) > 1:
494            for it in items:
495                pks.append(it.pk)
496            for pk in pks:
497                if pk == item.pk:
498                    if pk == pks[0]:
499                        previous_pk = pks[-1]
500                        next_pk = pks[1]
501                    elif pk == pks[-1]:
502                        previous_pk = pks[-2]
503                        next_pk = pks[0]
504                    else:
505                        previous_pk = pks[pks.index(pk)-1]
506                        next_pk = pks[pks.index(pk)+1]
507                    for it in items:
508                        if it.pk == previous_pk:
509                            previous = it
510                        if it.pk == next_pk:
511                            next = it
512                    previous = previous.public_id
513                    next = next.public_id
514        else:
515             previous = item.public_id
516             next = item.public_id
517
518        return previous, next
519
520    def item_detail(self, request, public_id=None, marker_id=None, width=None, height=None,
521                        template='telemeta/mediaitem_detail.html'):
522        """Show the details of a given item"""
523
524        if not public_id and marker_id:
525            marker = MediaItemMarker.objects.get(public_id=marker_id)
526            item_id = marker.item_id
527            item = MediaItem.objects.get(id=item_id)
528        else:
529            item = MediaItem.objects.get(public_id=public_id)
530
531        item_public_access = item.public_access != 'none' or item.collection.public_access != 'none'
532        if not item_public_access and not (request.user.is_staff or request.user.is_superuser):
533            mess = ugettext('Access not allowed')
534            title = ugettext('Item') + ' : ' + public_id + ' : ' + mess
535            description = ugettext('Please login or contact the website administator to get a private access.')
536            messages.error(request, title)
537            return render(request, 'telemeta/messages.html', {'description' : description})
538
539        # Get TimeSide processors
540        formats = []
541        for encoder in self.encoders:
542            #FIXME: timeside cannot encode to FLAC and OGG now :'(
543            if encoder.file_extension() != 'ogg' and encoder.file_extension() != 'flac':
544                formats.append({'name': encoder.format(), 'extension': encoder.file_extension()})
545
546        graphers = []
547        for grapher in self.graphers:
548            graphers.append({'name':grapher.name(), 'id': grapher.id()})
549        if request.REQUEST.has_key('grapher_id'):
550            grapher_id = request.REQUEST['grapher_id']
551        else:
552            grapher_id = 'waveform'
553
554        previous, next = self.item_previous_next(item)
555        self.item_analyze(item)
556        playlists = get_playlists(request)
557        public_access = get_public_access(item.public_access, str(item.recorded_from_date).split('-')[0],
558                                                str(item.recorded_to_date).split('-')[0])
559
560        related_media = MediaItemRelated.objects.filter(item=item)
561        for media in related_media:
562            if not media.mime_type:
563                media.set_mime_type()
564                media.save()
565            if not media.title and media.url:
566                try:
567                    from lxml import etree
568                    parser = etree.HTMLParser()
569                    tree = etree.parse(media.url, parser)
570                    title = tree.find(".//title").text
571                    title = title.replace('\n', '').strip()
572                    media.title = title
573                except:
574                    media.title = media.url
575                media.save()
576
577        return render(request, template,
578                    {'item': item, 'export_formats': formats,
579                    'visualizers': graphers, 'visualizer_id': grapher_id,
580                    'audio_export_enabled': getattr(settings, 'TELEMETA_DOWNLOAD_ENABLED', True),
581                    'previous' : previous, 'next' : next, 'marker': marker_id, 'playlists' : playlists,
582                    'public_access': public_access, 'width': width, 'height': height,
583                    'related_media': related_media,
584                    })
585
586    @method_decorator(permission_required('telemeta.change_mediaitem'))
587    def item_edit(self, request, public_id, template='telemeta/mediaitem_edit.html'):
588        """Edit a given item"""
589        item = MediaItem.objects.get(public_id=public_id)
590
591        formats = []
592        for encoder in self.encoders:
593            #FIXME: timeside cannot encode to FLAC and OGG now :'(
594            if encoder.file_extension() != 'ogg' and encoder.file_extension() != 'flac':
595                formats.append({'name': encoder.format(), 'extension': encoder.file_extension()})
596
597        graphers = []
598        for grapher in self.graphers:
599            graphers.append({'name':grapher.name(), 'id': grapher.id()})
600        if request.REQUEST.has_key('grapher_id'):
601            grapher_id = request.REQUEST['grapher_id']
602        else:
603            grapher_id = 'waveform'
604
605        previous, next = self.item_previous_next(item)
606        self.item_analyze(item)
607
608        if request.method == 'POST':
609            form = MediaItemForm(data=request.POST, files=request.FILES, instance=item)
610            if form.is_valid():
611                form.save()
612                code = form.cleaned_data['code']
613                if not code:
614                    code = str(item.id)
615                if form.files:
616                    self.cache_data.delete_item_data(code)
617                    self.cache_export.delete_item_data(code)
618                    flags = MediaItemTranscodingFlag.objects.filter(item=item)
619                    analyses = MediaItemAnalysis.objects.filter(item=item)
620                    for flag in flags:
621                        flag.delete()
622                    for analysis in analyses:
623                        analysis.delete()
624                item.set_revision(request.user)
625                return HttpResponseRedirect('/items/'+code)
626        else:
627            form = MediaItemForm(instance=item)
628
629        return render(request, template,
630                    {'item': item, 'export_formats': formats,
631                    'visualizers': graphers, 'visualizer_id': grapher_id,
632                    'audio_export_enabled': getattr(settings, 'TELEMETA_DOWNLOAD_ENABLED', True), "form": form,
633                    'previous' : previous, 'next' : next,
634                    })
635
636    def related_media_item_stream(self, request, item_public_id, media_id):
637        item = MediaItem.objects.get(public_id=item_public_id)
638        media = MediaItemRelated.objects.get(item=item, id=media_id)
639        response = HttpResponse(stream_from_file(media.file.path), mimetype=media.mime_type)
640#        response['Content-Disposition'] = 'attachment'
641        return response
642
643    @method_decorator(permission_required('telemeta.change_mediaitem'))
644    def related_media_edit(self, request, public_id, template):
645        item = MediaItem.objects.get(public_id=public_id)
646        MediaItemRelatedFormSet = inlineformset_factory(MediaItem, MediaItemRelated, form=MediaItemRelatedForm)
647        if request.method == 'POST':
648            formset = MediaItemRelatedFormSet(data=request.POST, files=request.FILES, instance=item)
649            if formset.is_valid():
650                formset.save()
651                item.set_revision(request.user)
652                return HttpResponseRedirect('/items/'+public_id)
653        else:
654            formset = MediaItemRelatedFormSet(instance=item)
655
656        return render(request, template, {'item': item, 'formset': formset,})
657
658    @method_decorator(permission_required('telemeta.add_mediaitem'))
659    def item_add(self, request, public_id=None, template='telemeta/mediaitem_add.html'):
660        """Add an item"""
661        if public_id:
662            collection = MediaCollection.objects.get(public_id=public_id)
663            item = MediaItem(collection=collection)
664        else:
665            item = MediaItem()
666        if request.method == 'POST':
667            form = MediaItemForm(data=request.POST, files=request.FILES, instance=item)
668            if form.is_valid():
669                form.save()
670                item.set_revision(request.user)
671                code = form.cleaned_data['code']
672                if not code:
673                    code = str(item.id)
674                return HttpResponseRedirect('/items/'+code)
675        else:
676            form = MediaItemForm(instance=item)
677
678        return render(request, template, {'item': item, 'form': form})
679
680    @method_decorator(permission_required('telemeta.add_mediaitem'))
681    def item_copy(self, request, public_id, template='telemeta/mediaitem_copy.html'):
682        """Copy a given item"""
683        if request.method == 'POST':
684            source_item = MediaItem.objects.get(public_id=public_id)
685            item = MediaItem()
686            form = MediaItemForm(data=request.POST, files=request.FILES, instance=item)
687            if form.is_valid():
688                form.save()
689                code = form.cleaned_data['code']
690                if not code:
691                    code = str(item.id)
692
693                performances = MediaItemPerformance.objects.filter(media_item=source_item)
694                for performance in performances:
695                    performance.pk = None
696                    performance.id = None
697                    performance.media_item = item
698                    performance.save()
699
700                keywords = MediaItemKeyword.objects.filter(item=source_item)
701                for keyword in keywords:
702                    keyword.pk = None
703                    keyword.id = None
704                    keyword.item = item
705                    keyword.save()
706
707                item.set_revision(request.user)
708                return HttpResponseRedirect('/items/'+code)
709        else:
710            item = MediaItem.objects.get(public_id=public_id)
711            form = MediaItemForm(instance=item)
712            form.file = None
713
714        return render(request, template, {'item': item, "form": form})
715
716    @method_decorator(permission_required('telemeta.delete_mediaitem'))
717    def item_delete(self, request, public_id):
718        """Delete a given item"""
719        item = MediaItem.objects.get(public_id=public_id)
720        collection = item.collection
721        item.delete()
722        return HttpResponseRedirect('/collections/'+collection.code)
723
724    def item_analyze(self, item):
725        analyses = MediaItemAnalysis.objects.filter(item=item)
726
727        if analyses:
728            if not item.approx_duration:
729                for analysis in analyses:
730                    if analysis.id == 'duration':
731                        value = analysis.value
732                        time = value.split(':')
733                        time[2] = time[2].split('.')[0]
734                        time = ':'.join(time)
735                        item.approx_duration = str(time)
736                        item.save()
737        else:
738            analyzers = []
739            analyzers_sub = []
740            if item.file:
741                decoder  = timeside.decoder.FileDecoder(item.file.path)
742                pipe = decoder
743                for analyzer in self.analyzers:
744                    subpipe = analyzer()
745                    analyzers_sub.append(subpipe)
746                    pipe = pipe | subpipe
747                pipe.run()
748
749                mime_type = decoder.format()
750                analysis = MediaItemAnalysis(item=item, name='MIME type',
751                                             analyzer_id='mime_type', unit='', value=mime_type)
752                analysis.save()
753                analysis = MediaItemAnalysis(item=item, name='Channels',
754                                             analyzer_id='channels',
755                                             unit='', value=decoder.channels())
756                analysis.save()
757                analysis = MediaItemAnalysis(item=item, name='Samplerate',
758                                             analyzer_id='samplerate', unit='Hz',
759                                             value=unicode(decoder.audiorate))
760                analysis.save()
761                analysis = MediaItemAnalysis(item=item, name='Resolution',
762                                             analyzer_id='resolution', unit='bits',
763                                             value=unicode(decoder.audiowidth))
764                analysis.save()
765
766                for analyzer in analyzers_sub:
767                    value = analyzer.result()
768                    if analyzer.id() == 'duration':
769                        approx_value = int(round(value))
770                        item.approx_duration = approx_value
771                        try:
772                            item.save()
773                        except:
774                            pass
775                        value = datetime.timedelta(0,value)
776
777                    analysis = MediaItemAnalysis(item=item, name=analyzer.name(),
778                                                 analyzer_id=analyzer.id(),
779                                                 unit=analyzer.unit(), value=str(value))
780                    analysis.save()
781
782    def item_analyze_xml(self, request, public_id):
783        item = MediaItem.objects.get(public_id=public_id)
784        analyses = MediaItemAnalysis.objects.filter(item=item)
785        analyzers = []
786        for analysis in analyses:
787            analyzers.append(analysis.to_dict())
788        mime_type = 'text/xml'
789        response = HttpResponse(self.cache_data.get_analyzer_xml(analyzers), mimetype=mime_type)
790        response['Content-Disposition'] = 'attachment; filename='+public_id+'.xml'
791        return response
792
793    def item_visualize(self, request, public_id, visualizer_id, width, height):
794        item = MediaItem.objects.get(public_id=public_id)
795        mime_type = 'image/png'
796        grapher_id = visualizer_id
797
798        for grapher in self.graphers:
799            if grapher.id() == grapher_id:
800                break
801
802        if grapher.id() != grapher_id:
803            raise Http404
804
805        size = width + '_' + height
806        image_file = '.'.join([public_id, grapher_id, size, 'png'])
807
808        if not self.cache_data.exists(image_file):
809            if item.file:
810                path = self.cache_data.dir + os.sep + image_file
811                decoder  = timeside.decoder.FileDecoder(item.file.path)
812                graph = grapher(width = int(width), height = int(height))
813                pipe = decoder | graph
814                pipe.run()
815                graph.watermark('timeside', opacity=.6, margin=(5,5))
816                f = open(path, 'w')
817                graph.render(path)
818                f.close()
819
820        response = HttpResponse(self.cache_data.read_stream_bin(image_file), mimetype=mime_type)
821        return response
822
823    def list_export_extensions(self):
824        "Return the recognized item export file extensions, as a list"
825        list = []
826        for encoder in self.encoders:
827            list.append(encoder.file_extension())
828        return list
829
830    def item_export(self, request, public_id, extension):
831        """Export a given media item in the specified format (OGG, FLAC, ...)"""
832
833        item = MediaItem.objects.get(public_id=public_id)
834        public_access = get_public_access(item.public_access,
835                                          str(item.recorded_from_date).split('-')[0],
836                                          str(item.recorded_to_date).split('-')[0])
837
838        if (not public_access or not extension in settings.TELEMETA_STREAMING_FORMATS) and \
839                    not (request.user.has_perm('telemeta.can_play_all_items') or request.user.is_superuser):
840            mess = ugettext('Access not allowed')
841            title = 'Item file : ' + public_id + '.' + extension + ' : ' + mess
842            description = ugettext('Please login or contact the website administator to get a private access.')
843            messages.error(request, title)
844            return render(request, 'telemeta/messages.html', {'description' : description})
845
846        for encoder in self.encoders:
847            if encoder.file_extension() == extension:
848                break
849
850        if encoder.file_extension() != extension:
851            raise Http404('Unknown export file extension: %s' % extension)
852
853        mime_type = encoder.mime_type()
854        file = public_id + '.' + encoder.file_extension()
855        audio = item.file.path
856
857        flag = MediaItemTranscodingFlag.objects.filter(item=item, mime_type=mime_type)
858        if not flag:
859            flag = MediaItemTranscodingFlag(item=item, mime_type=mime_type)
860            flag.value = False
861            flag.save()
862        else:
863            flag = flag[0]
864
865        analyzers = self.item_analyze(item)
866        if analyzers:
867            for analyzer in analyzers:
868                if analyzer['id'] == 'mime_type':
869                    format = analyzer['value']
870        else:
871            decoder = timeside.decoder.FileDecoder(audio)
872            format = decoder.format()
873
874        dc_metadata = dublincore.express_item(item).to_list()
875        mapping = DublinCoreToFormatMetadata(extension)
876        metadata = mapping.get_metadata(dc_metadata)
877
878        if mime_type in format:
879            # source > stream
880            if not extension in mapping.unavailable_extensions:
881                proc = encoder(audio)
882                proc.set_metadata(metadata)
883                proc.write_metadata()
884            response = HttpResponse(stream_from_file(audio), mimetype = mime_type)
885        else:
886            media = self.cache_export.dir + os.sep + file
887            if not self.cache_export.exists(file) or not flag.value:
888                # source > encoder > stream
889                decoder = timeside.decoder.FileDecoder(audio)
890                decoder.setup()
891                proc = encoder(media, streaming=True)
892                proc.setup(channels=decoder.channels(), samplerate=decoder.samplerate())
893                if extension in mapping.unavailable_extensions:
894                    metadata=None
895                response = HttpResponse(stream_from_processor(decoder, proc, flag, metadata=metadata), mimetype = mime_type)
896            else:
897                # cache > stream
898                response = HttpResponse(self.cache_export.read_stream_bin(file), mimetype = mime_type)
899
900        response['Content-Disposition'] = 'attachment'
901        return response
902
903    def item_playlist(self, request, public_id, template, mimetype):
904        try:
905            item = MediaItem.objects.get(public_id=public_id)
906        except ObjectDoesNotExist:
907            raise Http404
908
909        template = loader.get_template(template)
910        context = RequestContext(request, {'item': item, 'host': request.META['HTTP_HOST']})
911        return HttpResponse(template.render(context), mimetype=mimetype)
912
913    @method_decorator(permission_required('telemeta.change_mediaitem'))
914    def item_performances_edit(self, request, public_id, template):
915        item = MediaItem.objects.get(public_id=public_id)
916        PerformanceFormSet = inlineformset_factory(MediaItem, MediaItemPerformance, form=MediaItemPerformanceForm)
917        if request.method == 'POST':
918            formset = PerformanceFormSet(data=request.POST, instance=item)
919            if formset.is_valid():
920                formset.save()
921                return HttpResponseRedirect('/items/'+public_id)
922        else:
923            formset = PerformanceFormSet(instance=item)
924        return render(request, template, {'item': item, 'formset': formset,})
925
926    @method_decorator(permission_required('telemeta.change_mediaitem'))
927    def item_keywords_edit(self, request, public_id, template):
928        item = MediaItem.objects.get(public_id=public_id)
929        FormSet = inlineformset_factory(MediaItem, MediaItemKeyword)
930        if request.method == 'POST':
931            formset = FormSet(data=request.POST, instance=item)
932            if formset.is_valid():
933                formset.save()
934                return HttpResponseRedirect('/items/'+public_id)
935        else:
936            formset = FormSet(instance=item)
937        return render(request, template, {'item': item, 'formset': formset,})
938
939
940class AdminView(object):
941    """Provide Admin web UI methods"""
942
943    @method_decorator(permission_required('sites.change_site'))
944    def admin_index(self, request):
945        return render(request, 'telemeta/admin.html', self.__get_admin_context_vars())
946
947    @method_decorator(permission_required('sites.change_site'))
948    def admin_general(self, request):
949        return render(request, 'telemeta/admin_general.html', self.__get_admin_context_vars())
950
951    @method_decorator(permission_required('sites.change_site'))
952    def admin_enumerations(self, request):
953        return render(request, 'telemeta/admin_enumerations.html', self.__get_admin_context_vars())
954
955    @method_decorator(permission_required('sites.change_site'))
956    def admin_users(self, request):
957        users = User.objects.all()
958        return render(request, 'telemeta/admin_users.html', {'users': users})
959
960    def __get_enumerations_list(self):
961        from django.db.models import get_models
962        models = get_models(telemeta.models)
963
964        enumerations = []
965        for model in models:
966            if issubclass(model, Enumeration):
967                enumerations.append({"name": model._meta.verbose_name,
968                    "id": model._meta.module_name})
969
970        cmp = lambda obj1, obj2: unaccent_icmp(obj1['name'], obj2['name'])
971        enumerations.sort(cmp)
972        return enumerations
973
974    def __get_admin_context_vars(self):
975        return {"enumerations": self.__get_enumerations_list()}
976
977    def __get_enumeration(self, id):
978        from django.db.models import get_models
979        models = get_models(telemeta.models)
980        for model in models:
981            if model._meta.module_name == id:
982                break
983
984        if model._meta.module_name != id:
985            return None
986
987        return model
988
989    @method_decorator(permission_required('telemeta.change_keyword'))
990    def edit_enumeration(self, request, enumeration_id):
991
992        enumeration  = self.__get_enumeration(enumeration_id)
993        if enumeration == None:
994            raise Http404
995
996        vars = self.__get_admin_context_vars()
997        vars["enumeration_id"] = enumeration._meta.module_name
998        vars["enumeration_name"] = enumeration._meta.verbose_name
999        vars["enumeration_values"] = enumeration.objects.all()
1000        return render(request, 'telemeta/enumeration_edit.html', vars)
1001
1002    @method_decorator(permission_required('telemeta.add_keyword'))
1003    def add_to_enumeration(self, request, enumeration_id):
1004
1005        enumeration  = self.__get_enumeration(enumeration_id)
1006        if enumeration == None:
1007            raise Http404
1008
1009        enumeration_value = enumeration(value=request.POST['value'])
1010        enumeration_value.save()
1011
1012        return self.edit_enumeration(request, enumeration_id)
1013
1014    @method_decorator(permission_required('telemeta.change_keyword'))
1015    def update_enumeration(self, request, enumeration_id):
1016
1017        enumeration  = self.__get_enumeration(enumeration_id)
1018        if enumeration == None:
1019            raise Http404
1020
1021        if request.method == 'POST':
1022            enumeration.objects.filter(id__in=request.POST.getlist('sel')).delete()
1023
1024        return self.edit_enumeration(request, enumeration_id)
1025
1026    @method_decorator(permission_required('telemeta.change_keyword'))
1027    def edit_enumeration_value(self, request, enumeration_id, value_id):
1028
1029        enumeration  = self.__get_enumeration(enumeration_id)
1030        if enumeration == None:
1031            raise Http404
1032
1033        vars = self.__get_admin_context_vars()
1034        vars["enumeration_id"] = enumeration._meta.module_name
1035        vars["enumeration_name"] = enumeration._meta.verbose_name
1036        vars["enumeration_record"] = enumeration.objects.get(id__exact=value_id)
1037        return render(request, 'telemeta/enumeration_edit_value.html', vars)
1038
1039    @method_decorator(permission_required('telemeta.change_keyword'))
1040    def update_enumeration_value(self, request, enumeration_id, value_id):
1041
1042        if request.method == 'POST':
1043            enumeration  = self.__get_enumeration(enumeration_id)
1044            if enumeration == None:
1045                raise Http404
1046
1047            record = enumeration.objects.get(id__exact=value_id)
1048            record.value = request.POST["value"]
1049            record.save()
1050
1051        return self.edit_enumeration(request, enumeration_id)
1052
1053
1054class InstrumentView(object):
1055    """Provide Instrument web UI methods"""
1056
1057    @method_decorator(permission_required('telemeta.change_instrument'))
1058    def edit_instrument(self, request):
1059
1060        instruments = Instrument.objects.all().order_by('name')
1061        if instruments == None:
1062            raise Http404
1063        return render(request, 'telemeta/instrument_edit.html', {'instruments': instruments})
1064
1065    @method_decorator(permission_required('telemeta.add_instrument'))
1066    def add_to_instrument(self, request):
1067
1068        if request.method == 'POST':
1069            instrument = Instrument(name=request.POST['value'])
1070            instrument.save()
1071
1072        return self.edit_instrument(request)
1073
1074    @method_decorator(permission_required('telemeta.change_instrument'))
1075    def update_instrument(self, request):
1076
1077        if request.method == 'POST':
1078            Instrument.objects.filter(id__in=request.POST.getlist('sel')).delete()
1079
1080        return self.edit_instrument(request)
1081
1082    @method_decorator(permission_required('telemeta.change_instrument'))
1083    def edit_instrument_value(self, request, value_id):
1084        instrument = Instrument.objects.get(id__exact=value_id)
1085
1086        return render(request, 'telemeta/instrument_edit_value.html', {'instrument': instrument})
1087
1088    @method_decorator(permission_required('telemeta.change_instrument'))
1089    def update_instrument_value(self, request, value_id):
1090
1091        if request.method == 'POST':
1092            instrument = Instrument.objects.get(id__exact=value_id)
1093            instrument.name = request.POST["value"]
1094            instrument.save()
1095
1096        return self.edit_instrument(request)
1097
1098
1099class GeoView(object):
1100    """Provide Geo web UI methods"""
1101
1102    def list_continents(self, request):
1103        continents = MediaItem.objects.all().countries(group_by_continent=True)
1104        return render(request, 'telemeta/geo_continents.html',
1105                    {'continents': continents, 'gmap_key': settings.TELEMETA_GMAP_KEY })
1106
1107    def country_info(self, request, id):
1108        country = Location.objects.get(pk=id)
1109        return render(request, 'telemeta/country_info.html', {
1110            'country': country, 'continent': country.continents()[0]})
1111
1112    def list_countries(self, request, continent):
1113        continent = Location.objects.by_flatname(continent)[0]
1114        countries = MediaItem.objects.by_location(continent).countries()
1115
1116        return render(request, 'telemeta/geo_countries.html', {
1117            'continent': continent,
1118            'countries': countries
1119        })
1120
1121    def list_country_collections(self, request, continent, country):
1122        continent = Location.objects.by_flatname(continent)[0]
1123        country = Location.objects.by_flatname(country)[0]
1124        objects = MediaCollection.objects.enriched().by_location(country)
1125        return list_detail.object_list(request, objects,
1126            template_name='telemeta/geo_country_collections.html', paginate_by=20,
1127            extra_context={'country': country, 'continent': continent})
1128
1129    def list_country_items(self, request, continent, country):
1130        continent = Location.objects.by_flatname(continent)[0]
1131        country = Location.objects.by_flatname(country)[0]
1132        objects = MediaItem.objects.enriched().by_location(country)
1133        return list_detail.object_list(request, objects,
1134            template_name='telemeta/geo_country_items.html', paginate_by=20,
1135            extra_context={'country': country, 'continent': continent})
1136
1137class MarkerView(object):
1138    """Provide Collections web UI methods"""
1139
1140    @jsonrpc_method('telemeta.add_marker')
1141    def add_marker(request, marker):
1142        # marker must be a dict
1143        if isinstance(marker, dict):
1144            item_id = marker['item_id']
1145            item = MediaItem.objects.get(id=item_id)
1146            m = MediaItemMarker(item=item)
1147            m.public_id = marker['public_id']
1148            m.time = float(marker['time'])
1149            m.title = marker['title']
1150            m.description = marker['description']
1151            m.author = User.objects.get(username=marker['author'])
1152            m.save()
1153            m.set_revision(request.user)
1154        else:
1155            raise 'Error : Bad marker dictionnary'
1156
1157    @jsonrpc_method('telemeta.del_marker')
1158    def del_marker(request, public_id):
1159        m = MediaItemMarker.objects.get(public_id=public_id)
1160        m.delete()
1161
1162    @jsonrpc_method('telemeta.get_markers')
1163    def get_markers(request, item_id):
1164        item = MediaItem.objects.get(id=item_id)
1165        markers = MediaItemMarker.objects.filter(item=item)
1166        list = []
1167        for marker in markers:
1168            dict = {}
1169            dict['public_id'] = marker.public_id
1170            dict['time'] = str(marker.time)
1171            dict['title'] = marker.title
1172            dict['description'] = marker.description
1173            dict['author'] = marker.author.username
1174            list.append(dict)
1175        return list
1176
1177    @jsonrpc_method('telemeta.update_marker')
1178    def update_marker(request, marker):
1179        if isinstance(marker, dict):
1180            m = MediaItemMarker.objects.get(public_id=marker['public_id'])
1181            m.time = float(marker['time'])
1182            m.title = marker['title']
1183            m.description = marker['description']
1184            m.save()
1185            m.set_revision(request.user)
1186        else:
1187            raise 'Error : Bad marker dictionnary'
1188
1189    @jsonrpc_method('telemeta.get_marker_id')
1190    def get_marker_id(request, public_id):
1191        marker = MediaItemMarker.objects.get(public_id=public_id)
1192        return marker.id
1193
1194class PlaylistView(object):
1195    """Provide Collections web UI methods"""
1196
1197    @jsonrpc_method('telemeta.add_playlist')
1198    def add_playlist(request, playlist):
1199        # playlist must be a dict
1200        if isinstance(playlist, dict):
1201            m = Playlist()
1202            m.public_id = playlist['public_id']
1203            m.title = playlist['title']
1204            m.description = playlist['description']
1205            m.author = request.user
1206            m.save()
1207        else:
1208            raise 'Error : Bad playlist dictionnary'
1209
1210    @jsonrpc_method('telemeta.del_playlist')
1211    def del_playlist(request, public_id):
1212        m = Playlist.objects.get(public_id=public_id)
1213        m.delete()
1214
1215    @jsonrpc_method('telemeta.update_playlist')
1216    def update_playlist(request, playlist):
1217        if isinstance(playlist, dict):
1218            m = Playlist.objects.get(public_id=playlist['public_id'])
1219            m.title = float(playlist['title'])
1220            m.description = playlist['description']
1221            m.save()
1222        else:
1223            raise 'Error : Bad playlist dictionnary'
1224
1225    @jsonrpc_method('telemeta.add_playlist_resource')
1226    def add_playlist_resource(request, playlist_id, playlist_resource):
1227        # playlist_resource must be a dict
1228        if isinstance(playlist_resource, dict):
1229            m = PlaylistResource()
1230            m.public_id = playlist_resource['public_id']
1231            m.playlist = Playlist.objects.get(public_id=playlist_id, author=request.user)
1232            m.resource_type = playlist_resource['resource_type']
1233            m.resource_id = playlist_resource['resource_id']
1234            m.save()
1235        else:
1236            raise 'Error : Bad playlist_resource dictionnary'
1237
1238    @jsonrpc_method('telemeta.del_playlist_resource')
1239    def del_playlist_resource(request, public_id):
1240        m = PlaylistResource.objects.get(public_id=public_id)
1241        m.delete()
1242
1243
1244    def playlist_csv_export(self, request, public_id, resource_type):
1245        playlist = Playlist.objects.get(public_id=public_id, author=request.user)
1246        resources = PlaylistResource.objects.filter(playlist=playlist)
1247        response = HttpResponse(mimetype='text/csv')
1248        response['Content-Disposition'] = 'attachment; filename='+playlist.title+'_'+resource_type+'.csv'
1249        writer = UnicodeWriter(response)
1250
1251        elements = []
1252        for resource in resources:
1253            if resource_type == 'items':
1254                if resource.resource_type == 'collection':
1255                    collection = MediaCollection.objects.get(id=resource.resource_id)
1256                    collection_items = MediaItem.objects.filter(collection=collection)
1257                    for item in collection_items:
1258                        elements.append(item)
1259                elif resource.resource_type == 'item':
1260                    item = MediaItem.objects.get(id=resource.resource_id)
1261                    elements.append(item)
1262
1263            elif resource_type == 'collections':
1264                if resource.resource_type == 'collection':
1265                    collection = MediaCollection.objects.get(id=resource.resource_id)
1266                    elements.append(collection)
1267
1268        if elements:
1269            element = elements[0].to_dict()
1270            tags = element.keys()
1271            # code and title on the two first column
1272            tags.remove('code')
1273            tags.remove('title')
1274            tags.sort()
1275            tags.insert(0, 'title')
1276            tags.insert(0, 'code')
1277            writer.writerow(tags)
1278
1279            for element in elements:
1280                data = []
1281                element = element.to_dict()
1282                for tag in tags:
1283                    data.append(element[tag])
1284                writer.writerow(data)
1285        return response
1286
1287
1288class ProfileView(object):
1289    """Provide Collections web UI methods"""
1290
1291    @method_decorator(login_required)
1292    def profile_detail(self, request, username, template='telemeta/profile_detail.html'):
1293        user = User.objects.get(username=username)
1294        try:
1295            profile = user.get_profile()
1296        except:
1297            profile = None
1298        playlists = get_playlists(request, user)
1299        return render(request, template, {'profile' : profile, 'usr': user, 'playlists': playlists})
1300
1301    def profile_edit(self, request, username, template='telemeta/profile_edit.html'):
1302        if request.user.is_superuser:
1303            user_hidden_fields = ['profile-user', 'user-password', 'user-last_login', 'user-date_joined']
1304        else:
1305            user_hidden_fields = ['user-username', 'user-is_staff', 'profile-user', 'user-is_active',
1306                         'user-password', 'user-last_login', 'user-date_joined', 'user-groups',
1307                         'user-user_permissions', 'user-is_superuser', 'profile-expiration_date']
1308
1309        user = User.objects.get(username=username)
1310        if user != request.user and not request.user.is_staff:
1311            mess = ugettext('Access not allowed')
1312            title = ugettext('User profile') + ' : ' + username + ' : ' + mess
1313            description = ugettext('Please login or contact the website administator to get a private access.')
1314            messages.error(request, title)
1315            return render(request, 'telemeta/messages.html', {'description' : description})
1316
1317        try:
1318            profile = user.get_profile()
1319        except:
1320            profile = UserProfile(user=user)
1321
1322        if request.method == 'POST':
1323            user_form = UserChangeForm(request.POST, instance=user, prefix='user')
1324            profile_form = UserProfileForm(request.POST, instance=profile, prefix='profile')
1325            if user_form.is_valid() and profile_form.is_valid():
1326                user_form.save()
1327                profile_form.save()
1328                return HttpResponseRedirect('/users/'+username+'/profile/')
1329        else:
1330            user_form = UserChangeForm(instance=user, prefix='user')
1331            profile_form = UserProfileForm(instance=profile, prefix='profile')
1332            forms = [user_form, profile_form]
1333        return render(request, template, {'forms': forms, 'usr': user, 'user_hidden_fields': user_hidden_fields})
1334
1335
1336class LastestRevisionsFeed(Feed):
1337    "the RSS feed of the lastest revisions"
1338
1339    organization = settings.TELEMETA_ORGANIZATION
1340    subjects = settings.TELEMETA_SUBJECTS
1341    tags = ['title', 'description', 'comment']
1342    title = organization + ' - Telemeta - ' + ugettext('Last changes')
1343    link = ""
1344    description = ' '.join([subject.decode('utf-8') for subject in subjects])
1345    n_items = 100
1346
1347    def items(self):
1348        return get_revisions(self.n_items)
1349
1350    def item_title(self, r):
1351        element = r['element']
1352        if element.title == '':
1353            title = str(element.public_id)
1354        else:
1355            title = element.title
1356        return element.element_type + ' : ' + title
1357
1358    def item_description(self, r):
1359        revision = r['revision']
1360        element = r['element']
1361        description = '<b>modified by ' + revision.user.username + ' on ' + unicode(revision.time) + '</b><br /><br />'
1362        dict = element.to_dict()
1363        for tag in dict.keys():
1364            try:
1365                value = dict[tag]
1366                if value != '':
1367                    description += tag + ' : ' + value + '<br />'
1368            except:
1369                continue
1370        return description.encode('utf-8')
1371
1372    def item_link(self, r):
1373        revision = r['revision']
1374        element = r['element']
1375        link = '/' + revision.element_type + 's/' + str(element.public_id)
1376        return link
1377
1378
Note: See TracBrowser for help on using the repository browser.