src/cm/api/handlers.py
author raph
Mon, 19 Jul 2010 17:26:25 +0200
changeset 299 34b4038e3069
parent 297 173710f4b6d1
child 300 7aaf5c0d6af4
permissions -rw-r--r--
check with api version of security checking prior to fun call

from piston.handler import AnonymousBaseHandler, BaseHandler
from piston.utils import rc

from cm.models import Text,TextVersion, Role, UserRole, Comment
from cm.views import get_keys_from_dict, get_textversion_by_keys_or_404, get_text_by_keys_or_404, get_textversion_by_keys_or_404, redirect
from cm.security import get_texts_with_perm, has_perm, get_viewable_comments, \
    has_perm_on_text_api
from cm.security import get_viewable_comments
from cm.utils.embed import embed_html
from cm.views.create import CreateTextContentForm, create_text
from cm.views.texts import client_exchange, text_view_frame, text_view_comments, text_export
from cm.views.feeds import text_feed
from piston.utils import validate
from django.conf import settings

URL_PREFIX = settings.SITE_URL + '/api'
 
class AnonymousTextHandler(AnonymousBaseHandler):
    type = "Text methods"
    title = "Read text info"
    fields = ('key', 'title', 'format', 'content', 'created', 'modified', 'nb_comments', 'nb_versions', 'embed_html', ('last_text_version', ('created','modified', 'format', 'title', 'content')))   
    allowed_methods = ('GET', )   
    model = Text
    desc = """ Read text identified by `key`."""
    args = None

    @staticmethod
    def endpoint():
        return URL_PREFIX + '/text/{key}/'


    @has_perm_on_text_api('can_view_text')
    def read(self, request, key):
        
        text = get_text_by_keys_or_404(key)
        setattr(text,'nb_comments',len(get_viewable_comments(request, text.last_text_version.comment_set.all(), text)))
        setattr(text,'nb_versions',text.get_versions_number())
        setattr(text,'embed_html',embed_html(text.key))

        return text

class TextHandler(BaseHandler):
    type = "Text methods"    
    anonymous = AnonymousTextHandler
    allowed_methods = ('GET',)  
    no_display = True 

class AnonymousTextVersionHandler(AnonymousBaseHandler):
    type = "Text methods"
    title = "Read text version info"
    fields = ('key', 'title', 'format', 'content', 'created', 'modified', 'nb_comments',)   
    allowed_methods = ('GET', )   
    model = Text
    desc = """ Read text version identified by `version_key` inside text identified by `key`."""
    args = None

    @staticmethod
    def endpoint():
        return URL_PREFIX + '/text/{key}/{version_key}/'


    @has_perm_on_text_api('can_view_text')
    def read(self, request, key, version_key):
        text_version = get_textversion_by_keys_or_404(version_key, key=key)
        setattr(text_version,'nb_comments',len(get_viewable_comments(request, text_version.comment_set.all(), text_version.text)))

        return text_version

class TextVersionHandler(BaseHandler):
    type = "Text methods"    
    anonymous = AnonymousTextVersionHandler
    fields = ('key', 'title', 'format', 'content', 'created', 'modified', 'nb_comments',)   
    allowed_methods = ('GET', )   
    model = Text
    no_display = True 

    @has_perm_on_text_api('can_view_text')
    def read(self, request, key, version_key):
        text_version = get_textversion_by_keys_or_404(version_key, key=key)
        setattr(text_version,'nb_comments',len(get_viewable_comments(request, text_version.comment_set.all(), text_version.text)))

        return text_version

class AnonymousTextListHandler(AnonymousBaseHandler):
    title = "List texts"    
    type = "Text methods"    
    fields = ('key', 'title', 'created', 'modified', 'nb_comments', 'nb_versions',)   
    allowed_methods = ('GET',)   
    model = Text
    desc = """Lists texts on workspace."""        

    @staticmethod
    def endpoint():
        return URL_PREFIX + '/text/'

    def read(self, request):
        order_by = '-id'
        texts = get_texts_with_perm(request, 'can_view_text').order_by(order_by)        
        return texts

