Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

attempting to merge app-support into develop #7010

Merged
merged 40 commits into from
Jun 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
33c3660
Fix for mount point detection on Android with latest toolchain.
kollivier May 18, 2020
20a9993
getting started - thinking about if this will jive with mfd in 0.14
nucleogenesis May 29, 2020
b8c4c63
New login flow display logic
nucleogenesis Jun 3, 2020
9d648c6
Fix buttons wrap behaviour
Jun 3, 2020
4715728
Remove obsolete style
Jun 3, 2020
389bdac
Merge pull request #6981 from MisRob/button-wrap-fix
jonboiser Jun 3, 2020
e088a4c
Login Flow w/ password creation et al
nucleogenesis Jun 4, 2020
d72aeff
Lint, non-form events for PasswordTextbox component
nucleogenesis Jun 4, 2020
38c02c7
Add login page message with network access disabled
May 29, 2020
73b06a2
Set the new property and device settings UI
May 30, 2020
7aca977
Add migration
May 30, 2020
88b78e6
Created backend api to decide remote access permission
Jun 1, 2020
19195d6
Frontend detecting app network access permission
Jun 1, 2020
6ee4e26
Limit visibility in the frontend
Jun 3, 2020
360a16a
Use vuex store instead of browser function for isAppContext
Jun 3, 2020
f5bd720
some prettier
Jun 3, 2020
9507578
Closing backdoor
Jun 4, 2020
800ecc5
Merge pull request #6885 from kollivier/android-mount
indirectlylit Jun 5, 2020
1294fab
Added changes in the design and strings based on received feedback
Jun 5, 2020
20d4f15
linting
indirectlylit Jun 5, 2020
dc2ee67
update login warning page string
indirectlylit Jun 5, 2020
591c5b8
test fix
nucleogenesis Jun 5, 2020
b8b52af
Merge pull request #6955 from jredrejo/remote_access_device_settings
indirectlylit Jun 5, 2020
8219016
merge, resolving conflict in SignInPage/index.vue
indirectlylit Jun 6, 2020
49cec0c
fix typo
indirectlylit Jun 6, 2020
4d288cf
remove duplicate import
indirectlylit Jun 6, 2020
6c3895d
fix test
indirectlylit Jun 6, 2020
13b4f65
Merge pull request #6962 from nucleogenesis/login-list-users-in-app-c…
indirectlylit Jun 6, 2020
4a58444
merge
indirectlylit Jun 6, 2020
4b06b41
Merge pull request #7000 from indirectlylit/merge-013-app
indirectlylit Jun 8, 2020
66b80bb
allowRemoteAccess `undefined` from state - was a getter
nucleogenesis Jun 8, 2020
eb95280
Fix test expecting allow access in session, was in core
nucleogenesis Jun 8, 2020
13dad1a
Merge remote-tracking branch 'remotes/le/app-support' into merge-app
indirectlylit Jun 9, 2020
eb57e28
lint
indirectlylit Jun 9, 2020
06b6a76
merge migrations, again
indirectlylit Jun 9, 2020
2df646d
Merge pull request #7006 from nucleogenesis/allow-access-getter-fix
indirectlylit Jun 9, 2020
9a365ac
Merge remote-tracking branch 'le/app-support' into merge-app
indirectlylit Jun 9, 2020
11e8b26
cleanup from merge
indirectlylit Jun 9, 2020
a6a077f
Fix AppBar in setup wizard
jonboiser Jun 9, 2020
14dbc8b
Fix Facility links when in a multi-facility device
jonboiser Jun 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions kolibri/core/assets/src/state/modules/core/actions.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import client from 'kolibri.client';
import debounce from 'lodash/debounce';
import pick from 'lodash/pick';
import logger from 'kolibri.lib.logging';
Expand Down Expand Up @@ -170,6 +171,10 @@ export function clearError(store) {
store.commit('CORE_SET_ERROR', null);
}

export function clearLoginError(store) {
store.commit('CORE_SET_LOGIN_ERROR', null);
}

