from AccessControl import Unauthorized
from collective.workspace.interfaces import IWorkspace
from plone import api
from plone.app.testing import login
from ploneintranet import api as pi_api
from ploneintranet.workspace.tests.base import BaseTestCase
from Products.CMFCore.utils import _checkPermission as checkPermission
from zope.component import getMultiAdapter


class TestPolicy(BaseTestCase):
    def test_groups_created(self):
        """
        When a workspace is created it should also create a number of groups
        which correlate to the various policies on a workspace:
        - Consumer
        - Producer
        - Publisher
        - Moderator
        """
        self.login_as_portal_owner()
        workspace_folder = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "workspace",
        )
        workspace_folder_uid = api.content.get_uuid(workspace_folder)

        self.assertIsNotNone(api.group.get("Consumers:%s" % workspace_folder_uid))
        self.assertIsNotNone(api.group.get("Producers:%s" % workspace_folder_uid))
        self.assertIsNotNone(api.group.get("Publishers:%s" % workspace_folder_uid))
        self.assertIsNotNone(api.group.get("Moderators:%s" % workspace_folder_uid))

    def test_workspace_creator(self):
        """
        When a workspace is created, the creator should be added
        as a Workspace Admin
        """
        self.login_as_portal_owner()

        pi_api.userprofile.create(username="workspacecreator", email="test@test.com")

        # Make the creater or a Contributor on the portal
        api.user.grant_roles(
            username="workspacecreator", obj=self.portal, roles=["Contributor"]
        )
        # Login as the creator and create the workspace
        login(self.portal, "workspacecreator")
        workspace_folder = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "example-workspace",
            title="A workspace",
        )

        # The creator should now have the Manage workspace permission
        permissions = api.user.get_permissions(
            username="workspacecreator", obj=workspace_folder
        )
        self.assertTrue(
            permissions["ploneintranet.workspace: Manage workspace"],
            "Creator cannot manage workspace",
        )

    def test_workspace_policy_setting(self):
        """
        Check that we are able to set permission on a workspace
        """
        self.login_as_portal_owner()
        workspace = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "example-workspace",
            title="A workspace",
        )
        # check that accessing setting for the first time doesn't fail
        self.assertEqual(workspace.join_policy, "admin")
        self.assertEqual(workspace.participant_policy, "consumers")

        workspace.join_policy = "team"
        self.assertEqual(workspace.join_policy, "team")

        workspace.participant_policy = "producers"
        self.assertEqual(workspace.participant_policy, "producers")

    def test_workspace_policy_change_updates_existing_members(self):
        """
        Test that changing workspace policy updates all existing members
        with a new group.
        """
        self.login_as_portal_owner()
        workspace = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "example-workspace",
            title="A workspace",
        )
        # check that accessing setting for the first time doesn't fail
        workspace.participant_policy = "producers"
        self.assertEqual(workspace.participant_policy, "producers")

        username = "member_username"
        pi_api.userprofile.create(username=username, email="test@test.com")
        self.add_user_to_workspace(username, workspace)
        group = api.group.get("Producers:" + api.content.get_uuid(workspace))
        self.assertIn(username, group.getAllGroupMemberIds())
        workspace.participant_policy = "consumers"
        self.assertNotIn(username, group.getAllGroupMemberIds())

        group = api.group.get("Consumers:" + api.content.get_uuid(workspace))
        self.assertIn(username, group.getAllGroupMemberIds())

    def test_members_are_correctly_added_to_group_by_policy(self):
        """
        Check that members are correctly assigned to groups
        according to workspace policy settings and have correct roles
        """
        self.login_as_portal_owner()
        workspace = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "workspace",
        )
        # default participant policy state should be "consumers"
        self.assertEqual(workspace.participant_policy, "consumers")

        # create a member and add to workspace
        username = "member_username"
        pi_api.userprofile.create(username=username, email="test@test.com")
        self.add_user_to_workspace(username, workspace)

        group = api.group.get("Consumers:" + api.content.get_uuid(workspace))

        self.assertIn(username, group.getAllGroupMemberIds())
        self.assertIn(
            "TeamMember", api.user.get_roles(username=username, obj=workspace)
        )

        self.login_as_portal_owner()
        workspace = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "other-workspace",
        )
        self.assertEqual(workspace.participant_policy, "consumers")
        workspace.participant_policy = "producers"
        self.assertEqual(workspace.participant_policy, "producers")
        username = "Vladislav"
        pi_api.userprofile.create(username=username, email="test1@test.com")
        self.add_user_to_workspace(username, workspace)
        group = api.group.get("Producers:" + api.content.get_uuid(workspace))
        self.assertIn(username, group.getAllGroupMemberIds())
        self.login(username)
        self.assertIn(
            "Contributor", api.user.get_roles(username=username, obj=workspace)
        )
        self.assertIn(
            "TeamMember", api.user.get_roles(username=username, obj=workspace)
        )
        self.assertNotIn(
            "Reviewer", api.user.get_roles(username=username, obj=workspace)
        )

    def test_policy_exceptions(self):
        self.login_as_portal_owner()
        workspace = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "workspace",
        )
        # set default policy to producers
        workspace.participant_policy = "producers"

        # create some members and add to workspace
        username = "member_username"
        username2 = "member_username2"
        pi_api.userprofile.create(username=username, email="test@test.com")
        self.add_user_to_workspace(username, workspace)
        pi_api.userprofile.create(username=username2, email="test@test.com")
        self.add_user_to_workspace(username2, workspace)

        # Make an exception of username2
        # by moving them to a non-default group
        IWorkspace(workspace).add_to_team(username2, groups={"Consumers"})

        group = api.group.get("Producers:" + api.content.get_uuid(workspace))
        # username should be in the default group
        self.assertIn(username, group.getAllGroupMemberIds())
        # username two should *not* be in the default group
        self.assertNotIn(username2, group.getAllGroupMemberIds())

        # update default policy
        workspace.participant_policy = "moderators"

        group = api.group.get("Moderators:" + api.content.get_uuid(workspace))
        # username should have been moved to the new group
        self.assertIn(username, group.getAllGroupMemberIds())
        # username2 two should *not* be in the new default group
        self.assertNotIn(username2, group.getAllGroupMemberIds())

        # remove username2 as an exception by re-setting their groups
        IWorkspace(workspace).add_to_team(username2)
        self.assertIn(username2, group.getAllGroupMemberIds())

    def test_role_adapter(self):
        """
        test that the self publishers are also given the reviewer role if they
        are an owner
        """
        # first check that the role adapter doesn't add any roles
        # if a workspace cannot be acquired
        pi_api.userprofile.create(username="mrmanager", email="manager@test.com")
        with api.env.adopt_user("mrmanager"):
            with api.env.adopt_roles(("Member", "Manager")):
                folder = api.content.create(self.portal, "Folder", "folder")
        self.assertDictEqual(folder.__ac_local_roles__, {"mrmanager": ["Owner"]})

        workspace = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "workspace",
        )
        workspace.participant_policy = "publishers"
        username = "testuser"
        pi_api.userprofile.create(username=username, email="test@test.com")
        self.add_user_to_workspace(username, workspace)
        self.login(username)
        doc = api.content.create(container=workspace, type="Document", id="my-doc")
        local_roles = api.user.get_roles(username=username, obj=doc)
        self.assertIn("Owner", local_roles)
        self.assertIn("Contributor", local_roles)
        self.assertIn("SelfPublisher", local_roles)
        self.assertIn("Reviewer", local_roles)

    def test_join_policy_admin(self):
        """
        in an admin managed workspace, a user needs the
        manage workspace permission to update users
        """
        self.login_as_portal_owner()
        workspace = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "workspace",
        )
        workspace.join_policy = "admin"

        username = "regular_member"
        pi_api.userprofile.create(username=username, email="test@test.com")
        self.add_user_to_workspace(username, workspace)

        self.login(username)
        self.assertFalse(
            checkPermission("ploneintranet.workspace: Manage workspace", workspace)
        )
        # we're not relying on Manage roster anywhere, but verify anyway
        self.assertFalse(
            checkPermission("collective.workspace: Manage roster", workspace)
        )
        request = self.layer["request"].clone()
        request.method = "POST"
        params = {"user_id": ["wsadmin", "wsmember"], "batch-function": "add"}
        request.form.update(params)
        edit_form = getMultiAdapter(
            (workspace, request), name="sidebar.settings.members"
        )
        self.assertRaises(Unauthorized, edit_form.execute_batch_function)

    def test_join_policy_team(self):
        """
        in a team managed workspace a user only needs the view roster
        permission to update users
        """
        self.login_as_portal_owner()
        workspace = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "workspace",
        )
        workspace.join_policy = "team"

        username = "regular_member"
        pi_api.userprofile.create(username=username, email="test@test.com")
        self.add_user_to_workspace(username, workspace)
        # Add a second user to the site who is not initially a member
        pi_api.userprofile.create(username="party_animal", email="test@test.com")

        self.login(username)
        self.assertTrue(checkPermission("collective.workspace: View roster", workspace))
        request = self.layer["request"].clone()
        request.method = "POST"
        params = {"user_id": ["party_animal"], "batch-function": "add"}
        request.form.update(params)
        edit_form = getMultiAdapter(
            (workspace, request), name="sidebar.settings.members"
        )
        members = IWorkspace(workspace).members
        self.assertNotIn("party_animal", members)
        edit_form.__call__()
        members = IWorkspace(workspace).members
        self.assertIn("party_animal", members)
