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

0.16 into develop #11871

Merged
merged 46 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
8bdbf6c
Use responsive composable instead of mixin to fix errors from the mixin.
rtibbles Jan 25, 2024
1123395
Merge pull request #11791 from rtibbles/unresponsive
rtibbles Jan 26, 2024
2085868
Capture more errors from the backend and show error messages for them
Jan 26, 2024
5b47241
Force validation only if there are not imported users
Jan 29, 2024
6008a25
Merge pull request #11807 from jredrejo/small_validation_errors
marcellamaki Jan 31, 2024
c90a08a
Add is_full_facility_import to dataset API.
rtibbles Feb 1, 2024
0833e27
Add permission check to prevent signup on an LOD.
rtibbles Feb 1, 2024
be24516
Merge pull request #11827 from rtibbles/lod_or_not_lod_that_is_the_qu…
rtibbles Feb 2, 2024
9417edf
Remove redundant mastery label masking exercise card thumbnail
LianaHarris360 Feb 2, 2024
125b9f9
Merge pull request #11840 from LianaHarris360/remove-redundant-label
LianaHarris360 Feb 5, 2024
52898d9
Ensure facility id is properly sent to public signup viewset.
rtibbles Feb 7, 2024
f1a6b03
Conditionalize missing resource check when resource is not an empty o…
marcellamaki Feb 8, 2024
e69794f
Use FACILITY_CREDENTIAL_KEY constant for consistency.
rtibbles Feb 8, 2024
24ec3c4
Use passed in cache key function for cache keys.
rtibbles Feb 8, 2024
7bd2a2e
Override the RedisCache set method to not return a value in line with…
rtibbles Feb 8, 2024
dc97e82
Merge pull request #11846 from rtibbles/two_facilities_are_better_tha…
rtibbles Feb 8, 2024
32dd9a8
Merge pull request #11849 from rtibbles/naming_things_seems_easier
rtibbles Feb 9, 2024
b46cbb5
Merge pull request #11843 from marcellamaki/coach-report-loading-state
rtibbles Feb 9, 2024
7dd81e5
Pass the correct kwargs to the cleanupsyncs management command.
rtibbles Feb 10, 2024
c8e215f
Update with the latest strings from Crowdin after i18n-upload
radinamatic Feb 12, 2024
7c02ccb
'Frequency' was hidden
radinamatic Feb 12, 2024
a2f580d
Create canonical set of assignments when learner is assigned multiple…
bjester Feb 12, 2024
341092c
Fix Indonesian
radinamatic Feb 12, 2024
5c30fde
Merge pull request #11854 from rtibbles/cleanupsyncs_push_me_pull_you
bjester Feb 12, 2024
6159752
Merge pull request #11860 from bjester/canonicalized-assignments
rtibbles Feb 12, 2024
3f2e1ec
Merge pull request #11858 from radinamatic/test-update-crowdin
rtibbles Feb 12, 2024
fdcd779
Pin all installer actions to specific versions.
rtibbles Feb 13, 2024
8c3254f
Ensure that Kolibri can start regardless of whether redis and redis c…
rtibbles Feb 13, 2024
840b416
Catch error raised by Django when redis is not installed.
rtibbles Feb 13, 2024
e7c4633
Merge pull request #11863 from rtibbles/pinstallers
marcellamaki Feb 13, 2024
2837e15
Merge pull request #11868 from rtibbles/no_redis_cache_no_problem
rtibbles Feb 13, 2024
ab7e31a
Update changelog for 0.16.0 release
marcellamaki Feb 13, 2024
96755ec
Merge pull request #11870 from marcellamaki/update-changelog-016
marcellamaki Feb 13, 2024
de48056
Fix version parsing for release candidates.
rtibbles Feb 14, 2024
636b5b3
Merge pull request #11872 from rtibbles/rc_version
marcellamaki Feb 15, 2024
587fdcf
Reduce the chance of database locks interrupting soud syncing.
rtibbles Feb 15, 2024
460f5db
Update debian installer to include critical fix for raspberry Pi os.
rtibbles Feb 15, 2024
3fd5c1e
Merge pull request #11886 from rtibbles/locks_no_spoil_the_queue
rtibbles Feb 15, 2024
142dcfb
Merge pull request #11885 from rtibbles/debian_installer_update
rtibbles Feb 15, 2024
d96bc00
Set markdown to None in module cache to prevent it being imported by …
rtibbles Feb 17, 2024
96c528b
Merge pull request #11897 from rtibbles/markdown_markedoff
marcellamaki Feb 19, 2024
a4e4279
Prevent unique constraint saving errors.
rtibbles Feb 20, 2024
64abaf2
Ensure noarch dir is added to path when abi3 c extensions are used.
rtibbles Feb 20, 2024
0ca9ff1
Merge pull request #11904 from rtibbles/unique_removal_request
bjester Feb 20, 2024
0098f7e
Merge pull request #11905 from rtibbles/disty_crypto
bjester Feb 20, 2024
ca9bd42
Merge branch 'release-v0.16.x' into develop
rtibbles Feb 21, 2024
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
12 changes: 6 additions & 6 deletions .github/workflows/pr_build_kolibri.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,21 @@ jobs:
deb:
name: Build DEB file
needs: whl
uses: learningequality/kolibri-installer-debian/.github/workflows/build_deb.yml@master
uses: learningequality/kolibri-installer-debian/.github/workflows/build_deb.yml@v0.16.1
with:
tar-file-name: ${{ needs.whl.outputs.tar-file-name }}
ref: master
ref: v0.16.1
exe:
name: Build EXE file
needs: whl
uses: learningequality/kolibri-installer-windows/.github/workflows/build_exe.yml@develop
uses: learningequality/kolibri-installer-windows/.github/workflows/build_exe.yml@v1.6.0
with:
whl-file-name: ${{ needs.whl.outputs.whl-file-name }}
ref: develop
ref: v1.6.0
apk:
name: Build APK file
needs: whl
uses: learningequality/kolibri-installer-android/.github/workflows/build_apk.yml@develop
uses: learningequality/kolibri-installer-android/.github/workflows/build_apk.yml@v0.1.0
with:
tar-file-name: ${{ needs.whl.outputs.tar-file-name }}
ref: develop
ref: v0.1.0
24 changes: 12 additions & 12 deletions .github/workflows/release_kolibri.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ jobs:
dmg:
name: Build DMG file
needs: whl
uses: learningequality/kolibri-app/.github/workflows/build_mac.yml@main
uses: learningequality/kolibri-app/.github/workflows/build_mac.yml@v0.4.0
with:
whl-file-name: ${{ needs.whl.outputs.whl-file-name }}
release: true
ref: main
ref: v0.4.0
secrets:
KOLIBRI_MAC_APP_IDENTITY: ${{ secrets.KOLIBRI_MAC_APP_IDENTITY }}
KOLIBRI_MAC_APP_CERTIFICATE: ${{ secrets.KOLIBRI_MAC_APP_CERTIFICATE }}
Expand All @@ -56,10 +56,10 @@ jobs:
deb:
name: Build DEB file
needs: whl
uses: learningequality/kolibri-installer-debian/.github/workflows/build_deb.yml@master
uses: learningequality/kolibri-installer-debian/.github/workflows/build_deb.yml@v0.16.1
with:
tar-file-name: ${{ needs.whl.outputs.tar-file-name }}
ref: master
ref: v0.16.1
upload_deb:
uses: ./.github/workflows/upload_github_release_asset.yml
needs: deb
Expand All @@ -69,11 +69,11 @@ jobs:
exe:
name: Build EXE file
needs: whl
uses: learningequality/kolibri-installer-windows/.github/workflows/build_exe.yml@develop
uses: learningequality/kolibri-installer-windows/.github/workflows/build_exe.yml@v1.6.0
with:
whl-file-name: ${{ needs.whl.outputs.whl-file-name }}
release: true
ref: develop
ref: v1.6.0
secrets:
KOLIBRI_WINDOWS_INSTALLER_CERTIFICATE: ${{ secrets.KOLIBRI_WINDOWS_INSTALLER_CERTIFICATE }}
KOLIBRI_WINDOWS_INSTALLER_CERTIFICATE_PASSWORD: ${{ secrets.KOLIBRI_WINDOWS_INSTALLER_CERTIFICATE_PASSWORD }}
Expand All @@ -86,10 +86,10 @@ jobs:
zip:
name: Build Raspberry Pi Image
needs: deb
uses: learningequality/pi-gen/.github/workflows/build_zip.yml@master
uses: learningequality/pi-gen/.github/workflows/build_zip.yml@v0.16.0
with:
deb-file-name: ${{ needs.deb.outputs.deb-file-name }}
ref: master
ref: v0.16.0
upload_zip:
uses: ./.github/workflows/upload_github_release_asset.yml
needs: zip
Expand All @@ -99,11 +99,11 @@ jobs:
apk:
name: Build Android APK
needs: whl
uses: learningequality/kolibri-installer-android/.github/workflows/build_apk.yml@develop
uses: learningequality/kolibri-installer-android/.github/workflows/build_apk.yml@v0.1.0
with:
tar-file-name: ${{ needs.whl.outputs.tar-file-name }}
release: true
ref: develop
ref: v0.1.0
secrets:
KOLIBRI_ANDROID_APP_PRODUCTION_KEYSTORE: ${{ secrets.KOLIBRI_ANDROID_APP_PRODUCTION_KEYSTORE }}
KOLIBRI_ANDROID_APP_PRODUCTION_KEYSTORE_PASSWORD: ${{ secrets.KOLIBRI_ANDROID_APP_PRODUCTION_KEYSTORE_PASSWORD }}
Expand Down Expand Up @@ -196,9 +196,9 @@ jobs:
name: Release Android App
if: ${{ !github.event.release.prerelease }}
needs: [apk, block_release_step]
uses: learningequality/kolibri-installer-android/.github/workflows/release_apk.yml@develop
uses: learningequality/kolibri-installer-android/.github/workflows/release_apk.yml@v0.1.0
with:
version-code: ${{ needs.apk.outputs.version-code }}
ref: develop
ref: v0.1.0
secrets:
KOLIBRI_ANDROID_PLAY_STORE_API_SERVICE_ACCOUNT_JSON: ${{ secrets.KOLIBRI_ANDROID_PLAY_STORE_API_SERVICE_ACCOUNT_JSON }}
59 changes: 59 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,65 @@

