from plone import api
from ploneintranet.workspace.tests.base import BaseTestCase
from ploneintranet.workspace.tests.base import WorkflowBaseTestCase

VIEW = "View"
MODIFY = "Modify portal content"
DELETE = "Delete objects"

"""
This tests the workflow of an event in a workspacefolder.
Workflow of the workspace itself is tested elsewhere
in test_workflow_workspace.
"""


class TestEventWorkflow(BaseTestCase):
    def test_workflow_exists(self):
        """
        the event_workflow should be listed as a workflow
        """
        self.assertIn("event_workflow", self.portal_workflow.listWorkflows())

    def test_placeful_workflow(self):
        """
        The event_workflow should be applied automatically to
        events created inside a workspace
        """
        self.login_as_portal_owner()
        wftool = self.portal_workflow
        workspace = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "example-workspace",
        )
        event = api.content.create(workspace, "Event", "test-event-in-ws")
        self.assertListEqual(
            ["event_workflow"], [x.getId() for x in wftool.getWorkflowsFor(event)]
        )
        # default state is published
        self.assertEqual("published", api.content.get_state(event))


class TestSecretWorkspaceContentWorkflow(WorkflowBaseTestCase):

    # properly set this ones to change workspacefolder behavior
    _participant_policy = "producers"

    # These are the general permission that are almost
    # common to every test case
    _base_permissions_by_userid = {
        "wsadmin": {VIEW, MODIFY, DELETE},
        "wsowner": {VIEW, MODIFY},  # event owner, not workspace owner
        "wsmember": {VIEW},
        "intranet": set(),
        "extranet": set(),
        None: set(),  # anonymous
    }
    # but your test case may override this
    _test_specific_permissions_by_userid = {}

    def setUp(self):
        super().setUp()
        # Finally change the workspace folder policy and (eventually) its state
        self.workspace_folder.participant_policy = self._participant_policy

    def get_expected_permissions_for(self, userid):
        """Get the permission for the given userid (None => anonymous)

        First look in _test_specific_permissions_by_userid then in
        _base_permissions_by_userid.
        """
        return self._test_specific_permissions_by_userid.get(
            userid, self._base_permissions_by_userid[userid]
        )

    def check_permissions_for(self, userid):
        permissions = api.user.get_permissions(username=userid, obj=self.event)
        observed = {key for key in [VIEW, MODIFY, DELETE] if permissions[key]}
        expected = self.get_expected_permissions_for(userid)
        self.assertSetEqual(observed, expected)

    def test_admin_permissions(self):
        self.check_permissions_for("wsadmin")

    def test_owner_permissions(self):
        self.check_permissions_for("wsowner")

    def test_member_permissions(self):
        self.check_permissions_for("wsmember")

    def test_intranet_permissions(self):
        self.check_permissions_for("intranet")

    def test_extranet_permissions(self):
        self.check_permissions_for("extranet")

    def test_anonymous_permissions(self):
        self.logout()
        self.check_permissions_for(None)

    def test_setup_workflow_state(self):
        self.assertEqual(
            api.content.get_state(self.workspace_folder),
            "secret",
            "workspace is in incorrect state",
        )


class TestPrivateWorkspaceContentWorkflow(TestSecretWorkspaceContentWorkflow):
    """
    Content in a private workspace should have the same security
    View protections as content in a secret workspace.
    Inherit the test.
    """


class TestWorkspacePolicyConsumers(TestSecretWorkspaceContentWorkflow):
    """Test modify permissions for policy: consumers"""

    _participant_policy = "consumers"


class TestWorkspacePolicyProducers(TestSecretWorkspaceContentWorkflow):
    """Modify permission is identical to Consumers"""

    _participant_policy = "producers"


class TestWorkspacePolicyPublishers(TestSecretWorkspaceContentWorkflow):
    """Modify permission is identical to Consumers"""

    _participant_policy = "publishers"


class TestWorkspacePolicyModerators(TestSecretWorkspaceContentWorkflow):
    """
    Moderators allows teammembers to edit other people's content.
    """

    _participant_policy = "moderators"
    _test_specific_permissions_by_userid = {
        "wsowner": {VIEW, MODIFY, DELETE},
        "wsmember": {VIEW, MODIFY, DELETE},
    }
