import datetime import responses from responses import matchers from unifi_access.schemas import ( DoorGroupId, DoorGroupResource, DoorId, DoorResource, FetchAllVisitorsExpansion, NfcCardToken, TimePeriod, VisitorId, VisitReason, WeekSchedule, ) from .base import UnifiAccessTests class VisitorTests(UnifiAccessTests): @responses.activate def test_create_visitor(self) -> None: """4.2 Create Visitor""" responses.post( f"https://{self.host}/api/v1/developer/visitors", match=[ matchers.header_matcher(self.common_headers), matchers.json_params_matcher( { "first_name": "H", "last_name": "L", "remarks": "", "mobile_phone": "", "email": "", "visitor_company": "", "start_time": 1688546460, "end_time": 1788572799, # NOTE: typo'ed in api docs to "Interviemw" "visit_reason": "Interview", "week_schedule": { "sunday": [], "monday": [], "tuesday": [ {"start_time": "10:00:00", "end_time": "17:00:59"} ], "wednesday": [ {"start_time": "10:00:00", "end_time": "17:00:59"} ], "thursday": [ {"start_time": "11:00:00", "end_time": "17:00:59"} ], "friday": [ {"start_time": "10:00:00", "end_time": "17:00:59"} ], "saturday": [], }, "resources": [ { "id": "6ff875d2-af87-470b-9cb5-774c6596afc8", "type": "door", }, { "id": "5c496423-6d25-4e4f-8cdf-95ad5135188a", "type": "door_group", }, { "id": "d5573467-d6b3-4e8f-8e48-8a322b91664a", "type": "door_group", }, ], } ), ], json={ "code": "SUCCESS", "data": { "first_name": "H", "id": "fbe8d920-47d3-4cfd-bda7-bf4b0e26f73c", "last_name": "L", "nfc_cards": [], "resources": [ { "id": "5c496423-6d25-4e4f-8cdf-95ad5135188a", "name": "Test Group", "type": "door_group", }, { "id": "d5573467-d6b3-4e8f-8e48-8a322b91664a", "name": "UNVR", "type": "door_group", }, { "id": "369215b0-cabe-49b6-aeaa-e0b7ec6424d5", "name": "visitor-1691671529285", "type": "door_group", }, ], "schedule": { "id": "1fb849bb-e7e5-4516-8dd9-b78094a6708a", "is_default": False, "name": "schedule-1691671529237", "type": "access", "weekly": { "friday": [ {"end_time": "17:00:59", "start_time": "10:00:00"} ], "monday": [], "saturday": [], "sunday": [], "thursday": [ {"end_time": "17:00:59", "start_time": "11:00:00"} ], "tuesday": [ {"end_time": "17:00:59", "start_time": "10:00:00"} ], "wednesday": [ {"end_time": "17:00:59", "start_time": "10:00:00"} ], }, }, "schedule_id": "1fb849bb-e7e5-4516-8dd9-b78094a6708a", "status": "ACTIVE", }, "msg": "success", }, ) resp = self.client.create_visitor( first_name="H", last_name="L", remarks="", mobile_phone="", email="", visitor_company="", start_time=datetime.datetime.fromtimestamp(1688546460, tz=datetime.UTC), end_time=datetime.datetime.fromtimestamp(1788572799, tz=datetime.UTC), visit_reason=VisitReason.INTERVIEW, week_schedule=WeekSchedule( sunday=[], monday=[], tuesday=[ TimePeriod( start_time=datetime.time(10, 0, 0), end_time=datetime.time(17, 0, 59), ) ], wednesday=[ TimePeriod( start_time=datetime.time(10, 0, 0), end_time=datetime.time(17, 0, 59), ) ], thursday=[ TimePeriod( start_time=datetime.time(11, 0, 0), end_time=datetime.time(17, 0, 59), ) ], friday=[ TimePeriod( start_time=datetime.time(10, 0, 0), end_time=datetime.time(17, 0, 59), ) ], saturday=[], ), resources=[ DoorResource( id=DoorId("6ff875d2-af87-470b-9cb5-774c6596afc8"), ), DoorGroupResource( id=DoorGroupId("5c496423-6d25-4e4f-8cdf-95ad5135188a"), ), DoorGroupResource( id=DoorGroupId("d5573467-d6b3-4e8f-8e48-8a322b91664a") ), ], ) assert resp.id == "fbe8d920-47d3-4cfd-bda7-bf4b0e26f73c" @responses.activate def test_fetch_visitor(self) -> None: """4.3 Fetch Visitor""" visitor_id = VisitorId("76794bd8-98c0-49b6-9230-ba8c5812cf29") responses.get( f"https://{self.host}/api/v1/developer/visitors/{visitor_id}", match=[ matchers.header_matcher(self.common_headers), ], json={ "code": "SUCCESS", "data": { "first_name": "Hong+243", "id": "3566867c-fa04-4752-98f6-43cf9a342d4a", "last_name": "Lu", "nfc_cards": [ { "id": "100001", "token": "d27822fc682b478dc637c6db01813e465174df6e54ca515d8427db623cfda1d0", "type": "ua_card", } ], "pin_code": { "token": "bc3e3135013e2dcae119390b7897166e8cec3bcf5becb6b05578ab67634559ed" }, "resources": [ { "id": "fd293ecb-98d2-425b-a020-cb9365ea48b3", "name": "visitor-1690337152955", "type": "door_group", } ], "schedule": { "id": "6ccf9e1e-b174-476d-b2fe-96817c780fbf", "is_default": False, "name": "visitor-1690337152955", "type": "access", "weekly": None, }, "schedule_id": "6ccf9e1e-b174-476d-b2fe-96817c780fbf", "status": "VISITED", }, "msg": "success", }, ) resp = self.client.fetch_visitor(visitor_id=visitor_id) # TODO: verify correctness of data? @responses.activate def test_fetch_all_visitors(self) -> None: """4.4 Fetch All Visitors""" responses.get( f"https://{self.host}/api/v1/developer/visitors", match=[ matchers.header_matcher(self.common_headers), matchers.query_param_matcher({"page_num": 1, "page_size": 25}), ], # NOTE: no example data provided in api docs, so this was # retrieved from a running instance json={ "code": "SUCCESS", "data": [ { "avatar": "", "email": "", "end_time": 1731880901, "first_name": "Test", "id": "faaffd2e-b555-4991-810f-c18b36407c55", "inviter_id": "", "inviter_name": "", "last_name": "Visitor", "location_id": "", "mobile_phone": "", "nfc_cards": [], "remarks": "", "resources": [], "schedule": { "holiday_group": None, "holiday_group_id": "", "holiday_schedule": [], "id": "", "is_default": False, "name": "", "type": "", "weekly": None, }, "schedule_id": "", "start_time": 1731794501, "status": "UPCOMING", "visit_reason": "Business", "visitor_company": "", } ], "msg": "succ", "pagination": {"page_num": 1, "page_size": 1, "total": 1}, }, ) resp = self.client.fetch_all_visitors(page_num=1, page_size=25) assert resp.pagination # TODO: verify correctness of data? @responses.activate def test_fetch_all_visitors_by_keyword(self) -> None: """4.4 Fetch All Visitors""" responses.get( f"https://{self.host}/api/v1/developer/visitors", match=[ matchers.header_matcher(self.common_headers), matchers.query_param_matcher({"keyword": "H"}), ], # NOTE: no example data provided in api docs, so this was # retrieved from a running instance json={ "code": "SUCCESS", "data": [ { "avatar": "", "email": "", "end_time": 1731880901, "first_name": "Test H", "id": "faaffd2e-b555-4991-810f-c18b36407c55", "inviter_id": "", "inviter_name": "", "last_name": "Visitor", "location_id": "", "mobile_phone": "", "nfc_cards": [], "remarks": "", "resources": [], "schedule": { "holiday_group": None, "holiday_group_id": "", "holiday_schedule": [], "id": "", "is_default": False, "name": "", "type": "", "weekly": None, }, "schedule_id": "", "start_time": 1731794501, "status": "UPCOMING", "visit_reason": "Business", "visitor_company": "", } ], "msg": "succ", "pagination": {"page_num": 1, "page_size": 1, "total": 1}, }, ) resp = self.client.fetch_all_visitors(keyword="H") assert resp.pagination # TODO: verify correctness of data? @responses.activate def test_fetch_all_visitors_with_expand(self) -> None: """4.4 Fetch All Visitors""" responses.get( f"https://{self.host}/api/v1/developer/visitors", match=[ matchers.header_matcher(self.common_headers), matchers.query_param_matcher( { "expand[]": [ "access_policy", "resource", "schedule", "nfc_card", "pin_code", ] } ), ], # NOTE: no example data provided in api docs, so this was # retrieved from a running instance json={ "code": "SUCCESS", "data": [ { "avatar": "", "email": "", "end_time": 1731880901, "first_name": "Test", "id": "faaffd2e-b555-4991-810f-c18b36407c55", "inviter_id": "", "inviter_name": "", "last_name": "Visitor", "location_id": "", "mobile_phone": "", "nfc_cards": [], "remarks": "", "resources": [], "schedule": { "holiday_group": None, "holiday_group_id": "", "holiday_schedule": [], "id": "", "is_default": False, "name": "", "type": "", "weekly": None, }, "schedule_id": "", "start_time": 1731794501, "status": "UPCOMING", "visit_reason": "Business", "visitor_company": "", } ], "msg": "succ", "pagination": {"page_num": 1, "page_size": 1, "total": 1}, }, ) resp = self.client.fetch_all_visitors( expand=[ FetchAllVisitorsExpansion.ACCESS_POLICY, FetchAllVisitorsExpansion.RESOURCE, FetchAllVisitorsExpansion.SCHEDULE, FetchAllVisitorsExpansion.NFC_CARD, FetchAllVisitorsExpansion.PIN_CODE, ] ) assert resp.pagination # TODO: verify correctness of data? # NOTE: not taken from API example @responses.activate def test_fetch_all_visitors_without_expand(self) -> None: """4.4 Fetch All Visitors""" responses.get( f"https://{self.host}/api/v1/developer/visitors", match=[ matchers.header_matcher(self.common_headers), matchers.query_param_matcher({"expand[]": "none"}), ], # NOTE: retrieved from a running instance json={ "code": "SUCCESS", "data": [ { "avatar": "", "email": "", "end_time": 1731907089, "first_name": "Test", "id": "173c4cb9-e174-4a83-89fa-01ba8f25362f", "inviter_id": "", "inviter_name": "", "last_name": "Visitor", "location_id": "", "mobile_phone": "", "nfc_cards": [], "pin_code": {}, "remarks": "", "resources": [], "schedule_id": "", "start_time": 1731820689, "status": "UPCOMING", "visit_reason": "Business", "visitor_company": "", }, ], "msg": "succ", "pagination": {"page_num": 1, "page_size": 1, "total": 1}, }, ) resp = self.client.fetch_all_visitors(expand=[FetchAllVisitorsExpansion.NONE]) assert resp.pagination # TODO: verify correctness of data? # NOTE: not taken from API docs examples @responses.activate def test_fetch_all_visitors__unpaged(self) -> None: """4.4 Fetch All Visitors""" responses.get( f"https://{self.host}/api/v1/developer/visitors", match=[ matchers.header_matcher(self.common_headers), matchers.query_param_matcher({"page_num": 1, "page_size": 1}), ], json={ "code": "SUCCESS", "data": [ { "avatar": "", "email": "", "end_time": 1731880901, "first_name": "Test", "id": "faaffd2e-b555-4991-810f-c18b36407c55", "inviter_id": "", "inviter_name": "", "last_name": "Visitor", "location_id": "", "mobile_phone": "", "nfc_cards": [], "remarks": "", "resources": [], "schedule": { "holiday_group": None, "holiday_group_id": "", "holiday_schedule": [], "id": "", "is_default": False, "name": "", "type": "", "weekly": None, }, "schedule_id": "", "start_time": 1731794501, "status": "UPCOMING", "visit_reason": "Business", "visitor_company": "", } ], "msg": "succ", "pagination": {"page_num": 1, "page_size": 1, "total": 2}, }, ) responses.get( f"https://{self.host}/api/v1/developer/visitors", match=[ matchers.header_matcher(self.common_headers), matchers.query_param_matcher({"page_num": 2, "page_size": 1}), ], json={ "code": "SUCCESS", "data": [ { "avatar": "", "email": "", "end_time": 1731880901, "first_name": "Test", "id": "173c4cb9-e174-4a83-89fa-01ba8f25362f", "inviter_id": "", "inviter_name": "", "last_name": "Visitor", "location_id": "", "mobile_phone": "", "nfc_cards": [], "remarks": "", "resources": [], "schedule": { "holiday_group": None, "holiday_group_id": "", "holiday_schedule": [], "id": "", "is_default": False, "name": "", "type": "", "weekly": None, }, "schedule_id": "", "start_time": 1731794501, "status": "UPCOMING", "visit_reason": "Business", "visitor_company": "", } ], "msg": "succ", "pagination": {"page_num": 2, "page_size": 1, "total": 2}, }, ) resp = list(self.client.fetch_all_visitors__unpaged(page_size=1)) assert resp[0].id == "faaffd2e-b555-4991-810f-c18b36407c55" assert resp[1].id == "173c4cb9-e174-4a83-89fa-01ba8f25362f" @responses.activate def test_update_visitor(self) -> None: """4.5 Update Visitor""" visitor_id = VisitorId("37f2b996-c2c5-487b-aa22-8b453ff14a4b") responses.put( f"https://{self.host}/api/v1/developer/visitors/{visitor_id}", match=[ matchers.header_matcher(self.common_headers), matchers.json_params_matcher( { "first_name": "Test", "last_name": "L", "remarks": "", "mobile_phone": "", "email": "", "visitor_company": "", "start_time": 1688546460, "end_time": 1788572799, # NOTE: typo'ed in api docs to "Interviemw" "visit_reason": "Interview", "week_schedule": { "sunday": [], "monday": [ {"start_time": "10:00:00", "end_time": "17:00:59"} ], "tuesday": [], "wednesday": [ {"start_time": "10:00:00", "end_time": "17:00:59"} ], "thursday": [ {"start_time": "11:00:00", "end_time": "18:00:59"} ], "friday": [ {"start_time": "10:00:00", "end_time": "17:00:59"} ], "saturday": [], }, "resources": [ { "id": "6ff875d2-af87-470b-9cb5-774c6596afc8", "type": "door", }, { "id": "5c496423-6d25-4e4f-8cdf-95ad5135188a", "type": "door_group", }, { "id": "d5573467-d6b3-4e8f-8e48-8a322b91664a", "type": "door_group", }, ], } ), ], json={ "code": "SUCCESS", "data": { "first_name": "H", "id": "8564ce90-76ba-445f-b78b-6cca39af0130", "last_name": "L", "nfc_cards": [], "pin_code": None, "resources": [ { "id": "5c496423-6d25-4e4f-8cdf-95ad5135188a", "name": "Door-Group-1", "type": "door_group", }, { "id": "d5573467-d6b3-4e8f-8e48-8a322b91664a", "name": "UNVR", "type": "door_group", }, { "id": "e311ca94-172c-49fe-9c91-49bd8ecef845", "name": "visitor-1691646856144", "type": "door_group", }, ], "schedule": { "id": "c03bf601-0b90-4341-bce4-6061931e9f4e", "is_default": False, "name": "visitor-1691646856097", "type": "access", "weekly": { "friday": [ {"end_time": "17:00:59", "start_time": "10:00:00"} ], "monday": [ {"end_time": "17:00:59", "start_time": "10:00:00"} ], "saturday": [], "sunday": [], "thursday": [ {"end_time": "18:00:59", "start_time": "11:00:00"} ], "tuesday": [], "wednesday": [ {"end_time": "17:00:59", "start_time": "10:00:00"} ], }, }, "schedule_id": "c03bf601-0b90-4341-bce4-6061931e9f4e", "status": "ACTIVE", }, "msg": "success", }, ) resp = self.client.update_visitor( visitor_id=visitor_id, first_name="Test", last_name="L", remarks="", mobile_phone="", email="", visitor_company="", start_time=datetime.datetime.fromtimestamp(1688546460, tz=datetime.UTC), end_time=datetime.datetime.fromtimestamp(1788572799, tz=datetime.UTC), visit_reason=VisitReason.INTERVIEW, week_schedule=WeekSchedule( sunday=[], monday=[ TimePeriod( start_time=datetime.time(10, 0, 0), end_time=datetime.time(17, 0, 59), ) ], tuesday=[], wednesday=[ TimePeriod( start_time=datetime.time(10, 0, 0), end_time=datetime.time(17, 0, 59), ) ], thursday=[ TimePeriod( start_time=datetime.time(11, 0, 0), end_time=datetime.time(18, 0, 59), ) ], friday=[ TimePeriod( start_time=datetime.time(10, 0, 0), end_time=datetime.time(17, 0, 59), ) ], saturday=[], ), resources=[ DoorResource( id=DoorId("6ff875d2-af87-470b-9cb5-774c6596afc8"), ), DoorGroupResource( id=DoorGroupId("5c496423-6d25-4e4f-8cdf-95ad5135188a"), ), DoorGroupResource( id=DoorGroupId("d5573467-d6b3-4e8f-8e48-8a322b91664a") ), ], ) @responses.activate def test_delete_visitor(self) -> None: """4.6 Delete Visitor""" visitor_id = VisitorId("c81dfee6-5970-4938-bd30-40820e16ea01") responses.delete( f"https://{self.host}/api/v1/developer/visitors/{visitor_id}", match=[ matchers.header_matcher(self.common_headers), matchers.query_param_matcher({"is_force": "true"}), ], json={"code": "SUCCESS", "data": None, "msg": "success"}, ) self.client.delete_visitor(visitor_id=visitor_id, is_force=True) @responses.activate def test_assign_nfc_card_to_visitor(self) -> None: """4.7 Assign NFC Card To Visitor""" visitor_id = VisitorId("60b5c15e-9aff-4fc8-9547-d21d2e39c1ff") responses.put( f"https://{self.host}/api/v1/developer/visitors/{visitor_id}/nfc_cards", match=[ matchers.header_matcher(self.common_headers), matchers.json_params_matcher( { "token": "d27822fc682b478dc637c6db01813e465174df6e54ca515d8427db623cfda1d0", "force_add": True, } ), ], json={"code": "SUCCESS", "msg": "success"}, ) self.client.assign_nfc_card_to_visitor( visitor_id=visitor_id, token=NfcCardToken( "d27822fc682b478dc637c6db01813e465174df6e54ca515d8427db623cfda1d0" ), force_add=True, ) @responses.activate def test_unassign_nfc_card_from_visitor(self) -> None: """4.8 Unassign NFC Card From Visitor""" visitor_id = VisitorId("60b5c15e-9aff-4fc8-9547-d21d2e39c1ff") responses.put( f"https://{self.host}/api/v1/developer/visitors/{visitor_id}/nfc_cards/delete", match=[ matchers.header_matcher(self.common_headers), matchers.json_params_matcher( { "token": "d27822fc682b478dc637c6db01813e465174df6e54ca515d8427db623cfda1d0" } ), ], json={"code": "SUCCESS", "msg": "success"}, ) self.client.unassign_nfc_card_from_visitor( visitor_id=visitor_id, token=NfcCardToken( "d27822fc682b478dc637c6db01813e465174df6e54ca515d8427db623cfda1d0" ), ) @responses.activate def test_assign_pin_code_to_visitor(self) -> None: """4.9 Assign Pin Code To Visitor""" visitor_id = VisitorId("17d2f099-99df-429b-becb-1399a6937e5a") responses.put( f"https://{self.host}/api/v1/developer/visitors/{visitor_id}/pin_codes", match=[ matchers.header_matcher(self.common_headers), matchers.json_params_matcher({"pin_code": "57301208"}), ], json={"code": "SUCCESS", "msg": "success"}, ) self.client.assign_pin_code_to_visitor( visitor_id=visitor_id, pin_code="57301208", ) @responses.activate def test_unassign_pin_code_from_visitor(self) -> None: """4.10 Unassign Pin Code From Visitor""" visitor_id = VisitorId("17d2f099-99df-429b-becb-1399a6937e5a") responses.delete( f"https://{self.host}/api/v1/developer/visitors/{visitor_id}/pin_codes", match=[ matchers.header_matcher(self.common_headers), ], json={"code": "SUCCESS", "msg": "success"}, ) self.client.unassign_pin_code_from_visitor(visitor_id=visitor_id)