from plone import api
from plone.app.testing import IntegrationTesting
from plone.app.testing import login
from plone.app.testing import PloneSandboxLayer
from ploneintranet import api as pi_api
from ploneintranet.news.browser.interfaces import INewsContentLayer
from ploneintranet.news.testing import PLONEINTRANET_NEWS_FIXTURE
from ploneintranet.workspace.config import INTRANET_USERS_GROUP_ID
from zope.interface import alsoProvides

import unittest


class Layer(PloneSandboxLayer):

    defaultBases = (PLONEINTRANET_NEWS_FIXTURE,)

    def setUpPloneSite(self, portal):
        pi_api.userprofile.create(
            username="my_user",
            email="my_user@intranet.org",
            properties={"fullname": "My User"},
            approve=True,
        )
        pi_api.userprofile.create(
            username="other_user", email="other_user@intranet.org", approve=True
        )

        pi_api.userprofile.create(
            username="hr_member", email="hr_member@intranet.org", approve=True
        )
        pi_api.workgroup.create(groupid="hr", title="HR", members={"hr_member"})

        self.production_member = pi_api.userprofile.create(
            username="production_member",
            email="production_member@intranet.org",
            approve=True,
        )
        pi_api.workgroup.create(
            groupid="production", title="Production", members={"production_member"}
        )

        pi_api.userprofile.create(
            username="marketing_member",
            email="marketing_member@intranet.org",
            approve=True,
        )
        pi_api.workgroup.create(
            groupid="marketing", title="Marketing", members={"marketing_member"}
        )

        pi_api.workgroup.create(groupid="qa", title="QA")
        pi_api.workgroup.create(groupid="sales", title="Sales")

        api.user.grant_roles(username="my_user", obj=portal.news, roles=["Contributor"])

        with api.env.adopt_user(username="my_user"):
            api.content.create(
                type="ploneintranet.news.section",
                title="Existing Section",
                container=portal.news,
            )


FIXTURE = Layer()

LAYER = IntegrationTesting(
    bases=(FIXTURE,),
    name="PloneintranetnewsPermissionLayer:Integration",
)


