diff --git a/docs/changelog.rst b/docs/changelog.rst
index 5ab9cd9..67fc19f 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -1,6 +1,8 @@
Changelog
=========
+* :feature:`-` add new app :py:mod:`taskresults` that takes care of handling
+ asynchronous `Celery`_ results
* :feature:`-` add new task :py:func:`osusers.tasks.delete_ldap_group` (needs
gvaldap >= 0.2.0 on the LDAP side)
* :feature:`-` add a `customer` field to :py:class:`osusers.models.User`
@@ -30,10 +32,11 @@ Changelog
* :feature:`-` full test suite for osusers
* :feature:`-` full test suite for managemails app
* :feature:`-` full test suite for domains app
-* :feature:`-` `Celery `_ integration for ldap
- synchronization
+* :feature:`-` `Celery`_ integration for ldap synchronization
* :release:`0.1 <2014-05-25>`
* :feature:`-` initial model code for os users
* :feature:`-` initial model code for mail address and mailbox management
* :feature:`-` initial model code for domains
+
+.. _Celery: http://www.celeryproject.org/
diff --git a/docs/code.rst b/docs/code.rst
index db64b7f..eb4f62f 100644
--- a/docs/code.rst
+++ b/docs/code.rst
@@ -149,3 +149,29 @@ provides some functionality that is common to all gnuviechadmin subprojects.
.. autotask:: osusers.tasks.remove_ldap_user_from_group
.. autotask:: osusers.tasks.setup_file_mail_userdir
.. autotask:: osusers.tasks.setup_file_sftp_userdir
+
+
+:py:mod:`taskresults` app
+=========================
+
+.. automodule:: taskresults
+
+:py:mod:`admin `
+-----------------------------------
+
+.. automodule:: taskresults.admin
+
+:py:mod:`management.commands `
+---------------------------------------------------------------
+
+.. automodule:: taskresults.management.commands
+
+:py:mod:`fetch_taskresults `
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. automodule:: taskresults.management.commands.fetch_taskresults
+
+:py:mod:`models `
+-------------------------------------
+
+.. automodule:: taskresults.models
diff --git a/gnuviechadmin/gnuviechadmin/settings/base.py b/gnuviechadmin/gnuviechadmin/settings/base.py
index b770e8d..e30df47 100644
--- a/gnuviechadmin/gnuviechadmin/settings/base.py
+++ b/gnuviechadmin/gnuviechadmin/settings/base.py
@@ -224,6 +224,7 @@ DJANGO_APPS = (
# Apps specific for this project go here.
LOCAL_APPS = (
+ 'taskresults',
'domains',
'osusers',
'managemails',
diff --git a/gnuviechadmin/taskresults/__init__.py b/gnuviechadmin/taskresults/__init__.py
new file mode 100644
index 0000000..0b3d916
--- /dev/null
+++ b/gnuviechadmin/taskresults/__init__.py
@@ -0,0 +1,5 @@
+"""
+This is the taskresults app that is used for storing the results from
+asynchronous `Celery `_ tasks.
+
+"""
diff --git a/gnuviechadmin/taskresults/admin.py b/gnuviechadmin/taskresults/admin.py
new file mode 100644
index 0000000..cd47dc8
--- /dev/null
+++ b/gnuviechadmin/taskresults/admin.py
@@ -0,0 +1,12 @@
+"""
+This module defines the admin interface for the taskresults app.
+
+"""
+from __future__ import absolute_import
+
+from django.contrib import admin
+
+from .models import TaskResult
+
+
+admin.site.register(TaskResult)
diff --git a/gnuviechadmin/taskresults/management/__init__.py b/gnuviechadmin/taskresults/management/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/gnuviechadmin/taskresults/management/commands/__init__.py b/gnuviechadmin/taskresults/management/commands/__init__.py
new file mode 100644
index 0000000..4e6e692
--- /dev/null
+++ b/gnuviechadmin/taskresults/management/commands/__init__.py
@@ -0,0 +1,4 @@
+"""
+This module defines management commands for the taskresults app.
+
+"""
diff --git a/gnuviechadmin/taskresults/management/commands/fetch_taskresults.py b/gnuviechadmin/taskresults/management/commands/fetch_taskresults.py
new file mode 100644
index 0000000..8ccbd78
--- /dev/null
+++ b/gnuviechadmin/taskresults/management/commands/fetch_taskresults.py
@@ -0,0 +1,20 @@
+"""
+This model contains the implementation of a management command to fetch the
+results of all `Celery `_ tasks that are not
+marked as finished yet.
+
+"""
+from __future__ import unicode_literals
+
+from django.core.management.base import BaseCommand
+
+from taskresults.models import TaskResult
+
+
+class Command(BaseCommand):
+ help = "fetch task results"
+
+ def handle(self, *args, **options):
+ for taskresult in TaskResult.objects.filter(finished=False):
+ taskresult.fetch_result()
+ taskresult.save()
diff --git a/gnuviechadmin/taskresults/migrations/0001_initial.py b/gnuviechadmin/taskresults/migrations/0001_initial.py
new file mode 100644
index 0000000..7c405be
--- /dev/null
+++ b/gnuviechadmin/taskresults/migrations/0001_initial.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='TaskResult',
+ fields=[
+ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+ ('task_id', models.CharField(max_length=36, verbose_name='Task id')),
+ ('task_name', models.CharField(max_length=64, verbose_name='Task name')),
+ ('result', models.TextField(verbose_name='Task result')),
+ ('finished', models.BooleanField(default=False)),
+ ('state', models.CharField(max_length=16, verbose_name='Task state')),
+ ],
+ options={
+ 'verbose_name': 'Task result',
+ 'verbose_name_plural': 'Task results',
+ },
+ bases=(models.Model,),
+ ),
+ ]
diff --git a/gnuviechadmin/taskresults/migrations/__init__.py b/gnuviechadmin/taskresults/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/gnuviechadmin/taskresults/models.py b/gnuviechadmin/taskresults/models.py
new file mode 100644
index 0000000..7178c84
--- /dev/null
+++ b/gnuviechadmin/taskresults/models.py
@@ -0,0 +1,47 @@
+"""
+This model defines the database models to handle Celery AsyncResults.
+
+"""
+from __future__ import unicode_literals
+
+from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+from django.utils.translation import ugettext as _
+
+from gnuviechadmin.celery import app
+
+
+class TaskResultManager(models.Manager):
+ def create_task_result(self, asyncresult, name):
+ taskresult = self.create(task_id=asyncresult.id, task_name=name)
+ return taskresult
+
+
+@python_2_unicode_compatible
+class TaskResult(models.Model):
+ task_id = models.CharField(_('Task id'), max_length=36)
+ task_name = models.CharField(_('Task name'), max_length=64)
+ result = models.TextField(_('Task result'))
+ finished = models.BooleanField(default=False)
+ state = models.CharField(_('Task state'), max_length=16)
+
+ objects = TaskResultManager()
+
+ class Meta:
+ verbose_name = _('Task result')
+ verbose_name_plural = _('Task results')
+
+ def __str__(self):
+ return "{task_name} ({task_id}): {finished}".format(
+ task_name=self.task_name,
+ task_id=self.task_id,
+ finished=_('yes') if self.finished else _('no')
+ )
+
+ def fetch_result(self):
+ if not self.finished:
+ ar = app.AsyncResult(self.task_id)
+ res = ar.get(no_ack=True, timeout=1)
+ self.result = str(res)
+ self.state = ar.state
+ self.finished = True