class TextListHandler(BaseHandler):
    title = "Create text"    
    type = "Text methods"    
    allowed_methods = ('GET', 'POST')    
    fields = ('key', 'title', 'created', 'modified', 'nb_comments', 'nb_versions',)   
    model = Text
    anonymous = AnonymousTextListHandler
    desc = "Create a text with the provided parameters."
    args = """<br/>
`title`: title of the text<br/>
`format`: format content ('markdown', 'html')<br/>
`content`: content (in specified format)<br/>
`anon_role`: role to give to anon users: null, 4: commentator, 5: observer<br/>
        """
     
    @staticmethod
    def endpoint():
        return URL_PREFIX + '/text/'

    def read(self, request):
        order_by = '-id'
        texts = get_texts_with_perm(request, 'can_view_text').order_by(order_by)        
        return texts

    def create(self, request):
        form = CreateTextContentForm(request.POST)
        if form.is_valid():
            text = create_text(request.user, form.cleaned_data)
            anon_role = request.POST.get('anon_role', None)
            if anon_role:
                userrole = UserRole.objects.create(user=None, role=Role.objects.get(id=anon_role), text=text)         
            return {'key' : text.key , 'version_key' : text.last_text_version.key, 'created': text.created}
        else:
            resp = rc.BAD_REQUEST
        return resp

from cm.exception import UnauthorizedException
from cm.views.texts import text_delete

class TextDeleteHandler(BaseHandler):
    type = "Text methods"
    allowed_methods = ('POST', )    
    title = "Delete text"    
    desc = "Delete the text identified by `key`."

    @staticmethod
    def endpoint():
        return URL_PREFIX + '/text/{key}/delete/'

    def create(self, request, key):
        """
        Delete text identified by `key`.
        """
        try:
            text_delete(request, key=key)
        except UnauthorizedException:
            return rc.FORBIDDEN
        except KeyError:
            return rc.BAD_REQUEST
        return rc.DELETED

from cm.views.texts import text_pre_edit
 
class TextPreEditHandler(BaseHandler):
    type = "Text methods"
    allowed_methods = ('POST', )    
    title = "Ask for edit impact"    
    desc = "Returns the number of impacted comments."
    args = """<br />
`new_format`: new format content ('markdown', 'html')<br />        
`new_content`: new content (in specified format)<br />    
    """ 

    @staticmethod
    def endpoint():
        return URL_PREFIX + '/text/{key}/pre_edit/'
    
    def create(self, request, key):
        return text_pre_edit(request, key=key)

from cm.views.texts import text_edit
    
class TextEditHandler(BaseHandler):
    allowed_methods = ('POST', )    
    type = "Text methods"
    title = "Edit text"    
    desc = "Update text identified by `key`."
    args = """<br />
`title`: new title of the text<br />
`format`: new format content ('markdown', 'html')<br />
`content`: new content (in specified format)<br />
`note`: note to add to edit<br />
`new_version`: boolean: should a new version of the text be created?<br />
`keep_comments`: boolean: should existing comments be keep (if possible)?<br />
    """ 
    
    @staticmethod
    def endpoint():
        return URL_PREFIX + '/text/{key}/edit/'
    
    
    def create(self, request, key):
        res = text_edit(request, key=key)
        text = get_text_by_keys_or_404(key)
        text_version = text.last_text_version
        return {'version_key' : text_version.key , 'created': text_version.created}


class AnonymousTextFeedHandler(AnonymousBaseHandler):
    allowed_methods = ('GET',)    
    type = "Text methods"
    title = "Text feed"
    desc = "Returns text RSS feed."
    args = None
    
    @staticmethod
    def endpoint():
        return URL_PREFIX + '/text/{key}/feed/?'
    
    def read(self, request, key):
        return text_feed(request, key=key)

