Skip to content

Commit

Permalink
Merge pull request #10450 from rtibbles/studio_54
Browse files Browse the repository at this point in the history
Update remote browsing of Studio
  • Loading branch information
rtibbles authored Apr 13, 2023
2 parents f85f86b + 5001d35 commit df84c0d
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 84 deletions.
13 changes: 10 additions & 3 deletions kolibri/core/content/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ def _should_proxy_request(self, request):
def _get_request_headers(self, request):
return {
"Accept": request.META.get("HTTP_ACCEPT"),
"Accept-Encoding": request.META.get("HTTP_ACCEPT_ENCODING"),
# Don't proxy client's accept headers as it may include br for brotli
# that we cannot rely on having decompression for available on the server.
"Accept-Language": request.META.get("HTTP_ACCEPT_LANGUAGE"),
"Content-Type": request.META.get("CONTENT_TYPE"),
"If-None-Match": request.META.get("HTTP_IF_NONE_MATCH", ""),
Expand Down Expand Up @@ -154,6 +155,9 @@ def _hande_proxied_request(self, request):
response = requests.get(
remote_url, params=qs, headers=self._get_request_headers(request)
)
if response.status_code == 404:
raise Http404("Remote resource not found")
response.raise_for_status()
# If Etag is set on the response we have returned here, any further Etag will not be modified
# by the django etag decorator, so this should allow us to transparently proxy the remote etag.
try:
Expand Down Expand Up @@ -1721,6 +1725,9 @@ def kolibri_studio_status(self, request, **kwargs):
if resp.status_code == 404:
raise requests.ConnectionError("Kolibri Studio URL is incorrect!")
else:
return Response({"status": "online"})
data = resp.json()
data["available"] = True
data["status"] = "online"
return Response(data)
except requests.ConnectionError:
return Response({"status": "offline"})
return Response({"status": "offline", "available": False})
37 changes: 35 additions & 2 deletions kolibri/plugins/learn/assets/src/composables/useDevices.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,52 @@
*/

import { computed, getCurrentInstance, ref } from 'kolibri.lib.vueCompositionApi';
import { NetworkLocationResource } from 'kolibri.resources';
import { NetworkLocationResource, RemoteChannelResource } from 'kolibri.resources';
import { get, set } from '@vueuse/core';
import useMinimumKolibriVersion from 'kolibri.coreVue.composables.useMinimumKolibriVersion';
import { KolibriStudioId } from '../constants';
import { learnStrings } from '../views/commonLearnStrings';
import plugin_data from 'plugin_data';

// The refs are defined in the outer scope so they can be used as a shared store
const currentDevice = ref(null);

const KolibriStudioDeviceData = {
id: KolibriStudioId,
instance_id: KolibriStudioId,
base_url: plugin_data.studio_baseurl,
get device_name() {
return learnStrings.$tr('kolibriLibrary');
},
};

const { isMinimumKolibriVersion } = useMinimumKolibriVersion(0, 16, 0);

function fetchDevices() {
return NetworkLocationResource.list().then(devices => {
return Promise.all([
RemoteChannelResource.getKolibriStudioStatus(),
NetworkLocationResource.list(),
]).then(([studioResponse, devices]) => {
const studio = studioResponse.data;
devices = devices.filter(device => isMinimumKolibriVersion(device.kolibri_version));
if (studio.available && isMinimumKolibriVersion(studio.kolibri_version || '0.15.0')) {
return [
{
...studio,
...KolibriStudioDeviceData,
},
...devices,
];
}
return devices;
});
}

export function setCurrentDevice(id) {
if (id === KolibriStudioId) {
set(currentDevice, KolibriStudioDeviceData);
return Promise.resolve(KolibriStudioDeviceData);
}
return NetworkLocationResource.fetchModel({ id }).then(device => {
set(currentDevice, device);
return device;
Expand Down
45 changes: 9 additions & 36 deletions kolibri/plugins/learn/assets/src/modules/recommended/handlers.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { get } from '@vueuse/core';
import { ContentNodeResource, RemoteChannelResource } from 'kolibri.resources';
import { ContentNodeResource } from 'kolibri.resources';
import samePageCheckGenerator from 'kolibri.utils.samePageCheckGenerator';
import { PageNames, KolibriStudioId } from '../../constants';
import { PageNames } from '../../constants';
import useChannels from '../../composables/useChannels';
import { setCurrentDevice } from '../../composables/useDevices';
import useLearnerResources from '../../composables/useLearnerResources';
import { searchKeys } from '../../composables/useSearch';
import plugin_data from 'plugin_data';

const { channels, fetchChannels } = useChannels();

Expand Down Expand Up @@ -78,39 +77,13 @@ function _showLibrary(store, query, channels, baseurl) {
}

export function showLibrary(store, query, deviceId = null) {
/**
* ToDo: remove if block.
* Currently the channels & contentnode browser apis in studio
* are not able to load content using the the studio base url.
* Once studio is updated, this function will need to be refactored
* to use the else block code only.
*
* The if block is meant for UI viualization purposes only
* during development
*/
if (deviceId === KolibriStudioId) {
RemoteChannelResource.getKolibriStudioStatus().then(({ data }) => {
if (data.status === 'online') {
RemoteChannelResource.fetchCollection().then(channels => {
//This is a hack to return kolibri channels.
store.commit('SET_ROOT_NODES', channels);

store.commit('CORE_SET_PAGE_LOADING', false);
store.commit('CORE_SET_ERROR', null);
store.commit('SET_PAGE_NAME', PageNames.LIBRARY);
return Promise.resolve();
});
}
});
} else {
if (deviceId) {
return setCurrentDevice(deviceId).then(device => {
const baseurl = deviceId === KolibriStudioId ? plugin_data.studio_baseurl : device.base_url;
return fetchChannels({ baseurl }).then(channels => {
return _showLibrary(store, query, channels, baseurl);
});
if (deviceId) {
return setCurrentDevice(deviceId).then(device => {
const baseurl = device.base_url;
return fetchChannels({ baseurl }).then(channels => {
return _showLibrary(store, query, channels, baseurl);
});
}
return _showLibrary(store, query, get(channels));
});
}
return _showLibrary(store, query, get(channels));
}
13 changes: 11 additions & 2 deletions kolibri/plugins/learn/assets/src/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { setClasses, setResumableContentNodes } from '../composables/useLearnerR
import { setContentNodeProgress } from '../composables/useContentNodeProgress';
import { showTopicsTopic, showTopicsContent } from '../modules/topicsTree/handlers';
import { showLibrary } from '../modules/recommended/handlers';
import { PageNames, ClassesPageNames } from '../constants';
import { PageNames, ClassesPageNames, KolibriStudioId } from '../constants';
import LibraryPage from '../views/LibraryPage';
import HomePage from '../views/HomePage';
import TopicsPage from '../views/TopicsPage';
Expand Down Expand Up @@ -45,7 +45,7 @@ function hydrateHomePage() {
});
}

const optionalDeviceIdPathSegment = '/:deviceId([a-f0-9]{32}|kolibri-studio)?';
const optionalDeviceIdPathSegment = `/:deviceId([a-f0-9]{32}|${KolibriStudioId})?`;

export default [
{
Expand Down Expand Up @@ -205,6 +205,15 @@ export default [
name: PageNames.EXPLORE_LIBRARIES,
path: '/explore_libraries',
component: ExploreLibrariesPage,
handler: () => {
if (!get(isUserLoggedIn)) {
router.replace({ name: PageNames.LIBRARY });
return;
}
if (unassignedContentGuard()) {
return unassignedContentGuard();
}
},
},
{
path: '*',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,6 @@
{{ $tr('showingLibraries') }}
</p>
</div>
<LibraryItem
v-if="showKolibriLibrary"
:key="kolibriStudioId"
:deviceId="kolibriStudioId"
:deviceName="learnString('kolibriLibrary')"
deviceIcon="cloud"
:channels="kolibriLibraryChannels"
:showDescription="true"
:totalChannels="totalChannels"
:pinIcon="getPinIcon(true)"
/>
<LibraryItem
v-for="device in pinnedDevices"
:key="device['instance_id']"
Expand All @@ -35,7 +24,7 @@
:deviceIcon="getDeviceIcon(device)"
:channels="device.channels"
:totalChannels="device['total_channels']"
:pinIcon="getPinIcon(isPinned(device['instance_id']))"
:pinIcon="getPinIcon(true)"
@togglePin="handlePinToggle"
/>
<div v-if="areMoreDevicesAvailable">
Expand All @@ -54,7 +43,7 @@
:deviceIcon="getDeviceIcon(device)"
:channels="device.channels"
:totalChannels="device['total_channels']"
:pinIcon="getPinIcon(isPinned(device['instance_id']))"
:pinIcon="getPinIcon(false)"
@togglePin="handlePinToggle"
/>
<KButton
Expand All @@ -75,7 +64,6 @@
import ImmersivePage from 'kolibri.coreVue.components.ImmersivePage';
import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings';
import { crossComponentTranslator } from 'kolibri.utils.i18n';
import { RemoteChannelResource } from 'kolibri.resources';
import commonLearnStrings from '../commonLearnStrings';
import useChannels from '../../composables/useChannels';
import useDevices from '../../composables/useDevices';
Expand Down Expand Up @@ -108,9 +96,6 @@
data() {
return {
networkDevices: [],
kolibriLibraryChannels: [],
totalChannels: 0,
isKolibriLibraryLoaded: false,
moreDevices: [],
usersPins: [],
};
Expand All @@ -131,11 +116,12 @@
this.moreDevices.length > 0 && this.moreDevices.length < this.unpinnedDevices?.length
);
},
kolibriStudioId() {
return KolibriStudioId;
},
networkDevicesWithChannels() {
return this.networkDevices.filter(device => device.channels?.length > 0);
return this.networkDevices.filter(
device =>
device.channels?.length > 0 &&
(device.instance_id !== KolibriStudioId || this.isSuperuser)
);
},
pageHeaderStyle() {
return {
Expand All @@ -150,12 +136,12 @@
},
pinnedDevices() {
return this.networkDevicesWithChannels.filter(netdev => {
return this.usersPinsDeviceIds.includes(netdev.instance_id);
return (
this.usersPinsDeviceIds.includes(netdev.instance_id) ||
netdev.instance_id === KolibriStudioId
);
});
},
showKolibriLibrary() {
return this.isSuperuser && this.isKolibriLibraryLoaded;
},
unpinnedDevices() {
return this.networkDevicesWithChannels.filter(netdev => {
return !this.usersPinsDeviceIds.includes(netdev.instance_id);
Expand All @@ -171,19 +157,6 @@
});
});
RemoteChannelResource.getKolibriStudioStatus().then(({ data }) => {
if (data.status === 'online') {
RemoteChannelResource.fetchCollection()
.then(channels => {
this.isKolibriLibraryLoaded = true;
this.kolibriLibraryChannels = channels.slice(0, 4);
this.totalChannels = channels.length;
})
.catch(() => {
this.isKolibriLibraryLoaded = true;
});
}
});
this.fetchDevices().then(devices => {
this.networkDevices = devices;
for (const device of this.networkDevices) {
Expand All @@ -199,9 +172,6 @@
});
},
methods: {
isPinned(instance_id) {
return this.usersPinsDeviceIds.includes(instance_id);
},
createPin(instance_id) {
return this.createPinForUser(instance_id).then(response => {
const id = response.id;
Expand Down

0 comments on commit df84c0d

Please sign in to comment.