Skip to content

Commit ba2654c

Browse files
committed
Print is user is owner of org.
1 parent a970490 commit ba2654c

File tree

1 file changed

+39
-16
lines changed

1 file changed

+39
-16
lines changed

tools/last_user_activity.py

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,12 @@ async def get_org_members(
139139

140140
members.extend(page_members)
141141

142+
tasks = [check_user_admin(session, org, member["login"]) for member in members]
143+
admin_statuses = await asyncio.gather(*tasks)
144+
145+
for member, is_owner in zip(members, admin_statuses):
146+
member["is_owner"] = is_owner
147+
142148
# Cache the results
143149
cache[cache_key] = members # Using __setitem__ instead of set()
144150
print(f"[green]Cached {len(members)} members for {org}[/green]")
@@ -226,15 +232,19 @@ def clear_cache() -> None:
226232
print(f"[red]Error clearing cache: {str(e)}[/red]")
227233

228234

229-
async def check_user_admin(session: aiohttp.ClientSession, org: str, username: str) -> bool:
235+
async def check_user_admin(
236+
session: aiohttp.ClientSession, org: str, username: str
237+
) -> bool:
230238
url = f"https://api.github.com/orgs/{org}/memberships/{username}"
231239
async with session.get(url, headers=headers) as response:
232240
if response.status == 404:
233241
return False
234242
elif response.status != 200:
235-
print(f"[red]Error fetching membership for {username} in {org}: {response.status}[/red]")
243+
print(
244+
f"[red]Error fetching membership for {username} in {org}: {response.status}[/red]"
245+
)
236246
return False
237-
return (await response.json())['role'] == 'admin'
247+
return (await response.json())["role"] == "admin"
238248

239249

240250
async def main(orgs, debug: bool, timelimit_days: int):
@@ -245,7 +255,9 @@ async def main(orgs, debug: bool, timelimit_days: int):
245255

246256
# check who the current user is
247257
async with aiohttp.ClientSession() as session:
248-
async with session.get("https://api.github.com/user", headers=headers) as response:
258+
async with session.get(
259+
"https://api.github.com/user", headers=headers
260+
) as response:
249261
if response.status == 200:
250262
user_data = await response.json()
251263
current_user = user_data["login"]
@@ -277,12 +289,15 @@ async def main(orgs, debug: bool, timelimit_days: int):
277289

278290
# Get all members from all orgs
279291
all_members = {}
292+
org_owners = {}
280293
for org in orgs:
281294
members = await get_org_members(session, org, debug)
282295
for member in members:
283296
if member["login"] not in all_members:
284297
all_members[member["login"]] = []
285298
all_members[member["login"]].append(org)
299+
if member["is_owner"]:
300+
org_owners.setdefault(org, []).append(member["login"])
286301

287302
# Get activity for each user
288303
tasks = []
@@ -311,32 +326,42 @@ async def main(orgs, debug: bool, timelimit_days: int):
311326
if debug:
312327
print(f" [green]{current_user} is an admin in {org}[/green]")
313328
else:
314-
print(f" [yellow]{current_user} is not an admin in {org}, list of users will be incomplete (limited to public membership)[/yellow]")
329+
print(
330+
f" [yellow]{current_user} is not an admin in {org}, list of users will be incomplete (limited to public membership)[/yellow]"
331+
)
315332
n_active = 0
316333
n_inactive = 0
317334
for username, last_activity, user_orgs in sorted(
318335
user_activities,
319-
key=lambda x: (x[1], x[0])
320-
if x[1] is not None
321-
else (datetime.fromtimestamp(0).replace(tzinfo=timezone.utc), x[0]),
336+
key=lambda x: (
337+
(x[1], x[0])
338+
if x[1] is not None
339+
else (datetime.fromtimestamp(0).replace(tzinfo=timezone.utc), x[0])
340+
),
322341
reverse=True,
323342
):
324343
if org not in user_orgs:
325344
continue
326-
if last_activity is not None and last_activity > (datetime.now().replace(tzinfo=timezone.utc) - timedelta(days=timelimit_days)):
345+
if last_activity is not None and last_activity > (
346+
datetime.now().replace(tzinfo=timezone.utc)
347+
- timedelta(days=timelimit_days)
348+
):
327349
n_active += 1
328350
continue
329351
n_inactive += 1
330352
last_activity_ago = (
331-
humanize.naturaltime(datetime.now(last_activity.tzinfo) - last_activity)
353+
humanize.naturaltime(
354+
datetime.now(last_activity.tzinfo) - last_activity
355+
)
332356
if last_activity
333357
else "[red]never[/red]"
334358
)
335359
orgs_str = ", ".join(user_orgs)
336-
print(
337-
f" {username:<20}: Last activity {last_activity_ago}"
338-
)
339-
print(f" Found [red]{n_inactive} inactive[/red] and [green]{n_active} active[/green] users in {org} with last activity more recent than {timelimit_days} days.")
360+
u_owner = " (owner)" if username in org_owners.get(org, []) else ""
361+
print(f" {username+u_owner:<20}: Last activity {last_activity_ago}")
362+
print(
363+
f" Found [red]{n_inactive} inactive[/red] and [green]{n_active} active[/green] users in {org} with last activity more recent than {timelimit_days} days."
364+
)
340365

341366

342367
if __name__ == "__main__":
@@ -346,7 +371,6 @@ async def main(orgs, debug: bool, timelimit_days: int):
346371
)
347372
parser.add_argument("--debug", action="store_true", help="Show debug information")
348373

349-
350374
parser.add_argument(
351375
"--timelimit-days",
352376
type=int,
@@ -361,7 +385,6 @@ async def main(orgs, debug: bool, timelimit_days: int):
361385
)
362386
args = parser.parse_args()
363387

364-
365388
if args.clear_cache:
366389
clear_cache()
367390

0 commit comments

Comments
 (0)