require 'active_model/naming' module Scrivito # This class represents a CMS workspace # @api public class Workspace extend ActiveModel::Naming include ModelIdentity PublishPreventedDueToContentChange = Class.new(ScrivitoError) # 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 ||= published end end # Returns all the workspaces # @api public # @return [Array] def self.all result_json = CmsRestApi.get('/workspaces') result_json['results'].map do |raw_data| Workspace.new(WorkspaceData.new(raw_data)) end end def self.published find("published") end # Find a workspace by its id # @api public # @param [String] id # @return [Scrivito::Workspace] # @raise [Scrivito::ResourceNotFound] def self.find(id) cache.fetch(id) do workspace_data = CmsBackend.instance.find_workspace_data_by_id(id) unless workspace_data raise ResourceNotFound, "Could not find #{self} with id #{id}" end cache[id] = Workspace.new(workspace_data) 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 # Find a workspace by its id or title and set it as the currently used workspace. # @example # Scrivito::Workspace.use('6a75fe694eeeb093') # # Scrivito::Workspace.current.id # # => '6a75fe694eeeb093' # # Scrivito::Workspace.use('my working copy') # # Scrivito::Workspace.current.title # # => 'my working copy' # # # raises Scrivito::ResourceNotFound: # Scrivito::Workspace.use('missing') # @api public # @param [String] id_or_title # @return [void] # @raise [Scrivito::ResourceNotFound] def self.use(id_or_title) workspace = begin find(id_or_title) rescue ResourceNotFound find_by_title(id_or_title) end if workspace.blank? raise(ResourceNotFound, "Could not find #{self} with id or title #{id_or_title}") end self.current = workspace end delegate :content_state_id, :base_content_state_id, :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 current.reload 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) # Clear all cached instance variables. @base_revision = nil @memberships = nil @revision = nil end def api_request(verb, path, payload = nil) response = CmsRestApi.public_send(verb, "#{backend_url}#{path}", payload) reload if [:post, :put, :delete].include?(verb) response end def task_unaware_api_request(verb, path, payload = nil) CmsRestApi.task_unaware_request(verb, "#{backend_url}#{path}", payload) end # Updates this workspace's attributes # @api public # @param [Hash] attributes # @return [Scrivito::Workspace] def update(attributes) raise ScrivitoError, 'published workspace is not modifiable' if published? CmsRestApi.put(backend_url, workspace: attributes) 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", {}) Workspace.published.reload reset_workspace_if_current end # Rebases the current workspace on the published content # @api public def rebase CmsRestApi.put("#{backend_url}/rebase", {}) 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 or an empty +String+ # @api public # @return [String] def title return '' if published? @workspace_data.title || '' end # @api public # Returns the members of this workspace and their roles # # @return [MembershipCollection] def memberships @memberships ||= MembershipCollection.new(self) end def data @workspace_data end def published? self.id == 'published' end def outdated? !published? && Workspace.published.revision.id != base_revision_id end def revision unless data.content_state_id? # reload data from changes feed in order to obtain content_state_id reload raise InternalError unless data.content_state_id? end @revision ||= Revision.new(id: revision_id, workspace: self) end def base_revision if base_revision_id @base_revision ||= Revision.new( id: base_revision_id, workspace: self, base: true ) 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? end # {ObjCollection} for this working copy # @api public # @return {ObjCollection} def objs @objs ||= ObjCollection.new(self) end def inspect "<#{self.class} id=\"#{id}\" title=\"#{title}\">" end def has_modification_for?(obj_id) !!objs.find_including_deleted(obj_id).modification rescue Scrivito::ResourceNotFound false end def self.all_with_modification_for(obj_id) all.select do |ws| ws.has_modification_for?(obj_id) end end def conflict_warning_for(obj_id) self.class.all_with_modification_for(obj_id) - [self] end private def backend_url "/workspaces/#{id}" end def reset_workspace_if_current Workspace.cache.delete(id) if Workspace.current == self Workspace.current = Workspace.published end end end end