Skip to content
Closed
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
29 changes: 22 additions & 7 deletions contentcuration/contentcuration/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import json
from django.conf import settings
from django.contrib import admin
from django.core.cache import cache
from django.core.files.storage import FileSystemStorage
from django.db import IntegrityError, connections, models, connection
from django.db.models import Q, Sum, Max, Count, Case, When, IntegerField
Expand Down Expand Up @@ -345,7 +346,7 @@ class ContentNode(MPTTModel, models.Model):
# TODO: disallow nulls once existing models have been set
original_channel_id = UUIDField(primary_key=False, editable=False, null=True, db_index=True) # Original channel copied from
source_channel_id = UUIDField(primary_key=False, editable=False, null=True) # Immediate channel copied from
original_source_node_id = UUIDField(primary_key=False, editable=False, null=True) # Original node_id of node copied from (TODO: original_node_id clashes with original_node field - temporary)
original_source_node_id = UUIDField(primary_key=False, editable=False, null=True, db_index=True) # Original node_id of node copied from (TODO: original_node_id clashes with original_node field - temporary)
source_node_id = UUIDField(primary_key=False, editable=False, null=True) # Immediate node_id of node copied from

# Fields specific to content generated by Ricecooker
Expand Down Expand Up @@ -377,29 +378,43 @@ class ContentNode(MPTTModel, models.Model):
objects = TreeManager()

def get_original_node(self):

key = "original_channel_{}".format(self.original_source_node_id or self.pk)
cached_data = cache.get(key)
if cached_data:
return cached_data
original_node = self.original_node or self
if self.original_channel_id and self.original_source_node_id:
original_channel = Channel.objects.get(pk=self.original_channel_id)
return original_channel.main_tree.get_descendants().filter(node_id=self.original_source_node_id).first() or self

return self.original_node or self
original_node = original_channel.main_tree.get_descendants().filter(node_id=self.original_source_node_id).first() or self
cache.set(key, original_node, None)
return original_node

def get_associated_presets(self):
key = "associated_presets_{}".format(self.kind_id)
cached_data = cache.get(key)
if cached_data:
return cached_data
presets = FormatPreset.objects.filter(kind=self.kind).values()
cache.set(key, presets, None)
return presets

def get_channel(self):
root = self.get_root()
channel = root.channel_main or root.channel_trash or root.channel_language or root.channel_previous
channel = root.channel_main or root.channel_trash or root.channel_staging or root.channel_previous
if channel:
return channel.first()
return channel

def save(self, *args, **kwargs):
# Detect if node has been moved to another tree
if self.pk is not None and ContentNode.objects.filter(pk=self.pk).exists():
if self.pk and ContentNode.objects.filter(pk=self.pk).exists():
original = ContentNode.objects.get(pk=self.pk)
if original.parent and original.parent_id != self.parent_id and not original.parent.changed:
original.parent.changed = True
original.parent.save()

super(ContentNode, self).save(*args, **kwargs)

