from celery import Task


__all__ = ('PublicTask', 'permission_check')


class PublicTask(Task):
    public_name = 'unknown'

    @classmethod
    def check_permission(cls, request, state, context):
        """
        Override this method to define who can monitor this task.
        """
        return False

    def get_task_data(self):
        """
        Return a tuple with the state that should be set next and the results
        task.
        """
        state = 'STARTED'
        info = {
            'task_name': self.name,
            'context': self.request.get('permission_context', {}),
            'public_data': self.request.get('public_data', {}),
        }
        return state, info

    def update_progress_data(self):
        state, info = self.get_task_data()
        self.update_state(state=state, meta=info)

    def set_permission_context(self, context):
        """
        Set data that can be used by ``check_permission`` to authorize a
        request for the this task. By default it will be the ``kwargs`` passed
        into the task.
        """
        self.request.update(permission_context=context)
        self.update_progress_data()

    def set_public_data(self, data):
        """
        Set data that can be displayed in the frontend to authorized users.
        This might include progress data about the task.
        """
        self.request.update(public_data=data)
        self.update_progress_data()

    def run(self, *args, **kwargs):
        self.set_permission_context(kwargs)
        result = self.run_public(*args, **kwargs)
        if result is not None:
            self.set_public_data(result)
        state, info = self.get_task_data()
        return info

    def run_public(self, *args, **kwargs):
        raise NotImplementedError(
            'Public tasks must define the run_public method.')


def permission_check(check):
    """
    Class decorator for subclasses of PublicTask to sprinkle in re-usable
    permission checks::

        @permission_check(user_id_matches)
        class MyTask(PublicTask):
            def run_public(self, user_id):
                pass
    """

    def decorator(cls):
        cls.check_permission = staticmethod(check)
        return cls
    return decorator

@@ -18,16 +18,88 @@
 t Task%0A%0A
+from .retrieve import TaskNotFound%0Afrom .retrieve import get_task_data%0A%0A
 %0A__all__
@@ -102,16 +102,21 @@
 ll__ = (
+%0A    
 'PublicT
@@ -126,52 +126,155 @@
 ', '
-permission_check')%0A%0A%0Aclass PublicTask(Task):
+TaskNoPermission', 'permission_check',%0A    'get_public_task_data')%0A%0A%0Aclass PublicTask(Task):%0A    %22%22%22%0A    See oauth.tasks for usage example.%0A    %22%22%22
 %0A   
@@ -2433,8 +2433,1205 @@
 corator%0A
+%0A%0Aclass TaskNoPermission(Exception):%0A    def __init__(self, task_id, *args, **kwargs):%0A        message = 'No permission to access task with id %7Bid%7D'.format(%0A            id=task_id)%0A        super(TaskNoPermission, self).__init__(message, *args, **kwargs)%0A%0A%0Adef get_public_task_data(request, task_id):%0A    %22%22%22%0A    Return a 3-value tuple with the public name of the task, the current state%0A    of the task and the data that can be displayed publicly about this task.%0A%0A    Will raise %60TaskNoPermission%60 if %60request%60 has no permission to access info%0A    of the task with id %60task_id%60. This is also the case of no task with the%0A    given id exists.%0A    %22%22%22%0A    try:%0A        task, state, info = get_task_data(task_id)%0A    except TaskNotFound:%0A        # No task info has been found act like we don't have permission to see%0A        # the results.%0A        raise TaskNoPermission(task_id)%0A%0A    if not hasattr(task, 'check_permission'):%0A        raise TaskNoPermission(task_id)%0A%0A    context = info.get('context', %7B%7D)%0A    if not task.check_permission(request, state, context):%0A        raise TaskNoPermission(task_id)%0A    public_name = task.public_name%0A    return public_name, state, info.get('public_data', %7B%7D)%0A

Add interface to retrieve task data that the request is authorized for