List of the most important changes for each release.


## 0.16.0

### Features

#### Robust syncing of user data and resources
##### Support for quick learner setup and independent learners
- Kolibri has a new onboarding experience which allows joining a facility, and streamlines getting started as an independent learner with a rapid “on my own setup” option
- Independent learners can transfer their existing data and learning progress to a facility.
##### Resource discovery
- Assigned lesson and quiz resources are now automatically transferred to learner devices, allowing coaches to dynamically manage learner content, rather than an administrator needing to import all content devices before distribution.
- Administrators and independent learners are now able to view other Kolibri Libraries on their local network and browse their resources, without having to import content. If they are connected to the internet, they will be able to browse resources on the Kolibri Content Library (hosted on Kolibri Studio).
- Administrators can allow learners to download resources from other Kolibri Libraries to their device to view within Kolibri, even when they are no longer on the same network.
##### Support for administrators
- Administrators have a new option to add a PIN on learner-only devices, which allows an administrator easy access to the Device page while preventing learners from inadvertently making changes.
- Administrators are now able to schedule syncing of facility data on a recurring basis at custom intervals.
- When exporting log files, administrators are able to select the date range for the logs.
##### Practice quizzes
- This release supports practice quizzes, which are resources in the format of quizzes that learners can take in preparation for an assessment. They are able to see their score, and retry as many times as they would like, independently. Practice quiz resources are available through the Library, or can be assigned as part of a lesson. The same questions can also be assigned as a coach assigned quiz as a standardized assessment.