post_save_changes = False
if self.original_node is None:
self.original_node = self
Expand Down
197 changes: 94 additions & 103 deletions contentcuration/contentcuration/serializers.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
<div class="{{#if isfolder}} folder_item {{#unless isempty}}export_folder{{/unless}}{{/if}}" title="{{node.title}}">
{{#unless isfolder}}<span class="glyphicon glyphicon-{{#get_icon node.kind}}{{/get_icon}}"></span>{{/unless}}
<span class="export_item_title truncate">{{node.title}}</span>
<div class="export_item_title truncate">{{node.title}}</div>
{{#if isfolder}}
{{#if isempty}}
<em class="annotation">(empty)</em>
{{else}}
<em class="annotation">{{#format_count "Resource" node.metadata.resource_count}}{{/format_count}}</em>
<span id="menu_toggle_{{node.id}}" class="toggler glyphicon glyphicon-menu-right"></span>
{{/if}}
{{else}}
<em class="annotation">({{#format_file_size node.metadata.resource_size}}{{/format_file_size}})</em>
{{/if}}
</div>

{{#if isfolder}}
<div id="export_item_{{node.id}}_sub" class="subdirectory"> </div>
{{/if}}
{{/if}}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
</button>
<span id="export_totals" class="pull-right">
{{#format_count "Resource" node.metadata.resource_count}}{{/format_count}}
<em class="annotation" id="export_size">(Calculating size...)</em>
<em class="annotation" id="export_size">(Calculating...)</em>
</span>
<a class="action-text" data-dismiss="modal">
<span>CANCEL</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ var ExportModalView = BaseViews.BaseModalView.extend({
});

var self = this;
this.retrieve_nodes(this.model.get('children')).then(function(collection){
var size = collection.reduce(function(size, node){ return size + node.get('metadata').resource_size; }, 0);
this.model.calculate_size().then(function(size){
self.$("#export_size").text("(" + stringHelper.format_size(size) + ")");
});
},
Expand Down Expand Up @@ -62,7 +61,7 @@ var ExportListView = BaseViews.BaseListView.extend({
this.$el.html(this.template({id: this.model.get("id")}));
var self = this;
this.fetch_model(this.model).then(function(fetched){
self.collection.get_all_fetch(fetched.get("children")).then(function(fetchedCollection){
self.collection.get_all_fetch_simplified(fetched.get("children")).then(function(fetchedCollection){
self.load_content(fetchedCollection);
});
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@
<button disabled class="action-button pull-right" id="import_content_submit">
Select content to import...
</button>
<span id="import_file_count" class="pull-right"><em>No files selected</em></span>
<span id="import_file_metadata" class="pull-right">
<span id="import_file_count">0 Topics, 0 Resources</span>
(<em id="import_file_size">0B</em>)
</span>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
<div class="import_item_title truncate">{{node.title}}</div>
{{#if isfolder}}
{{#if node.children}}
{{#if isfolder}}
{{#unless is_channel}}<em class="import_metadata">{{#format_count "Resource" node.metadata.resource_count}}{{/format_count}}</em>{{/unless}}
{{else}}
<em class="import_metadata">{{#format_file_size node.metadata.resource_size}}{{/format_file_size}}</em>
{{/if}}
<div id="menu_toggle_{{node.id}}" class="toggler glyphicon glyphicon-triangle-top"></div>
{{!-- {{#unless is_channel}}<em class="import_metadata">{{#format_file_size node.metadata.resource_size}}{{/format_file_size}}</em>{{/unless}} --}}
{{else}}
<em class="import_metadata">(empty)</em>
{{/if}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,16 @@ var ImportView = BaseViews.BaseListView.extend({
}else{
totalCount += entry.get("metadata").total_count;
}

});
var data = this.importList.get_metadata();
totalCount = totalCount - data.count;

this.$("#import_file_count").html(totalCount + " Topic" + ((totalCount == 1)? ", " : "s, ") + data.count + " Resource" + ((data.count == 1)? " " : "s ") + stringHelper.format_size(data.size));
this.$("#import_file_count").html(totalCount + " Topic" + ((totalCount == 1)? ", " : "s, ") + data.count + " Resource" + ((data.count == 1)? "" : "s"));
var self = this;
this.$("#import_file_size").html("Calculating...")
collection.calculate_size().then(function(size){
self.$("#import_file_size").html(stringHelper.format_size(size));
});
},
import_content:function(){
var self = this;
Expand Down Expand Up @@ -172,7 +176,6 @@ var ImportList = BaseViews.BaseListView.extend({
this.metadata = {"count" : 0, "size":0};
this.views.forEach(function(entry){
self.metadata.count += entry.metadata.count;
self.metadata.size += entry.metadata.size;
});
return this.metadata;
}
Expand Down
101 changes: 66 additions & 35 deletions contentcuration/contentcuration/static/js/edit_channel/models.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,11 @@ var InvitationCollection = BaseCollection.extend({
});

/**** CHANNEL AND CONTENT MODELS ****/
function fetch_nodes_by_ids(ids){
var self = this;
function fetch_nodes(ids, url){
return new Promise(function(resolve, reject){
$.ajax({
method:"POST",
url: window.Urls.get_nodes_by_ids(),
url: url,
data: JSON.stringify(ids),
error: reject,
success: function(data) {
Expand All @@ -140,22 +139,10 @@ function fetch_nodes_by_ids(ids){
});
});
}
function fetch_nodes_by_ids_simplified(ids){
var self = this;
return new Promise(function(resolve, reject){
$.ajax({
method:"POST",
url: window.Urls.get_nodes_by_ids_simplified(),
data: JSON.stringify(ids),
error: reject,
success: function(data) {
resolve(new ContentNodeCollection(JSON.parse(data)));
}
});
});
function fetch_nodes_by_ids(ids){
return fetch_nodes(ids, window.Urls.get_nodes_by_ids());
}


var ContentNodeModel = BaseModel.extend({
root_list:"contentnode-list",
model_name:"ContentNodeModel",
Expand Down Expand Up @@ -214,6 +201,21 @@ var ContentNodeModel = BaseModel.extend({
data['randomize'] = (data['randomize'] !== undefined)? data['randomize'] : window.preferences.auto_randomize_questions;
this.set('extra_fields', data);
}
},
calculate_size: function(){
var self = this;
var promise = new Promise(function(resolve, reject){
$.ajax({
method:"POST",
url: window.Urls.get_total_size(),
data: JSON.stringify([self.id]),
error:reject,
success: function(data) {
resolve(JSON.parse(data).size);
}
});
});
return promise;
}
});

Expand Down Expand Up @@ -248,28 +250,61 @@ var ContentNodeCollection = BaseCollection.extend({
});
});
});
return promise;
},
get_all_fetch: function(ids, force_fetch){
force_fetch = (force_fetch)? true : false;
var self = this;
get_descendant_ids: function(){
var self = this;
return new Promise(function(resolve, reject){
var idlists = _.partition(ids, function(id){return force_fetch || !self.get({'id': id});});
var returnCollection = new ContentNodeCollection(self.filter(function(n){ return idlists[1].indexOf(n.id) >= 0; }))
fetch_nodes_by_ids(idlists[0]).then(function(fetched){
returnCollection.add(fetched.toJSON());
resolve(returnCollection);
});
$.ajax({
method:"POST",
url: window.Urls.get_node_descendants(),
data: JSON.stringify(self.pluck('id')),
success: function(data) {
resolve(JSON.parse(data).node_ids.split(" "));
},
error:reject
});
});
},
calculate_size: function(){
var self = this;
return new Promise(function(resolve, reject){
$.ajax({
method:"POST",
url: window.Urls.get_total_size(),
data: JSON.stringify(self.pluck('id')),
success: function(data) {
resolve(JSON.parse(data).size);
},
error:reject
});
});
},
has_all_data: function(){
return this.every(function(node){
return _.every(node.get('files'), function(file){
return typeof file == 'object';
});
});
},
get_all_fetch: function(ids, force_fetch){
return this.get_fetch_nodes(ids, window.Urls.get_nodes_by_ids(), force_fetch);
},
get_all_fetch_simplified: function(ids, force_fetch){
force_fetch = (force_fetch)? true : false;
return this.get_fetch_nodes(ids, window.Urls.get_nodes_by_ids_simplified(), force_fetch);
},
fetch_nodes_by_ids_complete: function(ids, force_fetch){
return this.get_fetch_nodes(ids, window.Urls.get_nodes_by_ids_complete(), force_fetch);
},
get_fetch_nodes: function(ids, url, force_fetch){
force_fetch = (force_fetch)? true : false;
var self = this;
return new Promise(function(resolve, reject){
var idlists = _.partition(ids, function(id){return force_fetch || !self.get({'id': id});});
var returnCollection = new ContentNodeCollection(self.filter(function(n){ return idlists[1].indexOf(n.id) >= 0; }))
fetch_nodes_by_ids_simplified(idlists[0]).then(function(fetched){
fetch_nodes(idlists[0], url).then(function(fetched){
returnCollection.add(fetched.toJSON());
self.add(fetched.toJSON());
self.sort();
resolve(returnCollection);
});
});
Expand All @@ -283,7 +318,7 @@ var ContentNodeCollection = BaseCollection.extend({
},
duplicate:function(target_parent){
var self = this;
var promise = new Promise(function(resolve, reject){
return new Promise(function(resolve, reject){
var sort_order =(target_parent) ? target_parent.get("metadata").max_sort_order + 1 : 1;
var parent_id = target_parent.get("id");

Expand All @@ -297,15 +332,11 @@ var ContentNodeCollection = BaseCollection.extend({
url: window.Urls.duplicate_nodes(),
data: JSON.stringify(data),
success: function(data) {
copied_list = JSON.parse(data).node_ids.split(" ");
self.get_all_fetch(copied_list).then(function(fetched){
resolve(fetched);
});
resolve(new ContentNodeCollection(JSON.parse(data)));
},
error:reject
});
});
return promise;
},
move:function(target_parent, max_order, min_order){
var self = this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ var MoveView = BaseViews.BaseListView.extend({
this.onmove = options.onmove;
this.collection = options.collection;

// Calculate valid moves using node descendants
this.to_move_ids = _.uniq(this.collection.reduce(function(l,n){ return l.concat(n.get('descendants')).concat(n.id);}, []));
this.render();
},
events: {
Expand Down Expand Up @@ -69,13 +67,19 @@ var MoveView = BaseViews.BaseListView.extend({
clipboard_node.set({'title': 'My Clipboard'});
fetched.add(clipboard_node);

// Render list
this.targetList = new MoveList({
model: null,
el: $("#target_list_area"),
is_target: true,
collection: fetched,
container: this
// Calculate valid moves using node descendants
var self = this;
this.collection.get_descendant_ids().then(function(ids){
self.to_move_ids = ids;

// Render list
self.targetList = new MoveList({
model: null,
el: $("#target_list_area"),
is_target: true,
collection: fetched,
container: self
});
});
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ var PreviewView = BaseViews.BaseView.extend({
},
load_default_value:function(){
this.current_preview = null;
if(this.model.get('files').length){
this.current_preview = _.min(this.model.get("files"), function(file){return file.preset.order});
var preview_files = _.filter(this.model.get("files"), function(f){ return f.preset.display; });
if(preview_files.length){
this.current_preview = _.min(preview_files, function(file){return file.preset.order});
}
},
load_presets:function(){
Expand Down Expand Up @@ -118,7 +119,7 @@ var PreviewView = BaseViews.BaseView.extend({
checksum:this.current_preview.checksum,
subtitles : this.get_subtitles()
}));
if(force_load && this.current_preview.recommended_kind === "video"){
if(force_load && this.model.get('kind') === "video"){
$("#preview_window video").load();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ ChannelEditRouter = Backbone.Router.extend({
clipboard_page:function(){
this.open_channel(true, true, window.current_user.get_clipboard());
},

open_channel: function(edit_mode_on, is_clipboard, root){
window.fileformats = this.fileformats ;
window.channels = this.channelCollection;
Expand Down
Loading