Repository: learningequality/kolibri

Issue:
"Device limitations" modal when attempting to import non-learner account behaves incorrectly
## Observed behavior

In the setup wizard, when importing individual user accounts, and entering the credentials of an admin user as the account to import, the popup modal has several issues:

<img width="474" alt="image" src="https://user-images.githubusercontent.com/618416/172494311-d6451841-304f-43ec-bd7d-a34822c8e53a.png">

- It shows the appropriate message (although "a admin" is incorrect), but only has a "cancel" option -- it should also allow you to continue ("OK").
- When you click cancel, it stays on the form it was on before, but then in the background it actually does initiate the single user import of the admin anyway, which isn't immediately apparent, until you reload or do something else, and then it pops you over to the device tab, logged in as the admin account you initially tried to import.

## Expected behavior

1. There should be both "OK" and "Cancel" options.
2. "OK" should take you to the next page in the sequence, showing the import of that user.
3. "Cancel" should actually cancel (not initiate the import silently in the background).
4. Stretch goal (but maybe not possible within 0.15): the indefinite article should take the form appropriate to the noun ("a coach" but "an admin").

## Steps to reproduce

1. Start with a fresh device, and a full-facility device elsewhere on the network
2. Choose "advanced > import individual user accounts"
3. Select the full-facility device from the list
4. Put in the credentials of an admin (or coach?)
5. Notice the modal that pops up, and cancel it
6. Wait a bit and then close and reopen, or refresh, the browser
7. Note that you've now been logged in as the admin account, which was synced

## Context

Extant on Kolibri 0.15.3

CC @radinamatic for replication 🙏 



Discussion:
The original spec for this issue intended there to be an import button here, if we have the string for it, would be great to implement this within the 0.15.x range:
![image](https://user-images.githubusercontent.com/1680573/172495955-2d2b0615-3c1f-42ba-9ffa-f0456bbf473f.png)

we have a commonCoreString for 'importAction' that can be used, so adding this to a planned patch
@radinamatic @pcenov can we confirm if this is now fixed in 0.16?
Well, some things have changed a bit, like the string that does not have a weird indefinite article, but other issues are still there:

![Ubuntu20 04 (start)  Running  - Oracle VM VirtualBox_007](https://user-images.githubusercontent.com/1457929/232618477-e616fa1c-10f8-42e5-8738-1e67d616c075.png)

From the original report:

-  `There should be both "OK" and "Cancel" options.`
   We are still missing the `OK` or `Import` buttons.
-  `"OK" should take you to the next page in the sequence, showing the import of that user.`
   This is still an issue, there seems to be no option to import an admin user from the full facility.
-  `"Cancel" should actually cancel (not initiate the import silently in the background).`
   I see a 400 error in the console but if I reload I'm still on the **Import individual user accounts** step, so not sure if there's a silent import in the background.
-  `Stretch goal: the indefinite article should take the form appropriate to the noun ("a coach" but "an admin").`
   We rephrased the string so there's no `a admin` anymore, but we did not count on admin user being a coach too, and having the resulting string as above _’dd (admin)’ is a coach, admin on ‘facility_name’._ 😅 



Resolving patch:
diff --git a/kolibri/core/auth/tasks.py b/kolibri/core/auth/tasks.py
--- a/kolibri/core/auth/tasks.py
+++ b/kolibri/core/auth/tasks.py
@@ -792,6 +792,7 @@ class PeerImportSingleSyncJobValidator(PeerSyncJobValidator):
     user_id = HexOnlyUUIDField(required=False)
     facility = HexOnlyUUIDField()
     using_admin = serializers.BooleanField(default=False, required=False)
+    force_non_learner_import = serializers.BooleanField(default=False, required=False)
 
     def validate(self, data):
         """
@@ -801,6 +802,7 @@ def validate(self, data):
         job_data = super(PeerImportSingleSyncJobValidator, self).validate(data)
         user_id = data.get("user_id", None)
         using_admin = data.get("using_admin", False)
+        force_non_learner_import = data.get("force_non_learner_import", False)
         # Use pre-validated base URL
         baseurl = job_data["kwargs"]["baseurl"]
         facility_id = data["facility"]
@@ -818,16 +820,17 @@ def validate(self, data):
         full_name = user_info["full_name"]
         roles = user_info["roles"]
 
-        # only learners can by synced:
-        not_syncable = (SUPERUSER, COACH, ASSIGNABLE_COACH, ADMIN)
-        if any(role in roles for role in not_syncable):
-            raise ValidationError(
-                detail={
-                    "id": DEVICE_LIMITATIONS,
-                    "full_name": full_name,
-                    "roles": ", ".join(roles),
-                }
-            )
+        # only learners can be synced unless user has confirmed intention to sync a non-learner:
+        if not force_non_learner_import:
+            not_syncable = (SUPERUSER, COACH, ASSIGNABLE_COACH, ADMIN)
+            if any(role in roles for role in not_syncable):
+                raise ValidationError(
+                    detail={
+                        "id": DEVICE_LIMITATIONS,
+                        "full_name": full_name,
+                        "roles": ", ".join(roles),
+                    }
+                )
 
         user_id = user_info["id"]
 


Test patch: