From 5e937de6c7998c60460f27abb79ab500d5ba98e8 Mon Sep 17 00:00:00 2001
From: Antoine Lambert <anlambert@softwareheritage.org>
Date: Thu, 16 Sep 2021 11:44:50 +0200
Subject: [PATCH] common/models: Add note text field to SaveOriginRequest model

It will enable to store a swh-web admin redacted note related to
the save request, for instance the reason of rejection or explain
why a submitted save request failed.

Related to T3256
---
 swh/web/api/views/origin_save.py              |  2 ++
 .../migrations/0012_saveoriginrequest_note.py | 21 +++++++++++++++++++
 swh/web/common/models.py                      |  2 ++
 swh/web/common/typing.py                      |  2 ++
 swh/web/tests/common/test_django_command.py   |  1 +
 swh/web/tests/common/test_origin_save.py      |  3 +++
 swh/web/tests/test_migrations.py              | 11 +++++-----
 7 files changed, 37 insertions(+), 5 deletions(-)
 create mode 100644 swh/web/common/migrations/0012_saveoriginrequest_note.py

diff --git a/swh/web/api/views/origin_save.py b/swh/web/api/views/origin_save.py
index a2d3366fd..d9370bdcd 100644
--- a/swh/web/api/views/origin_save.py
+++ b/swh/web/api/views/origin_save.py
@@ -85,6 +85,8 @@ def api_save_origin(request, visit_type, origin_url):
         :>json string visit_status: the status of the visit, either **full**,
             **partial**, **not_found** or **failed** if a visit occurred, null
             otherwise.
+        :>json string note: optional note giving details about the save request,
+            for instance why it has been rejected
 
         :statuscode 200: no error
         :statuscode 400: an invalid visit type or origin url has been provided
diff --git a/swh/web/common/migrations/0012_saveoriginrequest_note.py b/swh/web/common/migrations/0012_saveoriginrequest_note.py
new file mode 100644
index 000000000..6df1582f7
--- /dev/null
+++ b/swh/web/common/migrations/0012_saveoriginrequest_note.py
@@ -0,0 +1,21 @@
+# Copyright (C) 2021 The Software Heritage developers
+# See the AUTHORS file at the top-level directory of this distribution
+# License: GNU General Public License version 3, or any later version
+# See top-level LICENSE file for more information
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("swh_web_common", "0011_saveoriginrequest_user_ids"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="saveoriginrequest",
+            name="note",
+            field=models.TextField(null=True),
+        ),
+    ]
diff --git a/swh/web/common/models.py b/swh/web/common/models.py
index 380ecd776..fc2738aa3 100644
--- a/swh/web/common/models.py
+++ b/swh/web/common/models.py
@@ -102,6 +102,7 @@ class SaveOriginRequest(models.Model):
     )
     # store ids of users that submitted the request as string list
     user_ids = models.TextField(null=True)
+    note = models.TextField(null=True)
 
     class Meta:
         app_label = "swh_web_common"
@@ -127,6 +128,7 @@ class SaveOriginRequest(models.Model):
             visit_status=self.visit_status,
             visit_date=visit_date.isoformat() if visit_date else None,
             loading_task_id=self.loading_task_id,
+            note=self.note,
         )
 
     def __str__(self) -> str:
diff --git a/swh/web/common/typing.py b/swh/web/common/typing.py
index 760e3daac..b28204689 100644
--- a/swh/web/common/typing.py
+++ b/swh/web/common/typing.py
@@ -245,6 +245,8 @@ class SaveOriginRequestInfo(TypedDict):
     """End of the visit if terminated"""
     save_task_status: str
     """Status of the scheduled task"""
+    note: Optional[str]
+    """Optional note associated to the request, for instance rejection reason"""
 
 
 class OriginExistenceCheckInfo(TypedDict):
diff --git a/swh/web/tests/common/test_django_command.py b/swh/web/tests/common/test_django_command.py
index 3d64bb997..2c975210f 100644
--- a/swh/web/tests/common/test_django_command.py
+++ b/swh/web/tests/common/test_django_command.py
@@ -126,6 +126,7 @@ def fake_refreshed_data():
             save_task_status=meta["task_status"],
             id=i,
             loading_task_id=i,
+            note=None,
         )
         for i, meta in enumerate(entries)
     ]
diff --git a/swh/web/tests/common/test_origin_save.py b/swh/web/tests/common/test_origin_save.py
index d9faf684c..3eef778f2 100644
--- a/swh/web/tests/common/test_origin_save.py
+++ b/swh/web/tests/common/test_origin_save.py
@@ -324,6 +324,7 @@ def test_from_save_origin_request_to_save_request_info_dict(visit_date):
     request_date = datetime.now(tz=timezone.utc)
     _visit_date = request_date + timedelta(minutes=5) if visit_date else None
     request_date = datetime.now(tz=timezone.utc)
+    note = "request succeeded"
     sor = SaveOriginRequest(
         request_date=request_date,
         visit_type=_visit_type,
@@ -333,6 +334,7 @@ def test_from_save_origin_request_to_save_request_info_dict(visit_date):
         loading_task_status=None,
         visit_date=_visit_date,
         loading_task_id=1,
+        note=note,
     )
 
     assert sor.to_dict() == SaveOriginRequestInfo(
@@ -345,6 +347,7 @@ def test_from_save_origin_request_to_save_request_info_dict(visit_date):
         visit_status=sor.visit_status,
         visit_date=_visit_date.isoformat() if _visit_date else None,
         loading_task_id=sor.loading_task_id,
+        note=note,
     )
 
 
diff --git a/swh/web/tests/test_migrations.py b/swh/web/tests/test_migrations.py
index 3cb68884b..572d77f20 100644
--- a/swh/web/tests/test_migrations.py
+++ b/swh/web/tests/test_migrations.py
@@ -9,6 +9,7 @@ MIGRATION_0008 = "0008_save-code-now_indexes_20210106_1327"
 MIGRATION_0009 = "0009_saveoriginrequest_visit_status"
 MIGRATION_0010 = "0010_saveoriginrequest_user_id"
 MIGRATION_0011 = "0011_saveoriginrequest_user_ids"
+MIGRATION_0012 = "0012_saveoriginrequest_note"
 
 
 def test_migrations_09_add_visit_status_to_sor_model(migrator):
@@ -39,15 +40,15 @@ def test_migrations_10_add_user_id_to_sor_model(migrator):
     assert hasattr(new_model, "user_id") is True
 
 
-def test_migrations_11_add_user_ids_to_sor_model(migrator):
+def test_migrations_12_add_note_to_sor_model(migrator):
     """Ensures the migration adds the user_id field to SaveOriginRequest table"""
 
-    old_state = migrator.apply_initial_migration((APP_NAME, MIGRATION_0010),)
+    old_state = migrator.apply_initial_migration((APP_NAME, MIGRATION_0011),)
     old_model = old_state.apps.get_model(APP_NAME, "SaveOriginRequest")
 
-    assert hasattr(old_model, "user_ids") is False
+    assert hasattr(old_model, "note") is False
 
-    new_state = migrator.apply_tested_migration((APP_NAME, MIGRATION_0011))
+    new_state = migrator.apply_tested_migration((APP_NAME, MIGRATION_0012))
     new_model = new_state.apps.get_model(APP_NAME, "SaveOriginRequest")
 
-    assert hasattr(new_model, "user_ids") is True
+    assert hasattr(new_model, "note") is True
-- 
GitLab