# (c) cavaliba.com - test_user.py

import yaml

from django.test import override_settings
from django.test import TestCase
from django.test import TransactionTestCase
from django.urls import reverse
from django.core.cache import cache as cache_django

from tests import helper

from app_user.models import SireneUser
from app_user.models import SireneGroup
from app_user.models import SirenePermission


from app_user.user import user_get_login_by_email
from app_user.user import user_get_by_login

from app_user.group import group_get_by_id
from app_user.group import group_get_by_name
from app_user.group import group_get_by_data
from app_user.group import group_delete
from app_user.group import group_get_users


import app_home.cache as cache
from app_data.loader import load_broker





# WITHOUT Fixtures
# ----------------

class IAMTestNoFixture(TestCase):

    def setUp(self):
        cache.clear()

    def test_existing_perms(self):
        perms = SirenePermission.objects.all()
        count = len(perms)
        self.assertEqual(count, 0)

    # -----------------------
    # user
    # -----------------------

    # user get by email

    def test_user_get_by_email(self):

        datalist = yaml.safe_load('''
            - classname: _user
              keyname: user99
              email: user99@test.test
            ''')
        aaa = {'perms': ['p_user_create']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        login = user_get_login_by_email('user99@test.test')
        self.assertEqual(login, "user99")

        login = user_get_login_by_email('user99_invalid@test.test')
        self.assertIsNone(login)

        login = user_get_login_by_email('invalid')
        self.assertIsNone(login)

        login = user_get_login_by_email('')
        self.assertIsNone(login)

        login = user_get_login_by_email(None)
        self.assertIsNone(login)

    def test_group_get_users(self):

        datalist = yaml.safe_load('''
            - classname: _user
              keyname: user01
              email: user01@test.test

            - classname: _group
              keyname: group01
              users : ['user01']
            ''')
        aaa = {'perms': ['p_group_create', 'p_user_create']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        user01 = user_get_by_login('user01')
        self.assertEqual(user01.login, 'user01')

        group01 = group_get_by_name('group01')
        self.assertEqual(group01.keyname, 'group01')

        users = group_get_users(group01)
        self.assertEqual(len(users), 1)
        self.assertIn(user01, users)


class IAMTest(TestCase):

    fixtures = ["test"]

    def setUp(self):
        cache.clear()

    # -----------------------
    # user CRUD permission
    # -----------------------


    def test_user_create_allow(self):
        datalist = yaml.safe_load('''
            - classname: _user
              keyname: user_unittest
              _action: create
            ''')
        aaa = {'perms': ['p_user_create']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneUser.objects.filter(login='user_unittest').first()
        self.assertIsNotNone(classobj)

    def test_user_create_deny(self):
        datalist = yaml.safe_load('''
            - classname: _user
              keyname: user_unittest
              _action: create
            ''')
        aaa = {'perms': ['p_iam_access']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneUser.objects.filter(login='user_unittest').first()
        self.assertIsNone(classobj)

# delete

    def test_user_delete_allow(self):

        classobj = SireneUser.objects.filter(login='testuser01').first()
        self.assertIsNotNone(classobj)

        datalist = yaml.safe_load('''
            - classname: _user
              keyname: testuser01
              _action: delete
            ''')
        aaa = {'perms': ['p_user_delete']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneUser.objects.filter(login='testuser01').first()
        self.assertIsNone(classobj)

    def test_user_delete_deny(self):

        classobj = SireneUser.objects.filter(login='testuser01').first()
        self.assertIsNotNone(classobj)

        datalist = yaml.safe_load('''
            - classname: _user
              keyname: testuser01
              _action: delete
            ''')
        aaa = {'perms': ['p_ima_access']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneUser.objects.filter(login='testuser01').first()
        self.assertIsNotNone(classobj)

# update

    def test_user_update_allow(self):

        classobj = SireneUser.objects.filter(login='testuser01').first()
        self.assertEqual(classobj.displayname, "Test User 01")

        datalist = yaml.safe_load('''
            - classname: _user
              keyname: testuser01
              _action: update
              displayname: testnew
            ''')
        aaa = {'perms': ['p_user_update']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneUser.objects.filter(login='testuser01').first()
        self.assertEqual(classobj.displayname, "testnew")

    def test_user_update_deny(self):

        classobj = SireneUser.objects.filter(login='testuser01').first()
        self.assertEqual(classobj.displayname, "Test User 01")

        datalist = yaml.safe_load('''
            - classname: _user
              keyname: testuser01
              _action: update
              displayname: testnew
            ''')
        aaa = {'perms': ['p_iam_access']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneUser.objects.filter(login='testuser01').first()
        self.assertNotEqual(classobj.displayname, "testnew")

    # -----------------------
    # group CRUD permission
    # -----------------------
    def test_group_get_by_id(self):

        gobj = SireneGroup(keyname='group_unittest')
        gobj.save()

        gobj2 = group_get_by_id(gobj.id)
        self.assertEqual(gobj2.keyname, 'group_unittest')

    def test_group_get_by_data(self):

        gobj = SireneGroup(keyname='group_unittest')
        gobj.save()

        gobj2 = group_get_by_data({'keyname': 'group_unittest'})
        self.assertEqual(gobj2.keyname, 'group_unittest')

    def test_group_get_by_name(self):

        gobj = SireneGroup(keyname='group_unittest')
        gobj.save()

        gobj2 = group_get_by_name("group_unittest")
        self.assertEqual(gobj2.keyname, 'group_unittest')

    def test_group_delete(self):

        gobj = SireneGroup(keyname='group_unittest')
        gobj.save()

        gobj = group_get_by_name("group_unittest")
        g, err = group_delete(gobj)
        self.assertIsNot(err, False)
        self.assertIsInstance(g, SireneGroup)

        # non-existent group
        gobj = group_get_by_name("group_unittest2")
        g, err = group_delete(gobj)
        self.assertIn("group_delete", err)

    def test_group_delete_builtin(self):

        gobj = SireneGroup(keyname='group_unittest_builtin')
        gobj.is_builtin = True
        gobj.save()

        g,err = group_delete(gobj)
        self.assertIn("builtin", err)


# read

    # export
    # create

    def test_group_create_allow(self):
        datalist = yaml.safe_load('''
            - classname: _group
              keyname: group99
              _action: create
            ''')
        aaa = {'perms': ['p_group_create']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneGroup.objects.filter(keyname='group99').first()
        self.assertIsNotNone(classobj)

    def test_group_create_deny(self):
        datalist = yaml.safe_load('''
            - classname: _group
              keyname: group99
              _action: create
            ''')
        aaa = {'perms': ['p_iam_access']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneGroup.objects.filter(keyname='group99').first()
        self.assertIsNone(classobj)

# delete

    def test_group_delete_allow(self):

        classobj = SireneGroup.objects.filter(keyname='testgroup01').first()
        self.assertIsNotNone(classobj)

        datalist = yaml.safe_load('''
            - classname: _group
              keyname: testgroup01
              _action: delete
            ''')
        aaa = {'perms': ['p_group_delete']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneGroup.objects.filter(keyname='testgroup01').first()
        self.assertIsNone(classobj)

    def test_group_delete_deny(self):

        classobj = SireneGroup.objects.filter(keyname='testgroup01').first()
        self.assertIsNotNone(classobj)

        datalist = yaml.safe_load('''
            - classname: _group
              keyname: testgroup01
              _action: delete
            ''')
        aaa = {'perms': ['p_iam_access']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneGroup.objects.filter(keyname='testgroup01').first()
        self.assertIsNotNone(classobj)

# update

    def test_group_update_allow(self):

        classobj = SireneGroup.objects.filter(keyname='testgroup01').first()
        self.assertEqual(classobj.displayname, "TestGroup01")

        datalist = yaml.safe_load('''
            - classname: _group
              keyname: testgroup01
              _action: update
              displayname: testnew
            ''')
        aaa = {'perms': ['p_group_update']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneGroup.objects.filter(keyname='testgroup01').first()
        self.assertEqual(classobj.displayname, "testnew")

    def test_group_update_deny(self):

        classobj = SireneGroup.objects.filter(keyname='testgroup01').first()
        self.assertEqual(classobj.displayname, "TestGroup01")

        datalist = yaml.safe_load('''
            - classname: _group
              keyname: testgroup01
              _action: update
              displayname: testnew
            ''')
        aaa = {'perms': ['p_iam_access']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneGroup.objects.filter(keyname='testgroup01').first()
        self.assertNotEqual(classobj.displayname, "testnew")


# -----------------------
# role CRUD permission
# -----------------------

# read

    # export
    # create

    def test_role_create_allow(self):
        datalist = yaml.safe_load('''
            - classname: _role
              keyname: role99
              _action: create
            ''')
        aaa = {'perms': ['p_role_create']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneGroup.objects.filter(keyname='role99').first()
        self.assertIsNotNone(classobj)

    def test_role_create_deny(self):
        datalist = yaml.safe_load('''
            - classname: _role
              keyname: role99
              _action: create
            ''')
        aaa = {'perms': ['p_iam_access']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneGroup.objects.filter(keyname='role99').first()
        self.assertIsNone(classobj)

# delete

    def test_role_delete_allow(self):

        classobj = SireneGroup.objects.filter(keyname='role_test_01').first()
        self.assertIsNotNone(classobj)

        datalist = yaml.safe_load('''
            - classname: _role
              keyname: role_test_01
              _action: delete
            ''')
        aaa = {'perms': ['p_role_delete']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneGroup.objects.filter(keyname='role_test_01').first()
        self.assertIsNone(classobj)

    def test_role_delete_deny(self):

        classobj = SireneGroup.objects.filter(keyname='role_test_01').first()
        self.assertIsNotNone(classobj)

        datalist = yaml.safe_load('''
            - classname: _role
              keyname: role_test_01
              _action: delete
            ''')
        aaa = {'perms': ['p_iam_access']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneGroup.objects.filter(keyname='role_test_01').first()
        self.assertIsNotNone(classobj)

# update

    def test_role_update_allow(self):

        classobj = SireneGroup.objects.filter(keyname='role_test_01').first()
        self.assertEqual(classobj.displayname, "Test Role 01")

        datalist = yaml.safe_load('''
            - classname: _role
              keyname: role_test_01
              _action: update
              displayname: testnew
            ''')
        aaa = {'perms': ['p_role_update']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneGroup.objects.filter(keyname='role_test_01').first()
        self.assertEqual(classobj.displayname, "testnew")

    def test_role_update_deny(self):

        classobj = SireneGroup.objects.filter(keyname='role_test_01').first()
        self.assertEqual(classobj.displayname, "Test Role 01")

        datalist = yaml.safe_load('''
            - classname: _role
              keyname: role_test_01
              _action: update
              displayname: testnew
            ''')
        aaa = {'perms': ['p_iam_access']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SireneGroup.objects.filter(keyname='role_test_01').first()
        self.assertNotEqual(classobj.displayname, "testnew")


# ---------------------------
# permission CRUD permission
# ----------------------------

# read

    # export
    # create

    def test_permission_create_allow(self):
        datalist = yaml.safe_load('''
            - classname: _permission
              keyname: permission99
              _action: create
            ''')
        aaa = {'perms': ['p_permission_create']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SirenePermission.objects.filter(
            keyname='permission99').first()
        self.assertIsNotNone(classobj)

    def test_permission_create_deny(self):
        datalist = yaml.safe_load('''
            - classname: _permission
              keyname: permission99
              _action: create
            ''')
        aaa = {'perms': ['p_iam_access']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SirenePermission.objects.filter(
            keyname='permission99').first()
        self.assertIsNone(classobj)

# delete

    def test_permission_delete_allow(self):

        classobj = SirenePermission(keyname='p_unittest')
        classobj.save()

        classobj = SirenePermission.objects.filter(
            keyname='p_unittest').first()
        self.assertIsNotNone(classobj)

        datalist = yaml.safe_load('''
            - classname: _permission
              keyname: p_unittest
              _action: delete
            ''')
        aaa = {'perms': ['p_permission_delete']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SirenePermission.objects.filter(
            keyname='p_unittest').first()
        self.assertIsNone(classobj)

    def test_permission_delete_deny(self):

        classobj = SirenePermission(keyname='p_unittest')
        classobj.save()

        classobj = SirenePermission.objects.filter(
            keyname='p_unittest').first()
        self.assertIsNotNone(classobj)

        datalist = yaml.safe_load('''
            - classname: _permission
              keyname: p_unittest
              _action: delete
            ''')
        aaa = {'perms': ['p_iam_access']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SirenePermission.objects.filter(
            keyname='p_unittest').first()
        self.assertIsNotNone(classobj)

# update

    def test_permission_update_allow(self):

        classobj = SirenePermission.objects.filter(
            keyname='p_log_view').first()
        self.assertEqual(classobj.displayname, "p_log_view")

        datalist = yaml.safe_load('''
            - classname: _permission
              keyname: p_log_view
              _action: update
              displayname: testnew
            ''')
        aaa = {'perms': ['p_permission_update']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SirenePermission.objects.filter(
            keyname='p_log_view').first()
        self.assertEqual(classobj.displayname, "testnew")

    def test_permission_update_deny(self):

        classobj = SirenePermission.objects.filter(
            keyname='p_log_view').first()
        self.assertEqual(classobj.displayname, "p_log_view")

        datalist = yaml.safe_load('''
            - classname: _permission
              keyname: p_log_view
              _action: update
              displayname: testnew
            ''')
        aaa = {'perms': ['p_iam_access']}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = SirenePermission.objects.filter(
            keyname='p_log_view').first()
        self.assertNotEqual(classobj.displayname, "testnew")