class TestSectionPermissions(unittest.TestCase):

    layer = LAYER

    def setUp(self):
        self.portal = self.layer["portal"]
        self.request = self.layer["request"]
        self.existing_section = self.portal.news["existing-section"]
        alsoProvides(self.layer["request"], INewsContentLayer)

    def test_assign_default_access_on_create(self):
        login(self.layer["portal"], "my_user")
        app = self.portal.get("news")
        request = self.request.clone()
        request["method"] = "POST"
        request.form = {
            "type": "section",
            "title": "Test Section",
            "section_description": "Test",
            "section-description-visible": "on",
            "navigation": "main",
            "maintenance": "none",
            "maintainer_group_list": "",
            "contribution": "none",
            "contributor_group_list": "",
            "visibility": "all",
            "nav_visible_group_list": "",
            "form.id": "create",
            "form.buttons.create": "Create",
        }
        setattr(self.layer["app"], "REQUEST", request)
        add_view = api.content.get_view(context=app, request=request, name="publisher")
        add_view()
        section = app.get("test-section")

        self.assertSetEqual(set(section.maintainer_group_list), set())
        self.assertSetEqual(set(section.nav_visible_group_list), set())

        for permission in ["Modify portal content", "Add portal content"]:
            self.assertTrue(
                api.user.has_permission(permission, username="my_user", obj=section),
                msg=f'Owner does not have "{permission}" permission',
            )
            self.assertFalse(
                api.user.has_permission(permission, username="other_user", obj=section),
                msg=f'Other user has "{permission}" permission',
            )
        self.assertTrue(
            api.user.has_permission("View", username="my_user", obj=section),
            msg='Owner does not have "View" permission',
        )
        for permission in ["Modify portal content", "Add portal content"]:
            self.assertFalse(
                api.user.has_permission(permission, username="hr_member", obj=section),
                msg=('other group member has "{}" permission' "".format(permission)),
            )
        self.assertFalse(
            api.user.has_permission(
                "Add portal content", username="marketing_member", obj=section
            ),
        )

    def test_assign_specific_groups_on_create(self):
        login(self.layer["portal"], "my_user")
        app = self.portal.get("news")
        request = self.request.clone()
        request["method"] = "POST"
        request.form = {
            "type": "section",
            "title": "Test Section",
            "section_description": "Test",
            "section-description-visible": "on",
            "navigation": "main",
            "maintenance": "groups",
            "maintainer_group_list": "hr,qa",
            "contribution": "groups",
            "contributor_group_list": "marketing",
            "visibility": "groups",
            "nav_visible_group_list": "production,sales",
            "form.id": "create",
            "form.buttons.create": "Create",
        }
        setattr(self.layer["app"], "REQUEST", request)
        add_view = api.content.get_view(context=app, request=request, name="publisher")
        add_view()
        section = app.get("test-section")

        self.assertSetEqual(set(section.maintainer_group_list), {"hr", "qa"})
        self.assertSetEqual(
            set(section.nav_visible_group_list), {"production", "sales"}
        )

        for permission in ["Modify portal content", "Add portal content"]:
            self.assertTrue(
                api.user.has_permission(permission, username="my_user", obj=section),
                msg=f'Owner does not have "{permission}" permission',
            )
            self.assertFalse(
                api.user.has_permission(permission, username="other_user", obj=section),
                msg=f'Other user has "{permission}" permission',
            )
        self.assertTrue(
            api.user.has_permission("View", username="my_user", obj=section),
            msg='Owner does not have "View" permission',
        )
        for permission in ["View", "Modify portal content", "Add portal content"]:
            self.assertTrue(
                api.user.has_permission(permission, username="hr_member", obj=section),
                msg=(
                    'maintainer group member does not have "{}" permission'
                    "".format(permission)
                ),
            )
        self.assertTrue(
            api.user.has_permission(
                "Add portal content", username="marketing_member", obj=section
            ),
        )

    def test_assign_combination_on_create(self):
        login(self.layer["portal"], "my_user")
        app = self.portal.get("news")
        request = self.request.clone()
        request["method"] = "POST"
        request.form = {
            "type": "section",
            "title": "Test Section",
            "section_description": "Test",
            "section-description-visible": "on",
            "navigation": "main",
            "maintenance": "groups",
            "maintainer_group_list": "hr,production",
            "contribution": "none",
            "contributor_group_list": "",
            "visibility": "all",
            "nav_visible_group_list": "",
            "form.id": "create",
            "form.buttons.create": "Create",
        }
        setattr(self.layer["app"], "REQUEST", request)
        add_view = api.content.get_view(context=app, request=request, name="publisher")
        add_view()
        section = app.get("test-section")

        self.assertSetEqual(set(section.maintainer_group_list), {"hr", "production"})
        self.assertSetEqual(set(section.nav_visible_group_list), set())

        for permission in ["Modify portal content", "Add portal content"]:
            self.assertTrue(
                api.user.has_permission(permission, username="my_user", obj=section),
                msg=f'Owner does not have "{permission}" permission',
            )
            self.assertFalse(
                api.user.has_permission(permission, username="other_user", obj=section),
                msg=f'Other user has "{permission}" permission',
            )
        self.assertTrue(
            api.user.has_permission("View", username="other_user", obj=section),
            msg='Other user does not have "View" permission',
        )
        for permission in ["View", "Modify portal content", "Add portal content"]:
            self.assertTrue(
                api.user.has_permission(permission, username="hr_member", obj=section),
                msg=(
                    'maintainer group member does not have "{}" permission'
                    "".format(permission)
                ),
            )
        self.assertFalse(
            api.user.has_permission(
                "Add portal content", username="marketing_member", obj=section
            ),
        )

    def test_assign_default_access_on_edit(self):
        login(self.layer["portal"], "my_user")
        request = self.request.clone()
        request["method"] = "POST"
        request.form = {
            "title": "Existing Section",
            "description": "Test",
            "section-description-visible": "on",
            "navigation": "main",
            "show_descriptions": "on",
            "show_images": "on",
            "color": "on",
            "maintenance": "none",
            "maintainer_group_list": "",
            "contribution": "none",
            "contributor_group_list": "",
            "visibility": "all",
            "nav_visible_group_list": "",
        }
        setattr(self.layer["app"], "REQUEST", request)
        edit_view = api.content.get_view(
            context=self.existing_section,
            request=request,
            name="panel-edit-news-section-info.html",
        )
        edit_view()
        section = self.existing_section

        self.assertSetEqual(set(section.maintainer_group_list), set())
        self.assertSetEqual(set(section.nav_visible_group_list), set())

        for permission in ["Modify portal content", "Add portal content"]:
            self.assertTrue(
                api.user.has_permission(permission, username="my_user", obj=section),
                msg=f'Owner does not have "{permission}" permission',
            )
            self.assertFalse(
                api.user.has_permission(permission, username="other_user", obj=section),
                msg=f'Other user has "{permission}" permission',
            )
        self.assertTrue(
            api.user.has_permission("View", username="my_user", obj=section),
            msg='Owner does not have "View" permission',
        )
        for permission in ["Modify portal content", "Add portal content"]:
            self.assertFalse(
                api.user.has_permission(permission, username="hr_member", obj=section),
                msg=('other group member has "{}" permission' "".format(permission)),
            )
        self.assertFalse(
            api.user.has_permission(
                "Add portal content", username="marketing_member", obj=section
            ),
        )

    def test_assign_specific_groups_on_edit(self):
        login(self.layer["portal"], "my_user")
        request = self.request.clone()
        request["method"] = "POST"
        request.form = {
            "title": "Existing Section",
            "description": "Test",
            "section-description-visible": "on",
            "navigation": "main",
            "show_descriptions": "on",
            "show_images": "on",
            "color": "on",
            "maintenance": "groups",
            "maintainer_group_list": "hr,qa",
            "contribution": "groups",
            "contributor_group_list": "marketing",
            "visibility": "groups",
            "nav_visible_group_list": "production,sales",
        }
        setattr(self.layer["app"], "REQUEST", request)
        edit_view = api.content.get_view(
            context=self.existing_section,
            request=request,
            name="panel-edit-news-section-info.html",
        )
        edit_view()
        section = self.existing_section

        self.assertSetEqual(set(section.maintainer_group_list), {"hr", "qa"})
        self.assertSetEqual(
            set(section.nav_visible_group_list), {"production", "sales"}
        )

        for permission in ["Modify portal content", "Add portal content"]:
            self.assertTrue(
                api.user.has_permission(permission, username="my_user", obj=section),
                msg=f'Owner does not have "{permission}" permission',
            )
            self.assertFalse(
                api.user.has_permission(permission, username="other_user", obj=section),
                msg=f'Other user has "{permission}" permission',
            )
        self.assertTrue(
            api.user.has_permission("View", username="my_user", obj=section),
            msg='Owner does not have "View" permission',
        )
        for permission in ["View", "Modify portal content", "Add portal content"]:
            self.assertTrue(
                api.user.has_permission(permission, username="hr_member", obj=section),
                msg=(
                    'maintainer group member does not have "{}" permission'
                    "".format(permission)
                ),
            )
        self.assertTrue(
            api.user.has_permission(
                "Add portal content", username="marketing_member", obj=section
            ),
        )

    def test_assign_combination_on_edit(self):
        login(self.layer["portal"], "my_user")
        request = self.request.clone()
        request["method"] = "POST"
        request.form = {
            "title": "Existing Section",
            "description": "Test",
            "section-description-visible": "on",
            "navigation": "main",
            "show_descriptions": "on",
            "show_images": "on",
            "color": "on",
            "maintenance": "groups",
            "maintainer_group_list": "hr,production",
            "contribution": "none",
            "contributor_group_list": "",
            "visibility": "all",
            "nav_visible_group_list": "",
        }
        setattr(self.layer["app"], "REQUEST", request)
        edit_view = api.content.get_view(
            context=self.existing_section,
            request=request,
            name="panel-edit-news-section-info.html",
        )
        edit_view()
        section = self.existing_section

        self.assertSetEqual(set(section.maintainer_group_list), {"hr", "production"})
        self.assertSetEqual(set(section.nav_visible_group_list), set())

        for permission in ["Modify portal content", "Add portal content"]:
            self.assertTrue(
                api.user.has_permission(permission, username="my_user", obj=section),
                msg=f'Owner does not have "{permission}" permission',
            )
            self.assertFalse(
                api.user.has_permission(permission, username="other_user", obj=section),
                msg=f'Other user has "{permission}" permission',
            )
        self.assertTrue(
            api.user.has_permission("View", username="other_user", obj=section),
            msg='Other user does not have "View" permission',
        )
        for permission in ["View", "Modify portal content", "Add portal content"]:
            self.assertTrue(
                api.user.has_permission(permission, username="hr_member", obj=section),
                msg=(
                    'maintainer group member does not have "{}" permission'
                    "".format(permission)
                ),
            )
        self.assertFalse(
            api.user.has_permission(
                "Add portal content", username="marketing_member", obj=section
            ),
        )

    def test_unset_groups_on_edit(self):
        login(self.layer["portal"], "my_user")
        app = self.portal.get("news")
        request = self.request.clone()
        request["method"] = "POST"
        request.form = {
            "type": "section",
            "title": "Test Section",
            "section_description": "Test",
            "section-description-visible": "on",
            "navigation": "main",
            "maintenance": "groups",
            "maintainer_group_list": "hr,qa",
            "contribution": "groups",
            "contributor_group_list": "marketing",
            "visibility": "groups",
            "nav_visible_group_list": "production,sales",
            "form.id": "create",
            "form.buttons.create": "Create",
        }
        setattr(self.layer["app"], "REQUEST", request)
        add_view = api.content.get_view(context=app, request=request, name="publisher")
        add_view()
        section = app.get("test-section")

        self.assertSetEqual(set(section.maintainer_group_list), {"hr", "qa"})
        self.assertSetEqual(set(section.contributor_group_list), {"marketing"})
        self.assertSetEqual(
            set(section.nav_visible_group_list), {"production", "sales"}
        )

        request = self.request.clone()
        request["method"] = "POST"
        request.form = {
            "title": "Existing Section",
            "description": "Test",
            "section-description-visible": "on",
            "navigation": "main",
            "show_descriptions": "on",
            "show_images": "on",
            "color": "on",
            "maintenance": "none",
            "maintainer_group_list": "hr,qa",
            "contribution": "none",
            "contributor_group_list": "marketing",
            "visibility": "all",
            "nav_visible_group_list": "production,sales",
        }
        setattr(self.layer["app"], "REQUEST", request)
        edit_view = api.content.get_view(
            context=section, request=request, name="panel-edit-news-section-info.html"
        )
        edit_view()
        self.assertEqual(section.maintainer_group_list, set())
        self.assertEqual(section.contributor_group_list, set())
        self.assertEqual(section.nav_visible_group_list, set())

    def test_contribution_create_all(self):
        login(self.layer["portal"], "my_user")
        app = self.portal.get("news")
        request = self.request.clone()
        request["method"] = "POST"
        request.form = {
            "type": "section",
            "title": "Test Section",
            "section_description": "Test",
            "section-description-visible": "on",
            "navigation": "main",
            "maintenance": "groups",
            "maintainer_group_list": "qa",
            "contribution": "all",
            "contributor_group_list": "",
            "visibility": "groups",
            "nav_visible_group_list": "production,sales",
            "form.id": "create",
            "form.buttons.create": "Create",
        }
        setattr(self.layer["app"], "REQUEST", request)
        add_view = api.content.get_view(context=app, request=request, name="publisher")
        add_view()
        section = app.get("test-section")
        self.assertSetEqual(
            set(section.contributor_group_list), {INTRANET_USERS_GROUP_ID}
        )
        self.assertIn("hr_member", self.portal.groups.intranet.members)
        self.assertTrue(
            api.user.has_permission(
                "Add portal content", username="hr_member", obj=section
            ),
            msg='All users should have "Add portal content" permission',
        )

    def test_contribution_edit_from_groups_to_all_and_back(self):
        login(self.layer["portal"], "my_user")
        app = self.portal.get("news")
        request = self.request.clone()
        request["method"] = "POST"
        request.form = {
            "type": "section",
            "title": "Test Section",
            "section_description": "Test",
            "section-description-visible": "on",
            "navigation": "main",
            "maintenance": "groups",
            "maintainer_group_list": "qa",
            "contribution": "groups",
            "contributor_group_list": "marketing",
            "visibility": "groups",
            "nav_visible_group_list": "production,sales",
            "form.id": "create",
            "form.buttons.create": "Create",
        }
        setattr(self.layer["app"], "REQUEST", request)
        add_view = api.content.get_view(context=app, request=request, name="publisher")
        add_view()
        section = app.get("test-section")
        self.assertSetEqual(set(section.contributor_group_list), {"marketing"})
        self.assertTrue(
            api.user.has_permission(
                "Add portal content", username="marketing_member", obj=section
            ),
            msg='Marketing should have "Add portal content" permission',
        )
        self.assertFalse(
            api.user.has_permission(
                "Add portal content", username="hr_member", obj=section
            ),
            msg='HR should not have "Add portal content" permission',
        )

        request = self.request.clone()
        request["method"] = "POST"
        request.form = {
            "title": "Existing Section",
            "description": "Test",
            "section-description-visible": "on",
            "navigation": "main",
            "show_descriptions": "on",
            "show_images": "on",
            "color": "on",
            "maintenance": "none",
            "maintainer_group_list": "hr,qa",
            "contribution": "all",
            "contributor_group_list": "marketing",
            "visibility": "all",
            "nav_visible_group_list": "production,sales",
        }
        setattr(self.layer["app"], "REQUEST", request)
        edit_view = api.content.get_view(
            context=section, request=request, name="panel-edit-news-section-info.html"
        )
        edit_view()
        self.assertEqual(section.contributor_group_list, {INTRANET_USERS_GROUP_ID})
        self.assertTrue(
            api.user.has_permission(
                "Add portal content", username="marketing_member", obj=section
            ),
            msg='Marketing should have "Add portal content" permission',
        )
        self.assertTrue(
            api.user.has_permission(
                "Add portal content", username="hr_member", obj=section
            ),
            msg='HR should have "Add portal content" permission',
        )

        request = self.request.clone()
        request["method"] = "POST"
        request.form = {
            "title": "Existing Section",
            "description": "Test",
            "section-description-visible": "on",
            "navigation": "main",
            "show_descriptions": "on",
            "show_images": "on",
            "color": "on",
            "maintenance": "none",
            "maintainer_group_list": "hr,qa",
            "contribution": "groups",
            "contributor_group_list": "marketing",
            "visibility": "all",
            "nav_visible_group_list": "production,sales",
        }
        setattr(self.layer["app"], "REQUEST", request)
        edit_view = api.content.get_view(
            context=section, request=request, name="panel-edit-news-section-info.html"
        )
        edit_view()
        self.assertEqual(section.contributor_group_list, {"marketing"})
        self.assertTrue(
            api.user.has_permission(
                "Add portal content", username="marketing_member", obj=section
            ),
            msg='Marketing should have "Add portal content" permission',
        )
        self.assertFalse(
            api.user.has_permission(
                "Add portal content", username="hr_member", obj=section
            ),
            msg='HR should not have "Add portal content" permission',
        )

    def test_invisible_to_all(self):
        self.existing_section.navigation = "exclude"
        login(self.layer["portal"], "my_user")
        request = self.request.clone()
        app = self.portal.get("news")
        subnav = api.content.get_view(context=app, request=request, name="newssubnav")
        self.assertNotIn(
            self.existing_section,
            [section["obj"] for section in subnav.sections(show="visible")],
        )

    def test_visible_to_all(self):
        self.existing_section.navigation = "main"
        login(self.layer["portal"], "my_user")
        request = self.request.clone()
        app = self.portal.get("news")
        subnav = api.content.get_view(context=app, request=request, name="newssubnav")
        self.assertIn(
            self.existing_section,
            [section["obj"] for section in subnav.sections(show="visible")],
        )

    def test_visible_to_group(self):
        self.existing_section.navigation = "main"
        self.existing_section.nav_visible_group_list = ["hr"]
        login(self.layer["portal"], "hr_member")
        request = self.request.clone()
        app = self.portal.get("news")
        subnav = api.content.get_view(context=app, request=request, name="newssubnav")
        self.assertIn(
            self.existing_section,
            [section["obj"] for section in subnav.sections(show="visible")],
        )
        login(self.layer["portal"], "my_user")
        request = self.request.clone()
        app = self.portal.get("news")
        subnav = api.content.get_view(context=app, request=request, name="newssubnav")
        self.assertNotIn(
            self.existing_section,
            [section["obj"] for section in subnav.sections(show="visible")],
        )
