diff --git a/README.md b/README.md
index 0f7632ab3b540bd95957a90598a163a16f13fba2..0915fb3dfe17f1fb33abe1e505a469ac822c8552 100644
--- a/README.md
+++ b/README.md
@@ -43,26 +43,6 @@ You will need to edit the ImageMagick policy file to get PDF and Image imports t
 
 The line that sets the PDF policy is `<policy domain="coder" rights="none" pattern="PDF" />`. Replace `none` with `read|write` for it to work. See [this StackOverflow question](https://stackoverflow.com/questions/52998331) for more info.
 
-### GitLab OAuth setup
-
-Arkindex uses OAuth to let a user connect their GitLab account(s) and register Git repositories. In local development, you will need to register Arkindex as a GitLab OAuth application for it to work.
-
-Go to GitLab's [Applications settings](https://gitlab.teklia.com/profile/applications) and create a new application with the `api` scope and add the following callback URIs:
-
-```
-http://127.0.0.1:8000/api/v1/oauth/providers/gitlab/callback/
-http://ark.localhost:8000/api/v1/oauth/providers/gitlab/callback/
-https://ark.localhost/api/v1/oauth/providers/gitlab/callback/
-```
-
-Once the application is created, GitLab will provide you with an application ID and a secret. Use the `arkindex/config.yml` file to set them:
-
-```yaml
-gitlab:
-  app_id: 24cacf5004bf68ae9daad19a5bba391d85ad1cb0b31366e89aec86fad0ab16cb
-  app_secret: 9d96d9d5b1addd7e7e6119a23b1e5b5f68545312bfecb21d1cdc6af22b8628b8
-```
-
 ### Local image server
 
 Arkindex splits up image URLs in their image server and the image path. For example, a IIIF server at `http://iiif.irht.cnrs.fr/iiif/` and an image at `/Paris/JJ042/1.jpg` would be represented as an ImageServer instance holding one Image. Since Arkindex has a local IIIF server for image uploads and thumbnails, a special instance of ImageServer is required to point to this local server. In local development, this server should be available at `https://ark.localhost/iiif`. You will therefore need to create an ImageServer via the Django admin or the Django shell with this URL. To set the local server ID, you can add a custom setting in `arkindex/config.yml`:
@@ -161,9 +141,6 @@ SHELL_PLUS_POST_IMPORTS = [
     )),
     ('arkindex.project.aws', (
         'S3FileStatus',
-    )),
-    ('arkindex.users.models', (
-        'OAuthStatus',
     ))
 ]
 ```
diff --git a/arkindex/documents/fixtures/data.json b/arkindex/documents/fixtures/data.json
index efd6ebcd8817dca400f85166fbe46631cc9d803d..b515da387b3bc5741722cb1c5c03a4014682f7b8 100644
--- a/arkindex/documents/fixtures/data.json
+++ b/arkindex/documents/fixtures/data.json
@@ -1,7 +1,7 @@
 [
 {
     "model": "process.process",
-    "pk": "7b0b9c75-bffc-42f5-a646-c81e8197d171",
+    "pk": "55e92ea6-625a-4c30-9724-b1f327941cac",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
@@ -36,19 +36,19 @@
 },
 {
     "model": "process.process",
-    "pk": "8cec0605-06e6-4b8f-ba7d-3ec9f9f2a409",
+    "pk": "6f170a31-9cf3-4fef-a684-ce8c8a4000d2",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "name": "Process fixture",
-        "creator": 2,
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "mode": "workers",
+        "name": null,
+        "creator": 1,
+        "corpus": null,
+        "mode": "repository",
         "revision": null,
         "activity_state": "disabled",
         "started": null,
         "finished": null,
-        "farm": "409b6859-63b9-41f2-8449-ba737bca6624",
+        "farm": "d4639943-3bc5-4839-ba11-bac03818050c",
         "element": null,
         "folder_type": null,
         "element_type": null,
@@ -71,19 +71,19 @@
 },
 {
     "model": "process.process",
-    "pk": "9a08ea15-07be-4746-a0d9-7acca68e5c1b",
+    "pk": "6f8334b3-b89c-48ef-b69f-255a5c4f868d",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "name": null,
         "creator": 1,
         "corpus": null,
-        "mode": "repository",
+        "mode": "local",
         "revision": null,
         "activity_state": "disabled",
         "started": null,
         "finished": null,
-        "farm": "409b6859-63b9-41f2-8449-ba737bca6624",
+        "farm": null,
         "element": null,
         "folder_type": null,
         "element_type": null,
@@ -106,19 +106,19 @@
 },
 {
     "model": "process.process",
-    "pk": "b4b4b4af-c221-4c47-a784-cc1bac1a99b1",
+    "pk": "d9f1b26c-6aae-4e22-a9cc-d218a245794e",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "name": null,
-        "creator": 1,
-        "corpus": null,
-        "mode": "local",
+        "name": "Process fixture",
+        "creator": 2,
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "mode": "workers",
         "revision": null,
         "activity_state": "disabled",
         "started": null,
         "finished": null,
-        "farm": null,
+        "farm": "d4639943-3bc5-4839-ba11-bac03818050c",
         "element": null,
         "folder_type": null,
         "element_type": null,
@@ -141,29 +141,25 @@
 },
 {
     "model": "process.repository",
-    "pk": "9c6b9576-23e1-4efb-88ce-8a15550b06cb",
+    "pk": "c32a2335-9132-402b-9a3b-bd76b0140c1a",
     "fields": {
-        "url": "http://my_repo.fake/workers/worker",
-        "hook_token": "worker-hook-token",
-        "credentials": "217e2e72-f917-46de-9760-0e140bec08eb"
+        "url": "http://gitlab/repo"
     }
 },
 {
     "model": "process.repository",
-    "pk": "e4f4a2e6-b23b-48d2-bf86-b60c2b7d2810",
+    "pk": "eaa88eb6-31f6-464c-bba1-d64724703d2f",
     "fields": {
-        "url": "http://gitlab/repo",
-        "hook_token": "hook-token",
-        "credentials": "217e2e72-f917-46de-9760-0e140bec08eb"
+        "url": "http://my_repo.fake/workers/worker"
     }
 },
 {
     "model": "process.revision",
-    "pk": "2b024a21-5655-45b7-9fe0-d27b58a6a2d2",
+    "pk": "97306172-bca6-46a6-9789-4b084e09c008",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "repo": "9c6b9576-23e1-4efb-88ce-8a15550b06cb",
+        "repo": "eaa88eb6-31f6-464c-bba1-d64724703d2f",
         "hash": "1337",
         "message": "My w0rk3r",
         "author": "Test user"
@@ -171,11 +167,11 @@
 },
 {
     "model": "process.revision",
-    "pk": "f7845dce-ce21-49b6-9962-3eb9cec30a6d",
+    "pk": "c5cf2885-3440-4838-be93-d8211c8a811c",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "repo": "e4f4a2e6-b23b-48d2-bf86-b60c2b7d2810",
+        "repo": "c32a2335-9132-402b-9a3b-bd76b0140c1a",
         "hash": "42",
         "message": "Salve",
         "author": "Some user"
@@ -183,93 +179,105 @@
 },
 {
     "model": "process.worker",
-    "pk": "08ef0527-5af6-45c7-a84c-d9d69697e5ca",
+    "pk": "03ca969c-2fee-4a4c-b2f7-c283fb72bf91",
+    "fields": {
+        "name": "Worker requiring a GPU",
+        "slug": "worker-gpu",
+        "type": "7dee488e-7a48-434b-9163-6396972bff7f",
+        "description": "",
+        "repository": "eaa88eb6-31f6-464c-bba1-d64724703d2f",
+        "public": false,
+        "archived": null
+    }
+},
+{
+    "model": "process.worker",
+    "pk": "081bfea3-f8eb-4070-9cb4-6cc4e7b260b8",
     "fields": {
         "name": "Recognizer",
         "slug": "reco",
-        "type": "f089f069-68e8-48cc-a168-19a07a8681f8",
-        "repository": "9c6b9576-23e1-4efb-88ce-8a15550b06cb",
-        "public": false
+        "type": "250cfaca-9733-42ef-a265-b8e8aea73075",
+        "description": "",
+        "repository": "eaa88eb6-31f6-464c-bba1-d64724703d2f",
+        "public": false,
+        "archived": null
     }
 },
 {
     "model": "process.worker",
-    "pk": "25bfe0e8-7c7c-491e-b9b4-73498c4b5eb7",
+    "pk": "3d121605-190a-4faa-8085-e7c1bffc4297",
     "fields": {
         "name": "Document layout analyser",
         "slug": "dla",
-        "type": "36873927-4925-4eca-972b-f8dfed39cbe8",
-        "repository": "9c6b9576-23e1-4efb-88ce-8a15550b06cb",
-        "public": false
+        "type": "40620987-763e-4e69-baa8-5bdf28f8b6c3",
+        "description": "",
+        "repository": "eaa88eb6-31f6-464c-bba1-d64724703d2f",
+        "public": false,
+        "archived": null
     }
 },
 {
     "model": "process.worker",
-    "pk": "5222a3e0-b27c-43c2-96df-905613cfd55a",
+    "pk": "6a9a5388-c047-4bbf-9c41-86fbc578fd92",
     "fields": {
         "name": "Custom worker",
         "slug": "custom",
-        "type": "5371cc7b-b6c7-407a-a935-e97d05caf1cb",
+        "type": "a9458b4e-5ac9-4caa-b2fd-516b16222604",
+        "description": "",
         "repository": null,
-        "public": false
+        "public": false,
+        "archived": null
     }
 },
 {
     "model": "process.worker",
-    "pk": "913ff861-730c-40e1-9d47-d5d271586c35",
+    "pk": "a9950b39-1c6d-4dde-bbd5-9545871189f4",
     "fields": {
         "name": "File import",
         "slug": "file_import",
-        "type": "ba1d9a09-48d7-4ac5-8427-bbd51775ea7c",
-        "repository": "9c6b9576-23e1-4efb-88ce-8a15550b06cb",
-        "public": false
-    }
-},
-{
-    "model": "process.worker",
-    "pk": "ed512f68-389e-4e4d-8f96-103ecab3122b",
-    "fields": {
-        "name": "Worker requiring a GPU",
-        "slug": "worker-gpu",
-        "type": "fd2df8fb-cbc1-4c43-9abe-1a6db6122e59",
-        "repository": "9c6b9576-23e1-4efb-88ce-8a15550b06cb",
-        "public": false
+        "type": "6772567a-5429-4d97-b1aa-8c779d30c68f",
+        "description": "",
+        "repository": "eaa88eb6-31f6-464c-bba1-d64724703d2f",
+        "public": false,
+        "archived": null
     }
 },
 {
     "model": "process.worker",
-    "pk": "fc99199f-0f3a-4c0d-a033-db7f151910b1",
+    "pk": "ddeda096-4d97-45c5-95fc-600397638cb7",
     "fields": {
         "name": "Generic worker with a Model",
         "slug": "generic",
-        "type": "f089f069-68e8-48cc-a168-19a07a8681f8",
-        "repository": "9c6b9576-23e1-4efb-88ce-8a15550b06cb",
-        "public": false
+        "type": "250cfaca-9733-42ef-a265-b8e8aea73075",
+        "description": "",
+        "repository": "eaa88eb6-31f6-464c-bba1-d64724703d2f",
+        "public": false,
+        "archived": null
     }
 },
 {
     "model": "process.workertype",
-    "pk": "36873927-4925-4eca-972b-f8dfed39cbe8",
+    "pk": "250cfaca-9733-42ef-a265-b8e8aea73075",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "slug": "dla",
-        "display_name": "Document Layout Analysis"
+        "slug": "recognizer",
+        "display_name": "Recognizer"
     }
 },
 {
     "model": "process.workertype",
-    "pk": "5371cc7b-b6c7-407a-a935-e97d05caf1cb",
+    "pk": "40620987-763e-4e69-baa8-5bdf28f8b6c3",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "slug": "custom",
-        "display_name": "Custom"
+        "slug": "dla",
+        "display_name": "Document Layout Analysis"
     }
 },
 {
     "model": "process.workertype",
-    "pk": "ba1d9a09-48d7-4ac5-8427-bbd51775ea7c",
+    "pk": "6772567a-5429-4d97-b1aa-8c779d30c68f",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
@@ -279,38 +287,36 @@
 },
 {
     "model": "process.workertype",
-    "pk": "f089f069-68e8-48cc-a168-19a07a8681f8",
+    "pk": "7dee488e-7a48-434b-9163-6396972bff7f",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "slug": "recognizer",
-        "display_name": "Recognizer"
+        "slug": "worker",
+        "display_name": "Worker requiring a GPU"
     }
 },
 {
     "model": "process.workertype",
-    "pk": "fd2df8fb-cbc1-4c43-9abe-1a6db6122e59",
+    "pk": "a9458b4e-5ac9-4caa-b2fd-516b16222604",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "slug": "worker",
-        "display_name": "Worker requiring a GPU"
+        "slug": "custom",
+        "display_name": "Custom"
     }
 },
 {
     "model": "process.workerversion",
-    "pk": "06e97787-7dbd-424b-bd3e-40d4de6b107f",
+    "pk": "28cc29d7-c2c2-41d2-b051-4553f9535ea9",
     "fields": {
-        "worker": "ed512f68-389e-4e4d-8f96-103ecab3122b",
-        "revision": "2b024a21-5655-45b7-9fe0-d27b58a6a2d2",
+        "worker": "a9950b39-1c6d-4dde-bbd5-9545871189f4",
+        "revision": "97306172-bca6-46a6-9789-4b084e09c008",
         "version": null,
-        "configuration": {
-            "test": 42
-        },
+        "configuration": {},
         "state": "available",
-        "gpu_usage": "required",
+        "gpu_usage": "disabled",
         "model_usage": "disabled",
-        "docker_image": "a93301c3-bdac-4d06-ba22-b7066decd282",
+        "docker_image": "27166636-75bd-4296-adce-ba8fa09a36c5",
         "docker_image_iid": null,
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z"
@@ -318,18 +324,18 @@
 },
 {
     "model": "process.workerversion",
-    "pk": "5bb8f594-dff8-4145-8634-9ba88ff8a61d",
+    "pk": "38af2294-5e69-4c10-8daf-5bb1b58b182a",
     "fields": {
-        "worker": "5222a3e0-b27c-43c2-96df-905613cfd55a",
-        "revision": null,
-        "version": 1,
+        "worker": "081bfea3-f8eb-4070-9cb4-6cc4e7b260b8",
+        "revision": "97306172-bca6-46a6-9789-4b084e09c008",
+        "version": null,
         "configuration": {
-            "custom": "value"
+            "test": 42
         },
-        "state": "created",
+        "state": "available",
         "gpu_usage": "disabled",
         "model_usage": "disabled",
-        "docker_image": null,
+        "docker_image": "27166636-75bd-4296-adce-ba8fa09a36c5",
         "docker_image_iid": null,
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z"
@@ -337,16 +343,18 @@
 },
 {
     "model": "process.workerversion",
-    "pk": "6610938d-c68c-445c-a4cc-d21e574a8958",
+    "pk": "3e12e240-0b7e-43f1-8e63-0ccd0b851548",
     "fields": {
-        "worker": "913ff861-730c-40e1-9d47-d5d271586c35",
-        "revision": "2b024a21-5655-45b7-9fe0-d27b58a6a2d2",
+        "worker": "ddeda096-4d97-45c5-95fc-600397638cb7",
+        "revision": "97306172-bca6-46a6-9789-4b084e09c008",
         "version": null,
-        "configuration": {},
+        "configuration": {
+            "test": 42
+        },
         "state": "available",
         "gpu_usage": "disabled",
-        "model_usage": "disabled",
-        "docker_image": "a93301c3-bdac-4d06-ba22-b7066decd282",
+        "model_usage": "required",
+        "docker_image": "27166636-75bd-4296-adce-ba8fa09a36c5",
         "docker_image_iid": null,
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z"
@@ -354,18 +362,18 @@
 },
 {
     "model": "process.workerversion",
-    "pk": "daf05df4-45d9-4c60-811a-07bc88cacf0c",
+    "pk": "52ef38e2-e71e-4bcd-aa26-2eaad0d682ef",
     "fields": {
-        "worker": "25bfe0e8-7c7c-491e-b9b4-73498c4b5eb7",
-        "revision": "2b024a21-5655-45b7-9fe0-d27b58a6a2d2",
+        "worker": "03ca969c-2fee-4a4c-b2f7-c283fb72bf91",
+        "revision": "97306172-bca6-46a6-9789-4b084e09c008",
         "version": null,
         "configuration": {
             "test": 42
         },
         "state": "available",
-        "gpu_usage": "disabled",
+        "gpu_usage": "required",
         "model_usage": "disabled",
-        "docker_image": "a93301c3-bdac-4d06-ba22-b7066decd282",
+        "docker_image": "27166636-75bd-4296-adce-ba8fa09a36c5",
         "docker_image_iid": null,
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z"
@@ -373,18 +381,18 @@
 },
 {
     "model": "process.workerversion",
-    "pk": "e45fe700-2e3d-49c5-a40e-01e46009ac65",
+    "pk": "6fe5da3e-18f0-4c08-ab75-631c527534df",
     "fields": {
-        "worker": "fc99199f-0f3a-4c0d-a033-db7f151910b1",
-        "revision": "2b024a21-5655-45b7-9fe0-d27b58a6a2d2",
+        "worker": "3d121605-190a-4faa-8085-e7c1bffc4297",
+        "revision": "97306172-bca6-46a6-9789-4b084e09c008",
         "version": null,
         "configuration": {
             "test": 42
         },
         "state": "available",
         "gpu_usage": "disabled",
-        "model_usage": "required",
-        "docker_image": "a93301c3-bdac-4d06-ba22-b7066decd282",
+        "model_usage": "disabled",
+        "docker_image": "27166636-75bd-4296-adce-ba8fa09a36c5",
         "docker_image_iid": null,
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z"
@@ -392,18 +400,18 @@
 },
 {
     "model": "process.workerversion",
-    "pk": "f22fde5b-28db-459a-8257-cab7b58ef63d",
+    "pk": "c82df68d-f845-4e3d-a1de-4c84be97230a",
     "fields": {
-        "worker": "08ef0527-5af6-45c7-a84c-d9d69697e5ca",
-        "revision": "2b024a21-5655-45b7-9fe0-d27b58a6a2d2",
-        "version": null,
+        "worker": "6a9a5388-c047-4bbf-9c41-86fbc578fd92",
+        "revision": null,
+        "version": 1,
         "configuration": {
-            "test": 42
+            "custom": "value"
         },
-        "state": "available",
+        "state": "created",
         "gpu_usage": "disabled",
         "model_usage": "disabled",
-        "docker_image": "a93301c3-bdac-4d06-ba22-b7066decd282",
+        "docker_image": null,
         "docker_image_iid": null,
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z"
@@ -411,10 +419,10 @@
 },
 {
     "model": "process.workerrun",
-    "pk": "4c989351-7f30-4bb0-8424-31f56b33f925",
+    "pk": "4f2c84cf-f641-4d79-a7f0-d21075e61632",
     "fields": {
-        "process": "7b0b9c75-bffc-42f5-a646-c81e8197d171",
-        "version": "5bb8f594-dff8-4145-8634-9ba88ff8a61d",
+        "process": "6f8334b3-b89c-48ef-b69f-255a5c4f868d",
+        "version": "c82df68d-f845-4e3d-a1de-4c84be97230a",
         "model_version": null,
         "parents": "[]",
         "configuration": null,
@@ -425,49 +433,49 @@
 },
 {
     "model": "process.workerrun",
-    "pk": "5e8879fd-3da3-4bb0-83db-044d97ca9f89",
+    "pk": "ca9e5c86-ac92-4f73-b170-fff5e6331888",
     "fields": {
-        "process": "8cec0605-06e6-4b8f-ba7d-3ec9f9f2a409",
-        "version": "daf05df4-45d9-4c60-811a-07bc88cacf0c",
+        "process": "d9f1b26c-6aae-4e22-a9cc-d218a245794e",
+        "version": "6fe5da3e-18f0-4c08-ab75-631c527534df",
         "model_version": null,
         "parents": "[]",
         "configuration": null,
-        "summary": "Worker Document layout analyser @ daf05d",
+        "summary": "Worker Document layout analyser @ 6fe5da",
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z"
     }
 },
 {
     "model": "process.workerrun",
-    "pk": "c7fb12ab-d10f-4091-95d2-141e5b249a95",
+    "pk": "b68c0c89-1642-4ac3-813d-fa0fe5fbe54d",
     "fields": {
-        "process": "b4b4b4af-c221-4c47-a784-cc1bac1a99b1",
-        "version": "5bb8f594-dff8-4145-8634-9ba88ff8a61d",
+        "process": "d9f1b26c-6aae-4e22-a9cc-d218a245794e",
+        "version": "38af2294-5e69-4c10-8daf-5bb1b58b182a",
         "model_version": null,
-        "parents": "[]",
+        "parents": "[\"ca9e5c86-ac92-4f73-b170-fff5e6331888\"]",
         "configuration": null,
-        "summary": "Worker Custom worker @ version 1",
+        "summary": "Worker Recognizer @ 38af22",
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z"
     }
 },
 {
     "model": "process.workerrun",
-    "pk": "2d18ad3f-6e5e-4184-8518-dda1d384164e",
+    "pk": "b88f23f6-af5d-4e20-bc58-fcc4c9966c5f",
     "fields": {
-        "process": "8cec0605-06e6-4b8f-ba7d-3ec9f9f2a409",
-        "version": "f22fde5b-28db-459a-8257-cab7b58ef63d",
+        "process": "55e92ea6-625a-4c30-9724-b1f327941cac",
+        "version": "c82df68d-f845-4e3d-a1de-4c84be97230a",
         "model_version": null,
-        "parents": "[\"5e8879fd-3da3-4bb0-83db-044d97ca9f89\"]",
+        "parents": "[]",
         "configuration": null,
-        "summary": "Worker Recognizer @ f22fde",
+        "summary": "Worker Custom worker @ version 1",
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z"
     }
 },
 {
     "model": "documents.corpus",
-    "pk": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
+    "pk": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
@@ -480,33 +488,21 @@
 },
 {
     "model": "documents.elementtype",
-    "pk": "16c614aa-d6d4-4f55-afdd-0fada214362a",
+    "pk": "5b656298-6b77-441d-89bc-944f83e90318",
     "fields": {
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "slug": "surface",
-        "display_name": "Surface",
-        "folder": false,
-        "indexable": false,
-        "color": "28b62c"
-    }
-},
-{
-    "model": "documents.elementtype",
-    "pk": "1acf2b7e-3a52-40b4-b428-40b17992928f",
-    "fields": {
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "slug": "act",
-        "display_name": "Act",
-        "folder": false,
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "slug": "volume",
+        "display_name": "Volume",
+        "folder": true,
         "indexable": false,
         "color": "28b62c"
     }
 },
 {
     "model": "documents.elementtype",
-    "pk": "5e0a2e15-4493-4d27-a656-29396f01e9f6",
+    "pk": "a7a4d3cf-504a-4092-8828-5a19e3d31138",
     "fields": {
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
         "slug": "word",
         "display_name": "Word",
         "folder": false,
@@ -516,23 +512,23 @@
 },
 {
     "model": "documents.elementtype",
-    "pk": "83f66e14-eeaf-44e5-8be2-f1eddaa1a549",
+    "pk": "ac394477-b189-4a8c-b61a-194e15c7ca75",
     "fields": {
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "slug": "volume",
-        "display_name": "Volume",
-        "folder": true,
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "slug": "surface",
+        "display_name": "Surface",
+        "folder": false,
         "indexable": false,
         "color": "28b62c"
     }
 },
 {
     "model": "documents.elementtype",
-    "pk": "9a893dfa-75b2-4ecd-b8a4-0fa532faadfe",
+    "pk": "b377e013-b313-412a-bd95-58681f87857c",
     "fields": {
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "slug": "text_line",
-        "display_name": "Line",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "slug": "act",
+        "display_name": "Act",
         "folder": false,
         "indexable": false,
         "color": "28b62c"
@@ -540,9 +536,9 @@
 },
 {
     "model": "documents.elementtype",
-    "pk": "e2c64e0b-a931-4453-8d9f-e84876583f45",
+    "pk": "c0686e6f-f7ee-47a6-91ef-276dc1c74604",
     "fields": {
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
         "slug": "page",
         "display_name": "Page",
         "folder": false,
@@ -551,280 +547,292 @@
     }
 },
 {
-    "model": "documents.elementpath",
-    "pk": "065e9fcf-4b9e-4ed4-96ab-9a8b4dd7adbd",
+    "model": "documents.elementtype",
+    "pk": "d5db136a-308b-4719-8553-b9f1485dbd31",
     "fields": {
-        "element": "4405ebfe-b7db-43d1-8ccc-2f90443631c5",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\"]",
-        "ordering": 7
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "slug": "text_line",
+        "display_name": "Line",
+        "folder": false,
+        "indexable": false,
+        "color": "28b62c"
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "196df0fb-7dd3-4c21-bec5-86c68f702c2b",
+    "pk": "003b020e-d3e9-4ab7-b5de-2bf54ceba1e0",
     "fields": {
-        "element": "d418351a-7ad2-4ee6-9cb4-d306cdd0843d",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"9d4abe00-9e52-4ddf-a89d-5f4a67b6433b\"]",
+        "element": "41d359f5-3f19-4f17-9cbb-83b68f124ed4",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"a7d90223-fc30-4409-8ae6-2505695867d4\"]",
         "ordering": 2
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "21c4a14a-77e7-4af1-a521-b1b49b95e190",
+    "pk": "077144c7-d29c-4230-b87e-81336ec32ff1",
     "fields": {
-        "element": "23d22c17-9dc2-4034-978c-5ef2b6eff576",
+        "element": "7aa6af77-3552-46ff-afdd-ecf210c2da44",
         "path": "[]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "23b53148-bd39-4e84-b4f2-ea3f1f601a74",
+    "pk": "153359d1-24aa-4231-a101-0df86d3302fe",
     "fields": {
-        "element": "012cd391-bedc-4159-9be0-19d0b3c54f95",
-        "path": "[]",
-        "ordering": 0
+        "element": "a344a86c-c126-464b-927f-40a4583de0a2",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\"]",
+        "ordering": 4
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "37399b33-366c-4c50-bdb1-93286fda8f39",
+    "pk": "22f15836-34e5-4eed-975c-4eaa44cae20f",
     "fields": {
-        "element": "e8b3cc6e-6518-42d5-928e-d14cb6cd26ac",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"5a2b2988-b759-4fad-8282-1aae9cf39a31\"]",
+        "element": "01c3a423-096e-412d-b559-b1d6bcc2f4bc",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"bef956e0-f9f1-43c6-9409-cc64588fd4c2\"]",
         "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "48721e40-61d5-4860-895d-aea3f41282a3",
+    "pk": "25fff9a2-6747-4cfa-adab-29f1156c3926",
     "fields": {
-        "element": "15384754-31b5-43b1-b9e3-b39a07a893d6",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"9d4abe00-9e52-4ddf-a89d-5f4a67b6433b\"]",
-        "ordering": 1
+        "element": "9ce76cf5-862d-4645-8469-2d9bca27c5e9",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"6ef0d61a-9fd2-417e-b8cf-a68cdc569f8d\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "65cf5360-7d04-40dd-b74b-a13b70932510",
+    "pk": "2f797330-815a-4b4f-b033-0210ce06f116",
     "fields": {
-        "element": "393274b6-d4c0-425f-8a4e-6c957d527c83",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"9d4abe00-9e52-4ddf-a89d-5f4a67b6433b\"]",
+        "element": "429edf14-afcc-46f9-b2a0-5c24fab6aa57",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"d01d0065-f45f-42c5-82c9-d7b3e9e98cd1\"]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "6cbc60e4-a853-4ea8-8f81-001309f1e486",
+    "pk": "479d4e56-c8a7-4275-90ff-7775d385a1af",
     "fields": {
-        "element": "69814c5b-6f75-4bcb-aba0-60d9e3093bc5",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"a22f1a4f-ee4e-44f4-8ea8-217f685b77d4\"]",
-        "ordering": 0
+        "element": "02d9886a-65ee-4c39-b961-a28d2178df73",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"a7d90223-fc30-4409-8ae6-2505695867d4\"]",
+        "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "7142899c-fe90-4ca5-8ffb-0dcf1d2434a7",
+    "pk": "4b21fc9a-fd94-4567-a02c-2ddfb0a751d8",
     "fields": {
-        "element": "cbbbdf83-7832-4487-a76a-6eabb040df3d",
-        "path": "[\"23d22c17-9dc2-4034-978c-5ef2b6eff576\"]",
-        "ordering": 0
+        "element": "baccd487-e8fb-456a-9a2e-4fe0827d38bf",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\"]",
+        "ordering": 7
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "7bbcace8-10d3-48a5-834f-b34a72b68b8d",
+    "pk": "554746d0-9765-490b-91ad-a25d0369c0d3",
     "fields": {
-        "element": "d7165395-0cbf-4070-bd46-ad050fb63d33",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"b1fef6ad-84b9-4590-82dc-7d5e94f51772\"]",
-        "ordering": 0
+        "element": "794f4388-a512-49ad-abb8-6e9d234895f3",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"d01d0065-f45f-42c5-82c9-d7b3e9e98cd1\"]",
+        "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "7db41281-a9ea-4b19-a599-3147d6e29bdd",
+    "pk": "58f9ecc4-9b8f-4bf2-86bf-172fc8c76b9e",
     "fields": {
-        "element": "bd32400c-be2c-4fdf-bbb9-0166aad2e04b",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\"]",
-        "ordering": 3
+        "element": "f769df85-a9c6-49ae-a42a-32d01c8b0103",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"a344a86c-c126-464b-927f-40a4583de0a2\"]",
+        "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "858bb5c7-4981-4455-bfe6-ea5bbd7405e8",
+    "pk": "62c6e9ef-34e6-453d-9e84-da6e857797c7",
     "fields": {
-        "element": "b1fef6ad-84b9-4590-82dc-7d5e94f51772",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\"]",
-        "ordering": 1
+        "element": "5fc4e41b-a399-4794-84b4-6821bee6a996",
+        "path": "[\"7aa6af77-3552-46ff-afdd-ecf210c2da44\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "878c84b9-6983-481a-8117-7806647c50b0",
+    "pk": "649d5264-3184-4b2c-a452-c3575c28a352",
     "fields": {
-        "element": "f18b3232-3ef4-4ae0-a125-02dca0d859d6",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"5a2b2988-b759-4fad-8282-1aae9cf39a31\"]",
-        "ordering": 3
+        "element": "d15b508f-b7f4-4521-9346-757c641c7f54",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"bef956e0-f9f1-43c6-9409-cc64588fd4c2\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "95a27f11-258f-41b8-9f40-dd7ebd26419c",
+    "pk": "67f05365-3912-4135-ad73-6c9642876da6",
     "fields": {
-        "element": "9e9da196-7011-4c87-be3c-21b580992c93",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\"]",
-        "ordering": 4
+        "element": "2606fa5a-4356-4646-a6b6-c0d9adced4c8",
+        "path": "[\"7aa6af77-3552-46ff-afdd-ecf210c2da44\"]",
+        "ordering": 2
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "99989b98-d1a2-43e6-865c-ecf081147280",
+    "pk": "72332ada-b46e-473c-8681-eacbdcdd4e0c",
     "fields": {
-        "element": "22a1757a-1af7-4999-8e45-0428ea23cfed",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"b1fef6ad-84b9-4590-82dc-7d5e94f51772\"]",
-        "ordering": 1
+        "element": "6ef0d61a-9fd2-417e-b8cf-a68cdc569f8d",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\"]",
+        "ordering": 6
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "96af6dbc-51df-4bd2-a67f-cb211d51a246",
+    "fields": {
+        "element": "649a8f7c-2db7-43cf-82a5-ca86206d9d46",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\"]",
+        "ordering": 5
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "b1b1288b-90cc-43d6-8f67-8247776093cb",
+    "pk": "9bbe0819-eea7-48a5-9d4c-cbe33968412f",
     "fields": {
-        "element": "deb1ed5d-b954-4450-a4b4-edb0741efec8",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"9e9da196-7011-4c87-be3c-21b580992c93\"]",
+        "element": "bef956e0-f9f1-43c6-9409-cc64588fd4c2",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\"]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "b96f33dc-316f-43b3-8a4d-2d42232f470d",
+    "pk": "a2377e58-1a90-46a6-8d25-b805e8dd0621",
     "fields": {
-        "element": "ad6483f2-c90a-41ba-9dbd-9cd3dbf78146",
-        "path": "[\"23d22c17-9dc2-4034-978c-5ef2b6eff576\"]",
-        "ordering": 2
+        "element": "5012bb0c-0249-4507-813e-879682b9321e",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"a7d90223-fc30-4409-8ae6-2505695867d4\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "bce997cc-26c1-4175-9ff8-5fc36ab6f32d",
+    "pk": "b7765894-b58d-44d9-8293-3757dbf846cb",
     "fields": {
-        "element": "d6673022-bbc1-49a6-9d15-3eb68c7f7616",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\"]",
-        "ordering": 6
+        "element": "bb6a86ce-c3a9-47e0-8f6e-9dc9eb067d98",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"a344a86c-c126-464b-927f-40a4583de0a2\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "c3ee3805-4418-4fdb-885b-19f3e8044ca4",
+    "pk": "b7a1b98c-f79e-4e72-ad2c-f9c3cb0525bd",
     "fields": {
-        "element": "05ca5b27-06c8-4337-8548-9de459d39024",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"b1fef6ad-84b9-4590-82dc-7d5e94f51772\"]",
+        "element": "a6ec2e2c-7f41-4fc8-aa05-c3d3a4ffd44d",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"bef956e0-f9f1-43c6-9409-cc64588fd4c2\"]",
         "ordering": 2
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "c7d8d602-d24b-4d57-a370-3eed48992776",
+    "pk": "b9700ac6-7339-437c-8a4a-a0154d4d490e",
     "fields": {
-        "element": "5beef449-d994-407d-a881-d4a7d0e14ad7",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"5a2b2988-b759-4fad-8282-1aae9cf39a31\"]",
+        "element": "1a2f95f4-c69c-4d3e-babc-0cc61ea04b8b",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"baccd487-e8fb-456a-9a2e-4fe0827d38bf\"]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "cbc0702b-4cc2-4b85-a310-1a288bbec5ba",
+    "pk": "bc200b4d-4eba-43f5-a800-573609152cbd",
     "fields": {
-        "element": "bd078be2-bff4-4c8b-ae78-241f1e4b144b",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"4405ebfe-b7db-43d1-8ccc-2f90443631c5\"]",
+        "element": "cc07dfc7-811c-4550-b2d9-b309f6c282ff",
+        "path": "[]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "dac53794-ecac-486b-b9eb-60788dbf6a66",
+    "pk": "c70833cc-31fd-48a4-9d87-7af6b8d78271",
     "fields": {
-        "element": "5a2b2988-b759-4fad-8282-1aae9cf39a31",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\"]",
-        "ordering": 0
+        "element": "cc0ec6c0-8eae-44ca-8179-7417456b8229",
+        "path": "[\"7aa6af77-3552-46ff-afdd-ecf210c2da44\"]",
+        "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "db6fbd1f-d5ce-4b16-bc6b-3c96ae7234ca",
+    "pk": "cb05e758-c987-412d-b173-620b60e54bed",
     "fields": {
-        "element": "1a5805d2-da50-4fc3-916f-92402e479e6e",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"5a2b2988-b759-4fad-8282-1aae9cf39a31\"]",
-        "ordering": 2
+        "element": "447fa573-bf5b-4683-ab69-b7dcdc57c1f5",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"649a8f7c-2db7-43cf-82a5-ca86206d9d46\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "ddcb97c4-a28f-4936-938f-99d6fd5be54e",
+    "pk": "d5174202-d76c-43e0-bb09-a0bfd9046361",
     "fields": {
-        "element": "a22f1a4f-ee4e-44f4-8ea8-217f685b77d4",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\"]",
-        "ordering": 5
+        "element": "b13c0dc4-9e1d-4903-ba42-efff19ab32c2",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"bef956e0-f9f1-43c6-9409-cc64588fd4c2\"]",
+        "ordering": 3
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "e40b2625-b378-4a15-96aa-401a6970f5e8",
+    "pk": "d5abdd9e-5dca-49a6-a0b7-fb9d20925c61",
     "fields": {
-        "element": "96f1d3f6-c65a-44bd-827f-d2569aecc629",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"bd32400c-be2c-4fdf-bbb9-0166aad2e04b\"]",
-        "ordering": 0
+        "element": "a7d90223-fc30-4409-8ae6-2505695867d4",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\"]",
+        "ordering": 2
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "e87ca8aa-d0f3-4beb-8af6-438b4f3d543a",
+    "pk": "dbcb356a-d7da-4f81-99c4-86dbad2d4420",
     "fields": {
-        "element": "29f17e00-1d4a-46d8-91c3-db65667c2503",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"d6673022-bbc1-49a6-9d15-3eb68c7f7616\"]",
-        "ordering": 0
+        "element": "6c0b88e8-e83f-4781-ac4b-e46944e4e2f6",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\"]",
+        "ordering": 3
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "eba4b8e5-37fa-4d92-9136-fad469f1cc64",
+    "pk": "e64a336d-20c9-4c8b-9fb7-0632aa1dd7ac",
     "fields": {
-        "element": "28eb7ab5-b1da-46d2-bb94-f461570a4918",
-        "path": "[\"23d22c17-9dc2-4034-978c-5ef2b6eff576\"]",
-        "ordering": 1
+        "element": "7311f153-7a61-4fef-875b-ed36a2537fce",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"d01d0065-f45f-42c5-82c9-d7b3e9e98cd1\"]",
+        "ordering": 2
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "f1bb6429-7ddb-4bf5-8dde-fa7b4451ae7b",
+    "pk": "e9518a0a-0210-42d8-8f3e-fa7b25c64f49",
     "fields": {
-        "element": "80bbf4bf-5840-400d-a450-b777cd7508aa",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\", \"9e9da196-7011-4c87-be3c-21b580992c93\"]",
+        "element": "d01d0065-f45f-42c5-82c9-d7b3e9e98cd1",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\"]",
         "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "f40e4025-286a-4758-93b9-660672e58f85",
+    "pk": "f3d1dfb5-ab42-4a2b-ac74-ad914dd42985",
     "fields": {
-        "element": "9d4abe00-9e52-4ddf-a89d-5f4a67b6433b",
-        "path": "[\"012cd391-bedc-4159-9be0-19d0b3c54f95\"]",
-        "ordering": 2
+        "element": "3a4f3fd5-ca40-4dad-8317-532565ec3def",
+        "path": "[\"cc07dfc7-811c-4550-b2d9-b309f6c282ff\", \"6c0b88e8-e83f-4781-ac4b-e46944e4e2f6\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.element",
-    "pk": "012cd391-bedc-4159-9be0-19d0b3c54f95",
+    "pk": "01c3a423-096e-412d-b559-b1d6bcc2f4bc",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "83f66e14-eeaf-44e5-8be2-f1eddaa1a549",
-        "name": "Volume 1",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "a7a4d3cf-504a-4092-8828-5a19e3d31138",
+        "name": "ROY",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": null,
-        "polygon": null,
+        "image": "3ac0c089-ac48-45dd-9b18-77c1499fbe0e",
+        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -832,18 +840,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "05ca5b27-06c8-4337-8548-9de459d39024",
+    "pk": "02d9886a-65ee-4c39-b961-a28d2178df73",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "5e0a2e15-4493-4d27-a656-29396f01e9f6",
-        "name": "DATUM",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "a7a4d3cf-504a-4092-8828-5a19e3d31138",
+        "name": "ROY",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "749d041a-c431-4617-85ff-a0628f38737d",
-        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)",
+        "image": "c826c86a-e5d4-4de8-997b-31b65caf7011",
+        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -851,18 +859,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "15384754-31b5-43b1-b9e3-b39a07a893d6",
+    "pk": "1a2f95f4-c69c-4d3e-babc-0cc61ea04b8b",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "5e0a2e15-4493-4d27-a656-29396f01e9f6",
-        "name": "ROY",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "ac394477-b189-4a8c-b61a-194e15c7ca75",
+        "name": "Surface F",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "9f324936-0561-432a-8985-103b240e55ed",
-        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)",
+        "image": "c826c86a-e5d4-4de8-997b-31b65caf7011",
+        "polygon": "LINEARRING (600 600, 600 1000, 1000 1000, 1000 600, 600 600)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -870,18 +878,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "1a5805d2-da50-4fc3-916f-92402e479e6e",
+    "pk": "2606fa5a-4356-4646-a6b6-c0d9adced4c8",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "5e0a2e15-4493-4d27-a656-29396f01e9f6",
-        "name": "DATUM",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "c0686e6f-f7ee-47a6-91ef-276dc1c74604",
+        "name": "Volume 2, page 2r",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "71b96a29-ad88-4906-abeb-fd4a50d61af1",
-        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)",
+        "image": "3a90a6c2-5c43-4af2-993e-b46091607be6",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -889,18 +897,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "22a1757a-1af7-4999-8e45-0428ea23cfed",
+    "pk": "3a4f3fd5-ca40-4dad-8317-532565ec3def",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "5e0a2e15-4493-4d27-a656-29396f01e9f6",
-        "name": "ROY",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "ac394477-b189-4a8c-b61a-194e15c7ca75",
+        "name": "Surface A",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "749d041a-c431-4617-85ff-a0628f38737d",
-        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)",
+        "image": "3ac0c089-ac48-45dd-9b18-77c1499fbe0e",
+        "polygon": "LINEARRING (0 0, 0 600, 600 600, 600 0, 0 0)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -908,18 +916,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "23d22c17-9dc2-4034-978c-5ef2b6eff576",
+    "pk": "41d359f5-3f19-4f17-9cbb-83b68f124ed4",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "83f66e14-eeaf-44e5-8be2-f1eddaa1a549",
-        "name": "Volume 2",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "a7a4d3cf-504a-4092-8828-5a19e3d31138",
+        "name": "DATUM",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": null,
-        "polygon": null,
+        "image": "c826c86a-e5d4-4de8-997b-31b65caf7011",
+        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -927,18 +935,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "28eb7ab5-b1da-46d2-bb94-f461570a4918",
+    "pk": "429edf14-afcc-46f9-b2a0-5c24fab6aa57",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "e2c64e0b-a931-4453-8d9f-e84876583f45",
-        "name": "Volume 2, page 1v",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "a7a4d3cf-504a-4092-8828-5a19e3d31138",
+        "name": "PARIS",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "3ce03720-068d-45f0-9237-df2d744ef953",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
+        "image": "333f1f5d-eb17-40a9-8401-d2303a978d5d",
+        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -946,18 +954,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "29f17e00-1d4a-46d8-91c3-db65667c2503",
+    "pk": "447fa573-bf5b-4683-ab69-b7dcdc57c1f5",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "16c614aa-d6d4-4f55-afdd-0fada214362a",
-        "name": "Surface E",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "ac394477-b189-4a8c-b61a-194e15c7ca75",
+        "name": "Surface D",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "9f324936-0561-432a-8985-103b240e55ed",
-        "polygon": "LINEARRING (300 300, 300 600, 600 600, 600 300, 300 300)",
+        "image": "c826c86a-e5d4-4de8-997b-31b65caf7011",
+        "polygon": "LINEARRING (0 0, 0 300, 300 300, 300 0, 0 0)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -965,17 +973,17 @@
 },
 {
     "model": "documents.element",
-    "pk": "393274b6-d4c0-425f-8a4e-6c957d527c83",
+    "pk": "5012bb0c-0249-4507-813e-879682b9321e",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "5e0a2e15-4493-4d27-a656-29396f01e9f6",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "a7a4d3cf-504a-4092-8828-5a19e3d31138",
         "name": "PARIS",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "9f324936-0561-432a-8985-103b240e55ed",
+        "image": "c826c86a-e5d4-4de8-997b-31b65caf7011",
         "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)",
         "rotation_angle": 0,
         "mirrored": false,
@@ -984,18 +992,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "4405ebfe-b7db-43d1-8ccc-2f90443631c5",
+    "pk": "5fc4e41b-a399-4794-84b4-6821bee6a996",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "1acf2b7e-3a52-40b4-b428-40b17992928f",
-        "name": "Act 5",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "c0686e6f-f7ee-47a6-91ef-276dc1c74604",
+        "name": "Volume 2, page 1r",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": null,
-        "polygon": null,
+        "image": "65351fbb-f6ce-429b-8615-3782bd4e1192",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1003,18 +1011,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "5a2b2988-b759-4fad-8282-1aae9cf39a31",
+    "pk": "649a8f7c-2db7-43cf-82a5-ca86206d9d46",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "e2c64e0b-a931-4453-8d9f-e84876583f45",
-        "name": "Volume 1, page 1r",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "b377e013-b313-412a-bd95-58681f87857c",
+        "name": "Act 3",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "71b96a29-ad88-4906-abeb-fd4a50d61af1",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
+        "image": null,
+        "polygon": null,
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1022,18 +1030,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "5beef449-d994-407d-a881-d4a7d0e14ad7",
+    "pk": "6c0b88e8-e83f-4781-ac4b-e46944e4e2f6",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "5e0a2e15-4493-4d27-a656-29396f01e9f6",
-        "name": "PARIS",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "b377e013-b313-412a-bd95-58681f87857c",
+        "name": "Act 1",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "71b96a29-ad88-4906-abeb-fd4a50d61af1",
-        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)",
+        "image": null,
+        "polygon": null,
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1041,18 +1049,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "69814c5b-6f75-4bcb-aba0-60d9e3093bc5",
+    "pk": "6ef0d61a-9fd2-417e-b8cf-a68cdc569f8d",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "16c614aa-d6d4-4f55-afdd-0fada214362a",
-        "name": "Surface D",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "b377e013-b313-412a-bd95-58681f87857c",
+        "name": "Act 4",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "9f324936-0561-432a-8985-103b240e55ed",
-        "polygon": "LINEARRING (0 0, 0 300, 300 300, 300 0, 0 0)",
+        "image": null,
+        "polygon": null,
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1060,18 +1068,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "80bbf4bf-5840-400d-a450-b777cd7508aa",
+    "pk": "7311f153-7a61-4fef-875b-ed36a2537fce",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "16c614aa-d6d4-4f55-afdd-0fada214362a",
-        "name": "Surface C",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "a7a4d3cf-504a-4092-8828-5a19e3d31138",
+        "name": "DATUM",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "749d041a-c431-4617-85ff-a0628f38737d",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
+        "image": "333f1f5d-eb17-40a9-8401-d2303a978d5d",
+        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1079,18 +1087,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "96f1d3f6-c65a-44bd-827f-d2569aecc629",
+    "pk": "794f4388-a512-49ad-abb8-6e9d234895f3",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "16c614aa-d6d4-4f55-afdd-0fada214362a",
-        "name": "Surface A",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "a7a4d3cf-504a-4092-8828-5a19e3d31138",
+        "name": "ROY",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "71b96a29-ad88-4906-abeb-fd4a50d61af1",
-        "polygon": "LINEARRING (0 0, 0 600, 600 600, 600 0, 0 0)",
+        "image": "333f1f5d-eb17-40a9-8401-d2303a978d5d",
+        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1098,18 +1106,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "9d4abe00-9e52-4ddf-a89d-5f4a67b6433b",
+    "pk": "7aa6af77-3552-46ff-afdd-ecf210c2da44",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "e2c64e0b-a931-4453-8d9f-e84876583f45",
-        "name": "Volume 1, page 2r",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "5b656298-6b77-441d-89bc-944f83e90318",
+        "name": "Volume 2",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "9f324936-0561-432a-8985-103b240e55ed",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
+        "image": null,
+        "polygon": null,
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1117,18 +1125,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "9e9da196-7011-4c87-be3c-21b580992c93",
+    "pk": "9ce76cf5-862d-4645-8469-2d9bca27c5e9",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "1acf2b7e-3a52-40b4-b428-40b17992928f",
-        "name": "Act 2",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "ac394477-b189-4a8c-b61a-194e15c7ca75",
+        "name": "Surface E",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": null,
-        "polygon": null,
+        "image": "c826c86a-e5d4-4de8-997b-31b65caf7011",
+        "polygon": "LINEARRING (300 300, 300 600, 600 600, 600 300, 300 300)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1136,13 +1144,13 @@
 },
 {
     "model": "documents.element",
-    "pk": "a22f1a4f-ee4e-44f4-8ea8-217f685b77d4",
+    "pk": "a344a86c-c126-464b-927f-40a4583de0a2",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "1acf2b7e-3a52-40b4-b428-40b17992928f",
-        "name": "Act 3",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "b377e013-b313-412a-bd95-58681f87857c",
+        "name": "Act 2",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
@@ -1155,18 +1163,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "ad6483f2-c90a-41ba-9dbd-9cd3dbf78146",
+    "pk": "a6ec2e2c-7f41-4fc8-aa05-c3d3a4ffd44d",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "e2c64e0b-a931-4453-8d9f-e84876583f45",
-        "name": "Volume 2, page 2r",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "a7a4d3cf-504a-4092-8828-5a19e3d31138",
+        "name": "DATUM",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "7841d614-be5e-4ff6-82dd-4089cc644a19",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
+        "image": "3ac0c089-ac48-45dd-9b18-77c1499fbe0e",
+        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1174,17 +1182,17 @@
 },
 {
     "model": "documents.element",
-    "pk": "b1fef6ad-84b9-4590-82dc-7d5e94f51772",
+    "pk": "a7d90223-fc30-4409-8ae6-2505695867d4",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "e2c64e0b-a931-4453-8d9f-e84876583f45",
-        "name": "Volume 1, page 1v",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "c0686e6f-f7ee-47a6-91ef-276dc1c74604",
+        "name": "Volume 1, page 2r",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "749d041a-c431-4617-85ff-a0628f38737d",
+        "image": "c826c86a-e5d4-4de8-997b-31b65caf7011",
         "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
         "rotation_angle": 0,
         "mirrored": false,
@@ -1193,18 +1201,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "bd078be2-bff4-4c8b-ae78-241f1e4b144b",
+    "pk": "b13c0dc4-9e1d-4903-ba42-efff19ab32c2",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "16c614aa-d6d4-4f55-afdd-0fada214362a",
-        "name": "Surface F",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "d5db136a-308b-4719-8553-b9f1485dbd31",
+        "name": "Text line",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "9f324936-0561-432a-8985-103b240e55ed",
-        "polygon": "LINEARRING (600 600, 600 1000, 1000 1000, 1000 600, 600 600)",
+        "image": "3ac0c089-ac48-45dd-9b18-77c1499fbe0e",
+        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1212,13 +1220,13 @@
 },
 {
     "model": "documents.element",
-    "pk": "bd32400c-be2c-4fdf-bbb9-0166aad2e04b",
+    "pk": "baccd487-e8fb-456a-9a2e-4fe0827d38bf",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "1acf2b7e-3a52-40b4-b428-40b17992928f",
-        "name": "Act 1",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "b377e013-b313-412a-bd95-58681f87857c",
+        "name": "Act 5",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
@@ -1231,18 +1239,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "cbbbdf83-7832-4487-a76a-6eabb040df3d",
+    "pk": "bb6a86ce-c3a9-47e0-8f6e-9dc9eb067d98",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "e2c64e0b-a931-4453-8d9f-e84876583f45",
-        "name": "Volume 2, page 1r",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "ac394477-b189-4a8c-b61a-194e15c7ca75",
+        "name": "Surface B",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "2ee6f6af-ee3e-4ea8-86b6-d4bb0e4514ee",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
+        "image": "3ac0c089-ac48-45dd-9b18-77c1499fbe0e",
+        "polygon": "LINEARRING (600 600, 600 1000, 1000 1000, 1000 600, 600 600)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1250,18 +1258,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "d418351a-7ad2-4ee6-9cb4-d306cdd0843d",
+    "pk": "bef956e0-f9f1-43c6-9409-cc64588fd4c2",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "5e0a2e15-4493-4d27-a656-29396f01e9f6",
-        "name": "DATUM",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "c0686e6f-f7ee-47a6-91ef-276dc1c74604",
+        "name": "Volume 1, page 1r",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "9f324936-0561-432a-8985-103b240e55ed",
-        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)",
+        "image": "3ac0c089-ac48-45dd-9b18-77c1499fbe0e",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1269,13 +1277,13 @@
 },
 {
     "model": "documents.element",
-    "pk": "d6673022-bbc1-49a6-9d15-3eb68c7f7616",
+    "pk": "cc07dfc7-811c-4550-b2d9-b309f6c282ff",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "1acf2b7e-3a52-40b4-b428-40b17992928f",
-        "name": "Act 4",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "5b656298-6b77-441d-89bc-944f83e90318",
+        "name": "Volume 1",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
@@ -1288,18 +1296,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "d7165395-0cbf-4070-bd46-ad050fb63d33",
+    "pk": "cc0ec6c0-8eae-44ca-8179-7417456b8229",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "5e0a2e15-4493-4d27-a656-29396f01e9f6",
-        "name": "PARIS",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "c0686e6f-f7ee-47a6-91ef-276dc1c74604",
+        "name": "Volume 2, page 1v",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "749d041a-c431-4617-85ff-a0628f38737d",
-        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)",
+        "image": "9f7b7678-defd-4ce7-be9b-ed5b04da3c04",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1307,18 +1315,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "deb1ed5d-b954-4450-a4b4-edb0741efec8",
+    "pk": "d01d0065-f45f-42c5-82c9-d7b3e9e98cd1",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "16c614aa-d6d4-4f55-afdd-0fada214362a",
-        "name": "Surface B",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "c0686e6f-f7ee-47a6-91ef-276dc1c74604",
+        "name": "Volume 1, page 1v",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "71b96a29-ad88-4906-abeb-fd4a50d61af1",
-        "polygon": "LINEARRING (600 600, 600 1000, 1000 1000, 1000 600, 600 600)",
+        "image": "333f1f5d-eb17-40a9-8401-d2303a978d5d",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1326,18 +1334,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "e8b3cc6e-6518-42d5-928e-d14cb6cd26ac",
+    "pk": "d15b508f-b7f4-4521-9346-757c641c7f54",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "5e0a2e15-4493-4d27-a656-29396f01e9f6",
-        "name": "ROY",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "a7a4d3cf-504a-4092-8828-5a19e3d31138",
+        "name": "PARIS",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "71b96a29-ad88-4906-abeb-fd4a50d61af1",
-        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)",
+        "image": "3ac0c089-ac48-45dd-9b18-77c1499fbe0e",
+        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1345,18 +1353,18 @@
 },
 {
     "model": "documents.element",
-    "pk": "f18b3232-3ef4-4ae0-a125-02dca0d859d6",
+    "pk": "f769df85-a9c6-49ae-a42a-32d01c8b0103",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "9a893dfa-75b2-4ecd-b8a4-0fa532faadfe",
-        "name": "Text line",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "ac394477-b189-4a8c-b61a-194e15c7ca75",
+        "name": "Surface C",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": "71b96a29-ad88-4906-abeb-fd4a50d61af1",
-        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)",
+        "image": "333f1f5d-eb17-40a9-8401-d2303a978d5d",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1364,91 +1372,91 @@
 },
 {
     "model": "documents.entitytype",
-    "pk": "311d11f1-9a0d-42e8-b261-7f921d325a22",
+    "pk": "389cf24a-71b8-4d59-ba20-1bead9c19100",
     "fields": {
-        "name": "location",
+        "name": "organization",
         "color": "ff0000",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68"
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa"
     }
 },
 {
     "model": "documents.entitytype",
-    "pk": "7e7f01f6-fea3-454a-870f-1ef8a4416512",
+    "pk": "68cd175e-5519-469b-8795-4def01f68486",
     "fields": {
-        "name": "date",
+        "name": "person",
         "color": "ff0000",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68"
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa"
     }
 },
 {
     "model": "documents.entitytype",
-    "pk": "bbaaa893-ad44-45a0-aa03-975c8787ade1",
+    "pk": "79af3b80-5800-470e-9d50-76405371b35a",
     "fields": {
-        "name": "number",
+        "name": "location",
         "color": "ff0000",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68"
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa"
     }
 },
 {
     "model": "documents.entitytype",
-    "pk": "c0537bd2-7cc8-4612-abba-839869668a8c",
+    "pk": "a59ccd99-2b4f-4861-8480-e1d4481cd0d4",
     "fields": {
-        "name": "organization",
+        "name": "date",
         "color": "ff0000",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68"
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa"
     }
 },
 {
     "model": "documents.entitytype",
-    "pk": "d352ac6e-68a2-415b-898f-e234e58fb9f4",
+    "pk": "c4211cec-2f93-4e15-8e20-fb6597327b3c",
     "fields": {
-        "name": "person",
+        "name": "number",
         "color": "ff0000",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68"
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa"
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "081a5c4f-7af4-4705-aa97-aeff028176dd",
+    "pk": "23e55bee-fae7-433f-a1ce-4ff250f8a985",
     "fields": {
-        "element": "5a2b2988-b759-4fad-8282-1aae9cf39a31",
-        "worker_version": "f22fde5b-28db-459a-8257-cab7b58ef63d",
+        "element": "d15b508f-b7f4-4521-9346-757c641c7f54",
+        "worker_version": "38af2294-5e69-4c10-8daf-5bb1b58b182a",
         "worker_run": null,
-        "text": "Lorem ipsum dolor sit amet",
+        "text": "PARIS",
         "orientation": "horizontal-lr",
         "confidence": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "162d8843-380a-4e28-9132-642fa8639018",
+    "pk": "2cb7dd1f-8189-4b80-974f-051e089feb42",
     "fields": {
-        "element": "393274b6-d4c0-425f-8a4e-6c957d527c83",
-        "worker_version": "f22fde5b-28db-459a-8257-cab7b58ef63d",
+        "element": "41d359f5-3f19-4f17-9cbb-83b68f124ed4",
+        "worker_version": "38af2294-5e69-4c10-8daf-5bb1b58b182a",
         "worker_run": null,
-        "text": "PARIS",
+        "text": "DATUM",
         "orientation": "horizontal-lr",
         "confidence": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "23641b79-24ef-4931-8cb4-57dc8c3d71d8",
+    "pk": "4fe2f9a4-927b-4d0e-a094-eacfad911931",
     "fields": {
-        "element": "e8b3cc6e-6518-42d5-928e-d14cb6cd26ac",
-        "worker_version": "f22fde5b-28db-459a-8257-cab7b58ef63d",
+        "element": "5012bb0c-0249-4507-813e-879682b9321e",
+        "worker_version": "38af2294-5e69-4c10-8daf-5bb1b58b182a",
         "worker_run": null,
-        "text": "ROY",
+        "text": "PARIS",
         "orientation": "horizontal-lr",
         "confidence": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "39d8309a-5ee5-4654-be82-c863c4c3719c",
+    "pk": "65f20dc0-3ec0-46b5-b539-fa1c22055f9e",
     "fields": {
-        "element": "05ca5b27-06c8-4337-8548-9de459d39024",
-        "worker_version": "f22fde5b-28db-459a-8257-cab7b58ef63d",
+        "element": "7311f153-7a61-4fef-875b-ed36a2537fce",
+        "worker_version": "38af2294-5e69-4c10-8daf-5bb1b58b182a",
         "worker_run": null,
         "text": "DATUM",
         "orientation": "horizontal-lr",
@@ -1457,10 +1465,10 @@
 },
 {
     "model": "documents.transcription",
-    "pk": "4bb4012c-53b2-41be-ac0c-9d7b5067dc25",
+    "pk": "67d43d8f-0123-4d17-b496-527660f824d5",
     "fields": {
-        "element": "15384754-31b5-43b1-b9e3-b39a07a893d6",
-        "worker_version": "f22fde5b-28db-459a-8257-cab7b58ef63d",
+        "element": "01c3a423-096e-412d-b559-b1d6bcc2f4bc",
+        "worker_version": "38af2294-5e69-4c10-8daf-5bb1b58b182a",
         "worker_run": null,
         "text": "ROY",
         "orientation": "horizontal-lr",
@@ -1469,99 +1477,99 @@
 },
 {
     "model": "documents.transcription",
-    "pk": "62bd07d6-3521-408c-b01c-e4005677b906",
+    "pk": "6926bb8f-773f-4505-9b75-e93481a80198",
     "fields": {
-        "element": "1a5805d2-da50-4fc3-916f-92402e479e6e",
-        "worker_version": "f22fde5b-28db-459a-8257-cab7b58ef63d",
+        "element": "bef956e0-f9f1-43c6-9409-cc64588fd4c2",
+        "worker_version": "38af2294-5e69-4c10-8daf-5bb1b58b182a",
         "worker_run": null,
-        "text": "DATUM",
+        "text": "Lorem ipsum dolor sit amet",
         "orientation": "horizontal-lr",
         "confidence": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "764094d1-cef3-40d5-bdb9-849f802d9335",
+    "pk": "9cca8460-b694-4f75-be5b-c12f14f3e374",
     "fields": {
-        "element": "5beef449-d994-407d-a881-d4a7d0e14ad7",
-        "worker_version": "f22fde5b-28db-459a-8257-cab7b58ef63d",
+        "element": "02d9886a-65ee-4c39-b961-a28d2178df73",
+        "worker_version": "38af2294-5e69-4c10-8daf-5bb1b58b182a",
         "worker_run": null,
-        "text": "PARIS",
+        "text": "ROY",
         "orientation": "horizontal-lr",
         "confidence": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "aef2094a-b509-4865-bbad-698ab78984ec",
+    "pk": "b0707c31-eb72-45e2-8a66-0d45a4011a0d",
     "fields": {
-        "element": "22a1757a-1af7-4999-8e45-0428ea23cfed",
-        "worker_version": "f22fde5b-28db-459a-8257-cab7b58ef63d",
+        "element": "a6ec2e2c-7f41-4fc8-aa05-c3d3a4ffd44d",
+        "worker_version": "38af2294-5e69-4c10-8daf-5bb1b58b182a",
         "worker_run": null,
-        "text": "ROY",
+        "text": "DATUM",
         "orientation": "horizontal-lr",
         "confidence": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "c9bb2b39-7f18-4979-afb7-c544ee8e6f4b",
+    "pk": "cec50683-2c40-4a32-a7bd-332b3241e392",
     "fields": {
-        "element": "d418351a-7ad2-4ee6-9cb4-d306cdd0843d",
-        "worker_version": "f22fde5b-28db-459a-8257-cab7b58ef63d",
+        "element": "429edf14-afcc-46f9-b2a0-5c24fab6aa57",
+        "worker_version": "38af2294-5e69-4c10-8daf-5bb1b58b182a",
         "worker_run": null,
-        "text": "DATUM",
+        "text": "PARIS",
         "orientation": "horizontal-lr",
         "confidence": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "dc25ce06-ac14-44c6-8ad6-aa1d3ab20551",
+    "pk": "fe7bbe41-a811-4f62-b85f-b449e922f00f",
     "fields": {
-        "element": "d7165395-0cbf-4070-bd46-ad050fb63d33",
-        "worker_version": "f22fde5b-28db-459a-8257-cab7b58ef63d",
+        "element": "794f4388-a512-49ad-abb8-6e9d234895f3",
+        "worker_version": "38af2294-5e69-4c10-8daf-5bb1b58b182a",
         "worker_run": null,
-        "text": "PARIS",
+        "text": "ROY",
         "orientation": "horizontal-lr",
         "confidence": 1.0
     }
 },
 {
     "model": "documents.allowedmetadata",
-    "pk": "3b1250cb-94e7-4f8f-90f8-469ad21e2bf8",
+    "pk": "844cba89-47f3-403f-a200-580fea379535",
     "fields": {
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "date",
-        "name": "date"
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "location",
+        "name": "location"
     }
 },
 {
     "model": "documents.allowedmetadata",
-    "pk": "4f16502f-3813-43e0-871f-0984a1082672",
+    "pk": "e7707502-a7d2-4f1c-9c38-d5b95e3acc89",
     "fields": {
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
-        "type": "location",
-        "name": "location"
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
+        "type": "date",
+        "name": "date"
     }
 },
 {
     "model": "documents.allowedmetadata",
-    "pk": "b965e5fc-e3ba-4232-a710-57b2c2144dda",
+    "pk": "ea5bd9a8-dd37-4d0f-b829-58b92d8cfdf5",
     "fields": {
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
         "type": "text",
         "name": "folio"
     }
 },
 {
     "model": "documents.metadata",
-    "pk": "16f42e57-9495-406c-baae-51be7c97c544",
+    "pk": "2184f569-2343-4f99-b8b2-5865a8c79890",
     "fields": {
-        "element": "9d4abe00-9e52-4ddf-a89d-5f4a67b6433b",
+        "element": "d01d0065-f45f-42c5-82c9-d7b3e9e98cd1",
         "name": "folio",
         "type": "text",
-        "value": "2r",
+        "value": "1v",
         "entity": null,
         "worker_version": null,
         "worker_run": null
@@ -1569,12 +1577,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "43f60c5e-2fbd-4ac5-ae01-5aa73ebd4e27",
+    "pk": "28ccc70d-88d4-4594-9b36-c4777dd75139",
     "fields": {
-        "element": "9e9da196-7011-4c87-be3c-21b580992c93",
-        "name": "number",
+        "element": "bef956e0-f9f1-43c6-9409-cc64588fd4c2",
+        "name": "folio",
         "type": "text",
-        "value": "2",
+        "value": "1r",
         "entity": null,
         "worker_version": null,
         "worker_run": null
@@ -1582,12 +1590,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "49afc57d-3852-439d-aec3-dc9bae75d317",
+    "pk": "303b3216-7852-4d12-a7bc-792c228c819d",
     "fields": {
-        "element": "28eb7ab5-b1da-46d2-bb94-f461570a4918",
+        "element": "a7d90223-fc30-4409-8ae6-2505695867d4",
         "name": "folio",
         "type": "text",
-        "value": "1v",
+        "value": "2r",
         "entity": null,
         "worker_version": null,
         "worker_run": null
@@ -1595,12 +1603,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "7172ad8f-274e-4762-aa71-4b67e831a085",
+    "pk": "4796be93-6d1c-4e88-85a5-bfa3fd4c2df5",
     "fields": {
-        "element": "cbbbdf83-7832-4487-a76a-6eabb040df3d",
-        "name": "folio",
+        "element": "6ef0d61a-9fd2-417e-b8cf-a68cdc569f8d",
+        "name": "number",
         "type": "text",
-        "value": "1r",
+        "value": "4",
         "entity": null,
         "worker_version": null,
         "worker_run": null
@@ -1608,9 +1616,9 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "7feebc85-ae0c-4f84-a9c8-719c0334f365",
+    "pk": "50ed9eca-5b28-4ca3-8fe9-28829d245c41",
     "fields": {
-        "element": "5a2b2988-b759-4fad-8282-1aae9cf39a31",
+        "element": "5fc4e41b-a399-4794-84b4-6821bee6a996",
         "name": "folio",
         "type": "text",
         "value": "1r",
@@ -1621,12 +1629,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "995ffc3d-fd2b-4aa1-a0fd-bb06818d13c4",
+    "pk": "653bbae1-3470-47f3-b1e3-3369a5d0c2c6",
     "fields": {
-        "element": "d6673022-bbc1-49a6-9d15-3eb68c7f7616",
+        "element": "6c0b88e8-e83f-4781-ac4b-e46944e4e2f6",
         "name": "number",
         "type": "text",
-        "value": "4",
+        "value": "1",
         "entity": null,
         "worker_version": null,
         "worker_run": null
@@ -1634,12 +1642,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "9a20fe23-faf6-4579-8aa3-164bf0ebc9db",
+    "pk": "821dadd3-2f8d-483c-92e0-ba88be0873aa",
     "fields": {
-        "element": "4405ebfe-b7db-43d1-8ccc-2f90443631c5",
-        "name": "number",
+        "element": "2606fa5a-4356-4646-a6b6-c0d9adced4c8",
+        "name": "folio",
         "type": "text",
-        "value": "5",
+        "value": "2r",
         "entity": null,
         "worker_version": null,
         "worker_run": null
@@ -1647,12 +1655,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "9c7749d9-e519-44ec-8558-013f51bcff98",
+    "pk": "ad2dfca7-1056-41d0-8492-31aa1356b8b8",
     "fields": {
-        "element": "bd32400c-be2c-4fdf-bbb9-0166aad2e04b",
+        "element": "a344a86c-c126-464b-927f-40a4583de0a2",
         "name": "number",
         "type": "text",
-        "value": "1",
+        "value": "2",
         "entity": null,
         "worker_version": null,
         "worker_run": null
@@ -1660,9 +1668,9 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "d9d22295-6f93-4741-b548-8fc253f0a5fb",
+    "pk": "b3d6b05d-5cf7-4ace-bca4-8b50cb6326c6",
     "fields": {
-        "element": "a22f1a4f-ee4e-44f4-8ea8-217f685b77d4",
+        "element": "649a8f7c-2db7-43cf-82a5-ca86206d9d46",
         "name": "number",
         "type": "text",
         "value": "3",
@@ -1673,9 +1681,9 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "de76c9c1-0151-4b06-afcd-b44621414de1",
+    "pk": "db3febc5-f623-45c0-966a-780d55f2be57",
     "fields": {
-        "element": "b1fef6ad-84b9-4590-82dc-7d5e94f51772",
+        "element": "cc0ec6c0-8eae-44ca-8179-7417456b8229",
         "name": "folio",
         "type": "text",
         "value": "1v",
@@ -1686,12 +1694,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "de83d6be-9880-48fd-bbe7-2d171c0893a2",
+    "pk": "e691d260-dd78-42e2-81e0-be893f3abd74",
     "fields": {
-        "element": "ad6483f2-c90a-41ba-9dbd-9cd3dbf78146",
-        "name": "folio",
+        "element": "baccd487-e8fb-456a-9a2e-4fe0827d38bf",
+        "name": "number",
         "type": "text",
-        "value": "2r",
+        "value": "5",
         "entity": null,
         "worker_version": null,
         "worker_run": null
@@ -1714,12 +1722,12 @@
 },
 {
     "model": "images.image",
-    "pk": "2ee6f6af-ee3e-4ea8-86b6-d4bb0e4514ee",
+    "pk": "333f1f5d-eb17-40a9-8401-d2303a978d5d",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "server": 1,
-        "path": "img4",
+        "path": "img2",
         "width": 1000,
         "height": 1000,
         "hash": null,
@@ -1728,12 +1736,12 @@
 },
 {
     "model": "images.image",
-    "pk": "3ce03720-068d-45f0-9237-df2d744ef953",
+    "pk": "3a90a6c2-5c43-4af2-993e-b46091607be6",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "server": 1,
-        "path": "img5",
+        "path": "img6",
         "width": 1000,
         "height": 1000,
         "hash": null,
@@ -1742,7 +1750,7 @@
 },
 {
     "model": "images.image",
-    "pk": "71b96a29-ad88-4906-abeb-fd4a50d61af1",
+    "pk": "3ac0c089-ac48-45dd-9b18-77c1499fbe0e",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
@@ -1756,12 +1764,12 @@
 },
 {
     "model": "images.image",
-    "pk": "749d041a-c431-4617-85ff-a0628f38737d",
+    "pk": "65351fbb-f6ce-429b-8615-3782bd4e1192",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "server": 1,
-        "path": "img2",
+        "path": "img4",
         "width": 1000,
         "height": 1000,
         "hash": null,
@@ -1770,12 +1778,12 @@
 },
 {
     "model": "images.image",
-    "pk": "7841d614-be5e-4ff6-82dd-4089cc644a19",
+    "pk": "9f7b7678-defd-4ce7-be9b-ed5b04da3c04",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "server": 1,
-        "path": "img6",
+        "path": "img5",
         "width": 1000,
         "height": 1000,
         "hash": null,
@@ -1784,7 +1792,7 @@
 },
 {
     "model": "images.image",
-    "pk": "9f324936-0561-432a-8985-103b240e55ed",
+    "pk": "c826c86a-e5d4-4de8-997b-31b65caf7011",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
@@ -1798,64 +1806,64 @@
 },
 {
     "model": "users.right",
-    "pk": "056e0095-c923-4ad6-9c82-cbc4fd03be58",
-    "fields": {
-        "user": 2,
-        "group": null,
-        "content_type": 35,
-        "content_id": "735c70c6-bb6f-405e-8126-c01efd6ad747",
-        "level": 100
-    }
-},
-{
-    "model": "users.right",
-    "pk": "1b17d60e-bbc1-4116-bb4b-bb0cd2a65b0e",
+    "pk": "6aeee47f-82fc-4f8c-ba67-0950001f9165",
     "fields": {
         "user": 4,
         "group": null,
         "content_type": 35,
-        "content_id": "735c70c6-bb6f-405e-8126-c01efd6ad747",
+        "content_id": "154b84fc-9b5e-4224-8198-369424a6044f",
         "level": 10
     }
 },
 {
     "model": "users.right",
-    "pk": "6b9658f5-5a20-4268-8d84-80f0a0adb551",
+    "pk": "83388f8c-ab23-4a8f-a93a-5bcf1b1737ed",
     "fields": {
         "user": 2,
         "group": null,
         "content_type": 12,
-        "content_id": "409b6859-63b9-41f2-8449-ba737bca6624",
+        "content_id": "d4639943-3bc5-4839-ba11-bac03818050c",
         "level": 10
     }
 },
 {
     "model": "users.right",
-    "pk": "6bc35837-48e5-4bb5-bb41-642c5063b681",
+    "pk": "8422a688-f89c-450c-9f50-1aa390f8f679",
     "fields": {
-        "user": 3,
+        "user": 2,
         "group": null,
         "content_type": 35,
-        "content_id": "735c70c6-bb6f-405e-8126-c01efd6ad747",
-        "level": 50
+        "content_id": "154b84fc-9b5e-4224-8198-369424a6044f",
+        "level": 100
     }
 },
 {
     "model": "users.right",
-    "pk": "cf11fab0-8fc9-41b5-9a96-6464cc1b5581",
+    "pk": "94d056b0-9e9a-41b5-8287-445947594902",
     "fields": {
         "user": 2,
         "group": null,
         "content_type": 20,
-        "content_id": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
+        "content_id": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
         "level": 100
     }
 },
+{
+    "model": "users.right",
+    "pk": "ee07cbba-7ca5-4a6d-ac27-b782c25d294e",
+    "fields": {
+        "user": 3,
+        "group": null,
+        "content_type": 35,
+        "content_id": "154b84fc-9b5e-4224-8198-369424a6044f",
+        "level": 50
+    }
+},
 {
     "model": "users.user",
     "pk": 1,
     "fields": {
-        "password": "pbkdf2_sha256$390000$ZuasXMuh9i4eX0Ou9Aq1bL$QHVkSsvmF0+j2920P9h8CdsIDM8tK8/Qnv5m1Bvqu8s=",
+        "password": "pbkdf2_sha256$390000$R2D2dMVrU1brlgQ1SF0ww8$wbS/HqbXLiXpwanPA0BuF2I3DzULtf6iAFgOv0if9es=",
         "last_login": null,
         "email": "root@root.fr",
         "display_name": "Admin",
@@ -1870,7 +1878,7 @@
     "model": "users.user",
     "pk": 2,
     "fields": {
-        "password": "pbkdf2_sha256$390000$dtjfH2x1Y4Ux9pYBLOeuxJ$61IjrNARDyLvmRE/9jdfbc5jrcJBtv4hlGeNJJ4KV/o=",
+        "password": "pbkdf2_sha256$390000$IPXLTmkcsCErqMmLpDQ1uG$5sNFF32ArLCA6dVY/jQ51sdtYomLFiyxsEtsLJz5QMo=",
         "last_login": null,
         "email": "user@user.fr",
         "display_name": "Test user",
@@ -1913,26 +1921,13 @@
 },
 {
     "model": "users.group",
-    "pk": "735c70c6-bb6f-405e-8126-c01efd6ad747",
+    "pk": "154b84fc-9b5e-4224-8198-369424a6044f",
     "fields": {
         "name": "User group",
         "public": false,
         "use_in_new_project": false
     }
 },
-{
-    "model": "users.oauthcredentials",
-    "pk": "217e2e72-f917-46de-9760-0e140bec08eb",
-    "fields": {
-        "user": 2,
-        "provider_url": "https://somewhere",
-        "status": "created",
-        "token": "oauth-token",
-        "refresh_token": "refresh-token",
-        "expiry": "2100-12-31T23:59:59.999Z",
-        "account_name": null
-    }
-},
 {
     "model": "auth.permission",
     "pk": 1,
@@ -3205,806 +3200,770 @@
 {
     "model": "auth.permission",
     "pk": 142,
-    "fields": {
-        "name": "Can add OAuth credentials",
-        "content_type": 37,
-        "codename": "add_oauthcredentials"
-    }
-},
-{
-    "model": "auth.permission",
-    "pk": 143,
-    "fields": {
-        "name": "Can change OAuth credentials",
-        "content_type": 37,
-        "codename": "change_oauthcredentials"
-    }
-},
-{
-    "model": "auth.permission",
-    "pk": 144,
-    "fields": {
-        "name": "Can delete OAuth credentials",
-        "content_type": 37,
-        "codename": "delete_oauthcredentials"
-    }
-},
-{
-    "model": "auth.permission",
-    "pk": 145,
-    "fields": {
-        "name": "Can view OAuth credentials",
-        "content_type": 37,
-        "codename": "view_oauthcredentials"
-    }
-},
-{
-    "model": "auth.permission",
-    "pk": 146,
     "fields": {
         "name": "Can add user scope",
-        "content_type": 38,
+        "content_type": 37,
         "codename": "add_userscope"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 147,
+    "pk": 143,
     "fields": {
         "name": "Can change user scope",
-        "content_type": 38,
+        "content_type": 37,
         "codename": "change_userscope"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 148,
+    "pk": 144,
     "fields": {
         "name": "Can delete user scope",
-        "content_type": 38,
+        "content_type": 37,
         "codename": "delete_userscope"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 149,
+    "pk": 145,
     "fields": {
         "name": "Can view user scope",
-        "content_type": 38,
+        "content_type": 37,
         "codename": "view_userscope"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 150,
+    "pk": 146,
     "fields": {
         "name": "Can add corpus worker version",
-        "content_type": 39,
+        "content_type": 38,
         "codename": "add_corpusworkerversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 151,
+    "pk": 147,
     "fields": {
         "name": "Can change corpus worker version",
-        "content_type": 39,
+        "content_type": 38,
         "codename": "change_corpusworkerversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 152,
+    "pk": 148,
     "fields": {
         "name": "Can delete corpus worker version",
-        "content_type": 39,
+        "content_type": 38,
         "codename": "delete_corpusworkerversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 153,
+    "pk": 149,
     "fields": {
         "name": "Can view corpus worker version",
-        "content_type": 39,
+        "content_type": 38,
         "codename": "view_corpusworkerversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 154,
+    "pk": 150,
     "fields": {
         "name": "Can add data file",
-        "content_type": 40,
+        "content_type": 39,
         "codename": "add_datafile"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 155,
+    "pk": 151,
     "fields": {
         "name": "Can change data file",
-        "content_type": 40,
+        "content_type": 39,
         "codename": "change_datafile"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 156,
+    "pk": 152,
     "fields": {
         "name": "Can delete data file",
-        "content_type": 40,
+        "content_type": 39,
         "codename": "delete_datafile"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 157,
+    "pk": 153,
     "fields": {
         "name": "Can view data file",
-        "content_type": 40,
+        "content_type": 39,
         "codename": "view_datafile"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 158,
+    "pk": 154,
     "fields": {
         "name": "Can add git ref",
-        "content_type": 41,
+        "content_type": 40,
         "codename": "add_gitref"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 159,
+    "pk": 155,
     "fields": {
         "name": "Can change git ref",
-        "content_type": 41,
+        "content_type": 40,
         "codename": "change_gitref"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 160,
+    "pk": 156,
     "fields": {
         "name": "Can delete git ref",
-        "content_type": 41,
+        "content_type": 40,
         "codename": "delete_gitref"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 161,
+    "pk": 157,
     "fields": {
         "name": "Can view git ref",
-        "content_type": 41,
+        "content_type": 40,
         "codename": "view_gitref"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 162,
+    "pk": 158,
     "fields": {
         "name": "Can add process",
-        "content_type": 42,
+        "content_type": 41,
         "codename": "add_process"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 163,
+    "pk": 159,
     "fields": {
         "name": "Can change process",
-        "content_type": 42,
+        "content_type": 41,
         "codename": "change_process"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 164,
+    "pk": 160,
     "fields": {
         "name": "Can delete process",
-        "content_type": 42,
+        "content_type": 41,
         "codename": "delete_process"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 165,
+    "pk": 161,
     "fields": {
         "name": "Can view process",
-        "content_type": 42,
+        "content_type": 41,
         "codename": "view_process"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 166,
+    "pk": 162,
     "fields": {
         "name": "Can add process element",
-        "content_type": 43,
+        "content_type": 42,
         "codename": "add_processelement"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 167,
+    "pk": 163,
     "fields": {
         "name": "Can change process element",
-        "content_type": 43,
+        "content_type": 42,
         "codename": "change_processelement"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 168,
+    "pk": 164,
     "fields": {
         "name": "Can delete process element",
-        "content_type": 43,
+        "content_type": 42,
         "codename": "delete_processelement"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 169,
+    "pk": 165,
     "fields": {
         "name": "Can view process element",
-        "content_type": 43,
+        "content_type": 42,
         "codename": "view_processelement"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 170,
+    "pk": 166,
     "fields": {
         "name": "Can add repository",
-        "content_type": 44,
+        "content_type": 43,
         "codename": "add_repository"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 171,
+    "pk": 167,
     "fields": {
         "name": "Can change repository",
-        "content_type": 44,
+        "content_type": 43,
         "codename": "change_repository"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 172,
+    "pk": 168,
     "fields": {
         "name": "Can delete repository",
-        "content_type": 44,
+        "content_type": 43,
         "codename": "delete_repository"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 173,
+    "pk": 169,
     "fields": {
         "name": "Can view repository",
-        "content_type": 44,
+        "content_type": 43,
         "codename": "view_repository"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 174,
+    "pk": 170,
     "fields": {
         "name": "Can add revision",
-        "content_type": 45,
+        "content_type": 44,
         "codename": "add_revision"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 175,
+    "pk": 171,
     "fields": {
         "name": "Can change revision",
-        "content_type": 45,
+        "content_type": 44,
         "codename": "change_revision"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 176,
+    "pk": 172,
     "fields": {
         "name": "Can delete revision",
-        "content_type": 45,
+        "content_type": 44,
         "codename": "delete_revision"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 177,
+    "pk": 173,
     "fields": {
         "name": "Can view revision",
-        "content_type": 45,
+        "content_type": 44,
         "codename": "view_revision"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 178,
+    "pk": 174,
     "fields": {
         "name": "Can add worker",
-        "content_type": 46,
+        "content_type": 45,
         "codename": "add_worker"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 179,
+    "pk": 175,
     "fields": {
         "name": "Can change worker",
-        "content_type": 46,
+        "content_type": 45,
         "codename": "change_worker"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 180,
+    "pk": 176,
     "fields": {
         "name": "Can delete worker",
-        "content_type": 46,
+        "content_type": 45,
         "codename": "delete_worker"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 181,
+    "pk": 177,
     "fields": {
         "name": "Can view worker",
-        "content_type": 46,
+        "content_type": 45,
         "codename": "view_worker"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 182,
+    "pk": 178,
     "fields": {
         "name": "Can add worker activity",
-        "content_type": 47,
+        "content_type": 46,
         "codename": "add_workeractivity"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 183,
+    "pk": 179,
     "fields": {
         "name": "Can change worker activity",
-        "content_type": 47,
+        "content_type": 46,
         "codename": "change_workeractivity"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 184,
+    "pk": 180,
     "fields": {
         "name": "Can delete worker activity",
-        "content_type": 47,
+        "content_type": 46,
         "codename": "delete_workeractivity"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 185,
+    "pk": 181,
     "fields": {
         "name": "Can view worker activity",
-        "content_type": 47,
+        "content_type": 46,
         "codename": "view_workeractivity"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 186,
+    "pk": 182,
     "fields": {
         "name": "Can add worker configuration",
-        "content_type": 48,
+        "content_type": 47,
         "codename": "add_workerconfiguration"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 187,
+    "pk": 183,
     "fields": {
         "name": "Can change worker configuration",
-        "content_type": 48,
+        "content_type": 47,
         "codename": "change_workerconfiguration"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 188,
+    "pk": 184,
     "fields": {
         "name": "Can delete worker configuration",
-        "content_type": 48,
+        "content_type": 47,
         "codename": "delete_workerconfiguration"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 189,
+    "pk": 185,
     "fields": {
         "name": "Can view worker configuration",
-        "content_type": 48,
+        "content_type": 47,
         "codename": "view_workerconfiguration"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 190,
+    "pk": 186,
     "fields": {
         "name": "Can add worker type",
-        "content_type": 49,
+        "content_type": 48,
         "codename": "add_workertype"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 191,
+    "pk": 187,
     "fields": {
         "name": "Can change worker type",
-        "content_type": 49,
+        "content_type": 48,
         "codename": "change_workertype"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 192,
+    "pk": 188,
     "fields": {
         "name": "Can delete worker type",
-        "content_type": 49,
+        "content_type": 48,
         "codename": "delete_workertype"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 193,
+    "pk": 189,
     "fields": {
         "name": "Can view worker type",
-        "content_type": 49,
+        "content_type": 48,
         "codename": "view_workertype"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 194,
+    "pk": 190,
     "fields": {
         "name": "Can add worker version",
-        "content_type": 50,
+        "content_type": 49,
         "codename": "add_workerversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 195,
+    "pk": 191,
     "fields": {
         "name": "Can change worker version",
-        "content_type": 50,
+        "content_type": 49,
         "codename": "change_workerversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 196,
+    "pk": 192,
     "fields": {
         "name": "Can delete worker version",
-        "content_type": 50,
+        "content_type": 49,
         "codename": "delete_workerversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 197,
+    "pk": 193,
     "fields": {
         "name": "Can view worker version",
-        "content_type": 50,
+        "content_type": 49,
         "codename": "view_workerversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 198,
+    "pk": 194,
     "fields": {
         "name": "Can add worker run",
-        "content_type": 51,
+        "content_type": 50,
         "codename": "add_workerrun"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 199,
+    "pk": 195,
     "fields": {
         "name": "Can change worker run",
-        "content_type": 51,
+        "content_type": 50,
         "codename": "change_workerrun"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 200,
+    "pk": 196,
     "fields": {
         "name": "Can delete worker run",
-        "content_type": 51,
+        "content_type": 50,
         "codename": "delete_workerrun"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 201,
+    "pk": 197,
     "fields": {
         "name": "Can view worker run",
-        "content_type": 51,
+        "content_type": 50,
         "codename": "view_workerrun"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 202,
+    "pk": 198,
     "fields": {
         "name": "Can add process dataset",
-        "content_type": 52,
+        "content_type": 51,
         "codename": "add_processdataset"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 203,
+    "pk": 199,
     "fields": {
         "name": "Can change process dataset",
-        "content_type": 52,
+        "content_type": 51,
         "codename": "change_processdataset"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 204,
+    "pk": 200,
     "fields": {
         "name": "Can delete process dataset",
-        "content_type": 52,
+        "content_type": 51,
         "codename": "delete_processdataset"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 205,
+    "pk": 201,
     "fields": {
         "name": "Can view process dataset",
-        "content_type": 52,
+        "content_type": 51,
         "codename": "view_processdataset"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 206,
+    "pk": 202,
     "fields": {
         "name": "Can add dataset",
-        "content_type": 53,
+        "content_type": 52,
         "codename": "add_dataset"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 207,
+    "pk": 203,
     "fields": {
         "name": "Can change dataset",
-        "content_type": 53,
+        "content_type": 52,
         "codename": "change_dataset"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 208,
+    "pk": 204,
     "fields": {
         "name": "Can delete dataset",
-        "content_type": 53,
+        "content_type": 52,
         "codename": "delete_dataset"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 209,
+    "pk": 205,
     "fields": {
         "name": "Can view dataset",
-        "content_type": 53,
+        "content_type": 52,
         "codename": "view_dataset"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 210,
+    "pk": 206,
     "fields": {
         "name": "Can add metric key",
-        "content_type": 54,
+        "content_type": 53,
         "codename": "add_metrickey"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 211,
+    "pk": 207,
     "fields": {
         "name": "Can change metric key",
-        "content_type": 54,
+        "content_type": 53,
         "codename": "change_metrickey"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 212,
+    "pk": 208,
     "fields": {
         "name": "Can delete metric key",
-        "content_type": 54,
+        "content_type": 53,
         "codename": "delete_metrickey"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 213,
+    "pk": 209,
     "fields": {
         "name": "Can view metric key",
-        "content_type": 54,
+        "content_type": 53,
         "codename": "view_metrickey"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 214,
+    "pk": 210,
     "fields": {
         "name": "Can add model",
-        "content_type": 55,
+        "content_type": 54,
         "codename": "add_model"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 215,
+    "pk": 211,
     "fields": {
         "name": "Can change model",
-        "content_type": 55,
+        "content_type": 54,
         "codename": "change_model"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 216,
+    "pk": 212,
     "fields": {
         "name": "Can delete model",
-        "content_type": 55,
+        "content_type": 54,
         "codename": "delete_model"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 217,
+    "pk": 213,
     "fields": {
         "name": "Can view model",
-        "content_type": 55,
+        "content_type": 54,
         "codename": "view_model"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 218,
+    "pk": 214,
     "fields": {
         "name": "Can add model version",
-        "content_type": 56,
+        "content_type": 55,
         "codename": "add_modelversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 219,
+    "pk": 215,
     "fields": {
         "name": "Can change model version",
-        "content_type": 56,
+        "content_type": 55,
         "codename": "change_modelversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 220,
+    "pk": 216,
     "fields": {
         "name": "Can delete model version",
-        "content_type": 56,
+        "content_type": 55,
         "codename": "delete_modelversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 221,
+    "pk": 217,
     "fields": {
         "name": "Can view model version",
-        "content_type": 56,
+        "content_type": 55,
         "codename": "view_modelversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 222,
+    "pk": 218,
     "fields": {
         "name": "Can add metric value",
-        "content_type": 57,
+        "content_type": 56,
         "codename": "add_metricvalue"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 223,
+    "pk": 219,
     "fields": {
         "name": "Can change metric value",
-        "content_type": 57,
+        "content_type": 56,
         "codename": "change_metricvalue"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 224,
+    "pk": 220,
     "fields": {
         "name": "Can delete metric value",
-        "content_type": 57,
+        "content_type": 56,
         "codename": "delete_metricvalue"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 225,
+    "pk": 221,
     "fields": {
         "name": "Can view metric value",
-        "content_type": 57,
+        "content_type": 56,
         "codename": "view_metricvalue"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 226,
+    "pk": 222,
     "fields": {
         "name": "Can add dataset element",
-        "content_type": 58,
+        "content_type": 57,
         "codename": "add_datasetelement"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 227,
+    "pk": 223,
     "fields": {
         "name": "Can change dataset element",
-        "content_type": 58,
+        "content_type": 57,
         "codename": "change_datasetelement"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 228,
+    "pk": 224,
     "fields": {
         "name": "Can delete dataset element",
-        "content_type": 58,
+        "content_type": 57,
         "codename": "delete_datasetelement"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 229,
+    "pk": 225,
     "fields": {
         "name": "Can view dataset element",
-        "content_type": 58,
+        "content_type": 57,
         "codename": "view_datasetelement"
     }
 },
 {
     "model": "ponos.farm",
-    "pk": "409b6859-63b9-41f2-8449-ba737bca6624",
+    "pk": "d4639943-3bc5-4839-ba11-bac03818050c",
     "fields": {
         "name": "Wheat farm",
-        "seed": "9092a1fa53b98ee55ab02cf1d5e5bdb4652f2d020163b520e6c8e9cee0b0d3b4"
+        "seed": "0307fda00557ae52d5b623279314c220e0e132ac58897269042764e154194bea"
     }
 },
 {
     "model": "ponos.task",
-    "pk": "ef80eff8-75a8-4fe6-8c7a-46300faaa342",
+    "pk": "67b4f068-55e2-4a60-b1be-5bba33971d4d",
     "fields": {
         "run": 0,
         "depth": 0,
@@ -4020,21 +3979,22 @@
         "agent": null,
         "requires_gpu": false,
         "gpu": null,
-        "process": "9a08ea15-07be-4746-a0d9-7acca68e5c1b",
+        "process": "6f170a31-9cf3-4fef-a684-ce8c8a4000d2",
+        "worker_run": null,
         "container": null,
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "expiry": "2100-12-31T23:59:59.999Z",
         "extra_files": "{}",
-        "token": "GoYSPBE0SraH8hiWN3QuGiDsG4Y+V0FVsNw3Q3h9J14=",
+        "token": "3lmDYOM7SpizY+afINTbz+34JrevUErTkEC21ubCc5w=",
         "parents": []
     }
 },
 {
     "model": "ponos.artifact",
-    "pk": "a93301c3-bdac-4d06-ba22-b7066decd282",
+    "pk": "27166636-75bd-4296-adce-ba8fa09a36c5",
     "fields": {
-        "task": "ef80eff8-75a8-4fe6-8c7a-46300faaa342",
+        "task": "67b4f068-55e2-4a60-b1be-5bba33971d4d",
         "path": "/path/to/docker_build",
         "size": 42000,
         "content_type": "application/octet-stream",
@@ -4044,30 +4004,30 @@
 },
 {
     "model": "training.dataset",
-    "pk": "b7b3b1fa-b62a-4513-b99d-d4675e42525c",
+    "pk": "2233f882-da17-4468-94c0-f7ea5e8c8f69",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
         "creator": 2,
         "task": null,
-        "name": "Second Dataset",
-        "description": "dataset number two",
+        "name": "First Dataset",
+        "description": "dataset number one",
         "state": "open",
         "sets": "[\"training\", \"test\", \"validation\"]"
     }
 },
 {
     "model": "training.dataset",
-    "pk": "bf46bc61-d37c-49ba-9368-899de7524287",
+    "pk": "e8c15036-e0ea-4cc4-a370-981b739d5b55",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "76968a0c-d43f-4ba1-8cd0-0f7a0dcdaa68",
+        "corpus": "b925d835-ac8c-4f85-9f17-e2ba27cd4efa",
         "creator": 2,
         "task": null,
-        "name": "First Dataset",
-        "description": "dataset number one",
+        "name": "Second Dataset",
+        "description": "dataset number two",
         "state": "open",
         "sets": "[\"training\", \"test\", \"validation\"]"
     }
diff --git a/arkindex/documents/management/commands/bootstrap.py b/arkindex/documents/management/commands/bootstrap.py
index 23dda2d5e2b8e70cd10a90720ff506411d4b290f..e6ba4f199a32b46f22001be21a6e219561672dff 100644
--- a/arkindex/documents/management/commands/bootstrap.py
+++ b/arkindex/documents/management/commands/bootstrap.py
@@ -158,9 +158,6 @@ class Command(BaseCommand):
         # Create a fake worker version on a fake worker on a fake repo with a fake revision for file imports
         repo, created = Repository.objects.get_or_create(
             url=IMPORT_WORKER_REPO,
-            defaults={
-                "hook_token": str(uuid4()),
-            }
         )
         if created:
             self.success(f'Created Git repository for {IMPORT_WORKER_REPO}')
diff --git a/arkindex/documents/management/commands/build_fixtures.py b/arkindex/documents/management/commands/build_fixtures.py
index e7775bea98f0aeb1e8e326bd7dcf7fb9e7771aa7..cdc5f1282d4ceac416032797842c0241376d2d42 100644
--- a/arkindex/documents/management/commands/build_fixtures.py
+++ b/arkindex/documents/management/commands/build_fixtures.py
@@ -13,6 +13,7 @@ from arkindex.process.models import (
     FeatureUsage,
     Process,
     ProcessMode,
+    Repository,
     Worker,
     WorkerRun,
     WorkerType,
@@ -69,19 +70,9 @@ class Command(BaseCommand):
             level=Role.Guest.value
         )
 
-        # Create OAuth credentials for a user
-        creds = user.credentials.create(
-            provider_url='https://somewhere',
-            token='oauth-token',
-            refresh_token='refresh-token',
-            # Use an expiry very far away to avoid OAuth token refreshes in every test
-            expiry=datetime(2100, 12, 31, 23, 59, 59, 999999, timezone.utc),
-        )
-
         # Create a GitLab worker repository
-        gitlab_repo = creds.repos.create(
+        gitlab_repo = Repository.objects.create(
             url='http://gitlab/repo',
-            hook_token='hook-token',
         )
 
         # Create a revision on this repository
@@ -92,9 +83,8 @@ class Command(BaseCommand):
         )
 
         # Create another worker repository
-        worker_repo = creds.repos.create(
+        worker_repo = Repository.objects.create(
             url="http://my_repo.fake/workers/worker",
-            hook_token='worker-hook-token',
         )
 
         # Create a revision on this repository
diff --git a/arkindex/documents/management/commands/load_export.py b/arkindex/documents/management/commands/load_export.py
index 97e9d23fd6352ccf660b2990b5406e87b47b7696..fe47c5343a4760146c2792d909fa6bd63625283c 100644
--- a/arkindex/documents/management/commands/load_export.py
+++ b/arkindex/documents/management/commands/load_export.py
@@ -2,7 +2,6 @@
 import json
 import os
 import sqlite3
-import uuid
 from datetime import datetime, timezone
 from pathlib import Path
 
@@ -410,9 +409,6 @@ class Command(BaseCommand):
     def create_repository(self, row):
         repo, created = Repository.objects.get_or_create(
             url=row['repository_url'],
-            defaults={
-                'hook_token': str(uuid.uuid4()),
-            },
         )
         return repo, created
 
diff --git a/arkindex/documents/tests/commands/test_load_export.py b/arkindex/documents/tests/commands/test_load_export.py
index 160399ae9b41b6dae3ab56cc7d1e7a011c2167e4..06512fc5e123b2d38d860ea6c2ca90ddc45995fd 100644
--- a/arkindex/documents/tests/commands/test_load_export.py
+++ b/arkindex/documents/tests/commands/test_load_export.py
@@ -33,7 +33,7 @@ class TestLoadExport(FixtureTestCase):
         unexpected_fields_by_model = {
             'documents.elementtype': ['display_name', 'indexable'],
             'documents.mlclass': [],
-            'process.repository': ['hook_token', 'credentials', 'git_ref_revisions'],
+            'process.repository': ['git_ref_revisions'],
             'process.worker': [],
             'process.revision': ['message', 'author'],
             'process.workerversion': ['created', 'updated', 'configuration', 'state', 'docker_image', 'docker_image_iid'],
diff --git a/arkindex/documents/tests/tasks/test_corpus_delete.py b/arkindex/documents/tests/tasks/test_corpus_delete.py
index 3f112f1005fe3cfb3f8b42e39cb5322a894572a7..0b86d73b6c8913b5c8e467eb157267b87c0a42df 100644
--- a/arkindex/documents/tests/tasks/test_corpus_delete.py
+++ b/arkindex/documents/tests/tasks/test_corpus_delete.py
@@ -96,7 +96,6 @@ class TestDeleteCorpus(FixtureTestCase):
         # Create a separate corpus that should not get anything deleted
         cls.repo = Repository.objects.create(
             url='http://lol.git',
-            hook_token='h00k',
         )
         cls.corpus2 = Corpus.objects.create(name='Other corpus')
 
diff --git a/arkindex/process/admin.py b/arkindex/process/admin.py
index 22c24c2746671a60ae8583e72aa5ddd8e49a15f2..d3e44085cae805af3613a8b685fa7198ec7c4e01 100644
--- a/arkindex/process/admin.py
+++ b/arkindex/process/admin.py
@@ -76,7 +76,7 @@ class WorkerInline(admin.StackedInline):
 
 class RepositoryAdmin(admin.ModelAdmin):
     list_display = ('id', 'url')
-    fields = ('id', 'url', 'hook_token', 'credentials')
+    fields = ('id', 'url')
     readonly_fields = ('id', )
     inlines = [WorkerInline, UserMembershipInline, GroupMembershipInline]
 
diff --git a/arkindex/process/api.py b/arkindex/process/api.py
index 3de0ba3b3a5cfcee32c1554ab89dbbadd4803a91..2f9f3ed381717fd885cddadef4afdc0cc212fae8 100644
--- a/arkindex/process/api.py
+++ b/arkindex/process/api.py
@@ -5,7 +5,6 @@ from textwrap import dedent
 from uuid import UUID
 
 from django.conf import settings
-from django.core.mail import send_mail
 from django.db import transaction
 from django.db.models import (
     Avg,
@@ -24,7 +23,6 @@ from django.db.models import (
 from django.db.models.functions import Coalesce, Now
 from django.db.models.query import Prefetch
 from django.shortcuts import get_object_or_404
-from django.template.loader import render_to_string
 from django.utils.functional import cached_property
 from drf_spectacular.utils import (
     OpenApiExample,
@@ -51,7 +49,6 @@ from rest_framework.generics import (
 )
 from rest_framework.response import Response
 from rest_framework.serializers import Serializer
-from rest_framework.views import APIView
 
 from arkindex.documents.models import Corpus, Element, Selection
 from arkindex.ponos.authentication import TaskAuthentication
@@ -65,7 +62,6 @@ from arkindex.process.models import (
     Process,
     ProcessDataset,
     ProcessMode,
-    Repository,
     Revision,
     Worker,
     WorkerActivity,
@@ -75,9 +71,8 @@ from arkindex.process.models import (
     WorkerType,
     WorkerVersion,
 )
-from arkindex.process.providers import GitProvider
 from arkindex.process.serializers.files import DataFileCreateSerializer, DataFileSerializer
-from arkindex.process.serializers.git import ExternalRepositorySerializer, RevisionSerializer
+from arkindex.process.serializers.git import RevisionSerializer
 from arkindex.process.serializers.imports import (
     ApplyProcessTemplateSerializer,
     CorpusProcessSerializer,
@@ -131,7 +126,7 @@ from arkindex.project.tools import PercentileCont
 from arkindex.project.triggers import process_delete
 from arkindex.training.models import Dataset, Model
 from arkindex.training.serializers import DatasetSerializer
-from arkindex.users.models import OAuthCredentials, Role, Scope
+from arkindex.users.models import Role, Scope
 
 logger = logging.getLogger(__name__)
 
@@ -448,8 +443,6 @@ class ProcessRetry(ProcessACLMixin, ProcessQuerysetMixin, GenericAPIView):
         if process.mode == ProcessMode.Repository:
             if not process.revision:
                 raise ValidationError({'__all__': ['Git repository imports must have a revision set']})
-            if not process.revision.repo.enabled:
-                raise ValidationError({'__all__': ['Git repository does not have any valid credentials']})
 
     @extend_schema(
         operation_id='RetryProcess',
@@ -773,45 +766,6 @@ class ProcessDatasetManage(CreateAPIView, DestroyAPIView):
         return Response(status=status.HTTP_204_NO_CONTENT)
 
 
-@extend_schema(exclude=True)
-class GitRepositoryImportHook(APIView):
-    """
-    This endpoint is intended as a webhook for Git repository hosting applications like GitLab.
-    """
-
-    def post(self, request, pk=None, **kwargs):
-        repo = get_object_or_404(Repository, id=pk)
-        if not repo.enabled:
-            raise PermissionDenied(detail='No credentials available for this repository.')
-
-        try:
-            repo.provider_class(credentials=repo.credentials).handle_webhook(repo, request)
-        except Exception as e:
-            user = repo.credentials.user
-            # Notifying the user by mail that there was an error during webhook handling
-            sent = send_mail(
-                subject='An error occurred during Git hook handling',
-                message=render_to_string(
-                    'webhook_error.html',
-                    context={
-                        'user': user,
-                        'url': repo.url,
-                        'error': e.args[0],
-                    },
-                    request=request,
-                ),
-                from_email=None,
-                recipient_list=[user.email],
-                fail_silently=True,
-            )
-            if sent == 0:
-                logger.error(f'Failed to send webhook error email to {user.email}')
-
-            raise
-
-        return Response(status=status.HTTP_204_NO_CONTENT)
-
-
 @extend_schema_view(
     get=extend_schema(
         tags=['repos'],
@@ -829,75 +783,10 @@ class RepositoryList(RepositoryACLMixin, ListAPIView):
     def get_queryset(self):
         return self.readable_repositories \
             .annotate(authorized_users=Count('memberships')) \
-            .select_related('credentials') \
             .prefetch_related('workers__type') \
             .order_by('url')
 
 
-@extend_schema_view(
-    get=extend_schema(
-        operation_id='ListExternalRepositories',
-        parameters=[
-            OpenApiParameter(
-                'search',
-                description='Optional query terms to filter repositories',
-            )
-        ],
-        tags=['repos'],
-    ),
-    post=extend_schema(
-        operation_id='CreateExternalRepository',
-        description='Using the given OAuth credentials, this links an external Git repository '
-                    'to Arkindex, connects a push hook and starts an initial process.',
-        responses={201: ProcessSerializer},
-        tags=['repos'],
-    )
-)
-class AvailableRepositoriesList(ListCreateAPIView):
-    """
-    List repositories associated to user OAuth credentials
-
-    Using the given OAuth credentials ID, this uses the Git hosting
-    application API's search feature to look for a repository matching
-    the given query. Without a query, returns a full list.
-    """
-    permission_classes = (IsVerified, )
-    pagination_class = None
-    serializer_class = ExternalRepositorySerializer
-    queryset = OAuthCredentials.objects.none()
-
-    def get_queryset(self):
-        cred = get_object_or_404(OAuthCredentials, user=self.request.user, id=self.kwargs['pk'])
-        provider = cred.git_provider_class(credentials=cred)
-        repos = provider.list_repos(query=self.request.query_params.get('search'))
-        return map(provider.to_dict, repos)
-
-    @transaction.atomic
-    def create(self, request, *args, **kwargs):
-        serializer = self.get_serializer(data=request.data)
-        serializer.is_valid(raise_exception=True)
-        user = self.request.user
-        cred = get_object_or_404(OAuthCredentials, user=user, id=self.kwargs['pk'])
-        provider = cred.git_provider_class(credentials=cred)
-        repo = provider.create_repo(
-            request=self.request,
-            id=serializer.validated_data.get('id')
-        )
-        # Add an admin membership to the repository creator
-        repo.memberships.create(user=user, level=Role.Admin.value)
-
-        latest_commit_sha = provider.get_latest_commit_sha(repo)
-        rev, _ = provider.get_or_create_revision(repo, latest_commit_sha)
-
-        process = GitProvider.start_imports(provider, rev)
-
-        # Return the serialized process
-        return Response(
-            status=status.HTTP_201_CREATED,
-            data=ProcessSerializer(process, context={'request': self.request}).data,
-        )
-
-
 @extend_schema(
     tags=['repos'],
     description='Retrieve a repository',
diff --git a/arkindex/process/builder.py b/arkindex/process/builder.py
index 8469402e2de3766e1072980f8cdcc23428557bba..018703366c171302a1ba00b98e094faf93c76f40 100644
--- a/arkindex/process/builder.py
+++ b/arkindex/process/builder.py
@@ -187,8 +187,6 @@ class ProcessBuilder(object):
     def validate_repository(self) -> None:
         if self.process.revision is None:
             raise ValidationError('A revision is required to create an import workflow from GitLab repository')
-        if not self.process.revision.repo.enabled:
-            raise ValidationError('Git repository does not have any valid credentials')
 
     def validate_s3(self) -> None:
         if not self.process.bucket_name:
diff --git a/arkindex/process/management/commands/update_repositories_hooks.py b/arkindex/process/management/commands/update_repositories_hooks.py
deleted file mode 100644
index cd3b07efbe0dcabdd22a1fb57284027a06c9c2e2..0000000000000000000000000000000000000000
--- a/arkindex/process/management/commands/update_repositories_hooks.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from django.core.management.base import BaseCommand
-
-from arkindex.process.models import Repository
-
-
-class Command(BaseCommand):
-    help = "Update all Git repositories hooks"
-
-    def add_arguments(self, parser):
-        parser.add_argument(
-            "base_url",
-            type=str,
-            help="Base url used to build the new hooks",
-        )
-
-    def handle(self, base_url, *args, **kwargs):
-        for repository in Repository.objects.filter(credentials__isnull=False):
-            self.stdout.write(f"Updating {repository}")
-            repository.provider.create_hook(repository, base_url=base_url)
-
-        self.stdout.write(self.style.SUCCESS("All done"))
diff --git a/arkindex/process/management/commands/update_repositories_refs.py b/arkindex/process/management/commands/update_repositories_refs.py
deleted file mode 100644
index 9f175c812eb6af9461fceed3589c0ba8f335eaa9..0000000000000000000000000000000000000000
--- a/arkindex/process/management/commands/update_repositories_refs.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from django.core.management.base import BaseCommand
-
-from arkindex.process.models import Repository
-
-
-class Command(BaseCommand):
-    help = "Update all Git repositories references and trigger build processes"
-
-    def add_arguments(self, parser):
-        parser.add_argument(
-            "--repo-url",
-            type=str,
-            help="Limit process to one repository",
-        )
-
-    def handle(self, repo_url, *args, **kwargs):
-
-        repositories = Repository.objects.all()
-        if repo_url:
-            repositories = repositories.filter(url=repo_url)
-
-        for repository in repositories:
-
-            self.stdout.write(f"Updating refs for {repository}")
-
-            # List all refs
-            try:
-                repository.provider.update_repository_references(repository)
-            except Exception as e:
-                self.stderr.write(f"Failure for {repository}: {e}")
-
-        self.stdout.write("All done")
diff --git a/arkindex/process/migrations/0026_remove_repository_unique_repository_hook_token_and_more.py b/arkindex/process/migrations/0026_remove_repository_unique_repository_hook_token_and_more.py
new file mode 100644
index 0000000000000000000000000000000000000000..78d38d5ff6a2e188d72ad300c02205ff9f8ae152
--- /dev/null
+++ b/arkindex/process/migrations/0026_remove_repository_unique_repository_hook_token_and_more.py
@@ -0,0 +1,29 @@
+# Generated by Django 4.1.7 on 2023-12-20 11:43
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('process', '0025_worker_archived'),
+    ]
+
+    operations = [
+        migrations.RunSQL(
+            "ALTER TABLE process_repository DROP CONSTRAINT unique_repository_hook_token",
+            elidable=True,
+        ),
+        migrations.RemoveConstraint(
+            model_name='repository',
+            name='unique_repository_hook_token',
+        ),
+        migrations.RemoveField(
+            model_name='repository',
+            name='credentials',
+        ),
+        migrations.RemoveField(
+            model_name='repository',
+            name='hook_token',
+        ),
+    ]
diff --git a/arkindex/process/models.py b/arkindex/process/models.py
index 28daa7f3abd5d15236abaa416ae6ff325db1767e..2280bda9a4e5e635ece0ff1518e0b17321394df0 100644
--- a/arkindex/process/models.py
+++ b/arkindex/process/models.py
@@ -23,7 +23,6 @@ from arkindex.process.managers import (
     WorkerRunManager,
     WorkerVersionManager,
 )
-from arkindex.process.providers import get_provider
 from arkindex.project.aws import S3FileMixin, S3FileStatus
 from arkindex.project.fields import ArrayField, MD5HashField
 from arkindex.project.models import IndexableModel
@@ -549,9 +548,6 @@ class DataFile(S3FileMixin, models.Model):
 class Repository(models.Model):
     id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
     url = models.URLField()
-    hook_token = models.CharField(max_length=250)
-    credentials = models.ForeignKey(
-        'users.OAuthCredentials', on_delete=models.SET_NULL, related_name='repos', blank=True, null=True)
     git_ref_revisions = models.ManyToManyField('process.Revision', through='process.GitRef')
     memberships = GenericRelation('users.Right', 'content_id')
 
@@ -561,32 +557,9 @@ class Repository(models.Model):
             models.UniqueConstraint(
                 'url',
                 name='unique_repository_url',
-            ),
-            models.UniqueConstraint(
-                'hook_token',
-                name='unique_repository_hook_token',
-            ),
+            )
         ]
 
-    # Make this constant into a database field to be able to handle repositories from services other than GitLab
-    provider_name = 'GitLabProvider'
-
-    @property
-    def provider_class(self):
-        if not self.provider_name:
-            raise ValueError("Empty provider_name")
-        return get_provider(self.provider_name)
-
-    @property
-    def provider(self):
-        if self.provider_class is None:
-            raise NotImplementedError(f"Missing provider {self.provider_name}")
-        return self.provider_class(credentials=self.credentials)
-
-    @property
-    def enabled(self):
-        return self.credentials is not None and self.provider_class is not None
-
     def __str__(self):
         return f'{self.url}'
 
diff --git a/arkindex/process/providers.py b/arkindex/process/providers.py
deleted file mode 100644
index 0d51f8539814c6fc5ff3400cd9b055a469873624..0000000000000000000000000000000000000000
--- a/arkindex/process/providers.py
+++ /dev/null
@@ -1,391 +0,0 @@
-import base64
-import logging
-import urllib.parse
-import uuid
-from abc import ABC, abstractmethod
-
-from django.conf import settings
-from django.urls import reverse
-from gitlab import Gitlab, GitlabCreateError, GitlabGetError
-from rest_framework.exceptions import APIException, AuthenticationFailed, NotAuthenticated, ValidationError
-
-from arkindex.process.utils import get_default_farm
-
-logger = logging.getLogger(__name__)
-
-
-class GitProvider(ABC):
-
-    display_name = None
-
-    def __init__(self, credentials=None):
-        if credentials:
-            from arkindex.users.models import OAuthCredentials
-            assert isinstance(credentials, OAuthCredentials)
-        self.credentials = credentials
-
-    @abstractmethod
-    def list_repos(self, query=None):
-        """
-        List all repositories or filter with a search query.
-        """
-
-    @abstractmethod
-    def get_latest_commit_sha(self, repo):
-        """
-        Retrieve latest commit sha from the default branch on a given repository.
-        """
-
-    @abstractmethod
-    def create_repo(self, **kwargs):
-        """
-        Create a Repository instance from an external repository
-        """
-
-    @abstractmethod
-    def create_hook(self, repository, project_id=None, base_url=None):
-        """Create a webhook to receive events from the project"""
-
-    def update_or_create_ref(self, repo, revision, name, type):
-        """
-        Update or create a GitRef on a given repository:
-        - If a GitRef with given name already exists on the given repository, we only update the
-        linked revision with the given one
-        - Else a GitRef is created on the given repository thanks to given name, type and revision
-        """
-        from arkindex.process.models import GitRef
-        try:
-            ref = repo.refs.get(name=name)
-            ref.revision = revision
-            ref.save()
-        except GitRef.DoesNotExist:
-            # Limit the name length to the max size of GitRef name field
-            repo.refs.create(name=name[:250], type=type, revision=revision)
-
-    def get_or_create_revision(self, repo, sha, save=True):
-        from arkindex.process.models import Revision
-        try:
-            return self.get_revision(repo, sha), False
-        except Revision.DoesNotExist:
-            return self.create_revision(repo, sha, save=save), True
-
-    def get_revision(self, repo, sha):
-        return repo.revisions.get(hash=sha)
-
-    @abstractmethod
-    def create_revision(self, repo, sha, save=True):
-        """
-        Create a Revision instance for a given commit hash of a given repository.
-        """
-
-    @abstractmethod
-    def handle_webhook(self, repo, request):
-        """
-        Handle a webhook event on a given repository.
-        """
-
-    @abstractmethod
-    def to_dict(self, project):
-        """
-        Returns a dict specifying id, name and url from a repository
-        """
-
-    def start_imports(self, rev):
-        """
-        Create and start a process to build new worker(s) from a repository revision
-        """
-        from arkindex.process.models import ProcessMode
-        mode = ProcessMode.Repository
-        user = rev.repo.credentials.user
-        refs = ", ".join(rev.refs.values_list('name', flat=True))
-        if not refs:
-            refs = rev.hash
-        # Limit the name length to the max size of Process name field
-        name = f"Import {refs} from {rev.repo.url}"[:100]
-
-        farm = get_default_farm()
-        if not farm.is_available(user):
-            raise ValidationError("The owner of the OAuth credentials does not have access to the default farm.")
-
-        process = rev.processes.create(
-            creator=user,
-            mode=mode,
-            name=name,
-            farm=farm,
-        )
-        process.run()
-        return process
-
-
-class GitLabProvider(GitProvider):
-
-    display_name = "GitLab"
-
-    def _get_gitlab_client(self, credentials):
-        if credentials.expired:
-            credentials.provider.refresh_token()
-
-        return Gitlab(credentials.provider_url, oauth_token=credentials.token)
-
-    def _try_get_project(self, gl, id):
-        try:
-            return gl.projects.get(id)
-        except GitlabGetError as e:
-            raise APIException("Error while fetching GitLab project: {}".format(str(e)))
-
-    def _get_project_from_repo(self, repo):
-        assert repo.credentials, "Missing Gitlab credentials"
-
-        gl = self._get_gitlab_client(repo.credentials)
-        return self._try_get_project(gl, urllib.parse.urlsplit(repo.url).path.strip('/'))
-
-    def list_repos(self, query=None):
-        if not self.credentials:
-            raise NotAuthenticated
-        gl = self._get_gitlab_client(self.credentials)
-        # Creating a webhook on a repo requires Maintainer (40) or Owner (50) access levels
-        # See https://docs.gitlab.com/ce/api/members.html#valid-access-levels
-        return gl.projects.list(min_access_level=40, search=query, get_all=False)
-
-    def get_latest_commit_sha(self, repo):
-        project = self._get_project_from_repo(repo)
-        # Since ref_name isn't specified, we will use the repository default branch
-        # See : https://docs.gitlab.com/ee/api/commits.html#list-repository-commits
-        return project.commits.list(per_page=1, get_all=False)[0].id
-
-    def to_dict(self, project):
-        return {
-            'id': project.id,
-            'name': project.name_with_namespace,
-            'url': project.web_url
-        }
-
-    def create_repo(self, id=None, **kwargs):
-        if not self.credentials:
-            raise NotAuthenticated()
-
-        gl = self._get_gitlab_client(self.credentials)
-        project = self._try_get_project(gl, int(id))
-
-        from arkindex.process.models import Repository
-        if Repository.objects.filter(url=project.web_url).exists():
-            raise ValidationError("A repository with this URL already exists")
-
-        # Determine the user's access level on this project
-        # When it is inherited from the group and not overridden in the project, project_access is not defined.
-        # When the project isn't in a group, or the user is added to a specific project in a group,
-        # group_access is not defined. project_access overrides group_access.
-        access_level = 0
-        if project.permissions.get('group_access'):
-            access_level = project.permissions['group_access']['access_level']
-        if project.permissions.get('project_access'):
-            access_level = project.permissions['project_access']['access_level']
-
-        # Maintainer level (40) is required
-        if access_level < 40:
-            raise ValidationError("Maintainer or Owner access is required to add a GitLab repository")
-
-        repo = self.credentials.repos.create(
-            url=project.web_url,
-            hook_token=base64.b64encode(uuid.uuid4().bytes).decode('utf-8'),
-        )
-
-        self.create_hook(repo, project_id=int(id))
-
-        return repo
-
-    def create_hook(self, repository, project_id=None, base_url=None):
-        """
-        Configure the Gitlab hook to get events for a project.
-
-        If `project_id` is set, then the project is retrieved directly from its GitLab project ID
-        instead of matched using its path.
-
-        The webhook's URL will use `base_url` as its base URL if it is set, and otherwise
-        falls back on settings.BACKEND_PUBLIC_URL_OAUTH first, then settings.PUBLIC_HOSTNAME.
-        """
-        # Load project using a project ID or its repo path
-        gitlab = Gitlab(repository.credentials.provider_url, oauth_token=repository.credentials.token)
-        if project_id:
-            project = self._try_get_project(gitlab, project_id)
-        else:
-            path = urllib.parse.urlparse(repository.url).path[1:]
-            project = self._try_get_project(gitlab, path)
-
-        if base_url is None:
-            base_url = settings.BACKEND_PUBLIC_URL_OAUTH or settings.PUBLIC_HOSTNAME
-
-        if base_url is None:
-            raise APIException('Either the `base_url` argument, settings.BACKEND_PUBLIC_URL_OAUTH or settings.PUBLIC_HOSTNAME must be set.')
-
-        url = urllib.parse.urljoin(base_url, reverse('api:import-hook', kwargs={'pk': repository.id}))
-        logger.info(f"Webhook will be created as {url}")
-
-        # Delete already configured hooks to be able to update
-        for hook in project.hooks.list(all=True):
-            if hook.url == url:
-                hook.delete()
-                logger.info(f"Deleted existing hook {hook.id}")
-
-        try:
-            # Create a new hook
-            hook = project.hooks.create({
-                'url': url,
-                'push_events': True,
-                "tag_push_events": True,
-                'token': repository.hook_token,
-            })
-            logger.info(f"Created new hook {hook.id}")
-        except GitlabCreateError as e:
-            raise APIException("Error while creating GitLab hook: {}".format(str(e)))
-
-    def create_revision(self, repo, sha, save=True):
-        from arkindex.process.models import GitRefType, Revision
-
-        project = self._get_project_from_repo(repo)
-        commit = project.commits.get(sha)
-
-        rev = Revision(
-            repo=repo,
-            hash=sha,
-            message=commit.message,
-            author=commit.author_name,
-        )
-        if save:
-            rev.save()
-            for ref in commit.refs():
-                try:
-                    ref_type = GitRefType(ref['type'])
-                    self.update_or_create_ref(repo, rev, ref['name'], ref_type)
-                except ValueError:
-                    logger.warning(f'Git reference with type {ref["type"]} was ignored during revision creation')
-                    continue
-
-        return rev
-
-    def update_revision_references(self, repo, sha):
-        """
-        Update all references for a specific revision
-        This is needed when a tag is pushed after its commit
-        is already ingested
-        """
-        from arkindex.process.models import GitRefType
-
-        project = self._get_project_from_repo(repo)
-        commit = project.commits.get(sha)
-
-        rev = repo.revisions.get(hash=sha)
-        for ref in commit.refs():
-            try:
-                ref_type = GitRefType(ref['type'])
-                self.update_or_create_ref(repo, rev, ref['name'], ref_type)
-            except ValueError:
-                logger.warning(f'Git reference with type {ref["type"]} was ignored during revision creation')
-                continue
-
-    def update_repository_references(self, repo):
-        """
-        List all available references (branches and tags) on a remote repository
-        and create new references or update existing ones
-        New import process are started for new references
-        """
-        from arkindex.process.models import GitRefType
-        project = self._get_project_from_repo(repo)
-
-        def _update_reference(ref, ref_type):
-            assert isinstance(ref_type, GitRefType)
-            try:
-                rev, created = repo.revisions.get_or_create(
-                    hash=ref.commit['id'],
-                    defaults={
-                        'message': ref.commit['message'],
-                        'author': ref.commit['author_email'],
-                    }
-                )
-                self.update_or_create_ref(repo, rev, ref.name, ref_type)
-                if created:
-                    logger.info(f"Starting import for {ref_type.value} {ref.name}")
-                    self.start_imports(rev)
-            except ValueError:
-                logger.warning(f'{ref_type.value} {ref.name} was ignored during revision creation')
-
-        for branch in project.branches.list(get_all=True):
-            _update_reference(branch, GitRefType.Branch)
-
-        for tag in project.tags.list(get_all=True):
-            _update_reference(tag, GitRefType.Tag)
-
-    def handle_webhook(self, repo, request):
-        from arkindex.process.models import GitRefType
-
-        if 'HTTP_X_GITLAB_EVENT' not in request.META:
-            raise ValidationError("Missing GitLab event type")
-
-        if request.META['HTTP_X_GITLAB_EVENT'] not in ('Push Hook', 'Tag Push Hook'):
-            raise ValidationError("Unsupported GitLab event type")
-
-        if 'HTTP_X_GITLAB_TOKEN' not in request.META:
-            raise NotAuthenticated("Missing GitLab secret token")
-        if request.META['HTTP_X_GITLAB_TOKEN'] != repo.hook_token:
-            raise AuthenticationFailed("Invalid GitLab secret token")
-
-        if not isinstance(request.data, dict) or 'object_kind' not in request.data:
-            raise ValidationError('Bad payload format')
-
-        kind = request.data.get('object_kind')
-        if kind not in ('push', 'tag_push'):
-            raise ValidationError("Unsupported GitLab event type")
-
-        sha = request.data.get('checkout_sha')
-        if kind == 'tag_push':
-            if sha:
-                # When a commit SHA is present, we need to add a reference on an existing commit
-                self.update_revision_references(repo, sha)
-
-            else:
-                # If there isn't any SHA it means that a tag was deleted
-                ref = request.data.get('ref')
-                if not ref:
-                    raise ValidationError('Missing tag reference')
-
-                # Delete existing tag
-                tag_name = ref[10:] if ref.startswith('refs/tags/') else ref
-                repo.refs.filter(name=tag_name, type=GitRefType.Tag).delete()
-
-            return
-
-        if not sha:
-            # If there isn't any SHA it means that a branch was deleted
-            ref = request.data.get('ref')
-            if not ref:
-                raise ValidationError('Missing branch reference')
-
-            # Delete existing branch
-            branch_name = ref[11:] if ref.startswith('refs/heads/') else ref
-            repo.refs.filter(name=branch_name, type=GitRefType.Branch).delete()
-
-            return
-
-        # Already took care of this event
-        if repo.revisions.filter(hash=sha).exists():
-            return
-
-        rev = self.create_revision(repo, sha)
-
-        self.start_imports(rev)
-
-
-git_providers = [
-    GitLabProvider,
-]
-oauth_to_git = {
-    "gitlab": GitLabProvider,
-}
-
-
-def get_provider(name):
-    return next(filter(lambda p: p.__name__ == name, git_providers), None)
-
-
-def from_oauth(name):
-    return oauth_to_git.get(name)
diff --git a/arkindex/process/serializers/git.py b/arkindex/process/serializers/git.py
index 30dde44255665a2403410f992af211991267c001..eb2027c6cbc5695566f75b2375e9bc6be6b823a6 100644
--- a/arkindex/process/serializers/git.py
+++ b/arkindex/process/serializers/git.py
@@ -58,12 +58,3 @@ class RevisionWithRefsSerializer(serializers.ModelSerializer):
             'commit_url',
             'refs',
         )
-
-
-class ExternalRepositorySerializer(serializers.Serializer):
-    """
-    Serialize a Git repository from an external API
-    """
-    id = serializers.IntegerField(min_value=0)
-    name = serializers.CharField(read_only=True)
-    url = serializers.URLField(read_only=True)
diff --git a/arkindex/process/serializers/workers.py b/arkindex/process/serializers/workers.py
index 7c91b90adc3f3cd08a3abc2781279e887e44e429..47e994e1c18cdf0e4e4eba85121e7ba267aa658a 100644
--- a/arkindex/process/serializers/workers.py
+++ b/arkindex/process/serializers/workers.py
@@ -1,6 +1,3 @@
-import base64
-import urllib
-import uuid
 from collections import defaultdict
 from enum import Enum
 from textwrap import dedent
@@ -8,7 +5,6 @@ from textwrap import dedent
 from django.core.exceptions import ValidationError as DjangoValidationError
 from django.db import transaction
 from django.db.models import Max, Q
-from drf_spectacular.utils import extend_schema_field
 from rest_framework import serializers
 from rest_framework.exceptions import NotFound, PermissionDenied, ValidationError
 
@@ -390,29 +386,9 @@ class RepositorySerializer(serializers.ModelSerializer):
     """
     Serialize a repository
     """
-    enabled = serializers.BooleanField(read_only=True)
-    git_clone_url = serializers.SerializerMethodField()
     workers = WorkerLightSerializer(many=True, read_only=True)
     authorized_users = serializers.SerializerMethodField(read_only=True)
 
-    @extend_schema_field(serializers.CharField(allow_null=True))
-    def get_git_clone_url(self, repository):
-        # This check avoid to set git_clone_url when this serializer is used to list multiple
-        # repositories because self.instance value would be a list, even with Ponos task authentication.
-        # We also restrict to enabled repositories as disabled repos do not have OAuth credentials,
-        # and restrict to the repository set on the task's process, as it should only clone that one.
-        process = get_process_from_task_auth(self.context['request'])
-        if (
-            process
-            and isinstance(self.instance, Repository)
-            and self.instance.enabled
-            and process.revision_id is not None
-            and process.revision.repo_id == self.instance.id
-        ):
-            url = urllib.parse.urlparse(self.instance.url)
-            return f"https://oauth2:{repository.credentials.token}@{url.netloc}{url.path}"
-        return None
-
     def get_authorized_users(self, repo) -> int:
         count = getattr(repo, 'authorized_users', None)
         if count is None:
@@ -424,8 +400,6 @@ class RepositorySerializer(serializers.ModelSerializer):
         fields = (
             'id',
             'url',
-            'enabled',
-            'git_clone_url',
             'workers',
             'authorized_users',
         )
@@ -686,11 +660,7 @@ class DockerWorkerVersionSerializer(serializers.ModelSerializer):
         """
         # Retrieve or create the Git repository
         repository, created_repo = Repository.objects.using('default').get_or_create(
-            url=validated_data['repository_url'],
-            defaults={
-                # Generate a default hook token (DB constraint) even if no webhook is created
-                'hook_token': base64.b64encode(uuid.uuid4().bytes).decode('utf-8')
-            },
+            url=validated_data['repository_url']
         )
         # Grant an admin access to the repository in case it got created
         if created_repo:
diff --git a/arkindex/process/tests/test_create_process.py b/arkindex/process/tests/test_create_process.py
index d3fc48d8f8c14fda33c1206ca1ee046fa2901f38..92de6c29d908c184922ad98e6b7030c808146402 100644
--- a/arkindex/process/tests/test_create_process.py
+++ b/arkindex/process/tests/test_create_process.py
@@ -12,6 +12,7 @@ from arkindex.process.models import (
     ActivityState,
     Process,
     ProcessMode,
+    Repository,
     WorkerActivity,
     WorkerVersion,
     WorkerVersionState,
@@ -41,8 +42,7 @@ class TestCreateProcess(FixtureAPITestCase):
         cls.private_ml_class = cls.private_corpus.ml_classes.create(name='chouquette')
 
         # Workers ProcessMode
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get(url='http://my_repo.fake/workers/worker')
+        cls.repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
         cls.rev_1 = cls.repo.revisions.get()
         cls.rev_2 = cls.repo.revisions.create(
             hash='2',
diff --git a/arkindex/process/tests/test_docker_worker_version.py b/arkindex/process/tests/test_docker_worker_version.py
index 2b7f92a0557d6f98319c9b50c89f127675bc5d71..2576b7b8d1bca0481aeeb954f267c33fd24eb3ae 100644
--- a/arkindex/process/tests/test_docker_worker_version.py
+++ b/arkindex/process/tests/test_docker_worker_version.py
@@ -17,8 +17,7 @@ class TestDockerWorkerVersion(FixtureAPITestCase):
     @classmethod
     def setUpTestData(cls):
         super().setUpTestData()
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get(url='http://my_repo.fake/workers/worker')
+        cls.repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
         cls.rev = cls.repo.revisions.get()
         cls.worker = Worker.objects.get(slug='reco')
         cls.version = cls.worker.versions.get()
diff --git a/arkindex/process/tests/test_gitlab_provider.py b/arkindex/process/tests/test_gitlab_provider.py
deleted file mode 100644
index b7bc455074ecfaaa5c1d3974f2926def9c6a5919..0000000000000000000000000000000000000000
--- a/arkindex/process/tests/test_gitlab_provider.py
+++ /dev/null
@@ -1,786 +0,0 @@
-import collections
-from pathlib import Path
-from unittest.mock import MagicMock, patch
-
-import responses
-from django.test import override_settings
-from gitlab.exceptions import GitlabCreateError, GitlabGetError
-from responses import matchers
-from rest_framework.exceptions import APIException, AuthenticationFailed, NotAuthenticated, ValidationError
-
-from arkindex.process.models import GitRefType, Process, ProcessMode, Revision
-from arkindex.process.providers import GitLabProvider
-from arkindex.project.tests import FixtureTestCase
-
-SAMPLES = Path(__file__).absolute().parent / 'repository_conf_samples'
-
-
-class TestGitLabProvider(FixtureTestCase):
-    """
-    Test the GitLabProvider class
-    """
-
-    @classmethod
-    def setUpTestData(cls):
-        super().setUpTestData()
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get(url='http://gitlab/repo')
-        cls.rev = cls.repo.revisions.get()
-        cls.gl_patch = patch('arkindex.process.providers.Gitlab')
-
-    def setUp(self):
-        super().setUp()
-        self.gl_mock = self.gl_patch.start()
-
-    def tearDown(self):
-        super().tearDown()
-        self.gl_patch.stop()
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_list_repos(self):
-        """
-        Test GitLabProvider can list repositories from GitLab
-        """
-        GitLabProvider(credentials=self.creds).list_repos()
-
-        self.assertEqual(self.gl_mock.call_count, 1)
-        args, kwargs = self.gl_mock.call_args
-        self.assertTupleEqual(args, ('https://somewhere', ))
-        self.assertDictEqual(kwargs, {'oauth_token': self.creds.token})
-
-        self.assertEqual(self.gl_mock().projects.list.call_count, 1)
-        args, kwargs = self.gl_mock().projects.list.call_args
-        self.assertTupleEqual(args, ())
-        self.assertDictEqual(kwargs, {'get_all': False, 'min_access_level': 40, 'search': None})
-
-    @responses.activate
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost', GITLAB_APP_ID='abcd', GITLAB_APP_SECRET='s3kr3t')
-    def test_list_repos_refresh(self):
-        responses.post(
-            'https://somewhere/oauth/token',
-            match=[
-                matchers.urlencoded_params_matcher({
-                    'client_id': 'abcd',
-                    'client_secret': 's3kr3t',
-                    'redirect_uri': 'https://arkindex.localhost/api/v1/oauth/providers/gitlab/callback/',
-                    'grant_type': 'refresh_token',
-                    'refresh_token': 'refresh-token'
-                }),
-            ],
-            json={
-                'access_token': 'new-token',
-                'refresh_token': 'new-refresh-token',
-                'token_type': 'Bearer',
-                'created_at': 1582984800,
-                'expires_in': '3600',
-            },
-        )
-        responses.get('https://somewhere/api/v4/user', json={'id': 42, 'username': 'Someone'})
-        self.creds.expiry = None
-        self.creds.save()
-
-        GitLabProvider(credentials=self.creds).list_repos()
-
-        self.creds.refresh_from_db()
-        self.assertEqual(self.creds.token, 'new-token')
-        self.assertEqual(self.creds.refresh_token, 'new-refresh-token')
-        self.assertEqual(self.creds.account_name, 'Someone')
-        self.assertEqual(self.creds.expiry.isoformat(), '2020-02-29T15:00:00+00:00')
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_list_repos_query(self):
-        """
-        Test GitLabProvider can search repositories from GitLab
-        """
-        GitLabProvider(credentials=self.creds).list_repos(query='meh')
-
-        self.assertEqual(self.gl_mock.call_count, 1)
-        args, kwargs = self.gl_mock.call_args
-        self.assertTupleEqual(args, ('https://somewhere', ))
-        self.assertDictEqual(kwargs, {'oauth_token': self.creds.token})
-
-        self.assertEqual(self.gl_mock().projects.list.call_count, 1)
-        args, kwargs = self.gl_mock().projects.list.call_args
-        self.assertTupleEqual(args, ())
-        self.assertDictEqual(kwargs, {'get_all': False, 'min_access_level': 40, 'search': 'meh'})
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_list_repos_requires_credentials(self):
-        """
-        Test GitLabProvider checks for credentials when requesting repositories list
-        """
-        with self.assertRaises(NotAuthenticated):
-            GitLabProvider().list_repos()
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_create_repo(self):
-        """
-        Test GitLabProvider can create a Repository instance from a GitLab repo
-        """
-        self.gl_mock().projects.get.return_value.web_url = 'http://new_repo_url'
-        self.gl_mock().projects.get.return_value.permissions = {
-            'project_access': {'access_level': 50},
-            'group_access': None
-        }
-
-        glp = GitLabProvider(credentials=self.creds)
-
-        new_repo = glp.create_repo(id='1337')
-
-        self.assertEqual(self.gl_mock().projects.get.call_count, 2)
-        args, kwargs = self.gl_mock().projects.get.call_args
-        self.assertTupleEqual(args, (1337, ))
-        self.assertDictEqual(kwargs, {})
-
-        self.assertEqual(new_repo.url, 'http://new_repo_url')
-        self.assertEqual(new_repo.provider_name, 'GitLabProvider')
-
-        self.assertEqual(self.gl_mock().projects.get().hooks.create.call_count, 1)
-        args, kwargs = self.gl_mock().projects.get().hooks.create.call_args
-        self.assertEqual(len(args), 1)
-        self.assertDictEqual(kwargs, {})
-        self.assertDictEqual(args[0], {
-            'url': f'https://arkindex.localhost/api/v1/imports/hook/{new_repo.id}/',
-            'push_events': True,
-            'tag_push_events': True,
-            'token': new_repo.hook_token,
-        })
-
-    @responses.activate
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost', GITLAB_APP_ID='abcd', GITLAB_APP_SECRET='s3kr3t')
-    def test_create_repo_refresh(self):
-        responses.post(
-            'https://somewhere/oauth/token',
-            match=[
-                matchers.urlencoded_params_matcher({
-                    'client_id': 'abcd',
-                    'client_secret': 's3kr3t',
-                    'redirect_uri': 'https://arkindex.localhost/api/v1/oauth/providers/gitlab/callback/',
-                    'grant_type': 'refresh_token',
-                    'refresh_token': 'refresh-token'
-                }),
-            ],
-            json={
-                'access_token': 'new-token',
-                'refresh_token': 'new-refresh-token',
-                'token_type': 'Bearer',
-                'created_at': 1582984800,
-                'expires_in': '3600',
-            },
-        )
-        responses.get('https://somewhere/api/v4/user', json={'id': 42, 'username': 'Someone'})
-        self.creds.expiry = None
-        self.creds.save()
-
-        self.gl_mock().projects.get.return_value.web_url = 'http://new_repo_url'
-        self.gl_mock().projects.get.return_value.permissions = {
-            'project_access': {'access_level': 50},
-            'group_access': None
-        }
-
-        glp = GitLabProvider(credentials=self.creds)
-        glp.create_repo(id='1337')
-
-        self.creds.refresh_from_db()
-        self.assertEqual(self.creds.token, 'new-token')
-        self.assertEqual(self.creds.refresh_token, 'new-refresh-token')
-        self.assertEqual(self.creds.account_name, 'Someone')
-        self.assertEqual(self.creds.expiry.isoformat(), '2020-02-29T15:00:00+00:00')
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_create_repo_requires_credentials(self):
-        """
-        Test GitLabProvider checks for credentials when requesting a repository creation
-        """
-        with self.assertRaises(NotAuthenticated):
-            GitLabProvider().create_repo(id='repo_id')
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_create_repo_already_exists(self):
-        """
-        Test GitLabProvider checks for duplicate repositories
-        """
-        self.gl_mock().projects.get.return_value.web_url = 'http://new_repo_url'
-        self.gl_mock().projects.get.return_value.permissions = {
-            'project_access': {'access_level': 40},
-            'group_access': None
-        }
-
-        glp = GitLabProvider(credentials=self.creds)
-        glp.create_repo(id='1337')
-
-        with self.assertRaises(ValidationError):
-            GitLabProvider(credentials=self.creds).create_repo(
-                id='1337')
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_create_repo_requires_maintainer(self):
-        """
-        Test GitLabProvider checks for duplicate repositories
-        """
-        self.gl_mock().projects.get.return_value.web_url = 'http://new_repo_url'
-        self.gl_mock().projects.get.return_value.permissions = {
-            'group_access': {'access_level': 30},
-            'project_access': None,
-        }
-
-        glp = GitLabProvider(credentials=self.creds)
-
-        with self.assertRaisesRegex(
-                ValidationError,
-                'Maintainer or Owner access is required to add a GitLab repository'):
-            glp.create_repo(id='1337')
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_create_repo_handle_get_error(self):
-        """
-        Test GitLabProvider handles GitLab repo GET errors
-        """
-        self.gl_mock().projects.get.side_effect = GitlabGetError
-
-        with self.assertRaises(APIException):
-            GitLabProvider(credentials=self.creds).create_repo(id='1337')
-
-        self.assertEqual(self.gl_mock().projects.get.call_count, 1)
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_create_repo_handle_hook_create_error(self):
-        """
-        Test GitLabProvider handles GitLab hook creation errors
-        """
-        self.gl_mock().projects.get.return_value.web_url = 'http://new_repo_url'
-        self.gl_mock().projects.get.return_value.permissions = {
-            'project_access': {'access_level': 50}
-        }
-        self.gl_mock().projects.get.return_value.hooks.create.side_effect = GitlabCreateError
-
-        with self.assertRaises(APIException):
-            glp = GitLabProvider(credentials=self.creds)
-            glp.create_repo(id='1337')
-
-        self.assertEqual(self.gl_mock().projects.get.call_count, 2)
-        self.assertEqual(self.gl_mock().projects.get().hooks.create.call_count, 1)
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_update_or_create_ref(self):
-        """
-        Test GitLabProvider can create or update a GitRef instance for a repo and a revision
-        """
-        commit_refs = [
-            {'name': 'refs/tags/v0.1.0', 'type': 'tag'},
-            {'name': 'refs/heads/branch1', 'type': 'branch'},
-            {'name': 'refs/heads/branch2', 'type': 'branch'},
-        ]
-        rev1 = Revision(
-            repo=self.repo,
-            hash='1',
-            message='commit message',
-            author='bob',
-        )
-        rev1.save()
-        rev2 = Revision(
-            repo=self.repo,
-            hash='2',
-            message='commit message',
-            author='bob',
-        )
-        rev2.save()
-
-        # Assert that git references are created properly
-        for ref in commit_refs:
-            GitLabProvider(credentials=self.creds) \
-                .update_or_create_ref(self.repo, rev1, ref['name'], ref['type'])
-
-        refs = [
-            {'name': ref.name, 'type': ref.type, 'repo': ref.repository}
-            for ref in rev1.refs.all()
-        ]
-        self.assertEqual(len(refs), 3)
-        self.assertListEqual(refs, [
-            {'name': 'refs/tags/v0.1.0', 'type': GitRefType.Tag, 'repo': self.repo},
-            {'name': 'refs/heads/branch1', 'type': GitRefType.Branch, 'repo': self.repo},
-            {'name': 'refs/heads/branch2', 'type': GitRefType.Branch, 'repo': self.repo},
-        ])
-        self.assertEqual(len(self.repo.refs.all()), 3)
-
-        # Assert that git references are updated with another revision properly
-        GitLabProvider(credentials=self.creds) \
-            .update_or_create_ref(self.repo, rev2, commit_refs[0]['name'], commit_refs[0]['type'])
-        GitLabProvider(credentials=self.creds) \
-            .update_or_create_ref(self.repo, rev2, commit_refs[1]['name'], commit_refs[1]['type'])
-
-        refs_rev1 = [
-            {'name': ref.name, 'type': ref.type, 'repo': ref.repository}
-            for ref in rev1.refs.all()
-        ]
-        refs_rev2 = [
-            {'name': ref.name, 'type': ref.type, 'repo': ref.repository}
-            for ref in rev2.refs.all()
-        ]
-        self.assertEqual(len(refs_rev1), 1)
-        self.assertListEqual(refs_rev1, [
-            {'name': 'refs/heads/branch2', 'type': GitRefType.Branch, 'repo': self.repo},
-        ])
-        self.assertEqual(len(refs_rev2), 2)
-        self.assertListEqual(refs_rev2, [
-            {'name': 'refs/tags/v0.1.0', 'type': GitRefType.Tag, 'repo': self.repo},
-            {'name': 'refs/heads/branch1', 'type': GitRefType.Branch, 'repo': self.repo},
-        ])
-        self.assertEqual(len(self.repo.refs.all()), 3)
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_get_revision(self):
-        """
-        Test GitLabProvider can create a Revision instance for a repo by hash
-        """
-        revision, created = GitLabProvider(credentials=self.creds) \
-            .get_or_create_revision(self.repo, '42')
-
-        self.assertEqual(revision, self.rev)
-        self.assertFalse(created)
-        self.assertEqual(self.gl_mock.call_count, 0)
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_create_revision(self):
-        """
-        Test GitLabProvider can create a Revision instance for a repo by hash
-        """
-        self.gl_mock().projects.get.return_value.commits.get.return_value.refs.return_value = [
-            {'name': 'refs/tags/v0.1.0', 'type': 'tag'},
-            {'name': 'refs/heads/branch1', 'type': 'branch'},
-            {'name': 'refs/heads/branch2', 'type': 'branch'},
-            {'name': 'oh_no', 'type': 'all'},
-        ]
-        self.gl_mock().projects.get.return_value.commits.get.return_value.message = 'commit message'
-        self.gl_mock().projects.get.return_value.commits.get.return_value.author_name = 'bob'
-
-        revision, created = GitLabProvider(credentials=self.creds) \
-            .get_or_create_revision(self.repo, '1337')
-
-        self.assertTrue(created)
-        self.assertEqual(revision.hash, '1337')
-
-        # Assert that git references are created properly
-        refs = [
-            {
-                'name': ref.name,
-                'type': ref.type,
-                'repo': ref.repository,
-            }
-            for ref in revision.refs.all()
-        ]
-        self.assertEqual(len(refs), 3)
-        self.assertListEqual(refs, [
-            {'name': 'refs/tags/v0.1.0', 'type': GitRefType.Tag, 'repo': self.repo},
-            {'name': 'refs/heads/branch1', 'type': GitRefType.Branch, 'repo': self.repo},
-            {'name': 'refs/heads/branch2', 'type': GitRefType.Branch, 'repo': self.repo},
-        ])
-
-        self.assertEqual(revision.message, 'commit message')
-        self.assertEqual(revision.author, 'bob')
-
-        self.assertEqual(self.gl_mock().projects.get.call_count, 1)
-        self.assertEqual(self.gl_mock().projects.get().commits.get.call_count, 1)
-        args, kwargs = self.gl_mock().projects.get().commits.get.call_args
-        self.assertTupleEqual(args, ('1337', ))
-        self.assertDictEqual(kwargs, {})
-
-    @responses.activate
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost', GITLAB_APP_ID='abcd', GITLAB_APP_SECRET='s3kr3t')
-    def test_create_revision_refresh(self):
-        responses.post(
-            'https://somewhere/oauth/token',
-            match=[
-                matchers.urlencoded_params_matcher({
-                    'client_id': 'abcd',
-                    'client_secret': 's3kr3t',
-                    'redirect_uri': 'https://arkindex.localhost/api/v1/oauth/providers/gitlab/callback/',
-                    'grant_type': 'refresh_token',
-                    'refresh_token': 'refresh-token'
-                }),
-            ],
-            json={
-                'access_token': 'new-token',
-                'refresh_token': 'new-refresh-token',
-                'token_type': 'Bearer',
-                'created_at': 1582984800,
-                'expires_in': '3600',
-            },
-        )
-        responses.get('https://somewhere/api/v4/user', json={'id': 42, 'username': 'Someone'})
-        self.creds.expiry = None
-        self.creds.save()
-
-        self.gl_mock().projects.get.return_value.commits.get.return_value.refs.return_value = []
-        self.gl_mock().projects.get.return_value.commits.get.return_value.message = 'commit message'
-        self.gl_mock().projects.get.return_value.commits.get.return_value.author_name = 'bob'
-
-        GitLabProvider(credentials=self.creds).get_or_create_revision(self.repo, '1337')
-
-        self.creds.refresh_from_db()
-        self.assertEqual(self.creds.token, 'new-token')
-        self.assertEqual(self.creds.refresh_token, 'new-refresh-token')
-        self.assertEqual(self.creds.account_name, 'Someone')
-        self.assertEqual(self.creds.expiry.isoformat(), '2020-02-29T15:00:00+00:00')
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_handle_webhook_missing_headers(self):
-        """
-        Test GitLabProvider checks HTTP headers on webhooks
-        """
-        glp = GitLabProvider(credentials=self.creds)
-
-        request_mock = MagicMock()
-        request_mock.data = {
-            'object_kind': 'push',
-            'ref': 'refs/heads/master',
-            'checkout_sha': '1337',
-            'commits': [
-                {
-                    'message': 'commit message',
-                    'author': {
-                        'name': 'bob',
-                    }
-                }
-            ]
-        }
-
-        # Missing HTTP_X_GITLAB_TOKEN
-        request_mock.META = {
-            'HTTP_X_GITLAB_EVENT': 'Push Hook',
-        }
-        with self.assertRaises(NotAuthenticated):
-            glp.handle_webhook(self.repo, request_mock)
-
-        # Missing HTTP_X_GITLAB_EVENT
-        request_mock.META = {
-            'HTTP_X_GITLAB_TOKEN': 'hook-token',
-        }
-        with self.assertRaises(ValidationError):
-            glp.handle_webhook(self.repo, request_mock)
-
-        # Wrong HTTP_X_GITLAB_EVENT
-        request_mock.META = {
-            'HTTP_X_GITLAB_EVENT': 'Not a Push Hook',
-            'HTTP_X_GITLAB_TOKEN': 'hook-token',
-        }
-        with self.assertRaises(ValidationError):
-            glp.handle_webhook(self.repo, request_mock)
-
-        # Wrong HTTP_X_GITLAB_TOKEN
-        request_mock.META = {
-            'HTTP_X_GITLAB_EVENT': 'Push Hook',
-            'HTTP_X_GITLAB_TOKEN': 'not-the-hook-token',
-        }
-        with self.assertRaises(AuthenticationFailed):
-            glp.handle_webhook(self.repo, request_mock)
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_handle_webhook_create_revision(self):
-        """
-        Test GitLabProvider does create a revision when a push event is received
-        """
-        request_mock = MagicMock()
-        request_mock.META = {
-            'HTTP_X_GITLAB_EVENT': 'Push Hook',
-            'HTTP_X_GITLAB_TOKEN': 'hook-token',
-        }
-        sha = '1337'
-        request_mock.data = {
-            'object_kind': 'push',
-            'ref': 'refs/heads/master',
-            'checkout_sha': sha,
-            'commits': [
-                {
-                    'message': 'commit message',
-                    'author': {
-                        'name': 'bob',
-                    }
-                }
-            ]
-        }
-
-        self.gl_mock().projects.get.return_value.commits.get.return_value.refs.return_value = [
-            {'name': 'oh_no', 'type': 'tag'},
-            {'name': 'refs/heads/branch1', 'type': 'branch'},
-            {'name': 'refs/heads/branch2', 'type': 'branch'},
-        ]
-        self.gl_mock().projects.get.return_value.commits.get.return_value.message = 'commit message'
-        self.gl_mock().projects.get.return_value.commits.get.return_value.author_name = 'bob'
-
-        rev = self.repo.revisions.filter(hash=sha)
-        self.assertFalse(rev.exists())
-        repo_processes = Process.objects.filter(revision__repo_id=str(self.repo.id))
-        self.assertFalse(repo_processes.exists())
-        GitLabProvider(credentials=self.creds).handle_webhook(self.repo, request_mock)
-
-        di = repo_processes.get()
-        self.assertEqual(di.mode, ProcessMode.Repository)
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_handle_webhook_duplicate_events(self):
-        """
-        Test GitLabProvider checks for already handled events
-        """
-        request_mock = MagicMock()
-        request_mock.META = {
-            'HTTP_X_GITLAB_EVENT': 'Push Hook',
-            'HTTP_X_GITLAB_TOKEN': 'hook-token',
-        }
-        sha = '42'
-        request_mock.data = {
-            'object_kind': 'push',
-            'ref': 'refs/heads/master',
-            'checkout_sha': sha,
-            'commits': [
-                {
-                    'message': 'a',
-                    'author': {
-                        'name': 'me',
-                    }
-                }
-            ]
-        }
-
-        rev = self.repo.revisions.filter(hash=sha)
-        self.assertTrue(rev.exists())
-        repo_processes = Process.objects.filter(revision__repo_id=str(self.repo.id))
-        self.assertFalse(repo_processes.exists())
-        GitLabProvider(credentials=self.creds).handle_webhook(self.repo, request_mock)
-
-        # Checking that we didn't initiate revision creation
-        self.assertEqual(self.gl_mock().projects.get.call_count, 0)
-        self.assertEqual(self.gl_mock().projects.get().commits.get.call_count, 0)
-        self.assertFalse(repo_processes.exists())
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_handle_webhook_wrong_kind(self):
-        """
-        Test GitLabProvider gracefully fails when GitLab breaks things
-        """
-        sha = '1337'
-        rev = self.repo.revisions.filter(hash=sha)
-        self.assertFalse(rev.exists())
-        repo_processes = Process.objects.filter(revision__repo_id=str(self.repo.id))
-
-        glp = GitLabProvider(credentials=self.creds)
-        request_mock = MagicMock()
-        request_mock.META = {
-            'HTTP_X_GITLAB_EVENT': 'Push Hook',
-            'HTTP_X_GITLAB_TOKEN': 'hook-token',
-        }
-        request_mock.data = {
-            'object_kind': 'oh_no',  # Bad object kind
-            'ref': 'refs/heads/master',
-            'checkout_sha': sha,
-            'commits': [
-                {
-                    'message': 'b',
-                    'author': {
-                        'name': 'me',
-                    }
-                }
-            ]
-        }
-        with self.assertRaises(ValidationError):
-            glp.handle_webhook(self.repo, request_mock)
-        self.assertFalse(rev.exists())
-        self.assertFalse(repo_processes.exists())
-
-        # Breaking change: a list!
-        request_mock.data = [request_mock.data]
-        with self.assertRaises(ValidationError):
-            glp.handle_webhook(self.repo, request_mock)
-        self.assertFalse(rev.exists())
-        self.assertFalse(repo_processes.exists())
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_handle_webhook_delete_branch(self):
-        """
-        Test GitLabProvider properly handles a branch deletion
-        """
-        rev = Revision(
-            repo=self.repo,
-            hash='1',
-            message='commit message',
-            author='bob',
-        )
-        rev.save()
-        self.assertTrue(self.repo.revisions.filter(hash='1').exists())
-        repo_processes = Process.objects.filter(revision__repo_id=str(self.repo.id))
-
-        glp = GitLabProvider(credentials=self.creds)
-        glp.update_or_create_ref(self.repo, rev, 'test', GitRefType.Branch)
-        self.assertEqual(len(self.repo.refs.all()), 1)
-        request_mock = MagicMock()
-        request_mock.META = {
-            'HTTP_X_GITLAB_EVENT': 'Push Hook',
-            'HTTP_X_GITLAB_TOKEN': 'hook-token',
-        }
-        request_mock.data = {
-            'object_kind': 'push',
-            'ref': 'refs/heads/test',
-            'commits': []
-        }
-
-        glp.handle_webhook(self.repo, request_mock)
-        self.assertTrue(self.repo.revisions.filter(hash='1').exists())
-        self.assertEqual(len(self.repo.refs.all()), 0)
-        self.assertFalse(repo_processes.exists())
-
-    @responses.activate
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost', GITLAB_APP_ID='abcd', GITLAB_APP_SECRET='s3kr3t')
-    def test_handle_webhook_refresh(self):
-        responses.post(
-            'https://somewhere/oauth/token',
-            match=[
-                matchers.urlencoded_params_matcher({
-                    'client_id': 'abcd',
-                    'client_secret': 's3kr3t',
-                    'redirect_uri': 'https://arkindex.localhost/api/v1/oauth/providers/gitlab/callback/',
-                    'grant_type': 'refresh_token',
-                    'refresh_token': 'refresh-token'
-                }),
-            ],
-            json={
-                'access_token': 'new-token',
-                'refresh_token': 'new-refresh-token',
-                'token_type': 'Bearer',
-                'created_at': 1582984800,
-                'expires_in': '3600',
-            },
-        )
-        responses.get('https://somewhere/api/v4/user', json={'id': 42, 'username': 'Someone'})
-        self.creds.expiry = None
-        self.creds.save()
-
-        self.gl_mock().projects.get.return_value.commits.get.return_value.refs.return_value = []
-        self.gl_mock().projects.get.return_value.commits.get.return_value.message = 'commit message'
-        self.gl_mock().projects.get.return_value.commits.get.return_value.author_name = 'bob'
-
-        request_mock = MagicMock()
-        request_mock.META = {
-            'HTTP_X_GITLAB_EVENT': 'Push Hook',
-            'HTTP_X_GITLAB_TOKEN': 'hook-token',
-        }
-        request_mock.data = {
-            'object_kind': 'push',
-            'ref': 'refs/heads/something',
-            'commits': [],
-            'checkout_sha': '1337',
-        }
-
-        glp = GitLabProvider(credentials=self.creds)
-        glp.handle_webhook(self.repo, request_mock)
-
-        self.creds.refresh_from_db()
-        self.assertEqual(self.creds.token, 'new-token')
-        self.assertEqual(self.creds.refresh_token, 'new-refresh-token')
-        self.assertEqual(self.creds.account_name, 'Someone')
-        self.assertEqual(self.creds.expiry.isoformat(), '2020-02-29T15:00:00+00:00')
-
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_update_repo_references(self):
-        """
-        Check that we are able to fetch new branch and tags references
-        """
-        Ref = collections.namedtuple('Ref', 'name, commit')
-
-        # Add 2 commits on 2 branches
-        self.gl_mock().projects.get.return_value.branches.list.return_value = [
-            Ref("master", {"id": "commit1", "message": "A commit on master", "author_email": "someone@teklia.com"}),
-            # Create a commit with a very long branch name
-            Ref("A" * 1000, {"id": "commit2", "message": "My fancy feature", "author_email": "another@teklia.com"})
-        ]
-
-        # Add 1 new commit on a tag, and reuse a commit on another tag
-        self.gl_mock().projects.get.return_value.tags.list.return_value = [
-            Ref("v0.1", {"id": "commit0", "message": "This is a legacy version", "author_email": "old@teklia.com"}),
-            Ref("v1.0", {"id": "commit1", "message": "A commit on master", "author_email": "someone@teklia.com"})
-        ]
-
-        # Should only include data from fixtures at first
-        self.assertFalse(self.repo.revisions.exclude(id=self.rev.id).exists())
-        self.assertFalse(self.repo.refs.exists())
-
-        # Update references for this repo
-        provider = GitLabProvider(credentials=self.creds)
-        provider.update_repository_references(self.repo)
-
-        # We should now have 3 revisions
-        commit0 = self.repo.revisions.get(hash="commit0")
-        commit1 = self.repo.revisions.get(hash="commit1")
-        commit2 = self.repo.revisions.get(hash="commit2")
-        self.assertEqual(commit0.message, "This is a legacy version")
-        self.assertEqual(commit1.message, "A commit on master")
-        self.assertEqual(commit2.message, "My fancy feature")
-        self.assertEqual(commit0.author, "old@teklia.com")
-        self.assertEqual(commit1.author, "someone@teklia.com")
-        self.assertEqual(commit2.author, "another@teklia.com")
-
-        # Commit 1 should have a branch and a tag ref
-        self.assertListEqual(list(commit1.refs.values_list('name', 'type').order_by('name')), [
-            ('master', GitRefType.Branch),
-            ('v1.0', GitRefType.Tag),
-        ])
-
-        # Other commits only have one ref
-        self.assertListEqual(list(commit0.refs.values_list('name', 'type').order_by('name')), [
-            ('v0.1', GitRefType.Tag),
-        ])
-        self.assertListEqual(list(commit2.refs.values_list('name', 'type').order_by('name')), [
-            # Name has been restricted to 250 chars due to GitRef model constraint
-            ('A' * 250, GitRefType.Branch),
-        ])
-
-        # We should now have 3 new processes for these refs
-        self.assertListEqual(list(
-            Process
-            .objects
-            .filter(mode=ProcessMode.Repository, revision__isnull=False)
-            .values_list('name', 'mode', 'revision__hash')
-            .order_by('revision__hash')
-        ), [
-            ("Import v0.1 from http://gitlab/repo", ProcessMode.Repository, 'commit0'),
-            ("Import master from http://gitlab/repo", ProcessMode.Repository, 'commit1'),
-            # Last process name has been limited to 100 chars due to Process model constraint
-            (f"Import {'A' * 93}", ProcessMode.Repository, 'commit2'),
-        ])
-
-    @responses.activate
-    @override_settings(PUBLIC_HOSTNAME='https://arkindex.localhost', GITLAB_APP_ID='abcd', GITLAB_APP_SECRET='s3kr3t')
-    def test_update_repo_references_refresh(self):
-        responses.post(
-            'https://somewhere/oauth/token',
-            match=[
-                matchers.urlencoded_params_matcher({
-                    'client_id': 'abcd',
-                    'client_secret': 's3kr3t',
-                    'redirect_uri': 'https://arkindex.localhost/api/v1/oauth/providers/gitlab/callback/',
-                    'grant_type': 'refresh_token',
-                    'refresh_token': 'refresh-token'
-                }),
-            ],
-            json={
-                'access_token': 'new-token',
-                'refresh_token': 'new-refresh-token',
-                'token_type': 'Bearer',
-                'created_at': 1582984800,
-                'expires_in': '3600',
-            },
-        )
-        responses.get('https://somewhere/api/v4/user', json={'id': 42, 'username': 'Someone'})
-        self.creds.expiry = None
-        self.creds.save()
-
-        self.gl_mock().projects.get.return_value.branches.list.return_value = []
-        self.gl_mock().projects.get.return_value.tags.list.return_value = []
-
-        provider = GitLabProvider(credentials=self.creds)
-        provider.update_repository_references(self.repo)
-
-        self.creds.refresh_from_db()
-        self.assertEqual(self.creds.token, 'new-token')
-        self.assertEqual(self.creds.refresh_token, 'new-refresh-token')
-        self.assertEqual(self.creds.account_name, 'Someone')
-        self.assertEqual(self.creds.expiry.isoformat(), '2020-02-29T15:00:00+00:00')
diff --git a/arkindex/process/tests/test_process_datasets.py b/arkindex/process/tests/test_process_datasets.py
index a61ec306931425081bba986052fb16e75641b68d..2dce402d0caab3c71bc89db5cf2e1d48239c8f34 100644
--- a/arkindex/process/tests/test_process_datasets.py
+++ b/arkindex/process/tests/test_process_datasets.py
@@ -5,7 +5,7 @@ from django.urls import reverse
 from rest_framework import status
 
 from arkindex.documents.models import Corpus
-from arkindex.process.models import Process, ProcessDataset, ProcessMode
+from arkindex.process.models import Process, ProcessDataset, ProcessMode, Repository
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex.training.models import Dataset
 from arkindex.users.models import Role, User
@@ -48,8 +48,7 @@ class TestProcessDatasets(FixtureAPITestCase):
         cls.dataset_process_2.datasets.set([cls.dataset2])
 
         # For repository process
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get(url='http://my_repo.fake/workers/worker')
+        cls.repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
         cls.repo.memberships.create(user=cls.test_user, level=Role.Admin.value)
         cls.rev = cls.repo.revisions.get()
 
diff --git a/arkindex/process/tests/test_processes.py b/arkindex/process/tests/test_processes.py
index 80125798e18460ef51ec427c5b2b96e67986cd85..3a1a9f5f8b43d0a00fcdd03b134c8c3558b6da41 100644
--- a/arkindex/process/tests/test_processes.py
+++ b/arkindex/process/tests/test_processes.py
@@ -16,6 +16,7 @@ from arkindex.process.models import (
     DataFile,
     Process,
     ProcessMode,
+    Repository,
     WorkerActivity,
     WorkerActivityState,
     WorkerVersion,
@@ -38,8 +39,7 @@ class TestProcesses(FixtureAPITestCase):
         cls.default_farm = Farm.objects.create(name='Corn farm')
         cls.default_farm.memberships.create(user=cls.user, level=Role.Guest.value)
         cls.other_farm = Farm.objects.get(name='Wheat farm')
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get(url='http://my_repo.fake/workers/worker')
+        cls.repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
         cls.rev = cls.repo.revisions.get()
         cls.dataset1, cls.dataset2 = Dataset.objects.filter(corpus=cls.corpus).order_by('name')
         cls.private_corpus = Corpus.objects.create(name='Private corpus')
@@ -1851,23 +1851,6 @@ class TestProcesses(FixtureAPITestCase):
         self.assertTrue(self.elts_process.tasks.exists())
         self.assertFalse(delay_mock.called)
 
-    def test_retry_repo_disabled(self):
-        self.repository_process.revision = self.rev
-        self.repository_process.save()
-        self.repository_process.run()
-        self.repository_process.tasks.all().update(state=State.Error)
-        self.assertEqual(self.repository_process.state, State.Error)
-        self.creds.delete()
-        # Allow the user to do the retry
-        self.repo.memberships.filter(user=self.user).update(level=Role.Admin.value)
-        self.client.force_login(self.user)
-
-        with self.assertNumQueries(10):
-            response = self.client.post(reverse('api:process-retry', kwargs={'pk': self.repository_process.id}))
-            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-
-        self.assertEqual(response.json(), {'__all__': ['Git repository does not have any valid credentials']})
-
     @patch('arkindex.project.triggers.process_tasks.initialize_activity.delay')
     def test_retry_initialize_activity(self, delay_mock):
         """
diff --git a/arkindex/process/tests/test_providers.py b/arkindex/process/tests/test_providers.py
deleted file mode 100644
index 0a6fb5324795d37c52850948ab43d86d1d784481..0000000000000000000000000000000000000000
--- a/arkindex/process/tests/test_providers.py
+++ /dev/null
@@ -1,125 +0,0 @@
-from unittest.mock import patch
-
-from django.core import mail
-from django.urls import reverse
-from rest_framework import status
-
-from arkindex.process.providers import GitLabProvider, GitProvider
-from arkindex.project.tests import FixtureAPITestCase
-
-MAIL_CONTENT = """
-Hello Test user,
-
-An error occurred while processing a new push on your repository http://my_repo.fake/workers/worker.
-
-Error: Error during handle_webhook
-
-No process will be launched to import your new revision.
-Please, try again with another push or contact your system administrator.
-
---
-Arkindex
-
-"""
-
-REFRESH_TOKEN_MAIL_CONTENT = """
-Hello Test user,
-
-An error occurred while processing a new push on your repository http://my_repo.fake/workers/worker.
-
-Error: The OAuth token could not be refreshed. Please reconnect the OAuth account manually.
-Original error: No refresh token was stored for this OAuth token.
-
-No process will be launched to import your new revision.
-Please, try again with another push or contact your system administrator.
-
---
-Arkindex
-
-"""
-
-
-class TestProviders(FixtureAPITestCase):
-
-    @classmethod
-    def setUpTestData(cls):
-        super().setUpTestData()
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get(url='http://my_repo.fake/workers/worker')
-        cls.rev = cls.repo.revisions.get()
-
-    def test_init(self):
-        glp = GitLabProvider()
-        self.assertIsNone(glp.credentials)
-
-        glp = GitLabProvider(credentials=self.creds)
-        self.assertEqual(glp.credentials, self.creds)
-
-        with self.assertRaises(Exception):
-            GitLabProvider(credentials='not a OAuthCredentials')
-
-    @patch('arkindex.process.api.Repository.provider_class')
-    def test_webhook_no_credentials(self, provider_class):
-        self.client.force_login(self.user)
-        self.repo.credentials = None
-        self.repo.save()
-        response = self.client.post(reverse('api:import-hook', kwargs={'pk': self.repo.id}))
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-        self.assertDictEqual(response.json(), {'detail': 'No credentials available for this repository.'})
-        self.assertEqual(len(mail.outbox), 0)
-
-    @patch('arkindex.process.api.Repository.provider_class')
-    def test_webhook_handle_error(self, provider_class):
-        provider_class.return_value.handle_webhook.side_effect = Exception('Error during handle_webhook')
-        self.client.force_login(self.user)
-        with self.assertRaisesRegex(Exception, 'Error during handle_webhook'):
-            self.client.post(reverse('api:import-hook', kwargs={'pk': self.repo.id}))
-        self.assertTrue(provider_class.return_value.handle_webhook.called)
-        self.assertEqual(len(mail.outbox), 1)
-        self.assertEqual(mail.outbox[0].to, ['user@user.fr'])
-        self.assertEqual(mail.outbox[0].subject, 'An error occurred during Git hook handling')
-        self.assertEqual(mail.outbox[0].body, MAIL_CONTENT)
-
-    def test_webhook_handle_token_refresh_error(self):
-        """
-        The Git import hook should send an email for OAuthCredentials token refresh failures
-        """
-        self.client.force_login(self.user)
-        self.creds.refresh_token = None
-        self.creds.expiry = None
-        self.assertTrue(self.creds.expired)
-        self.creds.save()
-
-        self.client.post(
-            reverse('api:import-hook', kwargs={'pk': self.repo.id}),
-            {
-                'object_kind': 'push',
-                'ref': 'refs/heads/something',
-                'commits': [],
-                'checkout_sha': 'abcd',
-            },
-            HTTP_X_GITLAB_EVENT='Push Hook',
-            HTTP_X_GITLAB_TOKEN=self.repo.hook_token,
-        )
-
-        self.assertEqual(len(mail.outbox), 1)
-        self.assertEqual(mail.outbox[0].to, ['user@user.fr'])
-        self.assertEqual(mail.outbox[0].subject, 'An error occurred during Git hook handling')
-        self.assertEqual(mail.outbox[0].body, REFRESH_TOKEN_MAIL_CONTENT)
-
-    @patch('arkindex.process.api.Repository.provider_class')
-    def test_webhook(self, provider_class):
-        self.client.force_login(self.user)
-        response = self.client.post(reverse('api:import-hook', kwargs={'pk': self.repo.id}))
-        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
-        self.assertTrue(provider_class.return_value.handle_webhook.called)
-        self.assertEqual(len(mail.outbox), 0)
-
-    @patch('arkindex.process.models.Process.run')
-    def test_start_imports_workers(self, run_mock):
-        self.assertEqual(self.rev.processes.count(), 0)
-        GitProvider.start_imports(None, rev=self.rev)
-        self.assertEqual(self.rev.processes.count(), 1)
-        self.assertEqual(run_mock.call_count, 1)
-        _, run_kwargs = run_mock.call_args
-        self.assertDictEqual(run_kwargs, {})
diff --git a/arkindex/process/tests/test_repos.py b/arkindex/process/tests/test_repos.py
index 57c84d4d6d8701de8bda32a70dcb210fbc3c5e03..46b9a22bf8608a5ab00c92cdabb3b3848c996c19 100644
--- a/arkindex/process/tests/test_repos.py
+++ b/arkindex/process/tests/test_repos.py
@@ -1,12 +1,9 @@
-from unittest.mock import MagicMock, patch
-
 from django.urls import reverse
 from rest_framework import status
-from rest_framework.exceptions import ValidationError
 from rest_framework.serializers import DateTimeField
 
-from arkindex.ponos.models import Farm, State, Task
-from arkindex.process.models import ActivityState, Process, ProcessMode, Repository
+from arkindex.ponos.models import Farm
+from arkindex.process.models import ProcessMode, Repository
 from arkindex.project.tests import FixtureTestCase
 from arkindex.users.models import Role, User
 
@@ -16,9 +13,8 @@ class TestRepositories(FixtureTestCase):
     @classmethod
     def setUpTestData(cls):
         super().setUpTestData()
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get(url='http://my_repo.fake/workers/worker')
-        cls.repo_2 = cls.creds.repos.get(url='http://gitlab/repo')
+        cls.repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
+        cls.repo_2 = Repository.objects.get(url='http://gitlab/repo')
         cls.rev = cls.repo.revisions.get()
         cls.serialized_revision = {
             'id': str(cls.rev.id),
@@ -35,15 +31,11 @@ class TestRepositories(FixtureTestCase):
         return [
             {
                 'id': str(self.repo_2.id),
-                'enabled': True,
-                'git_clone_url': None,
                 'url': self.repo_2.url,
                 'workers': [],
                 'authorized_users': self.repo_2.memberships.count(),
             }, {
                 'id': str(self.repo.id),
-                'enabled': True,
-                'git_clone_url': None,
                 'url': self.repo.url,
                 'workers': [
                     {
@@ -57,35 +49,6 @@ class TestRepositories(FixtureTestCase):
             }
         ]
 
-    def test_delete_credentials_null(self):
-        """
-        Check deleting OAuthCredentials do not delete repositories and revisions
-        """
-        self.creds.delete()
-        self.assertTrue(Repository.objects.filter(url='http://my_repo.fake/workers/worker').exists())
-        self.repo.refresh_from_db()
-        self.assertTrue(self.repo.revisions.exists())
-
-    def test_no_credentials_no_process(self):
-        """
-        Check Repository import processes do not start without credentials
-        """
-        self.repo.credentials = None
-        self.repo.save()
-        task_count = Task.objects.count()
-
-        process = Process.objects.create(
-            mode=ProcessMode.Repository,
-            revision=self.rev,
-            creator=self.superuser,
-            farm=Farm.objects.first(),
-        )
-
-        with self.assertRaisesMessage(ValidationError, 'Git repository does not have any valid credentials'):
-            process.run()
-
-        self.assertEqual(Task.objects.count(), task_count)
-
     def test_list_repository_requires_login(self):
         with self.assertNumQueries(0):
             response = self.client.get(reverse('api:repository-list'))
@@ -157,8 +120,6 @@ class TestRepositories(FixtureTestCase):
         data = response.json()
         self.assertDictEqual(data, {
             'id': str(self.repo_2.id),
-            'enabled': True,
-            'git_clone_url': None,
             'url': self.repo_2.url,
             'workers': [],
             'authorized_users': self.repo_2.memberships.count(),
@@ -177,7 +138,7 @@ class TestRepositories(FixtureTestCase):
         task = process.tasks.get()
         self.repo_2.memberships.create(user=self.user, level=Role.Guest.value)
 
-        with self.assertNumQueries(6):
+        with self.assertNumQueries(4):
             response = self.client.get(
                 reverse('api:repository-retrieve', kwargs={'pk': str(self.repo_2.id)}),
                 HTTP_AUTHORIZATION=f'Ponos {task.token}',
@@ -186,8 +147,6 @@ class TestRepositories(FixtureTestCase):
 
         self.assertDictEqual(response.json(), {
             'id': str(self.repo_2.id),
-            'enabled': True,
-            'git_clone_url': 'https://oauth2:oauth-token@gitlab/repo',
             'url': self.repo_2.url,
             'workers': [],
             'authorized_users': self.repo_2.memberships.count(),
@@ -206,7 +165,7 @@ class TestRepositories(FixtureTestCase):
         task = process.tasks.get()
         self.repo_2.memberships.create(user=self.user, level=Role.Guest.value)
 
-        with self.assertNumQueries(6):
+        with self.assertNumQueries(4):
             response = self.client.get(
                 reverse('api:repository-retrieve', kwargs={'pk': str(self.repo_2.id)}),
                 HTTP_AUTHORIZATION=f'Ponos {task.token}',
@@ -215,16 +174,12 @@ class TestRepositories(FixtureTestCase):
 
         self.assertDictEqual(response.json(), {
             'id': str(self.repo_2.id),
-            'enabled': True,
-            'git_clone_url': None,
             'url': self.repo_2.url,
             'workers': [],
             'authorized_users': self.repo_2.memberships.count(),
         })
 
     def test_repository_retrieve_disabled_repo(self):
-        self.repo_2.credentials = None
-        self.repo_2.save()
         self.repo_2.memberships.create(user=self.user, level=Role.Guest.value)
         self.client.force_login(self.user)
         with self.assertNumQueries(5):
@@ -233,8 +188,6 @@ class TestRepositories(FixtureTestCase):
         data = response.json()
         self.assertDictEqual(data, {
             'id': str(self.repo_2.id),
-            'enabled': False,
-            'git_clone_url': None,
             'url': self.repo_2.url,
             'workers': [],
             'authorized_users': self.repo_2.memberships.count(),
@@ -242,10 +195,10 @@ class TestRepositories(FixtureTestCase):
 
     def test_repository_delete_not_admin(self):
         """
-        A user cannot delete a repository if he has no admin access, even if the repository is based on its credentials
+        A user cannot delete a repository if he has no admin access
         """
         creator = User.objects.create()
-        repo = Repository.objects.create(credentials=creator.credentials.create(), url='http://somewhere.com/repo')
+        repo = Repository.objects.create(url='http://somewhere.com/repo')
         repo.memberships.create(user=creator, level=Role.Contributor.value)
         self.client.force_login(creator)
         response = self.client.delete(reverse('api:repository-retrieve', kwargs={'pk': str(repo.id)}))
@@ -300,105 +253,3 @@ class TestRepositories(FixtureTestCase):
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         data = response.json()
         self.assertDictEqual(data, self.serialized_revision)
-
-    @patch('arkindex.users.models.OAuthCredentials.git_provider_class')
-    def test_list_repositories(self, git_provider_mock):
-        repos = [MagicMock(id=i) for i in range(1, 4)]
-        git_provider_mock().list_repos.return_value = repos
-        git_provider_mock().to_dict = lambda repo: {
-            'id': repo.id,
-            'name': f'Repository {repo.id}',
-            'url': f'http://repo_{repo.id}'
-        }
-
-        self.client.force_login(self.user)
-        response = self.client.get(
-            reverse('api:available-repositories', kwargs={'pk': self.creds.id})
-        )
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
-        self.assertEqual(response.json(), [
-            {'id': 1, 'name': 'Repository 1', 'url': 'http://repo_1'},
-            {'id': 2, 'name': 'Repository 2', 'url': 'http://repo_2'},
-            {'id': 3, 'name': 'Repository 3', 'url': 'http://repo_3'}
-        ])
-
-    def test_list_repositories_wrong_creds(self):
-        self.client.force_login(self.user)
-        response = self.client.get(
-            reverse('api:available-repositories', kwargs={'pk': '12341234-1234-1234-1234-123412341234'})
-        )
-        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
-
-    def test_list_repositories_create_id_required(self):
-        self.client.force_login(self.user)
-        response = self.client.post(reverse('api:available-repositories', kwargs={'pk': self.creds.id}))
-        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertEqual(response.json(), {'id': ['This field is required.']})
-
-    @patch('arkindex.users.models.OAuthCredentials.git_provider_class')
-    @patch('arkindex.process.models.Process.run')
-    def test_list_repositories_create_workers_repo(self, process_run_mock, git_provider_mock):
-        """
-        Importing a workers repository creates a workers process
-        """
-        self.client.force_login(self.user)
-        git_provider_mock().get_or_create_revision.return_value = self.rev, None
-        repo = Repository.objects.create(url='http://somewhere.com/repo')
-        git_provider_mock().create_repo.return_value = repo
-
-        with self.assertNumQueries(15):
-            response = self.client.post(reverse('api:available-repositories', kwargs={'pk': self.creds.id}), {'id': 1111})
-            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
-
-        process = Process.objects.get(revision=self.rev)
-        self.assertEqual(response.json(), {
-            'name': 'Import 1337 from http://my_repo.fake/workers/worker',
-            'id': str(process.id),
-            'corpus': None,
-            'element': None,
-            'element_type': None,
-            'ml_class_id': None,
-            'load_children': False,
-            'use_cache': False,
-            'use_gpu': False,
-            'activity_state': ActivityState.Disabled.value,
-            'element_name_contains': None,
-            'files': [],
-            'folder_type': None,
-            'mode': ProcessMode.Repository.value,
-            'revision': self.serialized_revision,
-            'state': State.Unscheduled.value,
-            'template_id': None,
-            'model_id': None,
-            'train_folder_id': None,
-            'validation_folder_id': None,
-            'test_folder_id': None,
-        })
-
-        # Thumbnails are not generated for Workers processes
-        self.assertEqual(process_run_mock.call_count, 1)
-        _, kwargs = process_run_mock.call_args
-        self.assertDictEqual(kwargs, {})
-        self.assertIsNone(process.corpus)
-        self.assertEqual(process.farm, self.farm)
-
-        # User is granted an admin access to the repository
-        repo_right = repo.memberships.get(user=self.user)
-        self.assertTrue(repo_right.level >= Role.Admin.value)
-
-    @patch('arkindex.users.models.OAuthCredentials.git_provider_class')
-    def test_add_repository_farm_guest(self, git_provider_mock):
-        self.client.force_login(self.user)
-        git_provider_mock().get_or_create_revision.return_value = self.rev, None
-        repo = Repository.objects.create(url='http://somewhere.com/repo')
-        git_provider_mock().create_repo.return_value = repo
-        self.farm.memberships.filter(user=self.user).delete()
-
-        with self.assertNumQueries(12):
-            response = self.client.post(reverse('api:available-repositories', kwargs={'pk': self.creds.id}), {'id': 1111})
-            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-
-        self.assertListEqual(response.json(), [
-            'The owner of the OAuth credentials does not have access to the default farm.',
-        ])
-        self.assertFalse(self.rev.processes.exists())
diff --git a/arkindex/process/tests/test_signals.py b/arkindex/process/tests/test_signals.py
index 5b73f455ef16a9d73baf70fa28fe85167923d7b5..edb82f701fdc1fc963784d717aff7ef727549aa1 100644
--- a/arkindex/process/tests/test_signals.py
+++ b/arkindex/process/tests/test_signals.py
@@ -12,6 +12,7 @@ from arkindex.ponos.models import Farm, State
 from arkindex.process.models import (
     ActivityState,
     ProcessMode,
+    Repository,
     Worker,
     WorkerActivityState,
     WorkerRun,
@@ -29,8 +30,7 @@ class TestSignals(FixtureAPITestCase):
     @classmethod
     def setUpTestData(cls):
         super().setUpTestData()
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get(url='http://my_repo.fake/workers/worker')
+        cls.repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
         cls.rev_1 = cls.repo.revisions.get()
         cls.rev_2 = cls.repo.revisions.create(
             hash='2',
diff --git a/arkindex/process/tests/test_worker_configurations.py b/arkindex/process/tests/test_worker_configurations.py
index a43e80f17d2f86c48e7c7860565c4376d7b999bb..519acc815723a5dc654e48b0d6e891bfd604a992 100644
--- a/arkindex/process/tests/test_worker_configurations.py
+++ b/arkindex/process/tests/test_worker_configurations.py
@@ -1,7 +1,7 @@
 from django.urls import reverse
 from rest_framework import status
 
-from arkindex.process.models import Revision, Worker
+from arkindex.process.models import Repository, Revision, Worker
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex.users.models import Role
 
@@ -11,8 +11,7 @@ class TestWorkerConfigurations(FixtureAPITestCase):
     @classmethod
     def setUpTestData(cls):
         super().setUpTestData()
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get(url='http://my_repo.fake/workers/worker')
+        cls.repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
         # User is the creator of the repository
         cls.repo.memberships.create(user=cls.user, level=Role.Admin.value)
         cls.rev = cls.repo.revisions.get()
diff --git a/arkindex/process/tests/test_workerruns.py b/arkindex/process/tests/test_workerruns.py
index cc08879e405276a4dbbef5e30d1f785b47ccbcd3..e4fa6e254afa8ffd3ca27ef4d30626d69bedecea 100644
--- a/arkindex/process/tests/test_workerruns.py
+++ b/arkindex/process/tests/test_workerruns.py
@@ -1,6 +1,5 @@
 import uuid
 from datetime import datetime, timezone
-from unittest.mock import patch
 
 from django.test import override_settings
 from django.urls import reverse
@@ -10,6 +9,7 @@ from rest_framework.exceptions import ValidationError
 from arkindex.ponos.models import Agent, Artifact, Farm, State
 from arkindex.process.models import (
     FeatureUsage,
+    GitRef,
     GitRefType,
     ProcessMode,
     Revision,
@@ -58,9 +58,6 @@ class TestWorkerRuns(FixtureAPITestCase):
         # Add an execution access right on the worker
         cls.worker_1.memberships.create(user=cls.user, level=Role.Contributor.value)
 
-        cls.creds = cls.user.credentials.get()
-        cls.gl_patch = patch('arkindex.process.providers.Gitlab')
-
         # Model and Model version setup
         cls.model_1 = Model.objects.create(name='My model')
         cls.model_1.memberships.create(user=cls.user, level=Role.Contributor.value)
@@ -846,10 +843,7 @@ class TestWorkerRuns(FixtureAPITestCase):
         """
         Check the GitRefs are retrieved with the revision
         """
-        from arkindex.process.providers import GitLabProvider
-
         # Create gitrefs and check they were created
-        self.gl_mock = self.gl_patch.start()
         commit_refs = [
             {'name': 'refs/tags/v0.1.0', 'type': 'tag'},
             {'name': 'refs/heads/branch1', 'type': 'branch'},
@@ -863,8 +857,7 @@ class TestWorkerRuns(FixtureAPITestCase):
         )
 
         for ref in commit_refs:
-            GitLabProvider(credentials=self.creds) \
-                .update_or_create_ref(self.repo, revision, ref['name'], ref['type'])
+            GitRef.objects.create(repository=self.repo, revision=revision, name=ref['name'], type=ref['type'])
 
         refs = [
             {'name': ref.name, 'type': ref.type, 'repo': ref.repository}
diff --git a/arkindex/process/tests/test_workers.py b/arkindex/process/tests/test_workers.py
index b77525c42e4395d99887be965cc0de80fac0454f..fff0e0d05f5b2d1bc211cd9567d0e98f7ea69c1b 100644
--- a/arkindex/process/tests/test_workers.py
+++ b/arkindex/process/tests/test_workers.py
@@ -32,8 +32,7 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
     @classmethod
     def setUpTestData(cls):
         super().setUpTestData()
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get(url='http://my_repo.fake/workers/worker')
+        cls.repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
         # User is the creator of the repository
         cls.repo.memberships.create(user=cls.user, level=Role.Admin.value)
         cls.rev = cls.repo.revisions.get()
@@ -436,9 +435,7 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
 
     def test_workers_list_filter_repository(self):
         repo2 = Repository.objects.create(
-            url='http://gitlab/repo2',
-            hook_token='hook-token2',
-            credentials=self.creds,
+            url='http://gitlab/repo2'
         )
         worker_2 = Worker.objects.create(
             repository=repo2,
@@ -478,9 +475,7 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
         A user can retrieve a worker by having contributor access on its repository
         """
         repo2 = Repository.objects.create(
-            url='http://gitlab/repo2',
-            hook_token='hook-token2',
-            credentials=self.creds,
+            url='http://gitlab/repo2'
         )
         worker_2 = repo2.workers.create(name='Worker 2', slug='worker_2', type=self.worker_type_dla)
         repo2.memberships.create(user=self.user, level=Role.Contributor.value)
@@ -1370,7 +1365,7 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
             hash='1337',
             message='A worker import I am admin on',
             author='Yann',
-            repo=self.creds.repos.get(url='http://gitlab/repo')
+            repo=Repository.objects.get(url='http://gitlab/repo')
         )
 
         with self.assertNumQueries(4):
diff --git a/arkindex/project/api_v1.py b/arkindex/project/api_v1.py
index e8d119d879cee29545e314fd39828e358925e612..fa57741099bb0ed914add56b844216d16c7664f9 100644
--- a/arkindex/project/api_v1.py
+++ b/arkindex/project/api_v1.py
@@ -77,7 +77,6 @@ from arkindex.ponos.api import (
 )
 from arkindex.process.api import (
     ApplyProcessTemplate,
-    AvailableRepositoriesList,
     BucketList,
     ClearProcess,
     CorpusProcess,
@@ -89,7 +88,6 @@ from arkindex.process.api import (
     DataFileList,
     DataFileRetrieve,
     FilesProcess,
-    GitRepositoryImportHook,
     ListProcessElements,
     ProcessDatasetManage,
     ProcessDatasets,
@@ -138,8 +136,6 @@ from arkindex.training.api import (
     ValidateModelVersion,
 )
 from arkindex.users.api import (
-    CredentialsList,
-    CredentialsRetrieve,
     GenericMembershipCreate,
     GenericMembershipsList,
     GroupDetails,
@@ -147,12 +143,8 @@ from arkindex.users.api import (
     JobList,
     JobRetrieve,
     MembershipDetails,
-    OAuthCallback,
-    OAuthRetry,
-    OAuthSignIn,
     PasswordReset,
     PasswordResetConfirm,
-    ProvidersList,
     UserCreate,
     UserEmailLogin,
     UserEmailVerification,
@@ -267,8 +259,6 @@ api = [
     # Git import workflows
     path('process/repos/', RepositoryList.as_view(), name='repository-list'),
     path('process/repos/<uuid:pk>/', RepositoryRetrieve.as_view(), name='repository-retrieve'),
-    path('process/repos/search/<uuid:pk>/', AvailableRepositoriesList.as_view(), name='available-repositories'),
-    path('imports/hook/<uuid:pk>/', GitRepositoryImportHook.as_view(), name='import-hook'),
     path('process/revisions/<uuid:pk>/', RevisionRetrieve.as_view(), name='revision-retrieve'),
 
     # Workers
@@ -328,14 +318,6 @@ api = [
     path('image/<uuid:pk>/', ImageRetrieve.as_view(), name='image-retrieve'),
     path('image/<uuid:pk>/elements/', ImageElements.as_view(), name='image-elements'),
 
-    # Manage OAuth integrations
-    path('oauth/providers/', ProvidersList.as_view(), name='providers-list'),
-    path('oauth/providers/<provider>/signin/', OAuthSignIn.as_view(), name='oauth-signin'),
-    path('oauth/providers/<provider>/callback/', OAuthCallback.as_view(), name='oauth-callback'),
-    path('oauth/credentials/', CredentialsList.as_view(), name='credentials-list'),
-    path('oauth/credentials/<uuid:pk>/', CredentialsRetrieve.as_view(), name='credentials-retrieve'),
-    path('oauth/credentials/<uuid:pk>/retry/', OAuthRetry.as_view(), name='oauth-retry'),
-
     # Authentication
     path('user/', UserRetrieve.as_view(), name='user-retrieve'),
     path('user/new/', UserCreate.as_view(), name='user-new'),
diff --git a/arkindex/project/checks.py b/arkindex/project/checks.py
index 9a16474737878f89300d5814997348b7e4fa2a4f..c7205f95830116266edf8d8e622f303ce1ed7681 100644
--- a/arkindex/project/checks.py
+++ b/arkindex/project/checks.py
@@ -116,28 +116,6 @@ def ponos_env_check(*args, **kwargs):
     return errors
 
 
-@register()
-@only_runserver
-def gitlab_oauth_check(*args, **kwargs):
-    from django.conf import settings
-    warnings = []
-    app_id = getattr(settings, 'GITLAB_APP_ID', None)
-    app_secret = getattr(settings, 'GITLAB_APP_SECRET', None)
-    if not app_id:
-        warnings.append(Warning(
-            'GitLab app ID is not set; Git imports will fail.',
-            hint='settings.GITLAB_APP_ID = {}'.format(repr(app_id)),
-            id='arkindex.W003',
-        ))
-    if not app_secret:
-        warnings.append(Warning(
-            'GitLab app secret is not set; Git imports will fail.',
-            hint='settings.GITLAB_APP_SECRET = {}'.format(repr(app_secret)),
-            id='arkindex.W004',
-        ))
-    return warnings
-
-
 @register()
 @only_runserver
 def s3_check(*args, **kwargs):
diff --git a/arkindex/project/settings.py b/arkindex/project/settings.py
index 22867b41cb5afe585132368e266ec8ae6582a8fe..2e3eab3e7d18ac7ed09ff67d5831c1e941aff9ea 100644
--- a/arkindex/project/settings.py
+++ b/arkindex/project/settings.py
@@ -280,7 +280,6 @@ SPECTACULAR_SETTINGS = {
             'description': 'Machine Learning models training',
         },
         {'name': 'datasets'},
-        {'name': 'oauth'},
         {'name': 'ponos'},
         {'name': 'repos'},
         {'name': 'search'},
@@ -310,9 +309,6 @@ IIIF_DOWNLOAD_TIMEOUT = (30, 60)
 # check_images sample size when checking all servers
 CHECK_IMAGES_SAMPLE_SIZE = 20
 
-# GitLab OAuth
-GITLAB_APP_ID = conf['gitlab']['app_id']
-GITLAB_APP_SECRET = conf['gitlab']['app_secret']
 
 if conf['cache']['type'] is None:
     conf['cache']['type'] = CacheType.Dummy if DEBUG else CacheType.Memory
@@ -586,12 +582,6 @@ LICENSE_KEY = conf['license']['key']
 LICENSE_PING_FREQUENCY = conf['license']['ping_frequency']
 LICENSE_HOSTNAME = conf['license']['hostname']
 
-# Specific setting to enable GitLab webhook when using PageKite, it should not be used in production.
-# It is used to change GitLab webhook URLs to go through a specified PageKite domain instead of localhost.
-# None by default.
-# You can override its value through local_settings.py file by assigning it 'http://YOURDOMAIN.pagekite.me'
-BACKEND_PUBLIC_URL_OAUTH = None
-
 # Optional default group to add new users to when they complete email verification
 SIGNUP_DEFAULT_GROUP = conf['signup_default_group']
 
diff --git a/arkindex/project/tests/test_checks.py b/arkindex/project/tests/test_checks.py
index 222238e8b90c639ce5c3f47ed35cbac603eef832..214be549bec8bfb5d663ebd1c38d9ed614ba94cf 100644
--- a/arkindex/project/tests/test_checks.py
+++ b/arkindex/project/tests/test_checks.py
@@ -88,31 +88,6 @@ class ChecksTestCase(TestCase):
             ),
         ])
 
-    @override_settings()
-    def test_gitlab_oauth_check(self):
-        from arkindex.project.checks import gitlab_oauth_check
-
-        del settings.GITLAB_APP_ID
-        del settings.GITLAB_APP_SECRET
-
-        self.assertListEqual(gitlab_oauth_check(), [
-            Warning(
-                'GitLab app ID is not set; Git imports will fail.',
-                hint='settings.GITLAB_APP_ID = None',
-                id='arkindex.W003',
-            ),
-            Warning(
-                'GitLab app secret is not set; Git imports will fail.',
-                hint='settings.GITLAB_APP_SECRET = None',
-                id='arkindex.W004',
-            ),
-        ])
-
-        settings.GITLAB_APP_ID = '1234'
-        settings.GITLAB_APP_SECRET = 's3kr3t'
-
-        self.assertListEqual(gitlab_oauth_check(), [])
-
     @override_settings()
     def test_s3_check(self):
         from arkindex.project.checks import s3_check
diff --git a/arkindex/project/urls.py b/arkindex/project/urls.py
index de393c87a537550d9079297bc81e3af0b46014e9..7ecaae664800222d763829341b3b7df6ca98b09e 100644
--- a/arkindex/project/urls.py
+++ b/arkindex/project/urls.py
@@ -19,8 +19,6 @@ urlpatterns = [
     # Frontend URLs the backend needs with django.urls.reverse
     # Link sent via email for password resets
     path('user/reset/<uidb64>/<token>/', frontend_view.as_view(), name='password_reset_confirm'),
-    # Redirection URL for successful OAuth2 flows
-    path('process/credentials/', frontend_view.as_view(), name='credentials'),
     path('process/<uuid:pk>/<int:run>', frontend_view.as_view(), name='frontend-process-details'),
     # Link to the corpus management page, shown in the Django admin
     path('corpus/<uuid:pk>', frontend_view.as_view(), name='frontend-corpus-details'),
diff --git a/arkindex/users/admin.py b/arkindex/users/admin.py
index aac4399da50225f15ece65e24a2f917000966f4b..74a14398a9fc7bb6930e3e73e11848ba52e464a8 100644
--- a/arkindex/users/admin.py
+++ b/arkindex/users/admin.py
@@ -7,7 +7,7 @@ from django.contrib.contenttypes.admin import GenericTabularInline
 from django.db.models.functions import Collate
 from enumfields.admin import EnumFieldListFilter
 
-from arkindex.users.models import Group, OAuthCredentials, Right, User, UserScope
+from arkindex.users.models import Group, Right, User, UserScope
 
 
 class UserCreationForm(forms.ModelForm):
@@ -122,25 +122,7 @@ class GroupAdmin(admin.ModelAdmin):
     inlines = (UserMembershipInline, )
 
 
-class OAuthCredentialAdmin(admin.ModelAdmin):
-    list_display = ('id', 'user', 'status')
-    list_filter = [('status', EnumFieldListFilter), ]
-    fields = ('id', 'user', 'token', 'refresh_token', 'expiry', 'status')
-    readonly_fields = ('id', )
-    search_fields = ('searchable_email', )
-
-    def get_queryset(self, request):
-        qs = super().get_queryset(request)
-        qs = qs.select_related('user')
-        # Django's search uses ILIKE, but LIKE is not supported in PostgreSQL with nondeterministic collations.
-        # We are using a case-insensitive collation to get unique case-insensitive emails, so to search properly,
-        # we first have to set the collation back to its default value, making it case-sensitive again;
-        # since Django uses ILIKE, it will be case-insensitive anyway.
-        return qs.annotate(searchable_email=Collate('user__email', 'default'))
-
-
 admin.site.register(User, UserAdmin)
-admin.site.register(OAuthCredentials, OAuthCredentialAdmin)
 # Register the custom GroupAdmin
 admin.site.register(Group, GroupAdmin)
 # and hide base GroupAdmin form contrib.auth
diff --git a/arkindex/users/api.py b/arkindex/users/api.py
index 8cb07fe06ea27bd1b89455821abd4c037b85598a..2cfb72e25b57d75ed03492f6d44419b9222b99c9 100644
--- a/arkindex/users/api.py
+++ b/arkindex/users/api.py
@@ -5,7 +5,6 @@ from uuid import UUID
 from django.conf import settings
 from django.contrib.auth import login, logout
 from django.contrib.auth.forms import PasswordResetForm
-from django.contrib.auth.mixins import UserPassesTestMixin
 from django.contrib.auth.tokens import default_token_generator
 from django.contrib.contenttypes.models import ContentType
 from django.core.mail import send_mail
@@ -14,18 +13,16 @@ from django.shortcuts import get_object_or_404
 from django.template.loader import render_to_string
 from django.urls import reverse
 from django.utils.http import urlsafe_base64_encode
-from django.views.generic import RedirectView
 from django_rq.queues import get_queue
 from django_rq.settings import QUEUES
 from drf_spectacular.types import OpenApiTypes
-from drf_spectacular.utils import OpenApiParameter, extend_schema, extend_schema_view, inline_serializer
+from drf_spectacular.utils import OpenApiParameter, extend_schema, extend_schema_view
 from rest_framework import serializers, status
 from rest_framework.exceptions import AuthenticationFailed, NotFound, PermissionDenied, ValidationError
 from rest_framework.generics import (
     CreateAPIView,
     ListAPIView,
     ListCreateAPIView,
-    RetrieveAPIView,
     RetrieveDestroyAPIView,
     RetrieveUpdateDestroyAPIView,
 )
@@ -38,8 +35,7 @@ from arkindex.documents.models import Corpus
 from arkindex.process.models import Worker
 from arkindex.project.mixins import ACLMixin, WorkerACLMixin
 from arkindex.project.permissions import IsAuthenticatedOrReadOnly, IsVerified
-from arkindex.users import providers
-from arkindex.users.models import Group, OAuthCredentials, OAuthStatus, Right, Role, Scope, User, UserScope
+from arkindex.users.models import Group, Right, Role, Scope, User, UserScope
 from arkindex.users.serializers import (
     EmailLoginSerializer,
     GenericMembershipSerializer,
@@ -49,9 +45,6 @@ from arkindex.users.serializers import (
     MembershipCreateSerializer,
     MembershipSerializer,
     NewUserSerializer,
-    OAuthCredentialsSerializer,
-    OAuthProviderClassSerializer,
-    OAuthRetrySerializer,
     PasswordResetConfirmSerializer,
     PasswordResetSerializer,
     UserSerializer,
@@ -61,64 +54,6 @@ from arkindex.users.utils import RightContent, get_max_level
 logger = logging.getLogger(__name__)
 
 
-@extend_schema_view(get=extend_schema(operation_id='ListOAuthProviders', tags=['oauth']))
-class ProvidersList(ListAPIView):
-    """
-    List supported OAuth providers
-    """
-    permission_classes = (IsVerified, )
-    serializer_class = OAuthProviderClassSerializer
-    pagination_class = None
-
-    def get_queryset(self):
-        return list(filter(lambda p: p.enabled(), providers.oauth_providers))
-
-
-@extend_schema(
-    tags=['oauth'],
-    parameters=[
-        OpenApiParameter(
-            'status',
-            description='Filter OAuth credentials by their status',
-            required=False,
-            enum=[status.value for status in OAuthStatus],
-        )
-    ]
-)
-class CredentialsList(ListAPIView):
-    """
-    List all OAuth credentials for the authenticated user.
-    """
-    permission_classes = (IsVerified, )
-    serializer_class = OAuthCredentialsSerializer
-
-    def get_queryset(self):
-        qs = self.request.user.credentials.order_by('id')
-        if 'status' in self.request.query_params:
-            qs = qs.filter(status=self.request.query_params['status'])
-        return qs
-
-
-@extend_schema(tags=['oauth'])
-@extend_schema_view(
-    delete=extend_schema(description='Delete OAuth credentials. This may disable access to some Git repositories.')
-)
-class CredentialsRetrieve(RetrieveDestroyAPIView):
-    """
-    Retrieve OAuth credentials.
-    """
-    permission_classes = (IsVerified, )
-    serializer_class = OAuthCredentialsSerializer
-    queryset = OAuthCredentials.objects.none()
-
-    def get_queryset(self):
-        return self.request.user.credentials.order_by('id')
-
-    def perform_destroy(self, instance):
-        instance.provider_class(credentials=instance).disconnect()
-        super().perform_destroy(instance)
-
-
 @extend_schema(tags=['users'])
 @extend_schema_view(
     get=extend_schema(description='Retrieve information about the authenticated user'),
@@ -355,114 +290,6 @@ class PasswordResetConfirm(CreateAPIView):
     serializer_class = PasswordResetConfirmSerializer
 
 
-class OAuthSignIn(APIView):
-    """
-    Start the OAuth authentication code flow for a given provider
-    """
-    permission_classes = (IsVerified, )
-    queryset = OAuthCredentials.objects.none()
-
-    @extend_schema(
-        operation_id='StartOAuthSignIn',
-        tags=['oauth'],
-        parameters=[
-            OpenApiParameter(
-                'provider',
-                location=OpenApiParameter.PATH,
-                required=True,
-                description='Provider name',
-            )
-        ],
-        responses=inline_serializer(
-            name='OAuthSignInResponse',
-            fields={'url': serializers.URLField(required=False, help_text="URL to the authorization endpoint.")}
-        )
-    )
-    def get(self, *args, **kwargs):
-        if 'provider' not in kwargs:
-            raise ValidationError('Missing provider')
-
-        provider_class = providers.get_provider(kwargs['provider'])
-        if not provider_class:
-            raise ValidationError('Unknown provider')
-
-        url = self.request.GET.get('url', provider_class.default_url)
-        if url:
-            parsed = urllib.parse.urlparse(url)
-            if (parsed.scheme != 'https'
-                    or parsed.netloc == ''
-                    or parsed.params != ''
-                    or parsed.query != ''
-                    or parsed.fragment != ''):
-                raise ValidationError('Invalid GitLab instance URL')
-
-        # Create OAuthCredentials without a token
-        creds = self.request.user.credentials.create(
-            provider_url=url,
-        )
-
-        return Response({
-            'url': provider_class(credentials=creds).get_authorize_uri(),
-        })
-
-
-@extend_schema_view(get=extend_schema(operation_id='RetryOAuthCredentials', tags=['oauth']))
-class OAuthRetry(RetrieveAPIView):
-    """
-    Retry the OAuth authentication code flow for pending credentials
-    """
-    permission_classes = (IsVerified, )
-    serializer_class = OAuthRetrySerializer
-    queryset = OAuthCredentials.objects.none()
-
-    def get_queryset(self):
-        return self.request.user.credentials
-
-    def get_object(self):
-        creds = super().get_object()
-        if creds.status == OAuthStatus.Done:
-            self.permission_denied()
-        return creds
-
-    def retrieve(self, request, *args, **kwargs):
-        creds = self.get_object()
-        return Response({
-            'url': creds.provider_class(credentials=creds).get_authorize_uri(),
-        })
-
-
-class OAuthCallback(UserPassesTestMixin, RedirectView):
-    """
-    Callback for OAuth responses
-    """
-    pattern_name = 'credentials'
-    permission_classes = (IsVerified, )
-    raise_exception = True
-
-    def test_func(self):
-        """
-        Perform Django REST framework permission checks, but without REST framework.
-        """
-        return all(perm().has_permission(self.request, self) for perm in self.permission_classes)
-
-    def get(self, request, *args, **kwargs):
-        assert 'provider' in kwargs
-        provider_class = providers.get_provider(kwargs['provider'])
-        if not provider_class:
-            raise ValueError('Unknown provider')
-        provider = provider_class()
-        try:
-            provider.handle_callback(request)
-            provider.credentials.status = OAuthStatus.Done
-        except Exception as e:
-            if not provider.credentials:
-                raise
-            provider.credentials.status = OAuthStatus.Error
-            logger.warning(f'OAuth callback error: {e}', exc_info=e)
-        provider.credentials.save()
-        return super().get(request)
-
-
 @extend_schema(tags=['users'])
 class GroupsList(ListCreateAPIView):
     """
diff --git a/arkindex/users/migrations/0001_initial.py b/arkindex/users/migrations/0001_initial.py
index f09617397f666eddc783a58aa24b3385cf1e5eef..8dc6ec7c91d5a901bf65dbb8841a1bff6604f496 100644
--- a/arkindex/users/migrations/0001_initial.py
+++ b/arkindex/users/migrations/0001_initial.py
@@ -8,10 +8,17 @@ import enumfields.fields
 from django.conf import settings
 from django.contrib.postgres.operations import CreateCollation
 from django.db import migrations, models
+from enumfields import Enum
 
 import arkindex.users.models
 
 
+class OAuthStatus(Enum):
+    Created = 'created'
+    Done = 'done'
+    Error = 'error'
+
+
 class Migration(migrations.Migration):
 
     initial = True
@@ -70,7 +77,7 @@ class Migration(migrations.Migration):
             fields=[
                 ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
                 ('provider_url', models.URLField()),
-                ('status', enumfields.fields.EnumField(default='created', enum=arkindex.users.models.OAuthStatus, max_length=10)),
+                ('status', enumfields.fields.EnumField(default='created', enum=OAuthStatus, max_length=10)),
                 ('token', models.CharField(blank=True, max_length=64, null=True)),
                 ('refresh_token', models.CharField(blank=True, max_length=64, null=True)),
                 ('expiry', models.DateTimeField(blank=True, null=True)),
diff --git a/arkindex/users/migrations/0003_delete_oauthcredentials.py b/arkindex/users/migrations/0003_delete_oauthcredentials.py
new file mode 100644
index 0000000000000000000000000000000000000000..d124d8dba938962c9b821fd8d445bb9084516ad2
--- /dev/null
+++ b/arkindex/users/migrations/0003_delete_oauthcredentials.py
@@ -0,0 +1,17 @@
+# Generated by Django 4.1.7 on 2023-12-20 11:43
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('process', '0026_remove_repository_unique_repository_hook_token_and_more'),
+        ('users', '0002_remove_user_transkribus_email'),
+    ]
+
+    operations = [
+        migrations.DeleteModel(
+            name='OAuthCredentials',
+        ),
+    ]
diff --git a/arkindex/users/models.py b/arkindex/users/models.py
index 3764f14854abf7be672a32b30d39380702c30d51..db686b0494c25536cfc57430677cc82482cba997 100644
--- a/arkindex/users/models.py
+++ b/arkindex/users/models.py
@@ -1,5 +1,4 @@
 import uuid
-from datetime import datetime, timezone
 
 from django.conf import settings
 from django.contrib.auth.models import AbstractBaseUser
@@ -12,7 +11,6 @@ from enumfields import Enum, EnumField
 from rq.utils import as_text
 
 from arkindex.users.managers import UserManager
-from arkindex.users.providers import get_provider
 
 
 class Role(Enum):
@@ -186,55 +184,6 @@ class Group(models.Model):
         return self.name
 
 
-class OAuthStatus(Enum):
-    Created = 'created'
-    Done = 'done'
-    Error = 'error'
-
-
-class OAuthCredentials(models.Model):
-    id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False)
-    user = models.ForeignKey('users.User', on_delete=models.CASCADE, related_name='credentials')
-    provider_url = models.URLField()
-    status = EnumField(OAuthStatus, default=OAuthStatus.Created)
-    token = models.CharField(max_length=64, blank=True, null=True)
-    refresh_token = models.CharField(max_length=64, blank=True, null=True)
-    expiry = models.DateTimeField(blank=True, null=True)
-    account_name = models.CharField(max_length=100, blank=True, null=True)
-
-    def __str__(self):
-        token_str = f"- {self.token[:6]}" if self.token else ''
-        return f"{self.provider_name} - {self.user.email} {token_str}".strip()
-
-    # Make this constant into a database field to be able to handle OAuth with services other than GitLab
-    provider_name = 'gitlab'
-
-    @property
-    def provider_class(self):
-        return get_provider(self.provider_name)
-
-    @property
-    def provider(self):
-        return self.provider_class(credentials=self)
-
-    @property
-    def git_provider_class(self):
-        from arkindex.process.providers import from_oauth
-        return from_oauth(self.provider_name)
-
-    @property
-    def git_provider(self):
-        return self.git_provider_class(credentials=self)
-
-    @property
-    def expired(self):
-        return self.expiry is None or self.expiry < datetime.now(timezone.utc)
-
-    class Meta:
-        verbose_name = 'OAuth credentials'
-        verbose_name_plural = 'OAuth credentials'
-
-
 class Scope(Enum):
 
     UploadS3Image = 'upload_s3_image'
diff --git a/arkindex/users/providers.py b/arkindex/users/providers.py
deleted file mode 100644
index c30fcb2367013f9c952a48331bfbe3a8e2a98f3d..0000000000000000000000000000000000000000
--- a/arkindex/users/providers.py
+++ /dev/null
@@ -1,199 +0,0 @@
-import urllib.parse
-from abc import ABC, abstractmethod
-from datetime import datetime, timedelta, timezone
-
-import requests
-from django.conf import settings
-from django.urls import reverse
-from gitlab import Gitlab, GitlabError
-from rest_framework.exceptions import AuthenticationFailed, NotAuthenticated
-
-
-class OAuthProvider(ABC):
-    """
-    An OAuth authentication provider.
-    """
-
-    display_name = ""
-    slug = ""
-
-    def __init__(self, credentials=None, url=None):
-        if credentials is not None:
-            from arkindex.users.models import OAuthCredentials
-            assert isinstance(credentials, OAuthCredentials)
-        self.credentials = credentials
-
-    @classmethod
-    @abstractmethod
-    def enabled(cls):
-        """
-        Boolean stating the provider's availability.
-        """
-
-    @abstractmethod
-    def get_callback_uri(self):
-        """
-        Get the OAuth callback URI
-        """
-
-    @abstractmethod
-    def get_authorize_uri(self):
-        """
-        Get the OAuth authorization endpoint URI
-        """
-
-    @abstractmethod
-    def handle_callback(self, request):
-        """
-        Handle a OAuth callback and save token data. Should raise exceptions if the process fails.
-        """
-
-    @abstractmethod
-    def refresh_token(self):
-        """
-        Refresh an expired OAuth token and update OAuthCredentials attributes.
-        """
-
-    @abstractmethod
-    def disconnect(self):
-        """
-        Erase token data and logout the user from the service.
-        """
-
-
-class GitLabOAuthProvider(OAuthProvider):
-
-    display_name = 'GitLab'
-    slug = 'gitlab'
-    default_url = 'https://gitlab.com'
-    authorize_endpoint = '/oauth/authorize'
-    token_endpoint = '/oauth/token'
-
-    @classmethod
-    def enabled(cls):
-        return settings.GITLAB_APP_ID and settings.GITLAB_APP_SECRET
-
-    def get_callback_uri(self):
-        url = reverse('api:oauth-callback', kwargs={'provider': self.slug})
-
-        if settings.BACKEND_PUBLIC_URL_OAUTH:
-            return urllib.parse.urljoin(settings.BACKEND_PUBLIC_URL_OAUTH, url)
-
-        assert settings.PUBLIC_HOSTNAME, 'PUBLIC_HOSTNAME is required to generate callback URIs'
-        return urllib.parse.urljoin(settings.PUBLIC_HOSTNAME, url)
-
-    def get_authorize_uri(self):
-        if not self.credentials:
-            return
-
-        return '{}?{}'.format(
-            urllib.parse.urljoin(self.credentials.provider_url, self.authorize_endpoint),
-            urllib.parse.urlencode({
-                'client_id': settings.GITLAB_APP_ID,
-                'redirect_uri': self.get_callback_uri(),
-                'scope': 'api',
-                'response_type': 'code',
-                'state': str(self.credentials.id),
-            }),
-        )
-
-    def handle_callback(self, request):
-        state = request.GET.get('state')
-        if not state:
-            raise ValueError('No state hash')
-
-        self.credentials = request.user.credentials.get(id=state)
-
-        if not any(param in request.GET for param in ('code', 'error')):
-            raise ValueError('Callback called without a valid response')
-        if 'error' in request.GET:
-            raise ValueError(request.GET.get('error_description', request.GET['error']))
-
-        from arkindex.users.models import OAuthStatus
-        assert self.credentials.status != OAuthStatus.Done, 'Cannot overwrite existing credentials'
-
-        self.grant_token(grant_type='authorization_code', code=request.GET.get('code', ''))
-
-    def refresh_token(self):
-        try:
-            assert self.credentials.refresh_token, 'No refresh token was stored for this OAuth token.'
-            self.grant_token(grant_type='refresh_token', refresh_token=self.credentials.refresh_token)
-        except Exception as e:
-            # Set an error state to allow the user to retry manually
-            from arkindex.users.models import OAuthStatus
-            self.credentials.status = OAuthStatus.Error
-            self.credentials.save()
-            raise AuthenticationFailed(
-                'The OAuth token could not be refreshed. Please reconnect the OAuth account manually.\n'
-                f'Original error: {e}'
-            )
-
-    def grant_token(self, **kwargs):
-        """
-        Use Doorkeeper's OAuth token endpoint to get a token, either from an OAuth authorization code flow
-        or when refreshing a token, and update the OAuthCredentials attributes.
-
-        https://github.com/doorkeeper-gem/doorkeeper/wiki/API-endpoint-descriptions-and-examples#post---oauthtoken
-        """
-        assert self.credentials is not None, 'An OAuthCredentials instance is required to use the OAuth token endpoint'
-
-        payload = {
-            'client_id': settings.GITLAB_APP_ID,
-            'client_secret': settings.GITLAB_APP_SECRET,
-            'redirect_uri': self.get_callback_uri(),
-        }
-        payload.update(kwargs)
-        response = requests.post(
-            urllib.parse.urljoin(self.credentials.provider_url, self.token_endpoint),
-            payload,
-        )
-        response.raise_for_status()
-        data = response.json()
-
-        assert 'access_token' in data, 'GitLab returned no OAuth token'
-        assert data.get('token_type', '').lower() == 'bearer', 'Unsupported OAuth token type'
-
-        self.credentials.token = data['access_token']
-        self.credentials.refresh_token = data.get('refresh_token')
-        # Get absolute date of expiration from the created_at UNIX timestamp and the seconds until expiration
-        self.credentials.expiry = datetime.fromtimestamp(data['created_at'], tz=timezone.utc) + timedelta(seconds=int(data['expires_in']))
-
-        gl = Gitlab(self.credentials.provider_url, oauth_token=self.credentials.token)
-        gl.auth()
-        self.credentials.account_name = gl.user.username
-
-        from arkindex.users.models import OAuthStatus
-        self.credentials.status = OAuthStatus.Done
-        self.credentials.save()
-
-    def disconnect(self):
-        if not self.credentials:
-            raise NotAuthenticated
-
-        if not self.credentials.token or not self.credentials.repos.exists():
-            return
-
-        # Remove all webhooks
-        try:
-            gl = Gitlab(self.credentials.provider_url, oauth_token=self.credentials.token)
-            for repo in self.credentials.repos.all():
-                project = gl.projects.get(urllib.parse.urlsplit(repo.url).path.strip('/'))
-                hook_url = urllib.parse.urljoin(
-                    settings.PUBLIC_HOSTNAME,
-                    reverse('api:import-hook', kwargs={'pk': repo.id})
-                )
-                # Try to find the webhook
-                hook = next((h for h in project.hooks.list() if h.url == hook_url), None)
-                if hook:
-                    hook.delete()
-        except GitlabError:
-            pass
-
-
-oauth_providers = [
-    GitLabOAuthProvider,
-]
-
-
-def get_provider(name):
-    return next(filter(lambda p: p.slug == name, oauth_providers), None)
diff --git a/arkindex/users/serializers.py b/arkindex/users/serializers.py
index 839c8696f71a3f9b1b6ff5abab86fe55ff449174..283124e5da19e2bbf4d384f7aa4c0729c548c984 100644
--- a/arkindex/users/serializers.py
+++ b/arkindex/users/serializers.py
@@ -11,8 +11,7 @@ from rest_framework.exceptions import PermissionDenied
 
 from arkindex.process.models import Worker
 from arkindex.project.mixins import WorkerACLMixin
-from arkindex.project.serializer_fields import EnumField
-from arkindex.users.models import Group, OAuthCredentials, OAuthStatus, Right, Role, User
+from arkindex.users.models import Group, Right, Role, User
 from arkindex.users.utils import RightContent, get_max_level
 
 
@@ -26,40 +25,6 @@ def validate_user_password(user, data):
     return data
 
 
-class OAuthCredentialsSerializer(serializers.ModelSerializer):
-
-    provider_name = serializers.CharField()
-    provider_display_name = serializers.CharField(source='provider_class.display_name')
-    status = EnumField(OAuthStatus)
-
-    class Meta:
-        model = OAuthCredentials
-        fields = (
-            'id',
-            'status',
-            'provider_name',
-            'provider_display_name',
-            'provider_url',
-            'account_name',
-        )
-
-
-class OAuthProviderClassSerializer(serializers.Serializer):
-
-    name = serializers.CharField(source='slug')
-    display_name = serializers.CharField()
-    default_url = serializers.URLField()
-
-
-class OAuthRetrySerializer(serializers.Serializer):
-    """
-    A serializer used by the OAuthRetry endpoint to return an authorization URL.
-    Required to get the OpenAPI schema generation to work.
-    """
-
-    url = serializers.URLField()
-
-
 class SimpleUserSerializer(serializers.ModelSerializer):
 
     class Meta:
diff --git a/arkindex/users/tests/test_credentials.py b/arkindex/users/tests/test_credentials.py
deleted file mode 100644
index 5669c7c7d3e5a5f96faa53802a39b403df9cb6ae..0000000000000000000000000000000000000000
--- a/arkindex/users/tests/test_credentials.py
+++ /dev/null
@@ -1,146 +0,0 @@
-import uuid
-
-from django.urls import reverse
-from rest_framework import status
-
-from arkindex.project.tests import FixtureTestCase
-from arkindex.users.models import OAuthCredentials, OAuthStatus, User
-
-
-class TestCredentials(FixtureTestCase):
-
-    @classmethod
-    def setUpTestData(cls):
-        super().setUpTestData()
-        cls.cred1 = cls.user.credentials.get()
-        cls.cred2 = cls.user.credentials.create(
-            provider_url='https://somewhere.else',
-            token='t0k3n',
-            status=OAuthStatus.Error,
-        )
-        cls.user2 = User.objects.create(email='user2@test.test', display_name='User 2', verified_email=True)
-        cls.cred3 = cls.user2.credentials.create(
-            provider_url='https://somewhere.else',
-            token='t0k3n',
-            status=OAuthStatus.Created,
-        )
-
-    def test_list_requires_login(self):
-        response = self.client.get(reverse('api:credentials-list'))
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-
-    def test_list(self):
-        self.client.force_login(self.user)
-        response = self.client.get(reverse('api:credentials-list'))
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
-        data = response.json()
-        self.assertCountEqual(data['results'], [
-            {
-                'id': str(self.cred1.id),
-                'status': 'created',
-                'provider_name': 'gitlab',
-                'provider_display_name': 'GitLab',
-                'provider_url': 'https://somewhere',
-                'account_name': None,
-            },
-            {
-                'id': str(self.cred2.id),
-                'status': 'error',
-                'provider_name': 'gitlab',
-                'provider_display_name': 'GitLab',
-                'provider_url': 'https://somewhere.else',
-                'account_name': None,
-            },
-        ])
-
-    def test_list_filtered(self):
-        self.client.force_login(self.user)
-        response = self.client.get(reverse('api:credentials-list'), {'status': 'error'})
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
-        data = response.json()
-        self.assertCountEqual(data['results'], [
-            {
-                'id': str(self.cred2.id),
-                'status': 'error',
-                'provider_name': 'gitlab',
-                'provider_display_name': 'GitLab',
-                'provider_url': 'https://somewhere.else',
-                'account_name': None,
-            },
-        ])
-
-    def test_credentials_retrieve_requires_login(self):
-        with self.assertNumQueries(0):
-            response = self.client.get(reverse('api:credentials-retrieve', kwargs={'pk': str(self.cred1.id)}))
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-
-    def test_credentials_retrieve_not_found(self):
-        fake_id = uuid.uuid4()
-        self.client.force_login(self.user)
-        with self.assertNumQueries(3):
-            response = self.client.get(reverse('api:credentials-retrieve', kwargs={'pk': str(fake_id)}))
-        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
-
-    def test_credentials_retrieve(self):
-        self.client.force_login(self.user)
-        with self.assertNumQueries(3):
-            response = self.client.get(reverse('api:credentials-retrieve', kwargs={'pk': str(self.cred1.id)}))
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
-        self.assertDictEqual(response.json(), {
-            'id': str(self.cred1.id),
-            'status': 'created',
-            'provider_name': 'gitlab',
-            'provider_display_name': 'GitLab',
-            'provider_url': 'https://somewhere',
-            'account_name': None,
-        })
-
-    def test_credentials_retrieve_wrong_user(self):
-        """
-        A user cannot retrieve another user's credentials
-        """
-        self.client.force_login(self.user)
-        with self.assertNumQueries(3):
-            response = self.client.get(reverse('api:credentials-retrieve', kwargs={'pk': str(self.cred3.id)}))
-        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
-
-    def test_credentials_display_with_token(self):
-        self.assertEqual(str(self.cred1), 'gitlab - user@user.fr - oauth-')
-
-    def test_credentials_display_no_token(self):
-        no_token = self.user.credentials.create(
-            provider_url='https://somewhere.else',
-            status=OAuthStatus.Created,
-        )
-        self.assertEqual(str(no_token), 'gitlab - user@user.fr')
-
-    def test_destroy_credentials_requires_logged_in(self):
-        with self.assertNumQueries(0):
-            response = self.client.delete(reverse('api:credentials-retrieve', kwargs={"pk": str(self.cred2.id)}))
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-        self.assertDictEqual(response.json(), {'detail': 'Authentication credentials were not provided.'})
-
-    def test_destroy_credentials_requires_verified(self):
-        self.user.verified_email = False
-        self.user.save()
-        self.client.force_login(self.user)
-        with self.assertNumQueries(2):
-            response = self.client.delete(reverse('api:credentials-retrieve', kwargs={"pk": str(self.cred2.id)}))
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-        self.assertDictEqual(response.json(), {'detail': 'You do not have permission to perform this action.'})
-
-    def test_destroy_credentials(self):
-        self.client.force_login(self.user)
-        with self.assertNumQueries(6):
-            response = self.client.delete(reverse('api:credentials-retrieve', kwargs={"pk": str(self.cred2.id)}))
-        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
-
-        # Make sure it does not exist anymore
-        with self.assertRaises(OAuthCredentials.DoesNotExist):
-            self.cred2.refresh_from_db()
-
-    def test_destroy_credentials_not_found(self):
-        self.client.force_login(self.user)
-        with self.assertNumQueries(3):
-            response = self.client.delete(reverse('api:credentials-retrieve', kwargs={"pk": str(uuid.uuid4())}))
-        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
diff --git a/arkindex/users/tests/test_generic_memberships.py b/arkindex/users/tests/test_generic_memberships.py
index 172789d620bb3edca8ddd5a17362aeb5adca7ad6..d35a130ee58169353d1e1e9638c14b0eb1c9887e 100644
--- a/arkindex/users/tests/test_generic_memberships.py
+++ b/arkindex/users/tests/test_generic_memberships.py
@@ -289,7 +289,7 @@ class TestMembership(FixtureAPITestCase):
         """
         A user is able to list members of a worker if he is a member of its repository
         """
-        repo = Repository.objects.get(hook_token='worker-hook-token')
+        repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
         worker = repo.workers.get(slug='reco')
         repo.memberships.create(user=self.user, level=Role.Guest.value)
         self.client.force_login(self.user)
@@ -784,7 +784,7 @@ class TestMembership(FixtureAPITestCase):
         """
         user = User.objects.create_user('test@test.de', 'Pa$$w0rd')
 
-        repo = Repository.objects.get(hook_token='worker-hook-token')
+        repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
         worker = repo.workers.get(slug='reco')
         repo.memberships.create(user=self.user, level=Role.Admin.value)
 
@@ -870,7 +870,7 @@ class TestMembership(FixtureAPITestCase):
         """
         Workers may specially have no member as they depends on a repository
         """
-        repo = Repository.objects.get(hook_token='worker-hook-token')
+        repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
         worker = repo.workers.get(slug='reco')
         membership = worker.memberships.create(user=self.user, level=Role.Admin.value)
         self.client.force_login(self.user)
@@ -951,7 +951,7 @@ class TestMembership(FixtureAPITestCase):
         """
         A worker member can inherit the right to add a member from its repository to edit a worker member
         """
-        repo = Repository.objects.get(hook_token='worker-hook-token')
+        repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
         worker = repo.workers.get(slug='reco')
         repo.memberships.create(user=self.user, level=Role.Admin.value)
 
@@ -999,7 +999,7 @@ class TestMembership(FixtureAPITestCase):
         """
         Workers may have no member as they depends on a repository
         """
-        repo = Repository.objects.get(hook_token='worker-hook-token')
+        repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
         worker = repo.workers.get(slug='reco')
         membership = worker.memberships.create(user=self.user, level=Role.Admin.value)
         self.client.force_login(self.user)
@@ -1051,7 +1051,7 @@ class TestMembership(FixtureAPITestCase):
         """
         A worker member can inherit the right to add a member from its repository to remove a worker member
         """
-        repo = Repository.objects.get(hook_token='worker-hook-token')
+        repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
         worker = repo.workers.get(slug='reco')
         repo.memberships.create(user=self.user, level=Role.Admin.value)
 
@@ -1066,13 +1066,13 @@ class TestMembership(FixtureAPITestCase):
             new_member.refresh_from_db()
 
     def test_right_unique_user(self):
-        repo = Repository.objects.get(hook_token='worker-hook-token')
+        repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
         repo.memberships.create(user=self.user, level=Role.Admin.value)
         with self.assertRaises(IntegrityError):
             repo.memberships.create(user=self.user, level=Role.Admin.value)
 
     def test_right_unique_group(self):
-        repo = Repository.objects.get(hook_token='worker-hook-token')
+        repo = Repository.objects.get(url='http://my_repo.fake/workers/worker')
         repo.memberships.create(group=self.group, level=Role.Admin.value)
         with self.assertRaises(IntegrityError):
             repo.memberships.create(group=self.group, level=Role.Admin.value)
diff --git a/arkindex/users/tests/test_gitlab_oauth.py b/arkindex/users/tests/test_gitlab_oauth.py
deleted file mode 100644
index a47f6ca89eb6d141dd42dfb878efa916b06414bc..0000000000000000000000000000000000000000
--- a/arkindex/users/tests/test_gitlab_oauth.py
+++ /dev/null
@@ -1,258 +0,0 @@
-import urllib.parse
-from unittest.mock import MagicMock, patch
-
-import responses
-from django.http.request import HttpRequest
-from django.test import override_settings
-from responses import matchers
-from rest_framework.exceptions import AuthenticationFailed
-
-from arkindex.project.tests import FixtureTestCase
-from arkindex.users.models import OAuthStatus
-from arkindex.users.providers import GitLabOAuthProvider
-
-
-class TestGitLabOAuthProvider(FixtureTestCase):
-
-    @classmethod
-    def setUpTestData(cls):
-        super().setUpTestData()
-        cls.creds = cls.user.credentials.get()
-        cls.gl_patch = patch('arkindex.users.providers.Gitlab')
-
-    def setUp(self):
-        super().setUp()
-        self.gl_mock = self.gl_patch.start()
-
-    def tearDown(self):
-        self.gl_patch.stop()
-        super().tearDown()
-
-    def test_enabled(self):
-        with self.settings(GITLAB_APP_ID=None, GITLAB_APP_SECRET=None):
-            self.assertFalse(GitLabOAuthProvider.enabled())
-        with self.settings(GITLAB_APP_ID='abcd', GITLAB_APP_SECRET='1234'):
-            self.assertTrue(GitLabOAuthProvider.enabled())
-
-    @override_settings(BACKEND_PUBLIC_URL_OAUTH='http://arkindex.localhost:8000', PUBLIC_HOSTNAME='http://arkindex.localhost:8080')
-    def test_callback_uri_dev_override(self):
-        self.assertEqual(GitLabOAuthProvider().get_callback_uri(), 'http://arkindex.localhost:8000/api/v1/oauth/providers/gitlab/callback/')
-
-    @override_settings(BACKEND_PUBLIC_URL_OAUTH=None, PUBLIC_HOSTNAME='https://arkindex.localhost/')
-    def test_callback_uri_public_hostname(self):
-        self.assertEqual(GitLabOAuthProvider().get_callback_uri(), 'https://arkindex.localhost/api/v1/oauth/providers/gitlab/callback/')
-
-    @override_settings(BACKEND_PUBLIC_URL_OAUTH=None, PUBLIC_HOSTNAME=None)
-    def test_callback_uri_request(self):
-        with self.assertRaisesMessage(AssertionError, 'PUBLIC_HOSTNAME is required to generate callback URIs'):
-            GitLabOAuthProvider().get_callback_uri()
-
-    @override_settings(BACKEND_PUBLIC_URL_OAUTH=None, PUBLIC_HOSTNAME='https://arkindex.localhost/')
-    def test_authorize_uri(self):
-        with self.settings(GITLAB_APP_ID='abcd'):
-            uri = GitLabOAuthProvider(credentials=self.creds).get_authorize_uri()
-        parsed = urllib.parse.urlparse(uri)
-        self.assertEqual(parsed.scheme, 'https')
-        self.assertEqual(parsed.netloc, 'somewhere')
-        self.assertEqual(parsed.path, '/oauth/authorize')
-        query = urllib.parse.parse_qs(parsed.query)
-        self.assertDictEqual(query, {
-            'client_id': ['abcd'],
-            'redirect_uri': ['https://arkindex.localhost/api/v1/oauth/providers/gitlab/callback/'],
-            'scope': ['api'],
-            'response_type': ['code'],
-            'state': [str(self.creds.id)],
-        })
-
-    def test_handle_callback_no_state(self):
-        request_mock = MagicMock(spec=HttpRequest)
-        request_mock.user = self.user
-        request_mock.GET = {}
-        with self.assertRaisesMessage(ValueError, 'No state hash'):
-            GitLabOAuthProvider().handle_callback(request_mock)
-
-    def test_handle_callback_bad_response(self):
-        request_mock = MagicMock(spec=HttpRequest)
-        request_mock.user = self.user
-        request_mock.GET = {'state': str(self.creds.id)}
-        with self.assertRaisesRegex(ValueError, 'valid response'):
-            GitLabOAuthProvider().handle_callback(request_mock)
-
-    def test_handle_callback_error(self):
-        request_mock = MagicMock(spec=HttpRequest)
-        request_mock.user = self.user
-        request_mock.GET = {'state': str(self.creds.id), 'error': 'error message'}
-        with self.assertRaisesMessage(ValueError, 'error message'):
-            GitLabOAuthProvider().handle_callback(request_mock)
-
-    def test_handle_callback_overwrite(self):
-        self.creds.status = OAuthStatus.Done
-        self.creds.save()
-        request_mock = MagicMock(spec=HttpRequest)
-        request_mock.user = self.user
-        request_mock.GET = {'state': str(self.creds.id), 'code': 'something'}
-        with self.assertRaisesRegex(Exception, 'overwrite'):
-            GitLabOAuthProvider().handle_callback(request_mock)
-
-    @responses.activate
-    @override_settings(BACKEND_PUBLIC_URL_OAUTH=None, PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_handle_callback_success(self):
-        responses.post(
-            'https://somewhere/oauth/token',
-            match=[
-                matchers.urlencoded_params_matcher({
-                    'client_id': 'abcd',
-                    'client_secret': 's3kr3t',
-                    'code': 'abc123',
-                    'redirect_uri': 'https://arkindex.localhost/api/v1/oauth/providers/gitlab/callback/',
-                    'grant_type': 'authorization_code',
-                }),
-            ],
-            json={
-                'access_token': 't0k3n',
-                'refresh_token': 'r3fr3sh',
-                'token_type': 'Bearer',
-                'created_at': 1582984800,
-                'expires_in': '3600',
-            },
-        )
-        request_mock = MagicMock(spec=HttpRequest)
-        request_mock.user = self.user
-        request_mock.GET = {'state': str(self.creds.id), 'code': 'abc123'}
-        request_mock.build_absolute_uri.return_value = 'callback'
-
-        self.gl_mock.return_value.user.username = 'bobby'
-
-        with self.settings(GITLAB_APP_ID='abcd', GITLAB_APP_SECRET='s3kr3t'):
-            GitLabOAuthProvider().handle_callback(request_mock)
-
-        self.creds.refresh_from_db()
-        self.assertEqual(self.creds.token, 't0k3n')
-        self.assertEqual(self.creds.refresh_token, 'r3fr3sh')
-        self.assertEqual(self.creds.expiry.isoformat(), '2020-02-29T15:00:00+00:00')
-        self.assertEqual(self.creds.account_name, 'bobby')
-        self.assertEqual(self.creds.status, OAuthStatus.Done)
-        self.assertEqual(self.gl_mock.return_value.auth.call_count, 1)
-
-        args, kwargs = self.gl_mock.call_args
-        self.assertEqual(args, ('https://somewhere', ))
-        self.assertDictEqual(kwargs, {'oauth_token': 't0k3n'})
-
-    @responses.activate
-    @override_settings(BACKEND_PUBLIC_URL_OAUTH=None, PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_refresh_token(self):
-        responses.post(
-            'https://somewhere/oauth/token',
-            match=[
-                matchers.urlencoded_params_matcher({
-                    'client_id': 'abcd',
-                    'client_secret': 's3kr3t',
-                    'redirect_uri': 'https://arkindex.localhost/api/v1/oauth/providers/gitlab/callback/',
-                    'grant_type': 'refresh_token',
-                    'refresh_token': 'r3fr3sh'
-                }),
-            ],
-            json={
-                'access_token': 't0k3n',
-                'refresh_token': 'r4fr4sh',
-                'token_type': 'Bearer',
-                'created_at': 1582984800,
-                'expires_in': '3600',
-            },
-        )
-
-        self.gl_mock.return_value.user.username = 'bobby'
-
-        self.creds.refresh_token = 'r3fr3sh'
-        self.creds.save()
-        self.assertEqual(self.creds.expiry.isoformat(), '2100-12-31T23:59:59.999000+00:00')
-        self.assertEqual(self.creds.token, 'oauth-token')
-
-        with self.settings(GITLAB_APP_ID='abcd', GITLAB_APP_SECRET='s3kr3t'):
-            GitLabOAuthProvider(credentials=self.creds).refresh_token()
-
-        self.assertEqual(self.creds.token, 't0k3n')
-        self.assertEqual(self.creds.refresh_token, 'r4fr4sh')
-        self.assertEqual(self.creds.expiry.isoformat(), '2020-02-29T15:00:00+00:00')
-        self.assertEqual(self.creds.account_name, 'bobby')
-        self.assertEqual(self.creds.status, OAuthStatus.Done)
-        self.assertEqual(self.gl_mock.return_value.auth.call_count, 1)
-
-        args, kwargs = self.gl_mock.call_args
-        self.assertEqual(args, ('https://somewhere', ))
-        self.assertDictEqual(kwargs, {'oauth_token': 't0k3n'})
-
-    @responses.activate
-    @override_settings(BACKEND_PUBLIC_URL_OAUTH=None, PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_refresh_token_error(self):
-        responses.post(
-            'https://somewhere/oauth/token',
-            match=[
-                matchers.urlencoded_params_matcher({
-                    'client_id': 'abcd',
-                    'client_secret': 's3kr3t',
-                    'redirect_uri': 'https://arkindex.localhost/api/v1/oauth/providers/gitlab/callback/',
-                    'grant_type': 'refresh_token',
-                    'refresh_token': 'r3fr3sh'
-                }),
-            ],
-            status=418,
-        )
-
-        self.creds.refresh_token = 'r3fr3sh'
-        self.creds.save()
-        self.assertEqual(self.creds.expiry.isoformat(), '2100-12-31T23:59:59.999000+00:00')
-        self.assertEqual(self.creds.token, 'oauth-token')
-
-        with self.settings(GITLAB_APP_ID='abcd', GITLAB_APP_SECRET='s3kr3t'), self.assertRaises(AuthenticationFailed):
-            GitLabOAuthProvider(credentials=self.creds).refresh_token()
-
-        self.assertEqual(self.creds.token, 'oauth-token')
-        self.assertEqual(self.creds.refresh_token, 'r3fr3sh')
-        self.assertEqual(self.creds.expiry.isoformat(), '2100-12-31T23:59:59.999000+00:00')
-        self.assertEqual(self.creds.status, OAuthStatus.Error)
-        self.assertFalse(self.gl_mock.return_value.auth.called)
-
-    @responses.activate
-    @override_settings(BACKEND_PUBLIC_URL_OAUTH=None, PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_refresh_token_none(self):
-        """
-        GitLabOAuthProvider.refresh_token should not try to refresh the OAuth token if there is
-        no refresh token on the OAuthCredentials
-        """
-        self.creds.refresh_token = None
-        self.creds.save()
-        self.assertEqual(self.creds.expiry.isoformat(), '2100-12-31T23:59:59.999000+00:00')
-        self.assertEqual(self.creds.token, 'oauth-token')
-
-        with self.settings(GITLAB_APP_ID='abcd', GITLAB_APP_SECRET='s3kr3t'), self.assertRaises(AuthenticationFailed):
-            GitLabOAuthProvider(credentials=self.creds).refresh_token()
-
-        self.assertEqual(self.creds.token, 'oauth-token')
-        self.assertIsNone(self.creds.refresh_token)
-        self.assertEqual(self.creds.expiry.isoformat(), '2100-12-31T23:59:59.999000+00:00')
-        self.assertEqual(self.creds.status, OAuthStatus.Error)
-        self.assertFalse(self.gl_mock.return_value.auth.called)
-
-    @override_settings(BACKEND_PUBLIC_URL_OAUTH=None, PUBLIC_HOSTNAME='https://arkindex.localhost')
-    def test_disconnect(self):
-        repo_1, repo_2 = self.creds.repos.order_by('hook_token')
-        # This hook does not match the expected hook URL and should not be removed
-        ignored_hook = MagicMock()
-        ignored_hook.url = 'https://potato.localhost/something'
-        repo_1_hook = MagicMock()
-        repo_1_hook.url = f'https://arkindex.localhost/api/v1/imports/hook/{repo_1.id}/'
-        repo_2_hook = MagicMock()
-        repo_2_hook.url = f'https://arkindex.localhost/api/v1/imports/hook/{repo_2.id}/'
-        self.gl_mock().projects.get.return_value.id = 'repo_id'
-        self.gl_mock().projects.get.return_value.hooks.list.return_value = [
-            ignored_hook, repo_1_hook, repo_2_hook
-        ]
-
-        GitLabOAuthProvider(credentials=self.creds).disconnect()
-
-        self.assertEqual(self.gl_mock().projects.get.call_count, 2)
-        self.assertEqual(self.gl_mock().projects.get.return_value.hooks.list.call_count, 2)
-        self.assertFalse(ignored_hook.delete.called)
-        self.assertEqual(repo_1_hook.delete.call_count, 1)
-        self.assertEqual(repo_2_hook.delete.call_count, 1)
diff --git a/arkindex/users/tests/test_providers.py b/arkindex/users/tests/test_providers.py
deleted file mode 100644
index 3179783fb8913e513e06d113552738e698e56d0d..0000000000000000000000000000000000000000
--- a/arkindex/users/tests/test_providers.py
+++ /dev/null
@@ -1,85 +0,0 @@
-
-from unittest.mock import MagicMock, patch
-
-from django.urls import reverse
-from rest_framework import status
-
-from arkindex.project.tests import FixtureTestCase
-from arkindex.users.models import OAuthStatus
-from arkindex.users.providers import get_provider
-
-
-class TestProviders(FixtureTestCase):
-
-    @classmethod
-    def setUpTestData(cls):
-        super().setUpTestData()
-        cls.creds = cls.user.credentials.get()
-
-    @classmethod
-    def setUpClass(cls):
-        super().setUpClass()
-        cls.provider_mock = MagicMock()
-        cls.provider_mock.slug = 'provider-slug'
-        cls.provider_mock.display_name = 'Provider Name'
-        cls.provider_mock.default_url = 'http://somewhere.com'
-        cls.provider_mock().credentials = cls.creds
-        # Patch global variable providers.oauth_providers
-        cls.providers_patch = patch('arkindex.users.providers.oauth_providers', [cls.provider_mock])
-
-    def setUp(self):
-        super().setUp()
-        self.providers_patch.start()
-
-    def tearDown(self):
-        super().tearDown()
-        self.providers_patch.stop()
-
-    @classmethod
-    def tearDownClass(cls):
-        super().tearDownClass()
-
-    def test_get_provider(self):
-        self.assertEqual(get_provider('provider-slug'), self.provider_mock)
-        self.assertIsNone(get_provider('doesnotexist'))
-
-    def test_list_providers(self):
-        self.client.force_login(self.user)
-        response = self.client.get(reverse('api:providers-list'))
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
-        data = response.json()
-        self.assertEqual(data, [
-            {
-                "name": self.provider_mock.slug,
-                "display_name": self.provider_mock.display_name,
-                "default_url": self.provider_mock.default_url
-            }
-        ])
-
-    def test_list_providers_requires_login(self):
-        response = self.client.get(reverse('api:providers-list'))
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-
-    def test_oauth_callback(self):
-        self.provider_mock().handle_callback.side_effect = None
-        self.client.force_login(self.user)
-        self.creds.status = OAuthStatus.Created
-        self.creds.save()
-        response = self.client.get(
-            reverse('api:oauth-callback', kwargs={'provider': 'provider-slug'}),
-        )
-        self.assertRedirects(response, reverse('credentials'), fetch_redirect_response=False)
-        self.creds.refresh_from_db()
-        self.assertEqual(self.creds.status, OAuthStatus.Done)
-
-    def test_oauth_callback_error(self):
-        self.provider_mock().handle_callback.side_effect = ValueError
-        self.client.force_login(self.user)
-        self.creds.status = OAuthStatus.Created
-        self.creds.save()
-        response = self.client.get(
-            reverse('api:oauth-callback', kwargs={'provider': 'provider-slug'}),
-        )
-        self.assertRedirects(response, reverse('credentials'), fetch_redirect_response=False)
-        self.creds.refresh_from_db()
-        self.assertEqual(self.creds.status, OAuthStatus.Error)
diff --git a/requirements.txt b/requirements.txt
index 5c6c517da482a0a41a4404796c9813c62d2a6acf..b98ed6359f777fa1be59de0cd2db8abadb8640ea 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -10,7 +10,6 @@ django-rq==2.8.1
 djangorestframework==3.12.4
 djangorestframework-simplejwt==5.2.2
 drf-spectacular==0.18.2
-python-gitlab==3.15.0
 python-memcached==1.59
 pytz==2023.3
 PyYAML==6.0