module Scrivito # This class represents a CMS workspace # @api public class Workspace PUBLISHED_ID = 'published' extend ActiveModel::Naming include ModelIdentity # Set the currently used workspace # @api public # @param [Scrivito::Workspace] workspace def self.current=(workspace) @current = workspace end def self.current_using_proc=(workspace_proc) @current = workspace_proc end # Returns the currently used workspace # @api public # @return [Scrivito::Workspace] def self.current if @current.respond_to? :call @current = @current.call else @current ||= default end end # Returns all the workspaces # @api public # @return [Array] def self.all result_json = CmsRestApi.get('/workspaces') result_json['results'].map do |workspace_json| Workspace.find(workspace_json['id']) end end def self.default published end def self.published cache.fetch(PUBLISHED_ID) do cache[PUBLISHED_ID] = find(PUBLISHED_ID) end end # Find a workspace by its id # @api public # @param [String] id # @return [Scrivito::Workspace] # @raise [Scrivito::ResourceNotFound] def self.find(id) if workspace_data = CmsBackend.instance.find_workspace_data_by_id(id) Workspace.new workspace_data else raise ResourceNotFound, "Could not find #{self} with id #{id}" end end # Find a workspace by its title. # If multiple workspaces share the same title, one of them is returned. # If no workspace with the given title can be found, nil is returned. # @api public # @param [String] title # @return [Scrivito::Workspace] def self.find_by_title(title) all.detect { |workspace| workspace.title == title } end delegate :content_state, :base_revision_id, :base_content_state, to: :data # Create a new workspace # @api public # @param [Hash] attributes # @return [Scrivito::Workspace] def self.create(attributes) workspace_json = CmsRestApi.post("/workspaces", workspace: attributes) self.find(workspace_json["id"]) end # reloads the current workspace to reflect any changes to it that may have happened concurrently # since it was loaded # @api public def self.reload id = current.id self.current_using_proc = proc { find(id) } end def self.cache @cache ||= {} end def initialize(workspace_data) @workspace_data = workspace_data end # Reloads this workspace to reflect any changes to it that may have happened concurrently since # it was loaded # @api public def reload @workspace_data = CmsBackend.instance.find_workspace_data_by_id(self.id) @revision = @base_revision = nil end # Updates this workspace's attributes # @api public # @param [Hash] attributes # @return [Scrivito::Workspace] def update(attributes) CmsRestApi.put(backend_url, workspace: attributes) self.reload end # Destroy this workspace # @api public def destroy reset_workspace_if_current CmsRestApi.delete(backend_url) end # Publish the changes of this workspace # @api public def publish CmsRestApi.put("#{backend_url}/publish", {}) reset_workspace_if_current end # Rebases the current workspace on the published content # @api public def rebase CmsRestApi.put("#{backend_url}/rebase", {}) self.reload end # Returns the id of the workspace # @api public # @return [String] def id @workspace_data.id end def revision_id @workspace_data.revision_id end # Returns the title of the workspace # @api public # @return [String] def title @workspace_data.title end def data @workspace_data end def published? self.id == 'published' end def rtc? self.id == 'rtc' end def revision @revision ||= Revision.new(id: revision_id, content_state: content_state, workspace: self) end def base_revision if base_revision_id @base_revision ||= Revision.new(id: base_revision_id, content_state: base_content_state) end end def as_current(&block) old_workspace = Workspace.current begin Workspace.current = self yield ensure Workspace.current = old_workspace end end def assert_revertable raise ScrivitoError, 'published workspace is not modifiable' if published? raise ScrivitoError, 'rtc workspace may contain attribute and class changes' if rtc? end # Find a {BasicObj Obj} by its id. # If the parameter is an Array containing ids, return a list of corresponding Objs. # @param [String, Integer, Array]id_or_list # @return [Obj, Array] # @api public def find_obj(id_or_list) find_filtering_deleted(id_or_list, false) end # Find a {BasicObj Obj} by its id. # If the parameter is an Array containing ids, return a list of corresponding Objs. # The results include deleted objects as well. # @param [String, Integer, Array]id_or_list # @return [Obj, Array] # @api public def find_obj_including_deleted(id_or_list) find_filtering_deleted(id_or_list, true) end # Find the {BasicObj Obj} with the given path. # Returns +nil+ if no matching Obj exists. # @param [String] path Path of the {BasicObj Obj}. # @return [Obj] # @api public def find_obj_by_path(path) find_objs_by(:path, [path]).first.first end # Returns the {BasicObj Obj} with the given permalink, or +nil+ if no matching Obj exists. # @param [String] permalink The permalink of the {BasicObj Obj}. # @return [Obj] # @api public def find_obj_by_permalink(permalink) find_objs_by(:permalink, [permalink]).first.first end def find_objs_by_parent_path(path) find_objs_by(:ppath, [path]).first end def find_obj_by_id(id) find_objs_by(:id, [id]).first.first end def find_objs_by_paths(paths) find_objs_by(:path, paths).map(&:first) end def inspect "<#{self.class} id=\"#{id}\" title=\"#{title}\">" end private def find_filtering_deleted(id_or_list, include_deleted) case id_or_list when Array find_objs_by(:id, id_or_list, include_deleted).map(&:first).compact else obj = find_objs_by(:id, [id_or_list.to_s], include_deleted).first.first obj or raise ResourceNotFound, "Could not find Obj with id #{id_or_list}" end end # accepts the name of an "obj_by" - view, a list of keys # and an "include_deleted" flag # returns a list of lists of Objs: a list of Objs for each given keys. def find_objs_by(view, keys, include_deleted = false) if include_deleted finder_method_name = :find_obj_data_including_deleted_by else finder_method_name = :find_obj_data_by end result = CmsBackend.instance.public_send(finder_method_name, revision, view, keys) result.map do |list| list.map do |obj_data| obj = BasicObj.instantiate(obj_data) obj.revision = revision obj end end end def backend_url "/workspaces/#{id}" end def reset_workspace_if_current if Workspace.current == self Workspace.current = Workspace.default end end end end