def test_before_create(self): from woost.models import CreateTrigger, Item # Declare the trigger trigger, response_log = self.make_trigger(CreateTrigger, execution_point="before", batch_execution=False) qname = "item1" item1 = Item(qname=qname) assert len(response_log) == 1 id = 234 item2 = Item(id=id) assert len(response_log) == 2 response = response_log[0] assert response["trigger"] is trigger assert response["items"] == [item1] assert response["user"] is self.user assert not response["batch"] assert response["context"]["values"]["qname"] == qname response = response_log[1] assert response["trigger"] is trigger assert response["items"] == [item2] assert response["user"] is self.user assert not response["batch"] assert response["context"]["values"]["id"] == id
def test_permission_expression(self): from woost.models import (Item, Publishable, User, ReadPermission, PermissionExpression) self.everybody_role.permissions.append( ReadPermission(matching_items={ "type": "woost.models.publishable.Publishable" }, authorized=True)) i1 = Item() i2 = Item() d1 = Publishable() d2 = Publishable() i1.insert() i2.insert() d1.insert() d2.insert() results = set( Item.select( filters=[PermissionExpression(User(), ReadPermission)])) assert results == set([d1, d2])
def test_after_insert_modify_delete(self): from cocktail.persistence import datastore from woost.models import (Item, User, InsertTrigger, ModifyTrigger, DeleteTrigger) response_log = [] insert_trigger = self.make_trigger(InsertTrigger, response_log, execution_point="after", batch_execution=False) modify_trigger = self.make_trigger(ModifyTrigger, response_log, execution_point="after", batch_execution=False) delete_trigger = self.make_trigger(DeleteTrigger, response_log, execution_point="after", batch_execution=False) # Create and insert an item item = Item() item.qname = "foo" item.insert() # Modify it item.qname = "bar" item.global_id = "foobar" # Delete it item.delete() # Commit the transaction; this should execute all the scheduled # responses datastore.commit() assert len(response_log) == 4 response = response_log.pop(0) assert response["trigger"] is insert_trigger assert response["items"] == [item] assert response["user"] is self.user assert not response["batch"] for member in (Item.qname, Item.global_id): response = response_log.pop(0) assert response["trigger"] is modify_trigger assert response["items"] == [item] assert response["context"]["member"] is member assert response["user"] is self.user assert not response["batch"] response = response_log[0] assert response["trigger"] is delete_trigger assert response["items"] == [item] assert response["user"] is self.user assert not response["batch"]
def test_language(self): from woost.models import ModifyTrigger, Item self.assert_match(ModifyTrigger(matching_languages=["en", "fr"]), (Item(), None, { "language": "en" }, True), (Item(), None, { "language": "fr" }, True), (Item(), None, { "language": None }, False), (Item(), None, { "language": "ru" }, False))
def test_after_insert(self): from cocktail.persistence import datastore from woost.models import InsertTrigger, Item # Declare the trigger trigger, response_log = self.make_trigger(InsertTrigger, execution_point="after", batch_execution=False) # Insert a new item, but abort the transaction # (the trigger shouldn't be called) item = Item() item.insert() assert not response_log datastore.abort() assert not response_log # Insert a new item, and commit the transaction # (the trigger should be executed) item = Item() item.insert() datastore.commit() assert len(response_log) == 1 response = response_log[0] assert response["trigger"] is trigger assert response["items"] == [item] assert response["user"] is self.user assert not response["batch"]
def test_after_delete(self): from cocktail.persistence import datastore from woost.models import DeleteTrigger, Item # Declare the trigger trigger, response_log = self.make_trigger(DeleteTrigger, execution_point="after", batch_execution=False) # Create and insert an item item = Item() item.insert() datastore.commit() # Delete the item, but abort the transaction. This shouldn't trigger # the response. item.delete() datastore.abort() assert not response_log # Delete the inserted item and commit the transaction. This should # trigger the response. item.delete() datastore.commit() assert len(response_log) == 1 response = response_log[0] assert response["trigger"] is trigger assert response["items"] == [item] assert response["user"] is self.user assert not response["batch"]
def test_before_insert(self): from woost.models import InsertTrigger, Item # Declare the trigger trigger, response_log = self.make_trigger(InsertTrigger, execution_point="before", batch_execution=False) # Create two items. This should trigger the response twice. item1 = Item() item1.insert() assert len(response_log) == 1 item2 = Item() item2.insert() assert len(response_log) == 2 response = response_log[0] assert response["trigger"] is trigger assert response["items"] == [item1] assert response["user"] is self.user assert not response["batch"] response = response_log[1] assert response["trigger"] is trigger assert response["items"] == [item2] assert response["user"] is self.user assert not response["batch"]
def test_user(self): from woost.models import ContentTrigger, Item, Role, User r1 = Role() r2 = Role() r3 = Role(base_roles=[r2]) u1 = User(roles=[r1]) u2 = User(roles=[r2]) u3 = User(roles=[r3]) self.assert_match(ContentTrigger(matching_roles=[r2]), (Item(), u2, {}, True), (Item(), u3, {}, True), (Item(), None, {}, False), (Item(), u1, {}, False))
def __call__(self, *args, **kwargs): rel = cherrypy.request.params.get("relation-select") # Open the item selector if rel: # Load persistent collection parameters before redirecting self.user_collection pos = rel.find("-") root_content_type_name = rel[:pos] selection_parameter = str(rel[pos + 1:]) for content_type in chain([Item], Item.derived_schemas()): if content_type.full_name == root_content_type_name: edit_stacks_manager = self.context["edit_stacks_manager"] edit_stack = edit_stacks_manager.current_edit_stack if edit_stack is None: edit_stack = edit_stacks_manager.create_edit_stack() edit_stacks_manager.current_edit_stack = edit_stack node = SelectionNode() node.content_type = content_type node.selection_parameter = selection_parameter edit_stack.push(node) raise cherrypy.HTTPRedirect( node.uri( selection=self.params.read( schema.String(selection_parameter)), client_side_scripting=self.client_side_scripting)) return BaseBackOfficeController.__call__(self, **kwargs)
def remove_drafts(e): from cocktail.persistence import datastore from woost.models import (Item, Permission, ContentPermission, MemberPermission, Trigger, ContentTrigger) from woost.models.utils import remove_broken_type remove_broken_type("woost.models.permission.ConfirmDraftPermission", existing_bases=(Item, Permission, ContentPermission)) remove_broken_type("woost.models.permission.ConfirmDraftPermission", existing_bases=(Item, Trigger, ContentTrigger)) for item in Item.select(): for key in "_is_draft", "_draft_source", "_drafts": try: delattr(item, key) except AttributeError: pass datastore.root.pop("woost.models.item.Item.is_draft", None) datastore.root.pop("woost.models.item.Item.draft_source", None) for permission in MemberPermission.select(): for key in ("drafts", "draft_source", "is_draft"): key = "woost.models.item.Item." + key if key in permission.matching_members: permission.matching_members.remove(key)
def get_produced_member(self): full_name = self.package_name + "." + self.member_name for cls in Item.schema_tree(): if cls.full_name == full_name: return cls
def resolve(self, path): try: self.edited_item = Item.require_instance(int(path.pop(0))) except: raise cherrypy.HTTPError(400) return self
def test_modified_member(self): from woost.models import ModifyTrigger, Item, Document self.assert_match( ModifyTrigger(matching_members=[ "woost.models.item.Item.qname", "woost.models.document.Document.title" ]), (Item(), None, { "member": Item.qname }, True), (Item(), None, { "member": Item.global_id }, False), (Document(), None, { "member": Document.title }, True), (Document(), None, { "member": Document.hidden }, False))
def form_adapter(self): adapter = FormControllerMixin.form_adapter(self) adapter.exclude([ "prefered_language", "roles", "password_confirmation", "enabled", "confirmed_email" ] + [key for key in Item.members()]) return adapter
def assign_global_identifiers(e): from woost import app from woost.models import Item from woost.models.synchronization import rebuild_manifest for item in Item.select(): item._global_id = app.installation_id + "-" + str(item.id) Item.global_id.rebuild_index() Item.synchronizable.rebuild_index() rebuild_manifest(True)
def test_delete(self): from datetime import datetime from woost.models import (Item, User, ChangeSet, changeset_context) author = User() author.insert() item = Item() item.insert() with changeset_context(author) as changeset: item.delete() assert list(ChangeSet.select()) == [changeset] assert changeset.author is author assert isinstance(changeset.date, datetime) assert changeset.changes.keys() == [item.id] change = changeset.changes[item.id] assert change.target is item assert change.action == "delete" assert change.changeset is changeset assert item.changes == [change] assert not item.id in Item.index
def __setstate__(self, state): EditNode.__setstate__(self, state) self.block_parent = Item.get_instance(state["block_parent"]) if self.block_parent: block_type = type(self.block_parent) self.block_slot = block_type.get_member(state["block_slot"]) anchor_id = state.get("block_anchor") if anchor_id is not None: self.block_anchor = Block.get_instance(anchor_id)
def test_content_permissions(self): from woost.models import (Item, Publishable, User, Role, Permission, CreatePermission, ReadPermission, ModifyPermission, DeletePermission) class TestPermission(Permission): pass item = Item() doc = Publishable() for permission_type in [ CreatePermission, ReadPermission, ModifyPermission, DeletePermission ]: role = Role() user = User(roles=[role]) # Permission denied (no permissions defined) self.assert_not_authorized(user, permission_type, target=doc) # Permission granted role.permissions.append( permission_type(matching_items={ "type": "woost.models.publishable.Publishable" }, authorized=True)) self.assert_authorized(user, permission_type, target=doc) # Permission denied (wrong target) self.assert_not_authorized(user, permission_type, target=item) # Permission denied (wrong permission type) self.assert_not_authorized(user, TestPermission) # Permission denied (prevailing negative permission) role.permissions.insert( 0, permission_type( matching_items={"type": "woost.models.item.Item"}, authorized=False)) self.assert_not_authorized(user, permission_type, target=doc)
def invoke(self, controller, selection): clipboard = get_block_clipboard_contents() if not clipboard: notify_user( translations("woost.block_clipboard.empty"), "error" ) else: try: block = Block.require_instance(clipboard["block"]) src_parent = Item.require_instance(clipboard["block_parent"]) src_slot = type(src_parent).get_member(clipboard["block_slot"]) except: notify_user( translations("woost.block_clipboard.error"), "error" ) else: # Remove the block from the source location if clipboard["mode"] == "cut": if isinstance(src_slot, schema.Reference): src_parent.set(src_slot, None) elif isinstance(src_slot, schema.Collection): src_collection = src_parent.get(src_slot) schema.remove(src_collection, block) # Or copy it elif clipboard["mode"] == "copy": block = block.create_copy() block.insert() # Add the block to its new position add_block( block, controller.block_parent, controller.block_slot, positioning = self.block_positioning, anchor = controller.block ) datastore.commit() del session[BLOCK_CLIPBOARD_SESSION_KEY] focus_block(block)
def remove_owner_field(e): from cocktail.persistence import datastore from woost.models import Item, ContentPermission, MemberPermission # Remove the owner value of every item for item in Item.select(): try: del item._owner except AttributeError: pass # Drop the index for the member full_member_name = "woost.models.item.Item.owner" datastore.root.pop(full_member_name, None) # Purge all references to the owner member from member permissions for permission in MemberPermission.select(): if permission.matching_members: member_count = len(permission.matching_members) try: permission.matching_members.remove(full_member_name) except (KeyError, ValueError): pass else: if member_count == 1: permission.delete() # Purge the 'owned-items' expression from all permissions for permission in ContentPermission.select(): matching_items = permission.matching_items if matching_items: try: filter = permission.matching_items["filter"] except KeyError: pass else: if filter == "owned-items" or (hasattr(filter, "__contains__") and "owned-items" in filter): permission.delete()
def test_target(self): from woost.models import (ContentTrigger, Item, Publishable, StandardPage, User, set_current_user) self.assert_match( ContentTrigger(matching_items={ "type": "woost.models.publishable.Publishable" }), (Publishable(), None, {}, True), (StandardPage(), None, {}, True), (Item(), None, {}, False), (ContentTrigger(), None, {}, False)) user = User() set_current_user(user) self.assert_match( ContentTrigger( matching_items={ "type": "woost.models.publishable.Publishable", "filter": "member-qname", "filter_operator0": "eq", "filter_value0": "foobar" }), (Publishable(), user, {}, False), (Publishable(qname="foobar"), user, {}, True))
def test_add_filters_from_selector(self): from cocktail.schema.expressions import Self from cocktail.persistence import Query results = Item.select( [Item.id.greater(15), Self.search("@localhost", languages=["en"])]) results_count = len(results) browser.open("/en/cms/content/?content_view=flat&search_expanded=true" "&page_size=%d" % (results_count + 1)) admin_login() # Add filters for i, filter_id in enumerate(("member-id", "global_search")): browser.fire_event("css=.new_filter_selector", "click") browser.fire_event("css=.new_filter-%s" % filter_id, "click") assert browser.jquery_count(".filters .filter_list .filter_entry") == 2 # Set values on filters browser.type("filter_operator0", "gt") browser.type("filter_value0", "15") browser.type("filter_value1", "@localhost") browser.click("css=.filters .search_button") browser.wait_for_page_to_load(10000) # Test the returned content rows_count = browser.jquery_count(".collection_display .item_row") assert rows_count == results_count # Supplied values must be preserved between page loads assert browser.get_selected_value("filter_operator0") == "gt" assert browser.get_value("filter_value0") == "15" assert browser.get_value("filter_value1") == "@localhost"
def test_before_modify(self): from woost.models import ModifyTrigger, Item, User # Declare the trigger trigger, response_log = self.make_trigger(ModifyTrigger, execution_point="before", batch_execution=False) # Create an item and initialize it. This shouldn't trigger any # response, since modifications happen before the item is inserted. item = Item() item.qname = "foo" item.insert() assert not response_log # Modify the inserted item two times. This should trigger the response # twice. item.qname = "bar" assert len(response_log) == 1 item.global_id = "foobar" assert len(response_log) == 2 response = response_log[0] assert response["trigger"] is trigger assert response["items"] == [item] assert response["context"]["member"] is Item.qname assert response["user"] is self.user assert not response["batch"] response = response_log[1] assert response["trigger"] is trigger assert response["items"] == [item] assert response["context"]["member"] is Item.global_id assert response["user"] is self.user assert not response["batch"]
def test_after_modify(self): from cocktail.persistence import datastore from woost.models import ModifyTrigger, Item # Declare the trigger trigger, response_log = self.make_trigger(ModifyTrigger, execution_point="after", batch_execution=False) # Create an item and initialize it. This shouldn't trigger any # response, since modifications happen before the item is inserted. item = Item() item.qname = "foo" item.insert() datastore.commit() assert not response_log # Modify the inserted item, but abort the transaction. Again, this # shouldn't trigger any response. item.qname = "bar" datastore.abort() assert not response_log # Modify the inserted item and commit the transaction. This should # trigger the response. item.qname = "spam" datastore.commit() assert len(response_log) == 1 response = response_log[0] assert response["trigger"] is trigger assert response["items"] == [item] assert response["context"]["member"] is Item.qname assert response["user"] is self.user assert not response["batch"]
def test_modify_batched_order(self): from cocktail.persistence import datastore from woost.models import ModifyTrigger, Item, User trigger, response_log = self.make_trigger( ModifyTrigger, execution_point="after", batch_execution=True, matching_members=["woost.models.item.Item.global_id"]) # Modifying a member that is not covered by the trigger should alter # the context passed to responses, even if it is modified before the # member that actions the response item = Item() item.insert() item.qname = "foo" item.global_id = "x1" datastore.commit() response = response_log[0] assert response["context"]["modified_members"] == { item: set([(Item.qname, None), (Item.global_id, None)]) }
def __init__(self, *args, **kwargs): Item.__init__(self, *args, **kwargs) self.__last_export_hashes = PersistentMapping()
def add_multisite_support(e): from cocktail.persistence import datastore from woost.models import Configuration, Website, Item root = datastore.root # Remove all back-references from the Site and Language models for item in Item.select(): for key in dir(item): if (key == "_site" or key.startswith("_Site_") or key.startswith("_Language_")): delattr(item, key) # Remove the instance of Site from the database site_id = list(Item.qname.index.values(key="woost.main_site"))[0] site = Item.index[site_id] site_state = site.__Broken_state__.copy() site_state["translations"] = dict( (lang, translation.__Broken_state__.copy()) for lang, translation in site_state.pop("_translations").iteritems()) Item.index.remove(site_id) Item.keys.remove(site_id) # Create the configuration object config = Configuration() config.qname = "woost.configuration" config.insert() # Create a website website = Website() website.insert() website.hosts = ["localhost"] config.websites.append(website) # Languages published_languages = [] for lang_id in root["woost.models.language.Language-keys"]: language = Item.index[lang_id] Item.index.remove(lang_id) Item.keys.remove(lang_id) language_state = language.__Broken_state__ config.languages.append(language_state["_iso_code"]) if language_state["_enabled"]: published_languages.append(language_state["_iso_code"]) if list(config.languages) != published_languages: config.published_languages = published_languages # Delete old indexes from the database for key in list(root): if (key.startswith("woost.models.site.Site") or key.startswith("woost.models.language.Language")): del root[key] # Settings that now belong in Configuration, as attributes config.secret_key = site_state.pop("secret_key") # Settings that now belong in Configuration, as regular fields for key in ("login_page", "generic_error_page", "not_found_error_page", "forbidden_error_page", "default_language", "backoffice_language", "heed_client_language", "timezone", "smtp_host", "smtp_user", "smtp_password"): config.set(key, site_state.pop("_" + key)) # Settings that now belong in Configuration, as collections for key in ("publication_schemes", "caching_policies", "renderers", "image_factories", "triggers"): config.set(key, list(site_state.pop("_" + key))) # Settings that now belong in Website, becoming translated fields for key in ("town", "region", "country"): value = site_state.pop("_" + key) for lang in config.languages: website.set(key, value, lang) # Settings that now belong in website, as translated fields for key in ("site_name", "organization_name", "keywords", "description"): for lang, translation_state in site_state["translations"].iteritems(): value = translation_state.pop("_" + key) website.set(key, value, lang) # Settings that now belong in website, as regular fields for key in ("logo", "icon", "home", "organization_url", "address", "postal_code", "phone_number", "fax_number", "email", "https_policy", "https_persistence"): website.set(key, site_state.pop("_" + key)) # Extension specific changes from woost.extensions.blocks import BlocksExtension if BlocksExtension.instance.enabled: config.common_blocks = list(site_state.pop("_common_blocks")) from woost.extensions.audio import AudioExtension if AudioExtension.instance.enabled: config.audio_encoders = list(site_state.pop("_audio_encoders")) config.audio_decoders = list(site_state.pop("_audio_decoders")) from woost.extensions.mailer import MailerExtension if MailerExtension.instance.enabled: from woost.extensions.mailer.mailing import Mailing for mailing in Mailing.select(): language = mailing._language if language: mailing._language = language.__Broken_state__["_iso_code"] from woost.extensions.googleanalytics import GoogleAnalyticsExtension if GoogleAnalyticsExtension.instance.enabled: account = GoogleAnalyticsExtension.instance._account del GoogleAnalyticsExtension.instance._account config.google_analytics_account = account # Rebuild all indexes Item.rebuild_indexes() # Preserve the remaining state datastore.root["woost.models.migration.multisite_leftovers"] = site_state
def rebuild_full_text_index(e): from woost.models import Item Item.rebuild_full_text_indexes(True)
def test_after_insert_batched(self): from cocktail.persistence import datastore from woost.models import InsertTrigger, Item # Declare the trigger trigger, response_log = self.make_trigger(InsertTrigger, execution_point="after", batch_execution=True) # Insert new items, but abort the transaction # (the trigger shouldn't be called) item1 = Item() item1.insert() assert not response_log item2 = Item() item2.insert() assert not response_log datastore.abort() assert not response_log # Create and insert two items, and commit the transaction. The response # should be triggered just once. item1 = Item() item1.insert() item2 = Item() item2.insert() datastore.commit() assert len(response_log) == 1 response = response_log[0] assert response["trigger"] is trigger assert response["items"] == set([item1, item2]) assert response["user"] is self.user assert response["batch"]
def test_after_modify_batched(self): from cocktail.persistence import datastore from woost.models import ModifyTrigger, Item, User # Declare the trigger trigger, response_log = self.make_trigger(ModifyTrigger, execution_point="after", batch_execution=True) # Create two items and initialize them. This shouldn't trigger any # response, since modifications happen before items are inserted. item1 = Item() item1.qname = "foo" item1.insert() item2 = Item() item2.global_id = "x1" item2.insert() datastore.commit() assert not response_log # Modify the inserted items, but abort the transaction. Again, this # shouldn't trigger any response. item1.qname = "bar" item2.global_id = "x2" datastore.abort() assert not response_log # Modify the inserted items and commit the transaction. This should # trigger the response just once. item1.qname = "spam" item2.global_id = "x3" datastore.commit() assert len(response_log) == 1 response = response_log[0] assert response["trigger"] is trigger assert response["items"] == set([item1, item2]) assert response["context"]["modified_members"] == { item1: set([(Item.qname, None)]), item2: set([(Item.global_id, None)]) } assert response["user"] is self.user assert response["batch"]