We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
My Channels not listing the new channels after import
## Summary

After importing a channel, whether from local drive or Internet, it does not appear under `My Channels` until page reload. 

## System information

 - Version: `0.5.0-beta9`
 - Operating system: Windows 7 & Ubuntu 16.10
 - Browser: Chrome

![ubuntu3 0 5-beta9 running - oracle vm virtualbox_494](https://user-images.githubusercontent.com/1457929/29728036-9cf986f8-89d6-11e7-99b0-fc0d7619fbdd.png)


On [version 0.4.0](https://github.com/learningequality/kolibri/issues/1640#issuecomment-313949731) at least there was a green notification, but now it's missing too:

![selection_328](https://user-images.githubusercontent.com/1457929/27996982-56743686-64ee-11e7-8f3d-cb2e1044b7d9.png)

State is correctly reported after deleting the channel, green notification included.

![ubuntu3 0 5-beta9 running - oracle vm virtualbox_496](https://user-images.githubusercontent.com/1457929/29727957-49d8e04a-89d6-11e7-8af6-3a70805475a4.png)

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `kolibri/tasks/api.py`
Content:
```
1 import logging as logger
2 import os
3 
4 import requests
5 from barbequeue.common.classes import State
6 from barbequeue.exceptions import UserCancelledError
7 from django.apps.registry import AppRegistryNotReady
8 from django.core.management import call_command
9 from django.db import connections
10 from django.http import Http404
11 from django.utils.translation import ugettext as _
12 from kolibri.content.models import ChannelMetadataCache
13 from kolibri.content.utils.channels import get_mounted_drives_with_channel_info
14 from kolibri.content.utils.paths import get_content_database_file_path, get_content_database_file_url
15 from rest_framework import serializers, viewsets
16 from rest_framework.decorators import list_route
17 from rest_framework.response import Response
18 
19 from .client import get_client
20 from .permissions import IsDeviceOwnerOnly
21 
22 try:
23     from django.apps import apps
24 
25     apps.check_apps_ready()
26 except AppRegistryNotReady:
27     import django
28 
29     django.setup()
30 
31 
32 logging = logger.getLogger(__name__)
33 
34 REMOTE_IMPORT = 'remoteimport'
35 LOCAL_IMPORT = 'localimport'
36 LOCAL_EXPORT = 'localexport'
37 
38 id_tasktype = {}
39 
40 class TasksViewSet(viewsets.ViewSet):
41     permission_classes = (IsDeviceOwnerOnly,)
42 
43     def list(self, request):
44         jobs_response = [_job_to_response(j) for j in get_client().all_jobs()]
45         ids = [job["id"] for job in jobs_response]
46         # Clean up old job tasktypes
47         for key in id_tasktype.keys():
48             if key not in ids:
49                 id_tasktype.pop(key)
50         get_client().clear(force=False)
51         return Response(jobs_response)
52 
53     def create(self, request):
54         # unimplemented. Call out to the task-specific APIs for now.
55         pass
56 
57     def retrieve(self, request, pk=None):
58         task = _job_to_response(get_client().status(pk))
59         return Response(task)
60 
61     def destroy(self, request, pk=None):
62         # unimplemented for now.
63         pass
64 
65     @list_route(methods=['post'])
66     def startremoteimport(self, request):
67         '''Download a channel's database from the main curation server, and then
68         download its content.
69 
70         '''
71 
72         if "channel_id" not in request.data:
73             raise serializers.ValidationError(
74                 "The 'channel_id' field is required.")
75 
76         channel_id = request.data['channel_id']
77 
78         # ensure the requested channel_id can be found on the central server, otherwise error
79         status = requests.head(
80             get_content_database_file_url(channel_id)).status_code
81         if status == 404:
82             raise Http404(
83                 _("The requested channel does not exist on the content server")
84             )
85 
86         task_id = get_client().schedule(
87             _networkimport, channel_id, track_progress=True, cancellable=True)
88 
89         id_tasktype[task_id] = REMOTE_IMPORT
90 
91         # attempt to get the created Task, otherwise return pending status
92         resp = _job_to_response(get_client().status(task_id))
93 
94         return Response(resp)
95 
96     @list_route(methods=['post'])
97     def startlocalimport(self, request):
98         """
99         Import a channel from a local drive, and copy content to the local machine.
100         """
101         # Importing django/running setup because Windows...
102 
103         if "drive_id" not in request.data:
104             raise serializers.ValidationError(
105                 "The 'drive_id' field is required.")
106 
107         task_id = get_client().schedule(
108             _localimport, request.data['drive_id'], track_progress=True, cancellable=True)
109 
110         id_tasktype[task_id] = LOCAL_IMPORT
111 
112         # attempt to get the created Task, otherwise return pending status
113         resp = _job_to_response(get_client().status(task_id))
114 
115         return Response(resp)
116 
117     @list_route(methods=['post'])
118     def startlocalexport(self, request):
119         '''
120         Export a channel to a local drive, and copy content to the drive.
121 
122         '''
123 
124         if "drive_id" not in request.data:
125             raise serializers.ValidationError(
126                 "The 'drive_id' field is required.")
127 
128         task_id = get_client().schedule(
129             _localexport, request.data['drive_id'], track_progress=True, cancellable=True)
130 
131         id_tasktype[task_id] = LOCAL_EXPORT
132 
133         # attempt to get the created Task, otherwise return pending status
134         resp = _job_to_response(get_client().status(task_id))
135 
136         return Response(resp)
137 
138     @list_route(methods=['post'])
139     def canceltask(self, request):
140         '''
141         Cancel a task with its task id given in the task_id parameter.
142         '''
143 
144         if 'task_id' not in request.data:
145             raise serializers.ValidationError(
146                 "The 'task_id' field is required.")
147 
148         get_client().cancel(request.data['task_id'])
149         get_client().clear(force=True)
150         return Response({})
151 
152     @list_route(methods=['post'])
153     def cleartasks(self, request):
154         '''
155         Cancels all running tasks.
156         '''
157 
158         get_client().clear(force=True)
159         return Response({})
160 
161     @list_route(methods=['get'])
162     def localdrive(self, request):
163         drives = get_mounted_drives_with_channel_info()
164 
165         # make sure everything is a dict, before converting to JSON
166         assert isinstance(drives, dict)
167         out = [mountdata._asdict() for mountdata in drives.values()]
168 
169         return Response(out)
170 
171 
172 def _networkimport(channel_id, update_progress=None, check_for_cancel=None):
173     call_command(
174         "importchannel",
175         "network",
176         channel_id,
177         update_progress=update_progress,
178         check_for_cancel=check_for_cancel)
179     try:
180         call_command(
181             "importcontent",
182             "network",
183             channel_id,
184             update_progress=update_progress,
185             check_for_cancel=check_for_cancel)
186     except UserCancelledError:
187         connections.close_all()  # close all DB connections (FIX for #1818)
188         try:
189             os.remove(get_content_database_file_path(channel_id))
190         except OSError:
191             pass
192         ChannelMetadataCache.objects.filter(id=channel_id).delete()
193         raise
194     connections.close_all()  # close all DB connections (FIX for #1818)
195 
196 def _localimport(drive_id, update_progress=None, check_for_cancel=None):
197     drives = get_mounted_drives_with_channel_info()
198     drive = drives[drive_id]
199     # copy channel's db file then copy all the content files from storage dir
200     try:
201         for channel in drive.metadata["channels"]:
202             call_command(
203                 "importchannel",
204                 "local",
205                 channel["id"],
206                 drive.datafolder,
207                 update_progress=update_progress,
208                 check_for_cancel=check_for_cancel)
209             call_command(
210                 "importcontent",
211                 "local",
212                 channel["id"],
213                 drive.datafolder,
214                 update_progress=update_progress,
215                 check_for_cancel=check_for_cancel)
216     except UserCancelledError:
217         connections.close_all()  # close all DB connections (FIX for #1818)
218         for channel in drive.metadata["channels"]:
219             channel_id = channel["id"]
220             try:
221                 os.remove(get_content_database_file_path(channel_id))
222             except OSError:
223                 pass
224             ChannelMetadataCache.objects.filter(id=channel_id).delete()
225         connections.close_all()  # close all DB connections (FIX for #1818)s
226         raise
227     connections.close_all()  # close all DB connections (FIX for #1818)
228 
229 
230 def _localexport(drive_id, update_progress=None, check_for_cancel=None):
231     drives = get_mounted_drives_with_channel_info()
232     drive = drives[drive_id]
233     for channel in ChannelMetadataCache.objects.all():
234         call_command(
235             "exportchannel",
236             channel.id,
237             drive.datafolder,
238             update_progress=update_progress,
239             check_for_cancel=check_for_cancel)
240         try:
241             call_command(
242                 "exportcontent",
243                 channel.id,
244                 drive.datafolder,
245                 update_progress=update_progress,
246                 check_for_cancel=check_for_cancel)
247         except UserCancelledError:
248             try:
249                 os.remove(get_content_database_file_path(channel.id, datafolder=drive.datafolder))
250             except OSError:
251                 pass
252             connections.close_all()  # close all DB connections (FIX for #1818)
253             raise
254     connections.close_all()  # close all DB connections (FIX for #1818)
255 
256 
257 def _job_to_response(job):
258     if not job:
259         return {
260             "type": None,
261             "status": State.SCHEDULED,
262             "percentage": 0,
263             "progress": [],
264             "id": None,
265         }
266     else:
267         return {
268             "type": id_tasktype.get(job.job_id),
269             "status": job.state,
270             "exception": str(job.exception),
271             "traceback": str(job.traceback),
272             "percentage": job.percentage_progress,
273             "id": job.job_id,
274         }
275
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/kolibri/tasks/api.py b/kolibri/tasks/api.py
--- a/kolibri/tasks/api.py
+++ b/kolibri/tasks/api.py
@@ -44,10 +44,10 @@
         jobs_response = [_job_to_response(j) for j in get_client().all_jobs()]
         ids = [job["id"] for job in jobs_response]
         # Clean up old job tasktypes
-        for key in id_tasktype.keys():
-            if key not in ids:
-                id_tasktype.pop(key)
-        get_client().clear(force=False)
+        keys_to_pop = [key for key in id_tasktype.keys() if key not in ids]
+        for key in keys_to_pop:
+            id_tasktype.pop(key)
+
         return Response(jobs_response)
 
     def create(self, request):
@@ -64,9 +64,9 @@
 
     @list_route(methods=['post'])
     def startremoteimport(self, request):
-        '''Download a channel's database from the main curation server, and then
+        '''
+        Download a channel's database from the main curation server, and then
         download its content.
-
         '''
 
         if "channel_id" not in request.data:

{"golden_diff": "diff --git a/kolibri/tasks/api.py b/kolibri/tasks/api.py\n--- a/kolibri/tasks/api.py\n+++ b/kolibri/tasks/api.py\n@@ -44,10 +44,10 @@\n         jobs_response = [_job_to_response(j) for j in get_client().all_jobs()]\n         ids = [job[\"id\"] for job in jobs_response]\n         # Clean up old job tasktypes\n-        for key in id_tasktype.keys():\n-            if key not in ids:\n-                id_tasktype.pop(key)\n-        get_client().clear(force=False)\n+        keys_to_pop = [key for key in id_tasktype.keys() if key not in ids]\n+        for key in keys_to_pop:\n+            id_tasktype.pop(key)\n+\n         return Response(jobs_response)\n \n     def create(self, request):\n@@ -64,9 +64,9 @@\n \n     @list_route(methods=['post'])\n     def startremoteimport(self, request):\n-        '''Download a channel's database from the main curation server, and then\n+        '''\n+        Download a channel's database from the main curation server, and then\n         download its content.\n-\n         '''\n \n         if \"channel_id\" not in request.data:\n", "issue": "My Channels not listing the new channels after import\n## Summary\r\n\r\nAfter importing a channel, whether from local drive or Internet, it does not appear under `My Channels` until page reload. \r\n\r\n## System information\r\n\r\n - Version: `0.5.0-beta9`\r\n - Operating system: Windows 7 & Ubuntu 16.10\r\n - Browser: Chrome\r\n\r\n![ubuntu3 0 5-beta9 running - oracle vm virtualbox_494](https://user-images.githubusercontent.com/1457929/29728036-9cf986f8-89d6-11e7-99b0-fc0d7619fbdd.png)\r\n\r\n\r\nOn [version 0.4.0](https://github.com/learningequality/kolibri/issues/1640#issuecomment-313949731) at least there was a green notification, but now it's missing too:\r\n\r\n![selection_328](https://user-images.githubusercontent.com/1457929/27996982-56743686-64ee-11e7-8f3d-cb2e1044b7d9.png)\r\n\r\nState is correctly reported after deleting the channel, green notification included.\r\n\r\n![ubuntu3 0 5-beta9 running - oracle vm virtualbox_496](https://user-images.githubusercontent.com/1457929/29727957-49d8e04a-89d6-11e7-8af6-3a70805475a4.png)\n", "before_files": [{"content": "import logging as logger\nimport os\n\nimport requests\nfrom barbequeue.common.classes import State\nfrom barbequeue.exceptions import UserCancelledError\nfrom django.apps.registry import AppRegistryNotReady\nfrom django.core.management import call_command\nfrom django.db import connections\nfrom django.http import Http404\nfrom django.utils.translation import ugettext as _\nfrom kolibri.content.models import ChannelMetadataCache\nfrom kolibri.content.utils.channels import get_mounted_drives_with_channel_info\nfrom kolibri.content.utils.paths import get_content_database_file_path, get_content_database_file_url\nfrom rest_framework import serializers, viewsets\nfrom rest_framework.decorators import list_route\nfrom rest_framework.response import Response\n\nfrom .client import get_client\nfrom .permissions import IsDeviceOwnerOnly\n\ntry:\n    from django.apps import apps\n\n    apps.check_apps_ready()\nexcept AppRegistryNotReady:\n    import django\n\n    django.setup()\n\n\nlogging = logger.getLogger(__name__)\n\nREMOTE_IMPORT = 'remoteimport'\nLOCAL_IMPORT = 'localimport'\nLOCAL_EXPORT = 'localexport'\n\nid_tasktype = {}\n\nclass TasksViewSet(viewsets.ViewSet):\n    permission_classes = (IsDeviceOwnerOnly,)\n\n    def list(self, request):\n        jobs_response = [_job_to_response(j) for j in get_client().all_jobs()]\n        ids = [job[\"id\"] for job in jobs_response]\n        # Clean up old job tasktypes\n        for key in id_tasktype.keys():\n            if key not in ids:\n                id_tasktype.pop(key)\n        get_client().clear(force=False)\n        return Response(jobs_response)\n\n    def create(self, request):\n        # unimplemented. Call out to the task-specific APIs for now.\n        pass\n\n    def retrieve(self, request, pk=None):\n        task = _job_to_response(get_client().status(pk))\n        return Response(task)\n\n    def destroy(self, request, pk=None):\n        # unimplemented for now.\n        pass\n\n    @list_route(methods=['post'])\n    def startremoteimport(self, request):\n        '''Download a channel's database from the main curation server, and then\n        download its content.\n\n        '''\n\n        if \"channel_id\" not in request.data:\n            raise serializers.ValidationError(\n                \"The 'channel_id' field is required.\")\n\n        channel_id = request.data['channel_id']\n\n        # ensure the requested channel_id can be found on the central server, otherwise error\n        status = requests.head(\n            get_content_database_file_url(channel_id)).status_code\n        if status == 404:\n            raise Http404(\n                _(\"The requested channel does not exist on the content server\")\n            )\n\n        task_id = get_client().schedule(\n            _networkimport, channel_id, track_progress=True, cancellable=True)\n\n        id_tasktype[task_id] = REMOTE_IMPORT\n\n        # attempt to get the created Task, otherwise return pending status\n        resp = _job_to_response(get_client().status(task_id))\n\n        return Response(resp)\n\n    @list_route(methods=['post'])\n    def startlocalimport(self, request):\n        \"\"\"\n        Import a channel from a local drive, and copy content to the local machine.\n        \"\"\"\n        # Importing django/running setup because Windows...\n\n        if \"drive_id\" not in request.data:\n            raise serializers.ValidationError(\n                \"The 'drive_id' field is required.\")\n\n        task_id = get_client().schedule(\n            _localimport, request.data['drive_id'], track_progress=True, cancellable=True)\n\n        id_tasktype[task_id] = LOCAL_IMPORT\n\n        # attempt to get the created Task, otherwise return pending status\n        resp = _job_to_response(get_client().status(task_id))\n\n        return Response(resp)\n\n    @list_route(methods=['post'])\n    def startlocalexport(self, request):\n        '''\n        Export a channel to a local drive, and copy content to the drive.\n\n        '''\n\n        if \"drive_id\" not in request.data:\n            raise serializers.ValidationError(\n                \"The 'drive_id' field is required.\")\n\n        task_id = get_client().schedule(\n            _localexport, request.data['drive_id'], track_progress=True, cancellable=True)\n\n        id_tasktype[task_id] = LOCAL_EXPORT\n\n        # attempt to get the created Task, otherwise return pending status\n        resp = _job_to_response(get_client().status(task_id))\n\n        return Response(resp)\n\n    @list_route(methods=['post'])\n    def canceltask(self, request):\n        '''\n        Cancel a task with its task id given in the task_id parameter.\n        '''\n\n        if 'task_id' not in request.data:\n            raise serializers.ValidationError(\n                \"The 'task_id' field is required.\")\n\n        get_client().cancel(request.data['task_id'])\n        get_client().clear(force=True)\n        return Response({})\n\n    @list_route(methods=['post'])\n    def cleartasks(self, request):\n        '''\n        Cancels all running tasks.\n        '''\n\n        get_client().clear(force=True)\n        return Response({})\n\n    @list_route(methods=['get'])\n    def localdrive(self, request):\n        drives = get_mounted_drives_with_channel_info()\n\n        # make sure everything is a dict, before converting to JSON\n        assert isinstance(drives, dict)\n        out = [mountdata._asdict() for mountdata in drives.values()]\n\n        return Response(out)\n\n\ndef _networkimport(channel_id, update_progress=None, check_for_cancel=None):\n    call_command(\n        \"importchannel\",\n        \"network\",\n        channel_id,\n        update_progress=update_progress,\n        check_for_cancel=check_for_cancel)\n    try:\n        call_command(\n            \"importcontent\",\n            \"network\",\n            channel_id,\n            update_progress=update_progress,\n            check_for_cancel=check_for_cancel)\n    except UserCancelledError:\n        connections.close_all()  # close all DB connections (FIX for #1818)\n        try:\n            os.remove(get_content_database_file_path(channel_id))\n        except OSError:\n            pass\n        ChannelMetadataCache.objects.filter(id=channel_id).delete()\n        raise\n    connections.close_all()  # close all DB connections (FIX for #1818)\n\ndef _localimport(drive_id, update_progress=None, check_for_cancel=None):\n    drives = get_mounted_drives_with_channel_info()\n    drive = drives[drive_id]\n    # copy channel's db file then copy all the content files from storage dir\n    try:\n        for channel in drive.metadata[\"channels\"]:\n            call_command(\n                \"importchannel\",\n                \"local\",\n                channel[\"id\"],\n                drive.datafolder,\n                update_progress=update_progress,\n                check_for_cancel=check_for_cancel)\n            call_command(\n                \"importcontent\",\n                \"local\",\n                channel[\"id\"],\n                drive.datafolder,\n                update_progress=update_progress,\n                check_for_cancel=check_for_cancel)\n    except UserCancelledError:\n        connections.close_all()  # close all DB connections (FIX for #1818)\n        for channel in drive.metadata[\"channels\"]:\n            channel_id = channel[\"id\"]\n            try:\n                os.remove(get_content_database_file_path(channel_id))\n            except OSError:\n                pass\n            ChannelMetadataCache.objects.filter(id=channel_id).delete()\n        connections.close_all()  # close all DB connections (FIX for #1818)s\n        raise\n    connections.close_all()  # close all DB connections (FIX for #1818)\n\n\ndef _localexport(drive_id, update_progress=None, check_for_cancel=None):\n    drives = get_mounted_drives_with_channel_info()\n    drive = drives[drive_id]\n    for channel in ChannelMetadataCache.objects.all():\n        call_command(\n            \"exportchannel\",\n            channel.id,\n            drive.datafolder,\n            update_progress=update_progress,\n            check_for_cancel=check_for_cancel)\n        try:\n            call_command(\n                \"exportcontent\",\n                channel.id,\n                drive.datafolder,\n                update_progress=update_progress,\n                check_for_cancel=check_for_cancel)\n        except UserCancelledError:\n            try:\n                os.remove(get_content_database_file_path(channel.id, datafolder=drive.datafolder))\n            except OSError:\n                pass\n            connections.close_all()  # close all DB connections (FIX for #1818)\n            raise\n    connections.close_all()  # close all DB connections (FIX for #1818)\n\n\ndef _job_to_response(job):\n    if not job:\n        return {\n            \"type\": None,\n            \"status\": State.SCHEDULED,\n            \"percentage\": 0,\n            \"progress\": [],\n            \"id\": None,\n        }\n    else:\n        return {\n            \"type\": id_tasktype.get(job.job_id),\n            \"status\": job.state,\n            \"exception\": str(job.exception),\n            \"traceback\": str(job.traceback),\n            \"percentage\": job.percentage_progress,\n            \"id\": job.job_id,\n        }\n", "path": "kolibri/tasks/api.py"}], "after_files": [{"content": "import logging as logger\nimport os\n\nimport requests\nfrom barbequeue.common.classes import State\nfrom barbequeue.exceptions import UserCancelledError\nfrom django.apps.registry import AppRegistryNotReady\nfrom django.core.management import call_command\nfrom django.db import connections\nfrom django.http import Http404\nfrom django.utils.translation import ugettext as _\nfrom kolibri.content.models import ChannelMetadataCache\nfrom kolibri.content.utils.channels import get_mounted_drives_with_channel_info\nfrom kolibri.content.utils.paths import get_content_database_file_path, get_content_database_file_url\nfrom rest_framework import serializers, viewsets\nfrom rest_framework.decorators import list_route\nfrom rest_framework.response import Response\n\nfrom .client import get_client\nfrom .permissions import IsDeviceOwnerOnly\n\ntry:\n    from django.apps import apps\n\n    apps.check_apps_ready()\nexcept AppRegistryNotReady:\n    import django\n\n    django.setup()\n\n\nlogging = logger.getLogger(__name__)\n\nREMOTE_IMPORT = 'remoteimport'\nLOCAL_IMPORT = 'localimport'\nLOCAL_EXPORT = 'localexport'\n\nid_tasktype = {}\n\nclass TasksViewSet(viewsets.ViewSet):\n    permission_classes = (IsDeviceOwnerOnly,)\n\n    def list(self, request):\n        jobs_response = [_job_to_response(j) for j in get_client().all_jobs()]\n        ids = [job[\"id\"] for job in jobs_response]\n        # Clean up old job tasktypes\n        keys_to_pop = [key for key in id_tasktype.keys() if key not in ids]\n        for key in keys_to_pop:\n            id_tasktype.pop(key)\n\n        return Response(jobs_response)\n\n    def create(self, request):\n        # unimplemented. Call out to the task-specific APIs for now.\n        pass\n\n    def retrieve(self, request, pk=None):\n        task = _job_to_response(get_client().status(pk))\n        return Response(task)\n\n    def destroy(self, request, pk=None):\n        # unimplemented for now.\n        pass\n\n    @list_route(methods=['post'])\n    def startremoteimport(self, request):\n        '''\n        Download a channel's database from the main curation server, and then\n        download its content.\n        '''\n\n        if \"channel_id\" not in request.data:\n            raise serializers.ValidationError(\n                \"The 'channel_id' field is required.\")\n\n        channel_id = request.data['channel_id']\n\n        # ensure the requested channel_id can be found on the central server, otherwise error\n        status = requests.head(\n            get_content_database_file_url(channel_id)).status_code\n        if status == 404:\n            raise Http404(\n                _(\"The requested channel does not exist on the content server\")\n            )\n\n        task_id = get_client().schedule(\n            _networkimport, channel_id, track_progress=True, cancellable=True)\n\n        id_tasktype[task_id] = REMOTE_IMPORT\n\n        # attempt to get the created Task, otherwise return pending status\n        resp = _job_to_response(get_client().status(task_id))\n\n        return Response(resp)\n\n    @list_route(methods=['post'])\n    def startlocalimport(self, request):\n        \"\"\"\n        Import a channel from a local drive, and copy content to the local machine.\n        \"\"\"\n        # Importing django/running setup because Windows...\n\n        if \"drive_id\" not in request.data:\n            raise serializers.ValidationError(\n                \"The 'drive_id' field is required.\")\n\n        task_id = get_client().schedule(\n            _localimport, request.data['drive_id'], track_progress=True, cancellable=True)\n\n        id_tasktype[task_id] = LOCAL_IMPORT\n\n        # attempt to get the created Task, otherwise return pending status\n        resp = _job_to_response(get_client().status(task_id))\n\n        return Response(resp)\n\n    @list_route(methods=['post'])\n    def startlocalexport(self, request):\n        '''\n        Export a channel to a local drive, and copy content to the drive.\n\n        '''\n\n        if \"drive_id\" not in request.data:\n            raise serializers.ValidationError(\n                \"The 'drive_id' field is required.\")\n\n        task_id = get_client().schedule(\n            _localexport, request.data['drive_id'], track_progress=True, cancellable=True)\n\n        id_tasktype[task_id] = LOCAL_EXPORT\n\n        # attempt to get the created Task, otherwise return pending status\n        resp = _job_to_response(get_client().status(task_id))\n\n        return Response(resp)\n\n    @list_route(methods=['post'])\n    def canceltask(self, request):\n        '''\n        Cancel a task with its task id given in the task_id parameter.\n        '''\n\n        if 'task_id' not in request.data:\n            raise serializers.ValidationError(\n                \"The 'task_id' field is required.\")\n\n        get_client().cancel(request.data['task_id'])\n        get_client().clear(force=True)\n        return Response({})\n\n    @list_route(methods=['post'])\n    def cleartasks(self, request):\n        '''\n        Cancels all running tasks.\n        '''\n\n        get_client().clear(force=True)\n        return Response({})\n\n    @list_route(methods=['get'])\n    def localdrive(self, request):\n        drives = get_mounted_drives_with_channel_info()\n\n        # make sure everything is a dict, before converting to JSON\n        assert isinstance(drives, dict)\n        out = [mountdata._asdict() for mountdata in drives.values()]\n\n        return Response(out)\n\n\ndef _networkimport(channel_id, update_progress=None, check_for_cancel=None):\n    call_command(\n        \"importchannel\",\n        \"network\",\n        channel_id,\n        update_progress=update_progress,\n        check_for_cancel=check_for_cancel)\n    try:\n        call_command(\n            \"importcontent\",\n            \"network\",\n            channel_id,\n            update_progress=update_progress,\n            check_for_cancel=check_for_cancel)\n    except UserCancelledError:\n        connections.close_all()  # close all DB connections (FIX for #1818)\n        try:\n            os.remove(get_content_database_file_path(channel_id))\n        except OSError:\n            pass\n        ChannelMetadataCache.objects.filter(id=channel_id).delete()\n        raise\n    connections.close_all()  # close all DB connections (FIX for #1818)\n\ndef _localimport(drive_id, update_progress=None, check_for_cancel=None):\n    drives = get_mounted_drives_with_channel_info()\n    drive = drives[drive_id]\n    # copy channel's db file then copy all the content files from storage dir\n    try:\n        for channel in drive.metadata[\"channels\"]:\n            call_command(\n                \"importchannel\",\n                \"local\",\n                channel[\"id\"],\n                drive.datafolder,\n                update_progress=update_progress,\n                check_for_cancel=check_for_cancel)\n            call_command(\n                \"importcontent\",\n                \"local\",\n                channel[\"id\"],\n                drive.datafolder,\n                update_progress=update_progress,\n                check_for_cancel=check_for_cancel)\n    except UserCancelledError:\n        connections.close_all()  # close all DB connections (FIX for #1818)\n        for channel in drive.metadata[\"channels\"]:\n            channel_id = channel[\"id\"]\n            try:\n                os.remove(get_content_database_file_path(channel_id))\n            except OSError:\n                pass\n            ChannelMetadataCache.objects.filter(id=channel_id).delete()\n        connections.close_all()  # close all DB connections (FIX for #1818)s\n        raise\n    connections.close_all()  # close all DB connections (FIX for #1818)\n\n\ndef _localexport(drive_id, update_progress=None, check_for_cancel=None):\n    drives = get_mounted_drives_with_channel_info()\n    drive = drives[drive_id]\n    for channel in ChannelMetadataCache.objects.all():\n        call_command(\n            \"exportchannel\",\n            channel.id,\n            drive.datafolder,\n            update_progress=update_progress,\n            check_for_cancel=check_for_cancel)\n        try:\n            call_command(\n                \"exportcontent\",\n                channel.id,\n                drive.datafolder,\n                update_progress=update_progress,\n                check_for_cancel=check_for_cancel)\n        except UserCancelledError:\n            try:\n                os.remove(get_content_database_file_path(channel.id, datafolder=drive.datafolder))\n            except OSError:\n                pass\n            connections.close_all()  # close all DB connections (FIX for #1818)\n            raise\n    connections.close_all()  # close all DB connections (FIX for #1818)\n\n\ndef _job_to_response(job):\n    if not job:\n        return {\n            \"type\": None,\n            \"status\": State.SCHEDULED,\n            \"percentage\": 0,\n            \"progress\": [],\n            \"id\": None,\n        }\n    else:\n        return {\n            \"type\": id_tasktype.get(job.job_id),\n            \"status\": job.state,\n            \"exception\": str(job.exception),\n            \"traceback\": str(job.traceback),\n            \"percentage\": job.percentage_progress,\n            \"id\": job.job_id,\n        }\n", "path": "kolibri/tasks/api.py"}]}