### Changes

#### Dev documentation/dev updates
- Updated node version to 18
- Getting started documentation updated
- Updated to Webpack 5
- Created Github actions for build pipeline
- Created Github action to add assets to PRs
- Task API changes have been finalized after initial work in 0.15. Documentation is now updated to describe how to interact with the API and define tasks in plugins.

#### Architectural changes
- There is a new page architecture that is used across all Kolibri plugins, and the component has been removed. (Selected relevant high level issues and PRs: #9102, #9128, 9134.)
- The Kolibri Process Bus has been updated to support easier composability for custom deployment architectures.
- Conditional promises have been removed.
- To support the new onboarding process for Kolibri, Kolibri apps can now access a capability to provide access controls based on the currently active operating system user.

#### API Breaking Changes
- Tasks API has now been finalized, previous methods for interacting with tasks that do not use the pluggable Tasks API have been removed.
- The drive info endpoint has been moved the into the device app but functionality remains the same
- The API for coordinating learner only device synchronization within a local area network has been updated to ensure robust and reliable syncing. Any users wishing to use learner only device synchronization must update all Kolibri devices to this newer version

#### API Additions (non-breaking changes)
- REST API for enabling and disabling plugins
- Add API endpoint and hook driven capability for UI initiated device restart
- Public signup viewset
- Public content metadata endpoints to support granular resource import

#### Accessibility improvements
- Landmarks have been added and refined across the Library page and its related subpages, for better accessibility. This is a first step in support of more robust accessibility support, particularly in terms of page navigation for screen reader users.

### Deprecations
- Support for Python 2.7 will be dropped in the upcoming version, 0.17. Upgrade your Python version to Python 3.6+ to continue working with Kolibri. More recent versions of Python 3 are recommended.
- Support for this Internet Explorer 11 will be dropped in the upcoming version, 0.17. We recommend installing other browsers, such as Mozilla Firefox or Google Chrome, in order to continue working with Kolibri.

### Kolibry Design System upgrades
- Kolibri is now using kolibri-design-system v2.0.0 (a major version upgrade!). Please see the KDS release's Github page for documentation and full details about breaking changes and new features.



## 0.15.12

### Added
Expand Down
2 changes: 1 addition & 1 deletion kolibri/core/assets/src/views/SyncStatusDescription.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
},
queuedDescription: {
message: 'The device is waiting to sync.',
context: 'Description of the device syncing status.',
context: 'Description of the device syncing status',
},
unableOrNoSyncDescription: {
message:
Expand Down
16 changes: 14 additions & 2 deletions kolibri/core/auth/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
from kolibri.core.device.utils import allow_guest_access
from kolibri.core.device.utils import allow_other_browsers_to_connect
from kolibri.core.device.utils import APP_AUTH_TOKEN_COOKIE_NAME
from kolibri.core.device.utils import is_full_facility_import
from kolibri.core.device.utils import valid_app_key_on_request
from kolibri.core.logger.models import UserSessionLog
from kolibri.core.mixins import BulkCreateMixin
Expand Down Expand Up @@ -180,6 +181,10 @@ class Meta:
fields = ["facility_id"]


def _is_full_facility_import(dataset):
return is_full_facility_import(dataset["id"])


class FacilityDatasetViewSet(ValuesViewset):
permission_classes = (KolibriAuthPermissions,)
filter_backends = (
Expand All @@ -205,7 +210,10 @@ class FacilityDatasetViewSet(ValuesViewset):
"preset",
)

field_map = {"allow_guest_access": lambda x: allow_guest_access()}
field_map = {
"allow_guest_access": lambda x: allow_guest_access(),
"is_full_facility_import": _is_full_facility_import,
}

def get_queryset(self):
return FacilityDataset.objects.filter(
Expand Down Expand Up @@ -772,7 +780,11 @@ class SignUpViewSet(viewsets.GenericViewSet, CreateModelMixin):
serializer_class = FacilityUserSerializer

def check_can_signup(self, serializer):
if not serializer.validated_data["facility"].dataset.learner_can_sign_up:
facility = serializer.validated_data["facility"]
if (
not facility.dataset.learner_can_sign_up
or not facility.dataset.full_facility_import
):
raise PermissionDenied("Cannot sign up to this facility")

def perform_create(self, serializer):
Expand Down
9 changes: 3 additions & 6 deletions kolibri/core/auth/kolibri_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ def handle_initial(self, context):
from kolibri.core.device.utils import device_provisioned

if context.is_receiver and device_provisioned():
is_pull = context.is_pull
is_push = context.is_push
pull = context.is_pull
push = context.is_push
sync_filter = str(context.filter)

instance_kwargs = {}
Expand All @@ -51,10 +51,7 @@ def handle_initial(self, context):

cleanupsync.enqueue(
kwargs=dict(
is_pull=is_pull,
is_push=is_push,
sync_filter=sync_filter,
**instance_kwargs
pull=pull, push=push, sync_filter=sync_filter, **instance_kwargs
)
)

Expand Down
7 changes: 7 additions & 0 deletions kolibri/core/auth/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,13 @@ def reset_to_default_settings(self, preset=None):
setattr(self, key, value)
self.save()

@cached_property
def full_facility_import(self):
"""
Returns True if this user is a member of a facility that has been fully imported.
"""
return is_full_facility_import(self.id)


class AbstractFacilityDataModel(FacilityDataSyncableModel):
"""
Expand Down
14 changes: 6 additions & 8 deletions kolibri/core/auth/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -613,20 +613,18 @@ def deletefacility(facility):


class CleanUpSyncsValidator(JobValidator):
is_pull = serializers.BooleanField(required=False)
is_push = serializers.BooleanField(required=False)
pull = serializers.BooleanField(required=False)
push = serializers.BooleanField(required=False)
sync_filter = serializers.CharField(required=True)
client_instance_id = HexOnlyUUIDField(required=False)
server_instance_id = HexOnlyUUIDField(required=False)

def validate(self, data):
if data.get("is_pull") is None and data.get("is_push") is None:
if data.get("pull") is None and data.get("push") is None:
raise serializers.ValidationError("Either pull or push must be specified")
elif data.get("pull") is data.get("push"):
raise serializers.ValidationError(
"Either is_pull or is_push must be specified"
)
elif data.get("is_pull") is data.get("is_push"):
raise serializers.ValidationError(
"Only one of is_pull or is_push needs to be specified"
"Only one of pull or push needs to be specified"
)

if (
Expand Down
26 changes: 12 additions & 14 deletions kolibri/core/auth/test/test_auth_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -802,26 +802,24 @@ class CleanUpSyncsTaskValidatorTestCase(TestCase):
def setUp(self):
self.kwargs = dict(
type=cleanupsync.__name__,
is_push=True,
is_pull=False,
push=True,
pull=False,
sync_filter=uuid4().hex,
client_instance_id=uuid4().hex,
)

def test_validator__no_push_no_pull(self):
self.kwargs.pop("is_push")
self.kwargs.pop("is_pull")
self.kwargs.pop("push")
self.kwargs.pop("pull")
validator = CleanUpSyncsValidator(data=self.kwargs)
with self.assertRaisesRegex(
serializers.ValidationError, "Either is_pull or is_push"
):
with self.assertRaisesRegex(serializers.ValidationError, "Either pull or push"):
validator.is_valid(raise_exception=True)

def test_validator__both_push_and_pull(self):
self.kwargs.update(is_pull=True)
self.kwargs.update(pull=True)
validator = CleanUpSyncsValidator(data=self.kwargs)
with self.assertRaisesRegex(
serializers.ValidationError, "Only one of is_pull or is_push"
serializers.ValidationError, "Only one of pull or push"
):
validator.is_valid(raise_exception=True)

Expand Down Expand Up @@ -853,8 +851,8 @@ def test_validator__no_sync_filter(self):
class CleanUpSyncsTaskTestCase(TestCase):
def setUp(self):
self.kwargs = dict(
is_push=True,
is_pull=False,
push=True,
pull=False,
sync_filter=uuid4().hex,
client_instance_id=uuid4().hex,
)
Expand All @@ -876,8 +874,8 @@ def test_calls_command(self, mock_call_command):
mock_call_command.assert_called_with(
"cleanupsyncs",
expiration=1,
is_push=self.kwargs["is_push"],
is_pull=self.kwargs["is_pull"],
push=self.kwargs["push"],
pull=self.kwargs["pull"],
sync_filter=self.kwargs["sync_filter"],
client_instance_id=self.kwargs["client_instance_id"],
)
Expand All @@ -903,7 +901,7 @@ def _create_sync(self, last_activity_timestamp=None, client_instance_id=None):
id=uuid4().hex,
active=True,
sync_session=sync_session,
push=self.kwargs["is_push"],
push=self.kwargs["push"],
filter=self.kwargs["sync_filter"],
last_activity_timestamp=last_activity_timestamp,
)
Expand Down
8 changes: 4 additions & 4 deletions kolibri/core/auth/test/test_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ def test_handle_initial__is_server(self, mock_task):
self.assertFalse(result)
mock_task.enqueue.assert_called_once_with(
kwargs=dict(
is_pull=self.context.is_pull,
is_push=self.context.is_push,
pull=self.context.is_pull,
push=self.context.is_push,
sync_filter=str(self.context.filter),
client_instance_id=self.context.sync_session.client_instance_id.hex,
)
Expand All @@ -53,8 +53,8 @@ def test_handle_initial__not_server(self, mock_task):
self.assertFalse(result)
mock_task.enqueue.assert_called_once_with(
kwargs=dict(
is_pull=self.context.is_pull,
is_push=self.context.is_push,
pull=self.context.is_pull,
push=self.context.is_push,
sync_filter=str(self.context.filter),
server_instance_id=self.context.sync_session.server_instance_id.hex,
)
Expand Down
Loading
Loading