Repository: slackapi/python-slack-sdk
Pull request #1029 (2021-06-05 11:51:42)

Update Audit Logs API response properties
## Summary

This pull request adds missing properties in the Audit Logs API response classes.

### Category (place an `x` in each of the `[ ]`)

- [ ] **slack_sdk.web.WebClient (sync/async)** (Web API client)
- [ ] **slack_sdk.webhook.WebhookClient (sync/async)** (Incoming Webhook, response_url sender)
- [ ] **slack_sdk.models** (UI component builders)
- [ ] **slack_sdk.oauth** (OAuth Flow Utilities)
- [ ] **slack_sdk.socket_mode** (Socket Mode client)
- [x] **slack_sdk.audit_logs** (Audit Logs API client)
- [ ] **slack_sdk.scim** (SCIM API client)
- [ ] **slack_sdk.rtm** (RTM client)
- [ ] **slack_sdk.signature** (Request Signature Verifier)
- [ ] `/docs-src` (Documents, have you run `./docs.sh`?)
- [ ] `/docs-src-v2` (Documents, have you run `./docs-v2.sh`?)
- [ ] `/tutorial` (PythOnBoardingBot tutorial)
- [ ] `tests`/`integration_tests` (Automated tests for this library)

## Requirements (place an `x` in each `[ ]`)

- [ ] I've read and understood the [Contributing Guidelines](https://github.com/slackapi/python-slack-sdk/blob/main/.github/contributing.md) and have done my best effort to follow them.
- [ ] I've read and agree to the [Code of Conduct](https://slackhq.github.io/code-of-conduct).
- [ ] I've run `python setup.py validate` after making the changes.