export function handleApiError(store, errorObject) {
let error = errorObject;
if (typeof errorObject === 'object' && !(errorObject instanceof Error)) {
Expand Down Expand Up @@ -206,6 +211,63 @@ export function setSession(store, { session, clientNow }) {
store.commit('CORE_SET_SESSION', session);
}

/**
* Signs in user and then sets their password
* this is used in the case where a learner has created an
* account without a password. At sign in, they will
* give a password - we sign them in to create the session,
* then we make a request to update their password before
* redirecting.
*
* @param {object} store The store.
* @param {object} sessionPayload The session payload.
*/
export function kolibriLoginWithNewPassword(store, payload) {
store.commit('CORE_SET_SIGN_IN_BUSY', true);
Lockr.set(UPDATE_MODAL_DISMISSED, false);

const { username, password, facility, user } = payload;

const sessionPayload = {
username,
password,
facility,
};

return SessionResource.saveModel({ data: sessionPayload })
.then(() => {
const path = `/api/auth/facilityuser/${user.id}/`;
const method = 'PATCH';
const entity = { password };
client({ path, method, entity }).then(() => {
// OIDC redirect
if (sessionPayload.next) {
redirectBrowser(sessionPayload.next);
}
// Normal redirect on login
else {
redirectBrowser();
}
});
})
.catch(error => {
store.commit('CORE_SET_SIGN_IN_BUSY', false);
const errorsCaught = CatchErrors(error, [
ERROR_CONSTANTS.INVALID_CREDENTIALS,
ERROR_CONSTANTS.MISSING_PASSWORD,
]);
if (errorsCaught) {
if (errorsCaught.includes(ERROR_CONSTANTS.INVALID_CREDENTIALS)) {
store.commit('CORE_SET_LOGIN_ERROR', LoginErrors.INVALID_CREDENTIALS);
} else if (errorsCaught.includes(ERROR_CONSTANTS.MISSING_PASSWORD)) {
store.commit('CORE_SET_LOGIN_ERROR', LoginErrors.PASSWORD_MISSING);
}
} else {
store.dispatch('handleApiError', error);
}
});
}

/**
* Signs in user.
*
Expand Down Expand Up @@ -285,6 +347,16 @@ export function saveDismissedNotification(store, notification_id) {
});
}

export function getRemoteAccessPermission(store) {
return client({
method: 'POST',
path: urls['kolibri:kolibri.plugins.device:allowremoteaccess'](),
}).then(response => {
const data = response.entity;
store.commit('SET_REMOTE_BROWSER_PERMISSION', data.allowed);
});
}

export function getFacilities(store) {
return FacilityResource.fetchCollection().then(facilities => {
store.commit('CORE_SET_FACILITIES', [...facilities]);
Expand Down
4 changes: 4 additions & 0 deletions kolibri/core/assets/src/state/modules/core/getters.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@ export function pageSessionId(state) {
export function demoBannerVisible(state, getters, rootState) {
return state.demoBannerVisible && rootState.pageName === 'SIGN_IN';
}

export function allowRemoteAccess(state) {
return state.allowRemoteAccess;
}
1 change: 1 addition & 0 deletions kolibri/core/assets/src/state/modules/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default {
list: [],
currentId: null,
},
allowRemoteAccess: false,
// facility
facilityConfig: {},
facilities: [],
Expand Down
3 changes: 3 additions & 0 deletions kolibri/core/assets/src/state/modules/core/mutations.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,7 @@ export default {
SET_CORE_BANNER_VISIBLE(state) {
state.demoBannerVisible = true;
},
SET_REMOTE_BROWSER_PERMISSION(state, enabled) {
state.allowRemoteAccess = enabled;
},
};
4 changes: 2 additions & 2 deletions kolibri/core/assets/src/state/modules/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ export default {
canManageContent(state) {
return state.can_manage_content;
},
canAccessUnassignedContent(state) {
return state.can_access_unassigned_content;
canAccessUnassignedContent(state, getters) {
return state.can_access_unassigned_content && getters.allowRemoteAccess;
},
isSuperuser(state) {
return state.kind.includes(UserKinds.SUPERUSER);
Expand Down
10 changes: 10 additions & 0 deletions kolibri/core/assets/src/views/userAccounts/PasswordTextbox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
v-bind="$attrs"
@blur="passwordBlurred = true"
@input="$emit('update:value', $event)"
@keydown.enter="checkErrorsAndSubmit"
/>

<KTextbox
Expand All @@ -24,6 +25,7 @@
:invalidText="shownConfirmationInvalidText"
:autocomplete="$attrs.autocomplete"
@blur="confirmationBlurred = true"
@keydown.enter="checkErrorsAndSubmit"
/>
</div>

Expand Down Expand Up @@ -117,6 +119,14 @@
this.$emit('update:value', '');
this.$refs.password.focus();
},
checkErrorsAndSubmit(e) {
if (this.valid) {
this.$emit('submitNewPassword');
} else {
// Blurring will cause validation errors to show if needed
e.target.blur();
}
},
},
$trs: {
confirmPasswordLabel: 'Re-enter password',
Expand Down
19 changes: 19 additions & 0 deletions kolibri/core/auth/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from django.contrib.auth import logout
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
from django.db.models import OuterRef
from django.db.models import Q
Expand Down Expand Up @@ -475,12 +476,30 @@ def create(self, request):
username = request.data.get("username", "")
password = request.data.get("password", "")
facility_id = request.data.get("facility", None)

# Find the FacilityUser we're looking for use later on
try:
unauthenticated_user = FacilityUser.objects.get(
username__iexact=username, facility=facility_id
)
except ObjectDoesNotExist:
unauthenticated_user = None

user = authenticate(username=username, password=password, facility=facility_id)
if user is not None and user.is_active:
# Correct password, and the user is marked "active"
login(request, user)
# Success!
return self.get_session_response(request)
elif (
unauthenticated_user is not None
and unauthenticated_user.password == "NOT_SPECIFIED"
):
# Here - we have a Learner whose password is "NOT_SPECIFIED" because they were created
# while the "Require learners to log in with password" setting was disabled - but now
# it is enabled again.
login(request, unauthenticated_user)
return self.get_session_response(request)
elif (
not password
and FacilityUser.objects.filter(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.28 on 2020-05-29 18:39
from __future__ import unicode_literals

from django.db import migrations
from django.db import models


class Migration(migrations.Migration):

dependencies = [
("device", "0007_deviceappkey"),
]

operations = [
migrations.AddField(
model_name="devicesettings",
name="allow_other_browsers_to_connect",
field=models.NullBooleanField(),
),
]
15 changes: 15 additions & 0 deletions kolibri/core/device/migrations/0009_merge_20200608_1716.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.29 on 2020-06-09 00:16
from __future__ import unicode_literals

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("device", "0008_merge_20200531_1829"),
("device", "0008_devicesettings_allow_other_browsers_to_connect"),
]

operations = []
1 change: 1 addition & 0 deletions kolibri/core/device/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class DeviceSettings(models.Model):
allow_peer_unlisted_channel_import = models.BooleanField(default=False)
allow_learner_unassigned_resource_access = models.BooleanField(default=True)
name = models.CharField(max_length=50, default=get_device_hostname)
allow_other_browsers_to_connect = models.NullBooleanField(null=True)

def save(self, *args, **kwargs):
self.pk = 1
Expand Down
1 change: 1 addition & 0 deletions kolibri/core/device/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class Meta:
"allow_guest_access",
"allow_peer_unlisted_channel_import",
"allow_learner_unassigned_resource_access",
"allow_other_browsers_to_connect",
)

def create(self, validated_data):
Expand Down
4 changes: 4 additions & 0 deletions kolibri/core/device/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ def allow_peer_unlisted_channel_import():
return get_device_setting("allow_peer_unlisted_channel_import", False)


def allow_other_browsers_to_connect():
return get_device_setting("allow_other_browsers_to_connect", False)


def set_device_settings(**kwargs):
from .models import DeviceSettings

Expand Down
6 changes: 4 additions & 2 deletions kolibri/core/discovery/utils/filesystem/posix.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,16 @@ def get_drive_list():

if sys.platform == "darwin":
MOUNT_PARSER = OSX_MOUNT_PARSER
elif on_android():
MOUNT_PARSER = RAW_MOUNT_PARSER
else:
MOUNT_PARSER = LINUX_MOUNT_PARSER

try:
drivelist = subprocess.Popen("mount", shell=True, stdout=subprocess.PIPE)
drivelisto, err = drivelist.communicate()
# Some Android devices at least now use the LINUX_MOUNT_PARSER format.
# Try it and revert to RAW_MOUNT_PARSER if we can't find any matches with it.
if on_android() and not MOUNT_PARSER.match(drivelisto.decode()):
MOUNT_PARSER = RAW_MOUNT_PARSER
except OSError: # couldn't run `mount`, let's try reading the /etc/mounts listing directly
with open("/proc/mounts") as f:
drivelisto = f.read()
Expand Down
1 change: 1 addition & 0 deletions kolibri/deployment/default/dev_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def webpack_redirect_view(request):
url(
r"^redoc/$", schema_view.with_ui("redoc", cache_timeout=0), name="schema-redoc"
),
url(r"^api-auth/", include("rest_framework.urls", namespace="rest_framework")),
]

if getattr(settings, "DEBUG_PANEL_ACTIVE", False):
Expand Down
1 change: 0 additions & 1 deletion kolibri/deployment/default/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@

url_patterns_prefixed = [
url(r"^admin/", include(admin.site.urls)),
url(r"^api-auth/", include("rest_framework.urls", namespace="rest_framework")),
url(r"", include(morango_urls)),
url(r"", include("kolibri.core.urls")),
url(r"", include(get_root_urls())),
Expand Down
Loading