-- 

-- @author Dave Bauer (dave@thedesignexperience.org)
-- @creation-date 2004-02-14
-- @cvs-id $Id: upgrade-5.1.0d1-5.1.0d2.sql,v 1.3.2.1 2006/03/19 22:26:40 emmar Exp $
--

-- new script replaces this one.

-- recreate pl/sql package


create or replace package file_storage
as

    function get_root_folder(
        --
        -- Returns the root folder corresponding to a particular
        -- package instance.
        --
        package_id in apm_packages.package_id%TYPE
    ) return fs_root_folders.folder_id%TYPE;

    function get_package_id(
        item_id in cr_items.item_id%TYPE
    ) return fs_root_folders.package_id%TYPE;

    function new_root_folder(
        --
        -- Creates a new root folder
        --
        package_id in apm_packages.package_id%TYPE,
        folder_name in cr_folders.label%TYPE default null,
        folder_url in cr_items.name%TYPE default null,
        description in cr_folders.description%TYPE default null
    ) return fs_root_folders.folder_id%TYPE;

    function new_file(
        --
        -- Create a file in CR in preparation for actual storage
        -- Wrapper for content_item.new
        --
        item_id in cr_items.item_id%TYPE default null,
        title in cr_items.name%TYPE,
        folder_id in cr_items.parent_id%TYPE,
        creation_user in acs_objects.creation_user%TYPE,
        creation_ip in acs_objects.creation_ip%TYPE,
        indb_p in char default 't'
    ) return cr_items.item_id%TYPE;

    procedure delete_file(
        --
        -- Delete a file and all its version
        -- Wrapper to content_item.delete
        --
        file_id in cr_items.item_id%TYPE
    );

    procedure rename_file(
        --
        -- Rename a file and all
        -- Wrapper to content_item__edit_name
        --
        file_id in cr_items.item_id%TYPE,
        title in cr_items.name%TYPE
    );

    function copy_file(
        --
        -- Copy a file, but only copy the live_revision
        --
        file_id in cr_items.item_id%TYPE,
        target_folder_id in cr_items.parent_id%TYPE,
        creation_user in acs_objects.creation_user%TYPE,
        creation_ip in acs_objects.creation_ip%TYPE
    ) return cr_revisions.revision_id%TYPE;

    procedure move_file(
        --
        -- Move a file, and all its versions, to a new folder
        --
        file_id in cr_items.item_id%TYPE,
        target_folder_id in cr_items.parent_id%TYPE,
        creation_user in acs_objects.creation_user%TYPE,
        creation_ip in acs_objects.creation_ip%TYPE
    );

    function get_title(
        --
        -- Unfortunately, title in the file-storage context refers
        -- to the name attribute in cr_items, not the title attribute in
        -- cr_revisions
        item_id in cr_items.item_id%TYPE
    ) return varchar;

    function get_parent_id(
	item_id in cr_items.item_id%TYPE
    ) return cr_items.item_id%TYPE;

    function get_content_type(
        --
        -- Wrapper for content_item. get_content_type
        --
        item_id in cr_items.item_id%TYPE
    ) return cr_items.content_type%TYPE;

    function get_folder_name(
       --
       -- Wrapper for content_folder__get_label
       --
       folder_id in cr_folders.folder_id%TYPE
    ) return cr_folders.label%TYPE;

    function new_version(
        --
        -- Create a new version of a file
        -- Wrapper for content_revision.new
        --
        filename in cr_revisions.title%TYPE,
        description in cr_revisions.description%TYPE,
        mime_type in cr_revisions.mime_type%TYPE,
        item_id in cr_items.item_id%TYPE,
        creation_user in acs_objects.creation_user%TYPE,
        creation_ip in acs_objects.creation_ip%TYPE
    ) return cr_revisions.revision_id%TYPE;

    function delete_version(
        --
        -- Delete a version of a file
        --
        file_id in cr_items.item_id%TYPE,
        version_id in cr_revisions.revision_id%TYPE
    ) return cr_items.parent_id%TYPE;

    function new_folder(
        --
        -- Create a folder
        --
        name in cr_items.name%TYPE,
        folder_name in cr_folders.label%TYPE,
        parent_id in cr_items.parent_id%TYPE,
        creation_user in acs_objects.creation_user%TYPE,
        creation_ip in acs_objects.creation_ip%TYPE
    ) return cr_folders.folder_id%TYPE;

    procedure delete_folder(
        --
        -- Delete a folder
        -- adding cascade_p but defaulting to false
	-- this will fail if a folder contains anything
	-- but just in case some other application uses
	-- this api it will not change the behavior
        folder_id in cr_folders.folder_id%TYPE,
	cascade_p in char default 'f'
    );

end file_storage;
/
show errors

