Skip to content

Commit cb774f3

Browse files
author
Corentin Mors
authored
Improve members and reports documentation (#108)
Add some documentation and an example of usage for the team report command.
1 parent ba3f050 commit cb774f3

File tree

3 files changed

+129
-1
lines changed

3 files changed

+129
-1
lines changed
+52-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,64 @@
11
# Listing members
22

3+
## Fetching the list of members
4+
35
Listing team members allows you to access many information about them, such as their email, their role, their 2FA status, their security score, etc.
46

57
```sh
68
dcli t members
79
```
810

9-
You can even pipe the output to `jq` to filter the results:
11+
## Filtering the list of members
12+
13+
You can pipe the output to `jq` to filter the results:
1014

1115
```sh
1216
dcli t members | jq '.members[] | select(.isTeamCaptain == true)'
1317
```
18+
19+
## Members interface
20+
21+
| Property | Type | Description |
22+
| --------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------ |
23+
| `members` | `Array` of `object` | Array of team members |
24+
| `members.userId` | `number` \| `undefined` | The user identifier of the user |
25+
| `members.login` | `string` | User login (usually email) |
26+
| `members.status` | `string` | Member status |
27+
| `members.joinedDateUnix` | `number` \| `null` | The join date of member in Unix time |
28+
| `members.lastUpdateDateUnix` | `number` \| `null` | Last updated date of member in Unix time |
29+
| `members.isBillingAdmin` | `boolean` | True if user is a billing admin, false otherwise |
30+
| `members.isTeamCaptain` | `boolean` | True if user is a team captain, false otherwise |
31+
| `members.isGroupManager` | `boolean` | True if user is a group manager, false otherwise |
32+
| `members.email` | `string` \| `undefined` | The user's account email |
33+
| `members.isAccountCreated` | `boolean` \| `undefined` | If user account is created |
34+
| `members.invitedDateUnix` | `number` | Date user was invited |
35+
| `members.token` | `object` | The user's invite token |
36+
| `members.token.userId` | `number` \| `undefined` | User identifier associated with the token |
37+
| `members.token.teamId` | `number` \| `undefined` | Team identifier associated with the token |
38+
| `members.token.token` | `string` \| `undefined` | Value of the invite token |
39+
| `members.token.isFresh` | `boolean` \| `undefined` | True if token is not used, false otherwise |
40+
| `members.token.inviteUserId` | `number` \| `undefined` | The user identifier of the inviter |
41+
| `members.revokedDateUnix` | `number` \| `null` | When user's account was revoked in Unix time |
42+
| `members.language` | `string` \| `undefined` | User's preferred language |
43+
| `members.nbrPasswords` | `number` \| `null` | Number of passwords stored by user |
44+
| `members.reused` | `number` \| `null` | Number of reused passwords |
45+
| `members.reusedDistinct` | `number` \| `null` | Number of distinct reused passwords |
46+
| `members.weakPasswords` | `number` \| `null` | Number of weak passwords |
47+
| `members.compromisedPasswords` | `number` \| `null` | Number of compromised passwords |
48+
| `members.averagePasswordStrength` | `number` \| `null` | Average password strength score |
49+
| `members.passwordStrength0_19Count` | `number` \| `null` | Number of passwords between 0 to 19 characters |
50+
| `members.passwordStrength20_39Count` | `number` \| `null` | Number of passwords between 20 to 39 characters |
51+
| `members.passwordStrength40_59Count` | `number` \| `null` | Number of passwords between 40 to 59 characters |
52+
| `members.passwordStrength60_79Count` | `number` \| `null` | Number of passwords between 60 to 79 characters |
53+
| `members.passwordStrength80_100Count` | `number` \| `null` | Number of passwords between 80 to 100 characters |
54+
| `members.safePasswords` | `number` \| `null` | Number of passwords considered safe |
55+
| `members.name` | `string` \| `null` | User's name |
56+
| `members.securityIndex` | `number` \| `null` | Security index |
57+
| `members.twoFAInformation` | `object` | 2FA information for the user |
58+
| `members.twoFAInformation.type` | `'sso'` \| `'email_token'` \| `'totp_device_registration'` \| `'totp_login'` \| `undefined` | 2FA type |
59+
| `members.twoFAInformation.phone` | `string` \| `null` | Phone number for 2FA |
60+
| `members.twoFAInformation.lastUpdateDateUnix` | `number` \| `null` | Last updated date of 2FA in Unix time |
61+
| `members.hasPublicKey` | `boolean` | True if user has a public key |
62+
| `billingAdmins` | `Array` of `string` | Array of emails of billing admins |
63+
| `page` | `number` | Current page of results |
64+
| `pages` | `number` | Total pages of results |

documentation/pages/business/reports.mdx

+77
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,85 @@
22

33
You can get reports on your team about the number of seats provisioned, used and pending. You can also get reports on the aggregated password health history of your team.
44

5+
## Fetch reports
6+
57
The following commands take in input the number of days to look back for the password health history. The default is 0 day.
68

79
```sh
810
dcli t report 30
911
```
12+
13+
## Generate graphics from reports
14+
15+
One way to consume password health history reports is to generate graphics from them.
16+
17+
![Example of graphic generated from a report](../../public/password-health-graphic.png)
18+
19+
The following Python script example will generate a graphic from the report.
20+
21+
```python
22+
import matplotlib.pyplot as plt
23+
import numpy as np
24+
25+
26+
def format_month(month: str):
27+
match month:
28+
case "01":
29+
return "Jan"
30+
case "02":
31+
return "Feb"
32+
case "03":
33+
return "Mar"
34+
case "04":
35+
return "Apr"
36+
case "05":
37+
return "May"
38+
case "06":
39+
return "Jun"
40+
case "07":
41+
return "Jui"
42+
case "08":
43+
return "Aug"
44+
case "09":
45+
return "Sep"
46+
case "10":
47+
return "Oct"
48+
case "11":
49+
return "Nov"
50+
case "12":
51+
return "Dec"
52+
53+
54+
def format_x_label(label: str):
55+
year, month = label.split("-")
56+
return f"{format_month(month)} {year}"
57+
58+
59+
def generate_graph(file_path: str, data):
60+
dates = []
61+
values = []
62+
for value in data:
63+
dates.append(np.datetime64(value["date"]))
64+
values.append(value["securityIndex"])
65+
66+
# create two subplots with the shared x and y axes
67+
fig, (ax) = plt.subplots(figsize=(10, 5))
68+
69+
ax.plot(dates, values, lw=2, color="#4e828f")
70+
ax.grid(True)
71+
72+
ax.set_ylabel("Security score")
73+
labels = ax.get_xticklabels()
74+
for label in labels:
75+
label._text = format_x_label(label._text)
76+
ax.set_xticklabels(labels)
77+
78+
ax.set_ylim(min(values) - 10, 100)
79+
80+
fig.suptitle("Evolution of the team security score")
81+
fig.autofmt_xdate()
82+
83+
plt.savefig(file_path)
84+
plt.close()
85+
return file_path
86+
```
Loading

0 commit comments

Comments
 (0)