class TextFeedHandler(BaseHandler):    
    type = "Text methods"
    anonymous = AnonymousTextFeedHandler
    allowed_methods = ('GET',)  
    no_display = True

    def read(self, request, key):
        return text_feed(request, key=key)
    
class TextVersionRevertHandler(BaseHandler):
    allowed_methods = ('POST', )    
    type = "Text methods"
    title = "Revert to specific text version"    
    desc = "Revert to a text version (i.e. copy this text_version which becomes the last text_version)."
    args = """<br />
`key`: text's key<br />
`version_key`: key of the version to revert to<br />
    """ 
    
    @staticmethod
    def endpoint():
        return URL_PREFIX + '/text/{key}/{version_key}/revert/'
    
    
    def create(self, request, key, version_key):
        text_version = get_textversion_by_keys_or_404(version_key, key=key)
        new_text_version = text_version.text.revert_to_version(version_key)
        return {'version_key' : new_text_version.key , 'created': new_text_version.created}

class TextVersionDeleteHandler(BaseHandler):
    allowed_methods = ('POST', )    
    type = "Text methods"
    title = "Delete a specific text version"    
    desc = "Delete a text version."
    args = """<br />
`key`: text's key<br />
`version_key`: key of the version to delete<br />
    """ 
    
    @staticmethod
    def endpoint():
        return URL_PREFIX + '/text/{key}/{version_key}/delete/'
    
    
    def create(self, request, key, version_key):
        text_version = get_textversion_by_keys_or_404(version_key, key=key)
        text_version.delete()
        return rc.ALL_OK    

## client methods

class AnonymousClientHandler(AnonymousBaseHandler):
    allowed_methods = ('POST',)    
    type = "Client methods"
    title = "Handles client methods"
    desc = "Handles client (ajax text view) methods."
    args = """<br />
post arguments
    """ 
    
    @staticmethod
    def endpoint():
        return URL_PREFIX + '/client/'
    
    def create(self, request):
        return client_exchange(request)

class ClientHandler(BaseHandler):    
    type = "Client methods"
    anonymous = AnonymousClientHandler
    allowed_methods = ('POST',)  
    no_display = True 

    def create(self, request):
        return client_exchange(request)

## embed methods
from django.views.i18n import javascript_catalog
from cm.urls import js_info_dict

class JSI18NHandler(AnonymousBaseHandler):
    allowed_methods = ('GET',)    
    type = "Embed methods"
    title = "Get js i18n dicts"
    desc = ""
    args = None
    
    @staticmethod
    def endpoint():
        return URL_PREFIX + '/jsi18n/'
    
    def read(self, request):
        return javascript_catalog(request, **js_info_dict)


class AnonymousCommentFrameHandler(AnonymousBaseHandler):
    allowed_methods = ('GET',)    
    type = "Embed methods"
    title = "Displays embedable frame"
    desc = ""
    args = None
    
    @staticmethod
    def endpoint():
        return URL_PREFIX + '/text/{key}/comments_frame/?prefix=/api'

    @has_perm_on_text_api('can_view_text')    
    def read(self, request, key):
        return text_view_frame(request, key=key)

class CommentFrameHandler(BaseHandler):    
    type = "Embed methods"
    anonymous = AnonymousCommentFrameHandler
    allowed_methods = ('GET',)  
    no_display = True 

    @has_perm_on_text_api('can_view_text')
    def read(self, request, key):
        return text_view_frame(request, key=key)

class AnonymousCommentHandler(AnonymousBaseHandler):
    allowed_methods = ('GET',)    
    type = "Embed methods"
    title = "Displays embedable frame"
    no_display = True 
    desc = ""
    args = None
    
    @staticmethod
    def endpoint():
        return URL_PREFIX + '/text/{key}/comments/{version_key}/?'
    
    @has_perm_on_text_api('can_view_text')    
    def read(self, request, key, version_key):
        return text_view_comments(request, key=key, version_key=version_key)

