示例#1
0
def create_channel(channel_data, user):
    """ Set up channel """
    # Set up initial channel
    channel, isNew = Channel.objects.get_or_create(id=channel_data['id'])

    # Add user as editor if channel is new or channel has no editors
    # Otherwise, check if user is an editor
    if isNew or channel.editors.count() == 0:
        channel.editors.add(user)
    elif user not in channel.editors.all():
        raise SuspiciousOperation(
            "User is not authorized to edit this channel")

    channel.name = channel_data['name']
    channel.description = channel_data['description']
    channel.thumbnail = channel_data['thumbnail']
    channel.deleted = False
    channel.source_id = channel_data.get('source_id')
    channel.source_domain = channel_data.get('source_domain')
    channel.source_url = channel_data.get(
        'source_domain') if isNew else channel.source_url
    channel.ricecooker_version = channel_data.get('ricecooker_version')
    channel.language_id = channel_data.get('language')

    # older versions of ricecooker won't be sending this field.
    if 'tagline' in channel_data:
        channel.tagline = channel_data['tagline']

    old_chef_tree = channel.chef_tree
    is_published = channel.main_tree is not None and channel.main_tree.published
    # Set up initial staging tree
    channel.chef_tree = ContentNode.objects.create(
        title=channel.name,
        kind_id=content_kinds.TOPIC,
        sort_order=get_next_sort_order(),
        published=is_published,
        content_id=channel.id,
        node_id=channel.id,
        source_id=channel.source_id,
        source_domain=channel.source_domain,
        extra_fields={'ricecooker_version': channel.ricecooker_version},
    )
    channel.chef_tree.save()
    channel.save()

    # Delete chef tree if it already exists
    if old_chef_tree and old_chef_tree != channel.staging_tree:
        # IMPORTANT: Do not remove this block, MPTT updating the deleted chefs block could hang the server
        with ContentNode.objects.disable_mptt_updates():
            garbage_node = get_deleted_chefs_root()
            old_chef_tree.parent = garbage_node
            old_chef_tree.title = "Old chef tree for channel {}".format(
                channel.pk)
            old_chef_tree.save()

    return channel  # Return new channel
示例#2
0
def create_channel(channel_data, user):
    """ Set up channel """
    # Set up initial channel
    channel, isNew = Channel.objects.get_or_create(id=channel_data['id'])

    # Add user as editor if channel is new or channel has no editors
    # Otherwise, check if user is an editor
    if isNew or channel.editors.count() == 0:
        channel.editors.add(user)
    elif user not in channel.editors.all():
        raise SuspiciousOperation("User is not authorized to edit this channel")

    channel.name = channel_data['name']
    channel.description = channel_data['description']
    channel.thumbnail = channel_data['thumbnail']
    channel.deleted = False
    channel.source_id = channel_data.get('source_id')
    channel.source_domain = channel_data.get('source_domain')
    channel.ricecooker_version = channel_data.get('ricecooker_version')
    channel.language_id = channel_data.get('language')

    old_chef_tree = channel.chef_tree
    is_published = channel.main_tree is not None and channel.main_tree.published
    # Set up initial staging tree
    channel.chef_tree = ContentNode.objects.create(
        title=channel.name,
        kind_id=content_kinds.TOPIC,
        sort_order=get_next_sort_order(),
        published=is_published,
        content_id=channel.id,
        node_id=channel.id,
        source_id=channel.source_id,
        source_domain=channel.source_domain,
        extra_fields=json.dumps({'ricecooker_version': channel.ricecooker_version}),
    )
    channel.chef_tree.save()
    channel.save()

    # Delete chef tree if it already exists
    if old_chef_tree and old_chef_tree != channel.staging_tree:
        # IMPORTANT: Do not remove this block, MPTT updating the deleted chefs block could hang the server
        with ContentNode.objects.disable_mptt_updates():
            garbage_node = get_deleted_chefs_root()
            old_chef_tree.parent = garbage_node
            old_chef_tree.title = "Old chef tree for channel {}".format(channel.pk)
            old_chef_tree.save()

    return channel  # Return new channel