codecov[bot]: # [Codecov](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1029?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi) Report
> Merging [#1029](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1029?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi) (56dab4d) into [main](https://codecov.io/gh/slackapi/python-slack-sdk/commit/15551b5a0970bd326b78e79f6d98c470a268614e?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi) (15551b5) will **increase** coverage by `0.67%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1029/graphs/tree.svg?width=650&height=150&src=pr&token=F0O7meYmtD&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi)](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1029?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi)

```diff
@@            Coverage Diff             @@
##             main    #1029      +/-   ##
==========================================
+ Coverage   83.66%   84.34%   +0.67%     
==========================================
  Files          95       95              
  Lines        8792     8880      +88     
==========================================
+ Hits         7356     7490     +134     
+ Misses       1436     1390      -46     
```


| [Impacted Files](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1029?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi) | Coverage Δ | |
|---|---|---|
| [slack\_sdk/audit\_logs/v1/logs.py](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1029/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi#diff-c2xhY2tfc2RrL2F1ZGl0X2xvZ3MvdjEvbG9ncy5weQ==) | `100.00% <100.00%> (+22.66%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1029?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1029?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi). Last update [15551b5...56dab4d](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1029?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi).


Patch:
diff --git a/slack_sdk/audit_logs/v1/logs.py b/slack_sdk/audit_logs/v1/logs.py
index 82d2418..5b398bc 100644
--- a/slack_sdk/audit_logs/v1/logs.py
+++ b/slack_sdk/audit_logs/v1/logs.py
@@ -93,6 +93,7 @@ class Details:
     expires_on: Optional[int]
     mobile_only: Optional[bool]
     web_only: Optional[bool]
+    non_sso_only: Optional[bool]
     type: Optional[str]
     is_workflow: Optional[bool]
     inviter: Optional[User]
@@ -112,6 +113,31 @@ class Details:
     app_previously_resolved: Optional[bool]
     admin_app_id: Optional[str]
     bot_id: Optional[str]
+    installer_user_id: Optional[str]
+    approver_id: Optional[str]
+    approval_type: Optional[str]
+    app_previously_approved: Optional[bool]
+    old_scopes: Optional[List[str]]
+    channels: Optional[List[str]]
+    permissions: Optional[List[Dict[str, Any]]]
+    new_version_id: Optional[str]
+    trigger: Optional[str]
+    export_type: Optional[str]
+    export_start_ts: Optional[str]
+    export_end_ts: Optional[str]
+    barrier_id: Optional[str]
+    primary_usergroup_id: Optional[str]
+    barriered_from_usergroup_ids: Optional[List[str]]
+    restricted_subjects: Optional[List[str]]
+    duration: Optional[int]
+    desktop_app_browser_quit: Optional[bool]
+    invite_id: Optional[str]
+    external_organization_id: Optional[str]
+    external_organization_name: Optional[str]
+    external_user_id: Optional[str]
+    external_user_email: Optional[str]
+    channel_id: Optional[str]
+    added_team_id: Optional[str]
     unknown_fields: Dict[str, Any]
 
     def __init__(
@@ -123,6 +149,7 @@ class Details:
         expires_on: Optional[int] = None,
         mobile_only: Optional[bool] = None,
         web_only: Optional[bool] = None,
+        non_sso_only: Optional[bool] = None,
         type: Optional[str] = None,
         is_workflow: Optional[bool] = None,
         inviter: Optional[User] = None,
@@ -142,6 +169,31 @@ class Details:
         app_previously_resolved: Optional[bool] = None,
         admin_app_id: Optional[str] = None,
         bot_id: Optional[str] = None,
+        installer_user_id: Optional[str] = None,
+        approver_id: Optional[str] = None,
+        approval_type: Optional[str] = None,
+        app_previously_approved: Optional[bool] = None,
+        old_scopes: Optional[List[str]] = None,
+        channels: Optional[List[str]] = None,
+        permissions: Optional[List[Dict[str, Any]]] = None,
+        new_version_id: Optional[str] = None,
+        trigger: Optional[str] = None,
+        export_type: Optional[str] = None,
+        export_start_ts: Optional[str] = None,
+        export_end_ts: Optional[str] = None,
+        barrier_id: Optional[str] = None,
+        primary_usergroup_id: Optional[str] = None,
+        barriered_from_usergroup_ids: Optional[List[str]] = None,
+        restricted_subjects: Optional[List[str]] = None,
+        duration: Optional[int] = None,
+        desktop_app_browser_quit: Optional[bool] = None,
+        invite_id: Optional[str] = None,
+        external_organization_id: Optional[str] = None,
+        external_organization_name: Optional[str] = None,
+        external_user_id: Optional[str] = None,
+        external_user_email: Optional[str] = None,
+        channel_id: Optional[str] = None,
+        added_team_id: Optional[str] = None,
         **kwargs,
     ) -> None:
         self.name = name
@@ -150,6 +202,7 @@ class Details:
         self.expires_on = expires_on
         self.mobile_only = mobile_only
         self.web_only = web_only
+        self.non_sso_only = non_sso_only
         self.type = type
         self.is_workflow = is_workflow
         self.inviter = inviter
@@ -170,6 +223,31 @@ class Details:
         self.admin_app_id = admin_app_id
         self.bot_id = bot_id
         self.unknown_fields = kwargs
+        self.installer_user_id = installer_user_id
+        self.approver_id = approver_id
+        self.approval_type = approval_type
+        self.app_previously_approved = app_previously_approved
+        self.old_scopes = old_scopes
+        self.channels = channels
+        self.permissions = permissions
+        self.new_version_id = new_version_id
+        self.trigger = trigger
+        self.export_type = export_type
+        self.export_start_ts = export_start_ts
+        self.export_end_ts = export_end_ts
+        self.barrier_id = barrier_id
+        self.primary_usergroup_id = primary_usergroup_id
+        self.barriered_from_usergroup_ids = barriered_from_usergroup_ids
+        self.restricted_subjects = restricted_subjects
+        self.duration = duration
+        self.desktop_app_browser_quit = desktop_app_browser_quit
+        self.invite_id = invite_id
+        self.external_organization_id = external_organization_id
+        self.external_organization_name = external_organization_name
+        self.external_user_id = external_user_id
+        self.external_user_email = external_user_email
+        self.channel_id = channel_id
+        self.added_team_id = added_team_id
 
 
 class App:
@@ -256,6 +334,66 @@ class File:
         self.unknown_fields = kwargs
 
 
+class Usergroup:
+    id: Optional[str]
+    name: Optional[str]
+    unknown_fields: Dict[str, Any]
+
+    def __init__(
+        self,
+        *,
+        id: Optional[str] = None,
+        name: Optional[str] = None,
+        **kwargs,
+    ) -> None:
+        self.id = id
+        self.name = name
+        self.unknown_fields = kwargs
+
+
+class Workflow:
+    id: Optional[str]
+    name: Optional[str]
+    domain: Optional[str]
+    unknown_fields: Dict[str, Any]
+
+    def __init__(
+        self,
+        *,
+        id: Optional[str] = None,
+        name: Optional[str] = None,
+        domain: Optional[str] = None,
+        **kwargs,
+    ) -> None:
+        self.id = id
+        self.name = name
+        self.domain = domain
+        self.unknown_fields = kwargs
+
+
+class InformationBarrier:
+    id: Optional[str]
+    primary_usergroup: Optional[str]
+    barriered_from_usergroups: Optional[List[str]]
+    restricted_subjects: Optional[List[str]]
+    unknown_fields: Dict[str, Any]
+
+    def __init__(
+        self,
+        *,
+        id: Optional[str] = None,
+        primary_usergroup: Optional[str] = None,
+        barriered_from_usergroups: Optional[List[str]] = None,
+        restricted_subjects: Optional[List[str]] = None,
+        **kwargs,
+    ) -> None:
+        self.id = id
+        self.primary_usergroup = primary_usergroup
+        self.barriered_from_usergroups = barriered_from_usergroups
+        self.restricted_subjects = restricted_subjects
+        self.unknown_fields = kwargs
+
+
 class Entity:
     type: Optional[str]
     user: Optional[User]
@@ -264,6 +402,9 @@ class Entity:
     channel: Optional[Channel]
     file: Optional[File]
     app: Optional[App]
+    usergroup: Optional[Usergroup]
+    workflow: Optional[Workflow]
+    barrier: Optional[InformationBarrier]
     unknown_fields: Dict[str, Any]
 
     def __init__(
@@ -276,6 +417,9 @@ class Entity:
         channel: Optional[Union[Channel, dict]] = None,
         file: Optional[Union[File, dict]] = None,
         app: Optional[Union[App, dict]] = None,
+        usergroup: Optional[Usergroup] = None,
+        workflow: Optional[Workflow] = None,
+        barrier: Optional[InformationBarrier] = None,
         **kwargs,
     ) -> None:
         self.type = type
@@ -289,6 +433,13 @@ class Entity:
         self.channel = Channel(**channel) if isinstance(channel, dict) else channel
         self.file = File(**file) if isinstance(file, dict) else file
         self.app = App(**app) if isinstance(app, dict) else app
+        self.usergroup = (
+            Usergroup(**usergroup) if isinstance(usergroup, dict) else usergroup
+        )
+        self.workflow = Workflow(**workflow) if isinstance(workflow, dict) else workflow
+        self.barrier = (
+            InformationBarrier(**barrier) if isinstance(barrier, dict) else barrier
+        )
         self.unknown_fields = kwargs
 
 


Test patch:
diff --git a/tests/slack_sdk/audit_logs/test_response.py b/tests/slack_sdk/audit_logs/test_response.py
index 74489f9..abe3aa9 100644
--- a/tests/slack_sdk/audit_logs/test_response.py
+++ b/tests/slack_sdk/audit_logs/test_response.py
@@ -3,12 +3,6 @@ import unittest
 
 from slack_sdk.audit_logs.v1.logs import LogsResponse
 
-from slack_sdk.audit_logs import AuditLogsClient, AuditLogsResponse
-from tests.slack_sdk.audit_logs.mock_web_api_server import (
-    cleanup_mock_web_api_server,
-    setup_mock_web_api_server,
-)
-
 
 class TestAuditLogsClient(unittest.TestCase):
     def setUp(self):
@@ -106,3 +100,240 @@ class TestAuditLogsClient(unittest.TestCase):
         self.assertIsNotNone(logs.entries[0].unknown_fields.get("new_attribute"))
         self.assertIsNotNone(logs.response_metadata.unknown_fields.get("new_attribute"))
         self.assertIsNotNone(logs.unknown_fields.get("new_attribute"))
+
+    def test_logs_complete(self):
+        logs = LogsResponse(**json.loads(logs_response_data))
+        self.assertIsNotNone(logs)
+        self.assertEqual(logs.response_metadata.next_cursor, "")
+        entry = logs.entries[0]
+        self.assertEqual(
+            list(entry.details.unknown_fields.keys()),
+            [],
+            f"found: {entry.details.unknown_fields.keys()}",
+        )
+        self.assertEqual(
+            list(entry.entity.unknown_fields.keys()),
+            [],
+            f"found: {entry.entity.unknown_fields.keys()}",
+        )
+        self.assertEqual(
+            list(entry.context.unknown_fields.keys()),
+            [],
+            f"found: {entry.context.unknown_fields.keys()}",
+        )
+        self.assertEqual(
+            list(entry.actor.unknown_fields.keys()),
+            [],
+            f"found: {entry.actor.unknown_fields.keys()}",
+        )
+
+
+logs_response_data = """{
+  "ok": false,
+  "warning": "",
+  "error": "",
+  "needed": "",
+  "provided": "",
+  "response_metadata": {
+    "next_cursor": ""
+  },
+  "entries": [
+    {
+      "id": "",
+      "date_create": 123,
+      "action": "",
+      "actor": {
+        "type": "",
+        "user": {
+          "id": "",
+          "name": "",
+          "email": "",
+          "team": ""
+        }
+      },
+      "entity": {
+        "type": "",
+        "app": {
+          "id": "",
+          "name": "",
+          "is_distributed": false,
+          "is_directory_approved": false,
+          "is_workflow_app": false,
+          "scopes": [
+            ""
+          ]
+        },
+        "user": {
+          "id": "",
+          "name": "",
+          "email": "",
+          "team": ""
+        },
+        "usergroup": {
+          "id": "",
+          "name": ""
+        },
+        "workspace": {
+          "id": "",
+          "name": "",
+          "domain": ""
+        },
+        "enterprise": {
+          "id": "",
+          "name": "",
+          "domain": ""
+        },
+        "file": {
+          "id": "",
+          "name": "",
+          "filetype": "",
+          "title": ""
+        },
+        "channel": {
+          "id": "",
+          "name": "",
+          "privacy": "",
+          "is_shared": false,
+          "is_org_shared": false,
+          "teams_shared_with": [
+            ""
+          ],
+          "original_connected_channel_id": ""
+        },
+        "workflow": {
+          "id": "",
+          "name": ""
+        },
+        "barrier": {
+          "id": "",
+          "primary_usergroup": "",
+          "barriered_from_usergroups": [
+            ""
+          ],
+          "restricted_subjects": [
+            ""
+          ]
+        }
+      },
+      "context": {
+        "session_id": "",
+        "location": {
+          "type": "",
+          "id": "",
+          "name": "",
+          "domain": ""
+        },
+        "ua": "",
+        "ip_address": ""
+      },
+      "details": {
+        "type": "",
+        "app_owner_id": "",
+        "scopes": [
+          ""
+        ],
+        "bot_scopes": [
+          ""
+        ],
+        "new_scopes": [
+          ""
+        ],
+        "previous_scopes": [
+          ""
+        ],
+        "inviter": {
+          "type": "",
+          "user": {
+            "id": "",
+            "name": "",
+            "email": "",
+            "team": ""
+          },
+          "id": "",
+          "name": "",
+          "email": "",
+          "team": ""
+        },
+        "kicker": {
+          "type": "",
+          "user": {
+            "id": "",
+            "name": "",
+            "email": "",
+            "team": ""
+          },
+          "id": "",
+          "name": "",
+          "email": "",
+          "team": ""
+        },
+        "installer_user_id": "",
+        "approver_id": "",
+        "approval_type": "",
+        "app_previously_approved": false,
+        "old_scopes": [
+          ""
+        ],
+        "name": "",
+        "bot_id": "",
+        "channels": [
+          ""
+        ],
+        "permissions": [
+          {
+            "resource": {
+              "type": "",
+              "grant": {
+                "type": "",
+                "resource_id": "",
+                "wildcard": {
+                  "type": ""
+                }
+              }
+            },
+            "scopes": [
+              ""
+            ]
+          }
+        ],
+        "shared_to": "",
+        "reason": "",
+        "is_internal_integration": false,
+        "is_workflow": false,
+        "mobile_only": false,
+        "web_only": false,
+        "non_sso_only": false,
+        "expires_on": 123,
+        "new_version_id": "",
+        "trigger": "",
+        "granular_bot_token": false,
+        "origin_team": "",
+        "target_team": "",
+        "resolution": "",
+        "app_previously_resolved": false,
+        "admin_app_id": "",
+        "export_type": "",
+        "export_start_ts": "",
+        "export_end_ts": "",
+        "barrier_id": "",
+        "primary_usergroup_id": "",
+        "barriered_from_usergroup_ids": [
+          ""
+        ],
+        "restricted_subjects": [
+          ""
+        ],
+        "duration": 123,
+        "desktop_app_browser_quit": false,
+        "invite_id": "",
+        "external_organization_id": "",
+        "external_organization_name": "",
+        "external_user_id": "",
+        "external_user_email": "",
+        "channel_id": "",
+        "added_team_id": ""
+      }
+    }
+  ]
+}
+"""