class CommentHandler(BaseHandler):    
    type = "Embed methods"
    anonymous = AnonymousCommentHandler
    allowed_methods = ('GET',)  
    no_display = True 

    @has_perm_on_text_api('can_view_text')
    def read(self, request, key, version_key):
        return text_view_comments(request, key=key, version_key=version_key)


class AnonymousTextExportHandler(AnonymousBaseHandler):
    allowed_methods = ('POST',)    
    type = "Embed methods"
    title = "undocumented"
    no_display = True 
    desc = ""
    args = None
    
    @staticmethod
    def endpoint():
        return URL_PREFIX + ' undocumented'
    
    @has_perm_on_text_api('can_view_text')    
    def create(self, request, key, format, download, whichcomments, withcolor):
        return text_export(request, key, format, download, whichcomments, withcolor, adminkey=None)

class TextExportHandler(BaseHandler):    
    type = "Embed methods"
    anonymous = AnonymousTextExportHandler
    allowed_methods = ('POST',)  
    no_display = True 

    @has_perm_on_text_api('can_view_text')
    def create(self, request, key, format, download, whichcomments, withcolor):
        return text_export(request, key, format, download, whichcomments, withcolor, adminkey=None)

class AnonymousCommentsHandler(AnonymousBaseHandler):
    allowed_methods = ('GET',)    
    type = "Comment methods"
    fields = ('id_key', 'title', 'format', 'content', 'created', 'name', ('text_version' , ('key', ('text', ('key',))) ))   
    model = Comment    
    title = "Get comments"
    desc = "Get comments from the workspace, most recent first."
    args = """<br />
`keys`: (optional) comma separated keys : limit comments from these texts only<br />
`name`: (optional) limit comments from this user only
`limit`: (optional) limit number of comments returned
    """ 
    
    @staticmethod
    def endpoint():
        return URL_PREFIX + '/comments/'
    
    def read(self, request):
        name = request.GET.get('name', None)
        limit = request.GET.get('limit', None)
        keys = request.GET.get('keys', None)
        query = Comment.objects.all()
        if keys:            
            query = query.filter(text_version__text__key__in=keys.split(','))
        if name:
            query = query.filter(name=name)
        query = query.order_by('-created')
        if limit:
            query = query[:int(limit)]
        return query

class CommentsHandler(BaseHandler):    
    type = "Comment methods"
    anonymous = AnonymousCommentsHandler
    allowed_methods = ('GET',)  
    fields = ('id_key', 'title', 'format', 'content', 'created', 'name', ('text_version' , ('key', ('text', ('key',))) ))   
    model = Comment
    no_display = True 

    def read(self, request):
        name = request.GET.get('name', None)
        limit = request.GET.get('limit', None)
        keys = request.GET.get('keys', None)
        query = Comment.objects.all()
        if keys:            
            query = query.filter(text_version__text__key__in=keys.split(','))
        if name:
            query = query.filter(name=name)
        query = query.order_by('-created')
        if limit:
            query = query[:int(limit)]
        return query
    
from piston.doc import documentation_view

from piston.handler import handler_tracker
from django.template import RequestContext
from piston.doc import generate_doc
from django.shortcuts import render_to_response

def documentation(request):
    """
    Generic documentation view. Generates documentation
    from the handlers you've defined.
    """
    docs = [ ]

    for handler in handler_tracker:
        doc = generate_doc(handler)
        setattr(doc,'type', handler.type)
        docs.append(doc)

    def _compare(doc1, doc2): 
       #handlers and their anonymous counterparts are put next to each other.
       name1 = doc1.name.replace("Anonymous", "")
       name2 = doc2.name.replace("Anonymous", "")
       return cmp(name1, name2)    
 
    #docs.sort(_compare)
       
    return render_to_response('api_doc.html', 
        { 'docs': docs }, RequestContext(request))

from piston.doc import generate_doc
DocHandler = generate_doc(TextPreEditHandler)