Repository: learningequality/kolibri

Issue:
Deprecate createsuperuser management command
## Summary

`createsuperuser` will create a user type that is no longer usable within Kolibri, either disable it, or modify it to do something useful. Similarly with `changepassword`.
manage createsuperuser allows for creation of same login multiple times
## Summary

Calling manage createsuperuser allows for creation of a login that was previously made (e.g. 'admin').  Existence of multiple accounts doesn't allow user to log in.

## System information

*Please specify the Kolibri version you were using and your operating system!*

 - Version: version 0.3
 - Operating system: Linux
 - Browser: Chrome

## Traceback or relevant snippet from server.log or browser console

```
INSERT TRACEBACK, LOG MESSAGES ETC. HERE
```

## How to reproduce

1. Use cmd line manage create superuser
2. Follow prompts to create a new login and password
3. Run kolibri start
4. Open in browser
5. Log in with freshly created login
6. Pressing on 'Log in" doesn't take you to main page

## Real-life consequences (anything community should be aware of, for instance how it affects your deployment)

There's no validation step which prevents an admin from creating the same login/password combo.  Will lead to confusion upon trying to log in.


Discussion:
Note this issue is related to need for some sort of tool for setting up Kolibri in a fully automated manner.

Richard said:

The simplest way would be to POST to this endpoint: https://github.com/learningequality/kolibri/blob/release-v0.6.x/kolibri/core/device/api.py#L17
With a payload of this shape: https://github.com/learningequality/kolibri/blob/release-v0.6.x/kolibri/core/device/serializers.py#L47
URL specified here: https://github.com/learningequality/kolibri/blob/release-v0.6.x/kolibri/core/device/api_urls.py


Confirmed the above API works and the following shell script can be used for provisioning:

```
export KOLIBRI_DEVICEPROVISION_FACILTY_NAME="Demo Facility"
export KOLIBRI_DEVICEPROVISION_PRESETS="formal" # other options "nonformal" "informal"
export KOLIBRI_DEVICEPROVISION_SUPERUSER_USERNAME="devowner"
export KOLIBRI_DEVICEPROVISION_SUPERUSER_PASSWORD="admin123"
# ('id', 'username', 'full_name', 'password', 'facility', 'roles')
export KOLIBRI_LANG="en"
export KOLIBRI_PORT=8000

generate_post_data()
{
  cat <<EOF
{
  "facility": {
    "name": "$KOLIBRI_DEVICEPROVISION_FACILTY_NAME"
  },
  "preset": "$KOLIBRI_DEVICEPROVISION_PRESETS",
  "superuser": {
    "username": "$KOLIBRI_DEVICEPROVISION_SUPERUSER_USERNAME",
    "password": "$KOLIBRI_DEVICEPROVISION_SUPERUSER_PASSWORD"
  },
  "language_id": "$KOLIBRI_LANG"
}
EOF
}

curl -i \
  -H "Content-Type:application/json" \
  --data "$(generate_post_data)" \
  -X POST \
  "http://localhost:$KOLIBRI_PORT/api/deviceprovision/"
```

Long term we can think about adding a management command analogous to:
```
{{kalite}} manage setup --username={{ kalite_admin_user }} --password={{ kalite_admin_password }} --noinput
```
but with facility/preset options...

note that simply disabling is not an option - we need a way for users to recover access to their data if they forget their password


Resolving patch:
diff --git a/kolibri/auth/models.py b/kolibri/auth/models.py
--- a/kolibri/auth/models.py
+++ b/kolibri/auth/models.py
@@ -36,6 +36,7 @@
 from kolibri.core.fields import DateTimeTzField
 from kolibri.utils.time import local_now
 from morango.certificates import Certificate
+from morango.manager import SyncableModelManager
 from morango.models import SyncableModel
 from morango.query import SyncableModelQuerySet
 from morango.utils.morango_mptt import MorangoMPTTModel
@@ -447,6 +448,28 @@ def filter_readable(self, queryset):
             return queryset.none()
 
 
+class FacilityUserModelManager(SyncableModelManager):
+
+    def create_superuser(self, username, password):
+
+        # import here to avoid circularity
+        from kolibri.core.device.models import DevicePermissions
+
+        # get the default facility
+        facility = Facility.get_default_facility()
+
+        # create the new account in that facility
+        superuser = FacilityUser(username=username, facility=facility)
+        superuser.set_password(password)
+        superuser.save()
+
+        # make the user a facility admin
+        facility.add_role(superuser, role_kinds.ADMIN)
+
+        # make the user into a superuser on this device
+        DevicePermissions.objects.create(user=superuser, is_superuser=True)
+
+
 @python_2_unicode_compatible
 class FacilityUser(KolibriAbstractBaseUser, AbstractFacilityDataModel):
     """
@@ -469,6 +492,8 @@ class FacilityUser(KolibriAbstractBaseUser, AbstractFacilityDataModel):
         )
     )
 
+    objects = FacilityUserModelManager()
+
     facility = models.ForeignKey("Facility")
 
     is_facility_user = True


Test patch: