def test_resource_count(self): topic_tree_node = tree() query = Metadata(topic_tree_node) results = query.annotate(**{RESOURCE_COUNT: ResourceCount()}) serialized = ContentNodeSerializer(topic_tree_node).data self.assertEqual( serialized.get('metadata').get('resource_count'), results.get(serialized.get('id')).get(RESOURCE_COUNT)) self.assertEqual(5, results.get(serialized.get('id')).get(RESOURCE_COUNT))
def test_descendant_count(self): topic_tree_node = tree() query = Metadata(topic_tree_node) results = query.annotate(**{DESCENDANT_COUNT: DescendantCount()}) serialized = ContentNodeSerializer(topic_tree_node).data self.assertEqual( serialized.get('metadata').get('total_count'), results.get(serialized.get('id')).get(DESCENDANT_COUNT)) self.assertEqual( 7, results.get(serialized.get('id')).get(DESCENDANT_COUNT))
def test_coach_count(self): topic_tree_node = tree() nested_topic = topic_tree_node.get_descendants().filter( kind=content_kinds.TOPIC).first() self.create_coach_node(nested_topic) query = Metadata(topic_tree_node) results = query.annotate(**{COACH_COUNT: CoachCount()}) serialized = ContentNodeSerializer(topic_tree_node).data self.assertEqual( serialized.get('metadata').get('coach_count'), results.get(serialized.get('id')).get(COACH_COUNT)) self.assertEqual(1, results.get(serialized.get('id')).get(COACH_COUNT))
def test_resource_size__topic(self): topic_tree_node = tree() nested_topic = topic_tree_node.get_descendants().filter( kind=content_kinds.TOPIC).first() self.create_coach_node(nested_topic) query = Metadata(topic_tree_node) results = query.annotate(**{RESOURCE_SIZE: ResourceSize()}) serialized = ContentNodeSerializer(topic_tree_node).data self.assertEqual( serialized.get('metadata').get('resource_size'), results.get(serialized.get('id')).get(RESOURCE_SIZE)) self.assertEqual(0, results.get(serialized.get('id')).get(RESOURCE_SIZE))
def test_assessment_count(self): tree() node = ContentNode.objects.get( node_id='00000000000000000000000000000005') query = Metadata(node) results = query.annotate(**{ASSESSMENT_COUNT: AssessmentCount()}) serialized = ContentNodeSerializer(node).data self.assertEqual( serialized.get('metadata').get('resource_count'), results.get(serialized.get('id')).get(ASSESSMENT_COUNT)) self.assertEqual( 3, results.get(serialized.get('id')).get(ASSESSMENT_COUNT))
def duplicate_nodes(request): logging.debug("Entering the copy_node endpoint") if request.method != 'POST': return HttpResponseBadRequest( "Only POST requests are allowed on this endpoint.") else: data = json.loads(request.body) try: nodes = data["nodes"] sort_order = data.get("sort_order") or 1 target_parent = data["target_parent"] channel_id = data["channel_id"] new_nodes = [] with transaction.atomic(): with ContentNode.objects.disable_mptt_updates(): for node_data in nodes: new_node = _duplicate_node_bulk(node_data['id'], sort_order=sort_order, parent=target_parent, channel_id=channel_id) new_nodes.append(new_node.pk) sort_order += 1 except KeyError: raise ObjectDoesNotExist( "Missing attribute from data: {}".format(data)) serialized = ContentNodeSerializer( ContentNode.objects.filter(pk__in=new_nodes), many=True).data return HttpResponse(JSONRenderer().render(serialized))
def get_nodes_by_ids(request): if request.method == 'POST': nodes = ContentNode.objects.prefetch_related('children').prefetch_related('files')\ .prefetch_related('assessment_items').prefetch_related('tags').filter(pk__in=json.loads(request.body))\ .defer('node_id', 'original_source_node_id', 'source_node_id', 'content_id', 'original_channel_id', 'source_channel_id', 'source_id', 'source_domain', 'created', 'modified') return HttpResponse(JSONRenderer().render( ContentNodeSerializer(nodes, many=True).data))
def get_nodes_by_ids(request, ids): nodes = ContentNode.objects.prefetch_related('children', 'files', 'assessment_items', 'tags')\ .filter(pk__in=ids.split(","))\ .defer('node_id', 'original_source_node_id', 'source_node_id', 'content_id', 'original_channel_id', 'source_channel_id', 'source_id', 'source_domain', 'created', 'modified') serializer = ContentNodeSerializer(nodes, many=True) return Response(serializer.data)
def get_node_path(request): if request.method == 'POST': data = json.loads(request.body) try: topic = ContentNode.objects.prefetch_related('children').get( node_id=data['topic_id'], tree_id=data['tree_id']) if topic.kind_id != content_kinds.TOPIC: node = ContentNode.objects.prefetch_related('files')\ .prefetch_related('assessment_items')\ .prefetch_related('tags').get(node_id=data['topic_id'], tree_id=data['tree_id']) nodes = node.get_ancestors(ascending=True) else: node = data['node_id'] and ContentNode.objects.prefetch_related('files')\ .prefetch_related('assessment_items')\ .prefetch_related('tags').get(node_id=data['node_id'], tree_id=data['tree_id']) nodes = topic.get_ancestors(include_self=True, ascending=True) return HttpResponse( json.dumps({ 'path': JSONRenderer().render( ContentNodeSerializer(nodes, many=True).data), 'node': node and JSONRenderer().render( ContentNodeEditSerializer(node).data), 'parent_node_id': topic.kind_id != content_kinds.TOPIC and node.parent and node.parent.node_id })) except ObjectDoesNotExist: return HttpResponseNotFound( "Invalid URL: the referenced content does not exist in this channel." )
def move_nodes(request): logging.debug("Entering the move_nodes endpoint") if request.method != 'POST': return HttpResponseBadRequest( "Only POST requests are allowed on this endpoint.") else: data = json.loads(request.body) try: nodes = data["nodes"] target_parent = ContentNode.objects.get(pk=data["target_parent"]) channel_id = data["channel_id"] min_order = data.get("min_order") or 0 max_order = data.get("max_order") or min_order + len(nodes) except KeyError: return ObjectDoesNotExist( "Missing attribute from data: {}".format(data)) all_ids = [] with transaction.atomic(): with ContentNode.objects.delay_mptt_updates(): for n in nodes: min_order = min_order + float(max_order - min_order) / 2 node = ContentNode.objects.get(pk=n['id']) _move_node(node, parent=target_parent, sort_order=min_order, channel_id=channel_id) all_ids.append(n['id']) serialized = ContentNodeSerializer( ContentNode.objects.filter(pk__in=all_ids), many=True).data return HttpResponse(JSONRenderer().render(serialized))
def sync_nodes(request): logging.debug("Entering the sync_nodes endpoint") if request.method != 'POST': return HttpResponseBadRequest( "Only POST requests are allowed on this endpoint.") else: data = json.loads(request.body) try: nodes = data["nodes"] channel_id = data['channel_id'] except KeyError: return ObjectDoesNotExist( "Missing attribute from data: {}".format(data)) all_nodes = [] with transaction.atomic(), ContentNode.objects.delay_mptt_updates(): for n in nodes: node, _ = _sync_node(ContentNode.objects.get(pk=n), channel_id, sync_attributes=True, sync_tags=True, sync_files=True, sync_assessment_items=True) if node.changed: node.save() all_nodes.append(node) return HttpResponse(JSONRenderer().render( ContentNodeSerializer(all_nodes, many=True).data))
def get_node_path(request, topic_id, tree_id, node_id): try: topic = ContentNode.objects.prefetch_related('children').get( node_id__startswith=topic_id, tree_id=tree_id) if topic.kind_id != content_kinds.TOPIC: node = ContentNode.objects.prefetch_related( 'files', 'assessment_items', 'tags').get(node_id__startswith=topic_id, tree_id=tree_id) nodes = node.get_ancestors(ascending=True) else: node = node_id and ContentNode.objects.prefetch_related( 'files', 'assessment_items', 'tags').get( node_id__startswith=node_id, tree_id=tree_id) nodes = topic.get_ancestors(include_self=True, ascending=True) return HttpResponse( json.dumps({ 'path': JSONRenderer().render( ContentNodeSerializer(nodes, many=True).data), 'node': node and JSONRenderer().render( ContentNodeEditSerializer(node).data), 'parent_node_id': topic.kind_id != content_kinds.TOPIC and node.parent and node.parent.node_id })) except ObjectDoesNotExist: return HttpResponseNotFound( "Invalid URL: the referenced content does not exist in this channel." )
def duplicate_nodes_task(self, user_id, channel_id, target_parent, node_ids, sort_order=1): new_nodes = [] user = User.objects.get(id=user_id) self.progress = 0.0 self.root_nodes_to_copy = len(node_ids) self.progress += 10.0 self.update_state(state='STARTED', meta={'progress': self.progress}) with transaction.atomic(): with ContentNode.objects.disable_mptt_updates(): for node_id in node_ids: new_node = duplicate_node_bulk(node_id, sort_order=sort_order, parent=target_parent, channel_id=channel_id, user=user, task_object=self) new_nodes.append(new_node.pk) sort_order += 1 return ContentNodeSerializer(ContentNode.objects.filter(pk__in=new_nodes), many=True).data
def test_fields_are_json_serializable(self): """ The serializer should return data that is ready for serialization, and not in 'object' form. """ node_ids = ['00000000000000000000000000000003', '00000000000000000000000000000004', '00000000000000000000000000000005'] objects = ContentNodeSerializer(ContentNode.objects.filter(node_id__in=node_ids), many=True).data for object in objects: ensure_no_querysets_in_serializer(object)
def test_repr_doesnt_evaluate_querysets(self): node_ids = [ "00000000000000000000000000000003", "00000000000000000000000000000004", "00000000000000000000000000000005", ] objects = ContentNodeSerializer( ContentNode.objects.filter(node_id__in=node_ids), many=True ) object = ContentNodeSerializer( ContentNode.objects.get(node_id=node_ids[0]) ) # Ensure we don't evaluate querysets when repr is called on a Serializer. See docs for # no_field_eval_repr in contentcuration/serializers.py for more info. obj_string = repr(object) assert "QuerySet" not in obj_string, "object __repr__ contains queryset: {}".format(obj_string) objs_string = repr(objects) assert "QuerySet" not in objs_string, "objects __repr__ contains queryset: {}".format(objs_string)
def duplicate_node_inline(request): logging.debug("Entering the copy_node endpoint") if request.method != 'POST': return HttpResponseBadRequest( "Only POST requests are allowed on this endpoint.") else: data = json.loads(request.body) try: node = ContentNode.objects.get(pk=data["node_id"]) channel_id = data["channel_id"] target_parent = ContentNode.objects.get(pk=data["target_parent"]) channel = target_parent.get_channel() request.user.can_edit(channel and channel.pk) record_node_duplication_stats( [node], ContentNode.objects.get(pk=target_parent.pk), Channel.objects.get(pk=channel_id)) new_node = None with transaction.atomic(): with ContentNode.objects.disable_mptt_updates(): sort_order = ( node.sort_order + node.get_next_sibling().sort_order ) / 2 if node.get_next_sibling() else node.sort_order + 1 new_node = _duplicate_node_bulk(node, sort_order=sort_order, parent=target_parent, channel_id=channel_id, user=request.user) if not new_node.title.endswith(_(" (Copy)")): new_node.title = new_node.title + _(" (Copy)") new_node.save() return HttpResponse(JSONRenderer().render( ContentNodeSerializer( ContentNode.objects.filter(pk=new_node.pk), many=True).data)) except KeyError: raise ObjectDoesNotExist( "Missing attribute from data: {}".format(data))
def duplicate_nodes(request): logging.debug("Entering the copy_node endpoint") if request.method != 'POST': return HttpResponseBadRequest( "Only POST requests are allowed on this endpoint.") data = json.loads(request.body) try: nodes = data["nodes"] sort_order = data.get("sort_order") or 1 channel_id = data["channel_id"] new_nodes = [] target_parent = ContentNode.objects.get(pk=data["target_parent"]) channel = target_parent.get_channel() request.user.can_edit(channel and channel.pk) nodes_being_copied = [] for node_data in nodes: nodes_being_copied.append( ContentNode.objects.get(pk=node_data['id'])) # record_node_duplication_stats(nodes_being_copied, ContentNode.objects.get(pk=target_parent.pk), # Channel.objects.get(pk=channel_id)) with transaction.atomic(): with ContentNode.objects.disable_mptt_updates(): for node_data in nodes: new_node = duplicate_node_bulk(node_data['id'], sort_order=sort_order, parent=target_parent, channel_id=channel_id, user=request.user) new_nodes.append(new_node.pk) sort_order += 1 except KeyError: raise ObjectDoesNotExist( "Missing attribute from data: {}".format(data)) serialized = ContentNodeSerializer( ContentNode.objects.filter(pk__in=new_nodes), many=True).data return HttpResponse(JSONRenderer().render(serialized))
def sync_channel_endpoint(request): logging.debug("Entering the sync_nodes endpoint") if request.method != 'POST': return HttpResponseBadRequest( "Only POST requests are allowed on this endpoint.") else: data = json.loads(request.body) try: nodes = sync_channel( Channel.objects.get(pk=data['channel_id']), sync_attributes=data.get('attributes'), sync_tags=data.get('tags'), sync_files=data.get('files'), sync_assessment_items=data.get('assessment_items'), sync_sort_order=data.get('sort'), ) return HttpResponse(JSONRenderer().render( ContentNodeSerializer(nodes, many=True).data)) except KeyError: return ObjectDoesNotExist( "Missing attribute from data: {}".format(data))