Esempio n. 1
0
def delete_treenode(request, project_id=None):
    """ If the skeleton has a single node, deletes the skeleton, and if so, if the skeleton is a model_of a neuron that was part_of group 'Isolated synaptic terminals', deletes the neuron. Returns the parent_id, if any."""
    treenode_id = int(request.POST.get('treenode_id', -1))
    # Raise an Exception if the user doesn't own the treenode or is not superuser
    can_edit_or_fail(request.user, treenode_id, 'treenode')
    #
    treenode = Treenode.objects.get(pk=treenode_id)
    parent_id = treenode.parent_id

    response_on_error = ''
    try:
        cursor = connection.cursor()
        if not parent_id:
            # This treenode is root.
            response_on_error = 'Could not retrieve children for treenode #%s' % treenode_id
            n_children = Treenode.objects.filter(parent=treenode).count()
            response_on_error = "Can't delete root node when it has children"
            if n_children > 0:
                # TODO yes you can, the new root is the first of the children, and other children become independent skeletons
                raise Exception("You can't delete the root node when it has children.")
            # Remove the original skeleton.
            # It is OK to remove it if it only had one node,
            # even if the skeleton's user does not match or the user is not superuser.
            # Fetch the neuron id, if it was a placeholder under 'Isolated synaptic terminals' group
            neuron_id = _in_isolated_synaptic_terminals(treenode.skeleton_id)
            # Delete the skeleton, which triggers deleting the ClassInstanceClassInstance relationship with neuron_id
            response_on_error = 'Could not delete skeleton.'
            # Extra check for errors, like having two root nodes
            count = Treenode.objects.filter(skeleton_id=treenode.skeleton_id).count()
            if 1 == count:
                ClassInstance.objects.filter(pk=treenode.skeleton_id).delete() # deletes as well treenodes that refer to the skeleton
            else:
                return HttpResponse(json.dumps({"error": "Can't delete isolated node: erroneously, its skeleton contains more than one treenode! Check for multiple root nodes."}))
            
            # If the neuron was part of the 'Isolated synaptic terminals' and no other skeleton is a model_of it, delete it
            if neuron_id:
                response_on_error = 'Could not delete neuron #%s' % neuron_id
                if _delete_if_empty(neuron_id):
                    print >> sys.stderr, "DELETED neuron %s from IST" % neuron_id

        else:
            # Treenode is not root, it has a parent and perhaps children.
            # Reconnect all the children to the parent.
            response_on_error = 'Could not update parent id of children nodes'
            Treenode.objects.filter(parent=treenode).update(parent=treenode.parent)

        # Remove treenode
        response_on_error = 'Could not delete treenode.'
        Treenode.objects.filter(pk=treenode_id).delete()
        return HttpResponse(json.dumps({'parent_id': parent_id}))

    except Exception as e:
        raise Exception(response_on_error + ': ' + str(e))
Esempio n. 2
0
def _join_skeleton(user, from_treenode_id, to_treenode_id, project_id):
    """ Take the IDs of two nodes, each belonging to a different skeleton,
    and make to_treenode be a child of from_treenode,
    and join the nodes of the skeleton of to_treenode
    into the skeleton of from_treenode,
    and delete the former skeleton of to_treenode."""
    if from_treenode_id is None or to_treenode_id is None:
        raise Exception('Missing arguments to _join_skeleton')

    response_on_error = ''
    try:
        to_treenode_id = int(to_treenode_id)
        cursor = connection.cursor()
        cursor.execute('''
        SELECT class_instance.user_id,
               treenode.skeleton_id,
               treenode.user_id
        FROM class_instance,
             treenode
        WHERE treenode.id = %s
          AND treenode.skeleton_id = class_instance.id
        ''' % to_treenode_id)
        to_skeleton_user_id, to_skid, to_treenode_user_id = cursor.fetchone()

        # Check if joining is allowed
        if 0 == Treenode.objects.filter(parent_id=to_treenode_id).count() and Treenode.objects.filter(pk=to_treenode_id).values_list('parent_id')[0][0] is None:
            # Is an isolated node, so it can be joined freely
            pass
        # If the treenode is not isolated, must own the skeleton or be superuser
        elif user.is_superuser or user.id == to_skeleton_user_id:
            pass
        # If the skeleton is a model_of a neuron that is part_of the 'Fragments' group
        # or the 'Isolated synaptic terminals' group, then it can be joined
        elif _under_fragments(to_skid):
            pass
        # Else, if the user owns the node (but not the skeleton), the join is possible only if all other nodes also belong to the user (such a situation occurs when the user ows both skeletons to join, or when part of a skeleton is split away from a larger one that belongs to someone else)
        elif user.id == to_treenode_user_id and 0 == Treenode.objects.filter(skeleton_id=to_skid).exclude(user=user).count():
            pass
        else:
            raise Exception("User %s with id #%s cannot join skeleton #%s, because the user doesn't own the skeleton or the skeleton contains nodes that belong to someone else." % (user.username, user.id, to_skid))

        from_treenode_id = int(from_treenode_id)
        from_treenode = Treenode.objects.get(pk=from_treenode_id)
        from_skid = from_treenode.skeleton_id

        if from_skid == to_skid:
            raise Exception('Cannot join treenodes of the same skeleton, this would introduce a loop.')
        
        from_neuron = _get_neuronname_from_skeletonid( project_id, from_skid )
        to_neuron = _get_neuronname_from_skeletonid( project_id, to_skid )

        # Reroot to_skid at to_treenode if necessary
        response_on_error = 'Could not reroot at treenode %s' % to_treenode_id
        _reroot_skeleton(to_treenode_id, project_id)

        # The target skeleton is removed and its treenode assumes
        # the skeleton id of the from-skeleton.

        response_on_error = 'Could not update Treenode table with new skeleton id for joined treenodes.'
        Treenode.objects.filter(skeleton=to_skid).update(skeleton=from_skid)

        response_on_error = 'Could not update TreenodeConnector table.'
        TreenodeConnector.objects.filter(
            skeleton=to_skid).update(skeleton=from_skid)

        # Determine if the neuron is part_of group 'Isolated synaptic terminals'
        response_on_error = 'Could not find neuron of skeleton #%s.' % to_skid
        neuron_id = _in_isolated_synaptic_terminals(to_skid)

        # Remove skeleton of to_id (deletes cicic part_of to neuron by cascade,
        # leaving the parent neuron dangling in the object tree).
        response_on_error = 'Could not delete skeleton with ID %s.' % to_skid
        ClassInstance.objects.filter(pk=to_skid).delete()

        # Remove the neuron if it belongs to 'Isolated synaptic terminals'
        # It is ok if the request.user doesn't match with the neuron's user_id or is not superuser.
        if neuron_id:
            response_on_error = 'Could not delete neuron with id %s.' % neuron_id
            if _delete_if_empty(neuron_id):
                print >> sys.stderr, "DELETED neuron %s from IST" % neuron_id

        # Update the parent of to_treenode.
        response_on_error = 'Could not update parent of treenode with ID %s' % to_treenode_id
        Treenode.objects.filter(id=to_treenode_id).update(parent=from_treenode_id, editor=user)

        insert_into_log(project_id, user.id, 'join_skeleton', from_treenode.location, 'Joined skeleton with ID %s (neuron: %s) into skeleton with ID %s (neuron: %s)' % (to_skid, to_neuron['neuronname'], from_skid, from_neuron['neuronname']) )

    except Exception as e:
        raise Exception(response_on_error + ':' + str(e))