Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
33 changes: 0 additions & 33 deletions contentcuration/contentcuration/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
from django.core.files.storage import default_storage

import contentcuration.models as models
from contentcuration.utils.garbage_collect import get_deleted_chefs_root
from contentcuration.viewsets.sync.constants import CHANNEL
from contentcuration.viewsets.sync.utils import generate_update_event


def write_file_to_storage(fobj, check_valid=False, name=None):
Expand Down Expand Up @@ -68,33 +65,3 @@ def get_hash(fobj):
md5.update(chunk)
fobj.seek(0)
return md5.hexdigest()


def activate_channel(channel, user):
user.check_channel_space(channel)

if channel.previous_tree and channel.previous_tree != channel.main_tree:
# IMPORTANT: Do not remove this block, MPTT updating the deleted chefs block could hang the server
with models.ContentNode.objects.disable_mptt_updates():
garbage_node = get_deleted_chefs_root()
channel.previous_tree.parent = garbage_node
channel.previous_tree.title = "Previous tree for channel {}".format(channel.pk)
channel.previous_tree.save()

channel.previous_tree = channel.main_tree
channel.main_tree = channel.staging_tree
channel.staging_tree = None
channel.save()

user.staged_files.all().delete()
user.set_space_used()

models.Change.create_change(generate_update_event(
channel.id,
CHANNEL,
{
"root_id": channel.main_tree.id,
"staging_root_id": None
},
channel_id=channel.id,
), applied=True, created_by_id=user.id)
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { mount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import VueRouter from 'vue-router';
import cloneDeep from 'lodash/cloneDeep';
import flushPromises from 'flush-promises';

import { RouteNames } from '../../constants';
import StagingTreePage from './index';
import { createStore } from 'shared/vuex/draggablePlugin/test/setup';
import { ContentKindsNames } from 'shared/leUtils/ContentKinds';
import { Channel } from 'shared/data/resources';

const localVue = createLocalVue();
localVue.use(Vuex);
Expand Down Expand Up @@ -217,9 +217,14 @@ describe('StagingTreePage', () => {
];
};

mockDeployCurrentChannel = jest.fn().mockResolvedValue('');
mockDeployCurrentChannel = jest.fn();
actions.currentChannel.deployCurrentChannel = mockDeployCurrentChannel;
//actions.channel.loadChannel = jest.fn().mockResolvedValue('')

Channel.waitForDeploying = () => {
return new Promise(resolve => {
return resolve(ROOT_ID);
});
};

wrapper = initWrapper({ getters, actions });
// make sure router is reset before each test
Expand Down Expand Up @@ -414,9 +419,11 @@ describe('StagingTreePage', () => {
});

it('redirects to a root tree page after deploy channel button click', async () => {
getDeployDialog(wrapper).vm.$emit('submit');
await flushPromises();
let waitForDeployingSpy = jest.spyOn(Channel, 'waitForDeploying');

await getDeployDialog(wrapper).vm.$emit('submit');

expect(waitForDeployingSpy).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.currentRoute.name).toBe(RouteNames.TREE_VIEW);
expect(wrapper.vm.$router.currentRoute.params).toEqual({
nodeId: ROOT_ID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<span class="grey--darken-2 grey--text">{{ $tr('reviewMode') }}</span>
</ToolBar>
<MainNavigationDrawer v-model="drawer" />
<LoadingText v-if="isLoading" />
<LoadingText v-if="isLoading || isDeploying" />
<VContent v-else-if="isEmpty">
<VLayout justify-center fill-height class="pt-5">
<VFlex class="text-xs-center">
Expand Down Expand Up @@ -204,8 +204,8 @@
data-test="deploy-dialog"
:title="$tr('deployChannel')"
:submitText="$tr('confirmDeployBtn')"
:submitDisabled="submitDisabled"
:cancelDisabled="submitDisabled"
:submitDisabled="isDeploying"
:cancelDisabled="isDeploying"
:cancelText="$tr('cancelDeployBtn')"
@submit="onDeployChannelClick"
@cancel="displayDeployDialog = false"
Expand Down Expand Up @@ -258,6 +258,7 @@
import ToolBar from 'shared/views/ToolBar';
import MainNavigationDrawer from 'shared/views/MainNavigationDrawer';
import OfflineText from 'shared/views/OfflineText';
import { Channel } from 'shared/data/resources';

export default {
name: 'StagingTreePage',
Expand Down Expand Up @@ -295,7 +296,7 @@
displayDeployDialog: false,
drawer: false,
elevated: false,
submitDisabled: false,
isDeploying: false,
};
},
computed: {
Expand Down Expand Up @@ -403,9 +404,11 @@
});
},
stagingId() {
this.$router.push({
name: RouteNames.STAGING_TREE_VIEW_REDIRECT,
});
if (this.hasStagingTree) {
this.$router.push({
name: RouteNames.STAGING_TREE_VIEW_REDIRECT,
});
}
},
},
created() {
Expand All @@ -432,7 +435,6 @@
},
methods: {
...mapActions(['showSnackbar', 'addViewModeOverride', 'removeViewModeOverride']),
...mapActions('channel', ['loadChannel']),
...mapActions('currentChannel', [
'loadCurrentChannelStagingDiff',
'deployCurrentChannel',
Expand Down Expand Up @@ -506,21 +508,24 @@
scroll(e) {
this.elevated = e.target.scrollTop > 0;
},
async onDeployChannelClick() {
this.submitDisabled = true;
try {
await this.deployCurrentChannel();
} catch (e) {
this.submitDisabled = false;
throw e;
}
await this.loadChannel(this.currentChannel.id);
onDeployChannelClick() {
this.displayDeployDialog = false;
this.isDeploying = true;

this.$router.push(this.rootTreeRoute);

this.showSnackbar({
text: this.$tr('channelDeployed'),
Channel.waitForDeploying(this.currentChannel.id).then(rootId => {
this.isDeploying = false;
this.$router.push({
name: RouteNames.TREE_VIEW,
params: {
nodeId: rootId,
},
});
this.showSnackbar({
text: this.$tr('channelDeployed'),
});
});

this.deployCurrentChannel();
},
},
$trs: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,7 @@ export function reloadCurrentChannelStagingDiff(context) {
}

export function deployCurrentChannel(context) {
let payload = {
channel_id: context.state.currentChannelId,
};
return client.post(window.Urls.activate_channel(), payload).catch(e => {
// If response is 'Bad request', channel must already be activated
if (e.response && e.response.status === 400) {
return Promise.resolve();
}
});
return Channel.deploy(context.state.currentChannelId);
}

export function publishChannel(context, version_notes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { CHANGE_TYPES, IGNORED_SOURCE, TABLE_NAMES } from './constants';
import db from './db';
import { INDEXEDDB_RESOURCES } from './registry';

const { CREATED, DELETED, UPDATED, MOVED, PUBLISHED, SYNCED } = CHANGE_TYPES;
const { CREATED, DELETED, UPDATED, MOVED, PUBLISHED, SYNCED, DEPLOYED } = CHANGE_TYPES;

export function applyMods(obj, mods) {
for (let keyPath in mods) {
Expand All @@ -28,6 +28,7 @@ export function collectChanges(changes) {
[MOVED]: [],
[PUBLISHED]: [],
[SYNCED]: [],
[DEPLOYED]: [],
};
}
collectedChanges[change.table][change.type].push(change);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const CHANGE_TYPES = {
COPIED: 5,
PUBLISHED: 6,
SYNCED: 7,
DEPLOYED: 8,
};
/**
* An array of change types that directly result in the creation of nodes
Expand Down
38 changes: 38 additions & 0 deletions contentcuration/contentcuration/frontend/shared/data/resources.js
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,44 @@ export const Channel = new Resource({
});
},

deploy(id) {
const change = {
key: id,
source: CLIENTID,
table: this.tableName,
type: CHANGE_TYPES.DEPLOYED,
channel_id: id,
};
return this.transaction({ mode: 'rw', source: IGNORED_SOURCE }, CHANGES_TABLE, () => {
return db[CHANGES_TABLE].put(change);
});
},

waitForDeploying(id) {
const observable = Dexie.liveQuery(() => {
return this.table
.where('id')
.equals(id)
.filter(channel => !channel['staging_root_id'] || channel['staging_root_id'] === null)
.toArray();
});

return new Promise((resolve, reject) => {
const subscription = observable.subscribe({
next(result) {
if (result.length === 1) {
subscription.unsubscribe();
resolve(result[0].root_id);
}
},
error() {
subscription.unsubscribe();
reject();
},
});
});
},

sync(id, { attributes = false, tags = false, files = false, assessment_items = false } = {}) {
const change = {
key: id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const ChangeTypeMapFields = {
]),
[CHANGE_TYPES.PUBLISHED]: commonFields.concat(['version_notes', 'language']),
[CHANGE_TYPES.SYNCED]: commonFields.concat(['attributes', 'tags', 'files', 'assessment_items']),
[CHANGE_TYPES.DEPLOYED]: commonFields,
};

function isSyncableChange(change) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from le_utils.constants import format_presets

from contentcuration import models as cc
from contentcuration.api import activate_channel
from contentcuration.constants import user_history
from contentcuration.models import ContentNode
from contentcuration.models import File
Expand Down Expand Up @@ -146,35 +145,6 @@ def test_old_staging_tree(self):
self.assertFalse(cc.ContentNode.objects.filter(parent=garbage_node).exists())
self.assertFalse(cc.ContentNode.objects.filter(pk=child_pk).exists())

def test_activate_channel(self):
previous_tree = self.channel.previous_tree
tree(parent=previous_tree)
garbage_node = get_deleted_chefs_root()

# Previous tree shouldn't be in garbage tree until activate_channel is called
self.assertFalse(
garbage_node.get_descendants().filter(pk=previous_tree.pk).exists()
)
activate_channel(self.channel, self.user)
garbage_node.refresh_from_db()
previous_tree.refresh_from_db()
self.channel.refresh_from_db()

# We can't use MPTT methods on the deleted chefs tree because we are not running the sort code
# for performance reasons, so just do a parent test instead.
self.assertTrue(previous_tree.parent == garbage_node)

# New previous tree should not be in garbage tree
self.assertFalse(self.channel.previous_tree.parent)
self.assertNotEqual(garbage_node.tree_id, self.channel.previous_tree.tree_id)

child_pk = previous_tree.children.first().pk

clean_up_deleted_chefs()

self.assertFalse(cc.ContentNode.objects.filter(parent=garbage_node).exists())
self.assertFalse(cc.ContentNode.objects.filter(pk=child_pk).exists())


THREE_MONTHS_AGO = datetime.now() - timedelta(days=93)

Expand Down
37 changes: 0 additions & 37 deletions contentcuration/contentcuration/tests/views/test_views_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,10 @@
from django.urls import reverse_lazy

from ..base import BaseAPITestCase
from contentcuration.models import Channel
from contentcuration.models import TaskResult
from contentcuration.utils.db_tools import TreeBuilder


class APIActivateChannelEndpointTestCase(BaseAPITestCase):
def test_200_post(self):
main_tree = TreeBuilder(user=self.user)
staging_tree = TreeBuilder(user=self.user)
self.channel.main_tree = main_tree.root
self.channel.staging_tree = staging_tree.root
self.channel.save()
response = self.post(
reverse_lazy("activate_channel"), {"channel_id": self.channel.id}
)
self.assertEqual(response.status_code, 200)

def test_404_no_permission(self):
new_channel = Channel.objects.create()
staging_tree = TreeBuilder(user=self.user, levels=1)
new_channel.staging_tree = staging_tree.root
new_channel.save()
response = self.post(
reverse_lazy("activate_channel"), {"channel_id": new_channel.id}
)
self.assertEqual(response.status_code, 404)

def test_200_no_change_in_space(self):
main_tree = TreeBuilder(user=self.user)
staging_tree = TreeBuilder(user=self.user)
self.channel.main_tree = main_tree.root
self.channel.staging_tree = staging_tree.root
self.channel.save()
self.user.disk_space = self.user.get_space_used(active_files=self.user.get_user_active_files())
self.user.save()
response = self.post(
reverse_lazy("activate_channel"), {"channel_id": self.channel.id}
)
self.assertEqual(response.status_code, 200)


class PublishingStatusEndpointTestCase(BaseAPITestCase):
def test_200_get(self):
self.user.is_admin = True
Expand Down
17 changes: 0 additions & 17 deletions contentcuration/contentcuration/tests/views/test_views_internal.py
Original file line number Diff line number Diff line change
Expand Up @@ -613,23 +613,6 @@ def test_404_no_permission(self):
self.assertEqual(response.status_code, 404)


class APIActivateChannelEndpointTestCase(BaseAPITestCase):
def test_200_post(self):
self.channel.staging_tree = self.channel.main_tree
self.channel.save()
response = self.post(
reverse_lazy("activate_channel_internal"), {"channel_id": self.channel.id}
)
self.assertEqual(response.status_code, 200)

def test_404_no_permission(self):
new_channel = Channel.objects.create()
response = self.post(
reverse_lazy("activate_channel_internal"), {"channel_id": new_channel.id}
)
self.assertEqual(response.status_code, 404)


class CheckUserIsEditorEndpointTestCase(BaseAPITestCase):
def test_200_post(self):
response = self.post(
Expand Down
Loading