"""
This script prints out a list of Lumos users who are not active and who are approver or admins
on AppStore applications.
This script does not consider two scenarios:
- When an inactive user is an approver in a permission
- When an inactive user is the only active user in an approver or admin group.
The output will look like this, for each user that is not active:
==============================================
user (<user_id>):
email: <user email>
first: <user first name>
last: <user last name>
Approver on these AppStore Apps:
- <app name> (<AppStore app URL>)
...
Admin on these AppStore Apps:
- <app name> (<AppStore app URL>)
...
"""
import typing
from dataclasses import dataclass
import requests
headers = {
"accept": "application/json",
"authorization": "Bearer <API TOKEN>",
}
# Initialize types and constants
@dataclass
class UserInfo:
email: str
first_name: str
last_name: str
@dataclass
class AppInfo:
id: str
name: str
@dataclass
class NonActiveUserEntry:
user: UserInfo
approver_apps: typing.List[AppInfo]
admin_apps: typing.List[AppInfo]
UserID = str
results: typing.Dict[UserID, NonActiveUserEntry] = {}
GET_APPSTORE_APPS_URL = "https://api.lumos.com/appstore/apps"
GET_APPSTORE_APPS_SETTINGS_URL = "https://api.lumos.com/appstore/apps/{app_id}/settings"
APP_URL = "https://app.lumosidentity.com/apps/{app_id}?tab=users"
# Define a helper function for recordkeeping.
def init_nonactive_user_entry(user: typing.Dict):
results[user["id"]] = NonActiveUserEntry(
user=UserInfo(
email=user["email"],
first_name=user["given_name"],
last_name=user["family_name"],
),
approver_apps=[],
admin_apps=[],
)
# Iterate through all AppStore Apps.
response = requests.get(GET_APPSTORE_APPS_URL, headers=headers)
response_page = response.json()
while len(response_page["items"]):
for app in response_page["items"]:
app_id = app["id"]
app_name = app["user_friendly_label"]
# Fetch AppStore app permissions, and extract out approvers or admins who are inactive.
response = requests.get(
GET_APPSTORE_APPS_SETTINGS_URL.format(app_id=app_id),
headers=headers,
)
response_json = response.json()
approver_users = response_json["request_flow"]["approvers"]["users"]
approver_stage_2_users = response_json["request_flow"]["approvers_stage_2"]["users"]
for user in approver_users + approver_stage_2_users:
if user["status"] == "ACTIVE":
continue
if user["id"] not in results:
init_nonactive_user_entry(user)
results[user["id"]].approver_apps.append(AppInfo(id=app_id, name=app_name))
admin_users = response_json["request_flow"]["admins"]["users"]
for user in admin_users:
if user["status"] == "ACTIVE":
continue
if user["id"] not in results:
init_nonactive_user_entry(user)
results[user["id"]].admin_apps.append(AppInfo(id=app_id, name=app_name))
response = requests.get(
GET_APPSTORE_APPS_URL,
headers=headers,
params={"size": 50, "page": response_page["page"] + 1},
)
response_page = response.json()
# Iterate, and print the dictionary.
for user_id in results:
user = results[user_id].user
approver_apps = results[user_id].approver_apps
admin_apps = results[user_id].admin_apps
print("==============================================")
print(f"user (id: {user_id}): ")
print(f"\temail: {user.email}")
print(f"\tfirst: {user.first_name}")
print(f"\tlast: {user.last_name}")
print("")
print("\t\t Approver on these AppStore Apps:")
for approver_app in approver_apps:
app_url = APP_URL.format(app_id=approver_app.id)
print(f"\t\t\t- {approver_app.name} ({app_url})")
print("\t\t Admin on these AppStore Apps:")
for admin_app in admin_apps:
app_url = APP_URL.format(app_id=admin_app.id)
print(f"\t\t\t- {admin_app.name} ({app_url})")