示例#3
0
    def handle(self, *args, **options):
        try:
            # Set up variables for restoration process
            print("\n\n********** STARTING CHANNEL RESTORATION **********")
            start = datetime.datetime.now()
            source_id = options['source_id']
            target_id = options.get('target') or source_id

            # Test connection to database
            print("Connecting to database for channel {}...".format(source_id))

            tempf = tempfile.NamedTemporaryFile(suffix=".sqlite3",
                                                delete=False)
            conn = None
            try:
                if options.get('download_url'):
                    response = requests.get(
                        '{}/content/databases/{}.sqlite3'.format(
                            options['download_url'], source_id))
                    for chunk in response:
                        tempf.write(chunk)
                else:
                    filepath = "/".join(
                        [settings.DB_ROOT, "{}.sqlite3".format(source_id)])
                    # Check if database exists
                    if not default_storage.exists(filepath):
                        raise IOError("The object requested does not exist.")
                    with default_storage.open(filepath) as fobj:
                        shutil.copyfileobj(fobj, tempf)

                tempf.close()
                conn = sqlite3.connect(tempf.name)
                cursor = conn.cursor()

                # Start by creating channel
                print("Creating channel...")
                channel, root_pk = create_channel(conn, target_id)
                if options.get('editor'):
                    channel.editors.add(
                        models.User.objects.get(email=options['editor']))
                    channel.save()

                # Create root node
                root = models.ContentNode.objects.create(
                    sort_order=models.get_next_sort_order(),
                    node_id=root_pk,
                    title=channel.name,
                    kind_id=content_kinds.TOPIC,
                    original_channel_id=target_id,
                    source_channel_id=target_id,
                )

                # Create nodes mapping to channel
                print("   Creating nodes...")
                with transaction.atomic():
                    create_nodes(cursor,
                                 target_id,
                                 root,
                                 download_url=options.get('download_url'))
                    # TODO: Handle prerequisites

                # Delete the previous tree if it exists
                old_previous = channel.previous_tree
                if old_previous:
                    old_previous.parent = get_deleted_chefs_root()
                    old_previous.title = "Old previous tree for channel {}".format(
                        channel.pk)
                    old_previous.save()

                # Save tree to target tree
                channel.previous_tree = channel.main_tree
                channel.main_tree = root
                channel.save()
            finally:
                conn and conn.close()
                tempf.close()
                os.unlink(tempf.name)

            # Print stats
            print("\n\nChannel has been restored (time: {ms})\n".format(
                ms=datetime.datetime.now() - start))
            print("\n\n********** RESTORATION COMPLETE **********\n\n")

        except EarlyExit as e:
            logging.warning(
                "Exited early due to {message}.".format(message=e.message))
            self.stdout.write(
                "You can find your database in {path}".format(path=e.db_path))
示例#4
0
def import_channel(source_id,
                   target_id=None,
                   download_url=None,
                   editor=None,
                   logger=None):
    """
    Import a channel from another Studio instance. This can be used to
    copy online Studio channels into local machines for development,
    testing, faster editing, or other purposes.

    :param source_id: The UUID of the channel to import from the source Studio instance.
    :param target_id: The UUID of the channel on the local instance. Defaults to source_id.
    :param download_url: The URL of the Studio instance to import from.
    :param editor: The email address of the user you wish to add as an editor, if any.

    """

    global log
    if logger:
        log = logger
    else:
        log = logging.getLogger(__name__)

    # Set up variables for the import process
    log.info("\n\n********** STARTING CHANNEL IMPORT **********")
    start = datetime.datetime.now()
    target_id = target_id or source_id

    # Test connection to database
    log.info("Connecting to database for channel {}...".format(source_id))

    tempf = tempfile.NamedTemporaryFile(suffix=".sqlite3", delete=False)
    conn = None
    try:
        if download_url:
            response = requests.get('{}/content/databases/{}.sqlite3'.format(
                download_url, source_id))
            for chunk in response:
                tempf.write(chunk)
        else:
            filepath = "/".join(
                [settings.DB_ROOT, "{}.sqlite3".format(source_id)])
            # Check if database exists
            if not default_storage.exists(filepath):
                raise IOError("The object requested does not exist.")
            with default_storage.open(filepath) as fobj:
                shutil.copyfileobj(fobj, tempf)

        tempf.close()
        conn = sqlite3.connect(tempf.name)
        cursor = conn.cursor()

        # Start by creating channel
        log.info("Creating channel...")
        channel, root_pk = create_channel(conn, target_id)
        if editor:
            channel.editors.add(models.User.objects.get(email=editor))
            channel.save()

        # Create root node
        root = models.ContentNode.objects.create(
            sort_order=models.get_next_sort_order(),
            node_id=root_pk,
            title=channel.name,
            kind_id=content_kinds.TOPIC,
            original_channel_id=target_id,
            source_channel_id=target_id,
        )

        # Create nodes mapping to channel
        log.info("   Creating nodes...")
        with transaction.atomic():
            create_nodes(cursor, target_id, root, download_url=download_url)
            # TODO: Handle prerequisites

        # Delete the previous tree if it exists
        old_previous = channel.previous_tree
        if old_previous:
            old_previous.parent = get_deleted_chefs_root()
            old_previous.title = "Old previous tree for channel {}".format(
                channel.pk)
            old_previous.save()

        # Save tree to target tree
        channel.previous_tree = channel.main_tree
        channel.main_tree = root
        channel.save()
    finally:
        conn and conn.close()
        tempf.close()
        os.unlink(tempf.name)

    # Print stats
    log.info("\n\nChannel has been imported (time: {ms})\n".format(
        ms=datetime.datetime.now() - start))
    log.info("\n\n********** IMPORT COMPLETE **********\n\n")