create or replace package body file_storage
as

    function get_root_folder(
        package_id in apm_packages.package_id%TYPE
    ) return fs_root_folders.folder_id%TYPE
    is
        v_folder_id             fs_root_folders.folder_id%TYPE;
    begin
        select folder_id
        into v_folder_id
        from fs_root_folders
        where package_id = get_root_folder.package_id;

        return v_folder_id;
    end get_root_folder;

    function get_package_id(
        item_id in cr_items.item_id%TYPE
    ) return fs_root_folders.package_id%TYPE
    is
        v_package_id            fs_root_folders.package_id%TYPE;
    begin
        select fs_root_folders.package_id
        into v_package_id
        from fs_root_folders,
             (select cr_items.item_id
              from cr_items
              connect by prior cr_items.parent_id = cr_items.item_id
              start with cr_items.item_id = get_package_id.item_id) this
        where fs_root_folders.folder_id = this.item_id;

        return v_package_id;

    exception when NO_DATA_FOUND then
        return null;
    end get_package_id;

    function new_root_folder(
        --
        -- A hackish function to get around the fact that we can't run
        -- code automatically when a new package instance is created.
        --
        package_id in apm_packages.package_id%TYPE,
        folder_name in cr_folders.label%TYPE,
        folder_url in cr_items.name%TYPE,
        description in cr_folders.description%TYPE default null
    ) return fs_root_folders.folder_id%TYPE
    is
        v_folder_id             fs_root_folders.folder_id%TYPE;
    begin

        v_folder_id := content_folder.new(
            name => file_storage.new_root_folder.folder_url,
            label => file_storage.new_root_folder.folder_name,
            context_id => file_storage.new_root_folder.package_id,
            description => file_storage.new_root_folder.description
        );

        insert
        into fs_root_folders
        (package_id, folder_id)
        values
        (package_id, v_folder_id);

        -- allow child items to be added
        content_folder.register_content_type(v_folder_id,'content_revision','t');
        content_folder.register_content_type(v_folder_id,'content_folder','t');
        content_folder.register_content_type(v_folder_id,'content_extlink','t');
        content_folder.register_content_type(v_folder_id,'content_symlink','t');

        return v_folder_id;
    end new_root_folder;

    function new_file(
        --
        -- Create a file in CR in preparation for actual storage
        -- Wrapper for content_item.new
        --
        item_id in cr_items.item_id%TYPE default null,
        title in cr_items.name%TYPE,
        folder_id in cr_items.parent_id%TYPE,
        creation_user in acs_objects.creation_user%TYPE,
        creation_ip in acs_objects.creation_ip%TYPE,
        indb_p in char default 't'
    ) return cr_items.item_id%TYPE
    is
        v_item_id               cr_items.item_id%TYPE;
    begin
        if new_file.indb_p = 't'
        then
            v_item_id := content_item.new(
                item_id => new_file.item_id,
                name => new_file.title,
                parent_id => new_file.folder_id,
                creation_user => new_file.creation_user,
                context_id => new_file.folder_id,
                creation_ip => new_file.creation_ip,
                content_type => 'file_storage_object',
                item_subtype => 'content_item'
            );
        else
            v_item_id := content_item.new(
                name => new_file.title,
                parent_id => new_file.folder_id,
                creation_user => new_file.creation_user,
                context_id => new_file.folder_id,
                creation_ip => new_file.creation_ip,
                content_type => 'file_storage_object',
                item_subtype => 'content_item',
                storage_type => 'file'
            );
        end if;

        acs_object.update_last_modified(file_storage.new_file.folder_id,new_file.creation_user,new_file.creation_ip);

        return v_item_id;
    end new_file;

    procedure delete_file(
        --
        -- Delete a file and all its version
        -- Wrapper to content_item__delete
        --
        file_id in cr_items.item_id%TYPE
    )
    is
    begin
        content_item.del(item_id => file_storage.delete_file.file_id);
    end delete_file;

    procedure rename_file(
        --
        -- Rename a file and all
        -- Wrapper to content_item__edit_name
        --
        file_id in cr_items.item_id%TYPE,
        title in cr_items.name%TYPE
    )
    is
    begin
        content_item.edit_name(
            item_id => file_storage.rename_file.file_id,
            name => file_storage.rename_file.title
        );
    end rename_file;

    function copy_file(
        --
        -- Copy a file, but only copy the live_revision
        --
        file_id in cr_items.item_id%TYPE,
        target_folder_id in cr_items.parent_id%TYPE,
        creation_user in acs_objects.creation_user%TYPE,
        creation_ip in acs_objects.creation_ip%TYPE
    ) return cr_revisions.revision_id%TYPE
    is
        v_title                 cr_items.name%TYPE;
        v_live_revision         cr_items.live_revision%TYPE;
        v_filename              cr_revisions.title%TYPE;
        v_description           cr_revisions.description%TYPE;
        v_mime_type             cr_revisions.mime_type%TYPE;
        v_content_length        cr_revisions.content_length%TYPE;
        v_lob                   cr_revisions.content%TYPE;
        v_file_path             cr_revisions.filename%TYPE;
        v_new_file_id           cr_items.item_id%TYPE;
        v_new_version_id        cr_revisions.revision_id%TYPE;
        v_indb_p                char;
    begin
        -- We copy only the title from the file being copied, and attributes of the
        -- live revision
        select i.name, i.live_revision, r.title, r.description,
               r.mime_type, r.content, r.filename, r.content_length,
               decode(i.storage_type,'lob','t','f')
        into v_title, v_live_revision, v_filename, v_description,
             v_mime_type, v_lob, v_file_path, v_content_length,
             v_indb_p
        from cr_items i, cr_revisions r
        where r.item_id = i.item_id
        and r.revision_id = i.live_revision
        and i.item_id = file_storage.copy_file.file_id;

        -- We should probably use the copy functions of CR
        -- when we optimize this function
        v_new_file_id := file_storage.new_file(
            title => v_title,
            folder_id => file_storage.copy_file.target_folder_id,
            creation_user => file_storage.copy_file.creation_user,
            creation_ip => file_storage.copy_file.creation_ip,
            indb_p => v_indb_p
        );

        v_new_version_id := file_storage.new_version(
            filename => v_filename,
            description => v_description,
            mime_type => v_mime_type,
            item_id => v_new_file_id,
            creation_user => file_storage.copy_file.creation_user,
            creation_ip => file_storage.copy_file.creation_ip
        );

        -- Oracle is easier, since lobs are true lobs
        -- For now, we simply copy the file name
        update cr_revisions
        set filename = v_file_path,
            content = v_lob,
            content_length = v_content_length
        where revision_id = v_new_version_id;

        acs_object.update_last_modified(file_storage.copy_file.target_folder_id,file_storage.copy_file.creation_user,file_storage.copy_file.creation_ip);

        return v_new_version_id;
    end copy_file;

    procedure move_file(
        --
        -- Move a file, and all its versions, to a new folder
        --
        file_id in cr_items.item_id%TYPE,
        target_folder_id in cr_items.parent_id%TYPE,
        creation_user in acs_objects.creation_user%TYPE,
        creation_ip in acs_objects.creation_ip%TYPE
    )
    is
    begin
        content_item.move(
            item_id => file_storage.move_file.file_id,
            target_folder_id => file_storage.move_file.target_folder_id
        );

        acs_object.update_last_modified(file_storage.move_file.target_folder_id,file_storage.move_file.creation_user,file_storage.move_file.creation_ip);

    end;

    function new_version(
        --
        -- Create a new version of a file
        -- Wrapper for content_revision.new
        --
        filename in cr_revisions.title%TYPE,
        description in cr_revisions.description%TYPE,
        mime_type in cr_revisions.mime_type%TYPE,
        item_id in cr_items.item_id%TYPE,
        creation_user in acs_objects.creation_user%TYPE,
        creation_ip in acs_objects.creation_ip%TYPE
    ) return cr_revisions.revision_id%TYPE
    is
        v_revision_id           cr_revisions.revision_id%TYPE;
        v_folder_id             cr_items.parent_id%TYPE;
    begin
        -- Create a revision
        v_revision_id := content_revision.new(
            title => new_version.filename,
            description => new_version.description,
            mime_type => new_version.mime_type,
            item_id => new_version.item_id,
            creation_user => new_version.creation_user,
            creation_ip => new_version.creation_ip
        );

        -- Make live the newly created revision
        content_item.set_live_revision(revision_id => v_revision_id);

        select cr_items.parent_id
        into v_folder_id
        from cr_items
        where cr_items.item_id = file_storage.new_version.item_id;

        acs_object.update_last_modified(v_folder_id,new_version.creation_user,new_version.creation_ip);
        acs_object.update_last_modified(new_version.item_id,new_version.creation_user,new_version.creation_ip);
        return v_revision_id;

        exception when NO_DATA_FOUND then
            return v_revision_id;
    end new_version;

    function get_title(
        --
        -- Unfortunately, title in the file-storage context refers
        -- to the name attribute in cr_items, not the title attribute in
        -- cr_revisions
        item_id in cr_items.item_id%TYPE
    ) return varchar
    is
        v_title                 cr_items.name%TYPE;
        v_content_type          cr_items.content_type%TYPE;
    begin
        select content_type
        into v_content_type
        from cr_items
        where item_id = get_title.item_id;

        if v_content_type = 'content_folder'
        then
             select label
             into v_title
             from cr_folders
             where folder_id = get_title.item_id;
        else if v_content_type = 'content_symlink'
            then
                select label into v_title
                from cr_symlinks
                where symlink_id = get_title.item_id;
            else
		select crr.title into v_title
		from cr_revisions crr, cr_items cri
		where crr.revision_id=cri.live_revision
		and cri.item_id=get_title.item_id;
            end if;
        end if;

        return v_title;
    end get_title;

    function get_parent_id(
        item_id in cr_items.item_id%TYPE
    ) return cr_items.item_id%TYPE
    is
        v_parent_id             cr_items.item_id%TYPE;
    begin
        select parent_id
        into v_parent_id
        from cr_items
        where item_id = get_parent_id.item_id;

	return v_parent_id;
    end get_parent_id;

    function get_content_type(
        --
        -- Wrapper for content_item. get_content_type
        --
        item_id in cr_items.item_id%TYPE
    ) return cr_items.content_type%TYPE
    is
        v_content_type          cr_items.content_type%TYPE;
    begin
        v_content_type := content_item.get_content_type(
            item_id => file_storage.get_content_type.item_id
        );

        return v_content_type;
    end get_content_type;

    function get_folder_name(
        --
        -- Wrapper for content_folder.get_label
        --
        folder_id in cr_folders.folder_id%TYPE
    ) return cr_folders.label%TYPE
    is
       v_folder_name            cr_folders.label%TYPE;
    begin
        v_folder_name := content_folder.get_label(
            folder_id => file_storage.get_folder_name.folder_id
        );

        return v_folder_name;
    end get_folder_name;

    function delete_version(
        --
        -- Delete a version of a file
        --
        file_id in cr_items.item_id%TYPE,
        version_id in cr_revisions.revision_id%TYPE
    ) return cr_items.parent_id%TYPE
    is
        v_parent_id             cr_items.parent_id%TYPE;
    begin
        if file_storage.delete_version.version_id = content_item.get_live_revision(file_storage.delete_version.file_id)
        then
            content_revision.del(file_storage.delete_version.version_id);
            content_item.set_live_revision(
                content_item.get_latest_revision(file_storage.delete_version.file_id)
            );
        else
            content_revision.del(file_storage.delete_version.version_id);
        end if;

        -- If the live revision is null, we have deleted the last version above
        select decode(live_revision, null, parent_id, 0)
        into v_parent_id
        from cr_items
        where item_id = file_storage.delete_version.file_id;

        -- Unfortunately, due to PostgreSQL behavior with regards referential integrity,
        -- we cannot delete the content_item entry if there are no more revisions.
        return v_parent_id;
    end delete_version;

    function new_folder(
        --
        -- Create a folder
        --
        name in cr_items.name%TYPE,
        folder_name in cr_folders.label%TYPE,
        parent_id in cr_items.parent_id%TYPE,
        creation_user in acs_objects.creation_user%TYPE,
        creation_ip in acs_objects.creation_ip%TYPE
    ) return cr_folders.folder_id%TYPE
    is
        v_folder_id             cr_folders.folder_id%TYPE;
    begin
        -- Create a new folder
        v_folder_id := content_folder.new(
            name => file_storage.new_folder.name,
            label => file_storage.new_folder.folder_name,
            parent_id => file_storage.new_folder.parent_id,
            creation_user => file_storage.new_folder.creation_user,
            creation_ip => file_storage.new_folder.creation_ip
        );

        -- register the standard content types
        content_folder.register_content_type(
            v_folder_id,                -- folder_id
            'content_revision',        -- content_type
            't'                        -- include_subtypes
        );

        content_folder.register_content_type(
            v_folder_id,                -- folder_id
            'content_folder',        -- content_type
            't'                        -- include_subtypes
        );

        content_folder.register_content_type(
            v_folder_id,               -- folder_id
            'content_extlink',         -- content_type
            't'                        -- include_subtypes
        );

        content_folder.register_content_type(
            v_folder_id,               -- folder_id
            'content_symlink',         -- content_type
            't'                        -- include_subtypes
        );

        -- Give the creator admin privileges on the folder
        acs_permission.grant_permission(
            v_folder_id,                             -- object_id
            file_storage.new_folder.creation_user,  -- grantee_id
            'admin'                                     -- privilege
        );

        return v_folder_id;
    end new_folder;

    procedure delete_folder(
        --
        -- Delete a folder
        --
        folder_id in cr_folders.folder_id%TYPE,
	cascade_p in char default 'f'
    )
    is
    begin
        content_folder.del(
            folder_id => file_storage.delete_folder.folder_id,
	    cascade_p => file_storage.delete_folder.cascade_p
        );
    end delete_folder;

end file_storage;
/
show errors;
