# (c) cavaliba.com - tests / api - start_api() logs each refused request once

from django.core.cache import cache as cache_django
from django.test import TestCase

import app_home.cache as cache
from app_data.api.aaa import api_deny_reason
from app_home.models import CavalibaEvent
from tests import helper


class TestApiAccessDeniedLogged(TestCase):
    def setUp(self):
        cache.clear()
        cache_django.clear()
        CavalibaEvent.objects.all().delete()

    def _denials(self):
        return list(
            CavalibaEvent.objects.filter(outcome="denied").values_list("action", "reason", "actor")
        )

    def test_missing_key(self):
        self.client.get("/api/version/")
        self.assertEqual(self._denials(), [("api.access", "missing_key", "")])
        event = CavalibaEvent.objects.get(action="api.access")
        self.assertEqual((event.channel, event.origin), ("api", "/api/version/"))

    def test_invalid_credentials(self):
        self.client.get("/api/version/", HTTP_X_CAVALIBA_KEY="nokey secret")
        self.assertEqual(self._denials(), [("api.access", "invalid_credentials", "API:nokey")])

    def test_missing_permission(self):
        helper.add_apikey(keyname="weakkey", acl="")
        self.client.get("/api/version/", HTTP_X_CAVALIBA_KEY="weakkey testpassword")
        self.assertEqual(self._denials(), [("api.access", "permission_denied", "API:weakkey")])
        event = CavalibaEvent.objects.get(action="api.access")
        self.assertEqual(event.extra, {"permission": "p_info"})

    def test_allowed_request_logs_its_own_access(self):
        headers = helper.add_apikey_admin()
        self.client.get("/api/version/", HTTP_X_CAVALIBA_KEY=headers["X-Cavaliba-Key"])
        self.assertEqual(self._denials(), [])
        event = CavalibaEvent.objects.get(action="version.get")
        self.assertEqual((event.actor, event.actor_kind), ("API:test", "apikey"))

    def test_api_root_denied_without_start_api(self):
        self.client.get("/api/", REMOTE_ADDR="10.5.5.5")
        event = CavalibaEvent.objects.get(action="api.index")
        self.assertEqual((event.outcome, event.client_ip), ("denied", "10.5.5.5"))

    def test_reason_mapping(self):
        self.assertEqual(api_deny_reason({"error": "unauthoried credentials"}), "ip_denied")
        self.assertEqual(api_deny_reason({"error": "something else"}), "denied")
        self.assertEqual(api_deny_reason(None), "denied")
