Skip to content

Commit 86221cb

Browse files
authored
Merge pull request #138 from Labelbox/ms/user-access-management
Ms/user access management
2 parents 56a366c + 7c44e40 commit 86221cb

17 files changed

+971
-48
lines changed

examples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
| Labels | [Github](basics/labels.ipynb) | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Labelbox/labelbox-python/blob/develop/examples/basics/labels.ipynb) |
1717
| Ontologies | [Github](basics/ontologies.ipynb) | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Labelbox/labelbox-python/blob/develop/examples/basics/ontologies.ipynb) |
1818
| Projects | [Github](basics/projects.ipynb) | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Labelbox/labelbox-python/blob/develop/examples/basics/projects.ipynb) |
19+
| User Management | [Github](basics/user_management.ipynb) | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Labelbox/labelbox-python/blob/develop/examples/basics/user_management.ipynb) |
1920
------
2021

2122
## [Label Export](label_export)

examples/basics/user_management.ipynb

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "shaped-syria",
6+
"metadata": {},
7+
"source": [
8+
"# User Management\n",
9+
"* This notebook covers the following:\n",
10+
" * create invites\n",
11+
" * query for remaining allowed invites to an organization\n",
12+
" * set and update organization roles\n",
13+
" * assign users to projects\n",
14+
" * set / update / revoke project role\n",
15+
" * delete users from org\n",
16+
"* User invite functions are currently experimental. This means that their interfaces could change."
17+
]
18+
},
19+
{
20+
"cell_type": "code",
21+
"execution_count": 1,
22+
"id": "limiting-terry",
23+
"metadata": {},
24+
"outputs": [],
25+
"source": "!pip install labelbox"
26+
},
27+
{
28+
"cell_type": "code",
29+
"execution_count": 2,
30+
"id": "hungarian-recipient",
31+
"metadata": {},
32+
"outputs": [],
33+
"source": "from labelbox import Project, Dataset, Client, User\nfrom labelbox.schema.organization import ProjectRole\nfrom getpass import getpass\nimport os"
34+
},
35+
{
36+
"cell_type": "code",
37+
"execution_count": 3,
38+
"id": "intended-course",
39+
"metadata": {},
40+
"outputs": [],
41+
"source": "# If you don't want to give google access to drive you can skip this cell\n# and manually set `API_KEY` below.\n\nCOLAB = \"google.colab\" in str(get_ipython())\nif COLAB:\n !pip install colab-env -qU\n from colab_env import envvar_handler\n envvar_handler.envload()\n\nAPI_KEY = os.environ.get(\"LABELBOX_API_KEY\")\nif not os.environ.get(\"LABELBOX_API_KEY\"):\n API_KEY = getpass(\"Please enter your labelbox api key\")\n if COLAB:\n envvar_handler.add_env(\"LABELBOX_API_KEY\", API_KEY)"
42+
},
43+
{
44+
"cell_type": "markdown",
45+
"id": "raising-nightlife",
46+
"metadata": {},
47+
"source": [
48+
"* You have to specifically enable experimental features to use this functionality. Notice the \n",
49+
"`enable_experimental = True`\n",
50+
" * enables users to send invites and checking the number of seats available via the sdk"
51+
]
52+
},
53+
{
54+
"cell_type": "code",
55+
"execution_count": 4,
56+
"id": "polished-hampshire",
57+
"metadata": {},
58+
"outputs": [],
59+
"source": "ENDPOINT = \"https://api.labelbox.com/graphql\"\nclient = Client(api_key=API_KEY, endpoint=ENDPOINT, enable_experimental=True)\norganization = client.get_organization()"
60+
},
61+
{
62+
"cell_type": "code",
63+
"execution_count": 5,
64+
"id": "outer-cattle",
65+
"metadata": {},
66+
"outputs": [],
67+
"source": "# Please provide a dummy email here:\n# Preferrably one you can access. If you have a google account you can do email+1@<domain>.com\nDUMMY_EMAIL = \"< SET THIS >\"\n# This should be set to an account that you wan't to change the permissions for.\n# You could invite a new user, accept the invite and use that account if you don't want to effect any active users\nDUMMY_USER_ACCOUNT_ID = \"ckneh4n8c9qvq0706uwwg5i16\""
68+
},
69+
{
70+
"cell_type": "markdown",
71+
"id": "central-performer",
72+
"metadata": {},
73+
"source": [
74+
"### Roles\n",
75+
"* When inviting a new user to an organization, there are various roles to select from.\n",
76+
"* All available roles to your org can be accessed via `client.get_roles()`"
77+
]
78+
},
79+
{
80+
"cell_type": "code",
81+
"execution_count": 6,
82+
"id": "later-dealing",
83+
"metadata": {},
84+
"outputs": [
85+
{
86+
"name": "stdout",
87+
"output_type": "stream",
88+
"text": [
89+
"LABELER : cjlvi914y1aa20714372uvzjv\n",
90+
"REVIEWER : cjlvi919b1aa50714k75euii5\n",
91+
"TEAM_MANAGER : cjlvi919q1aa80714b7z3xuku\n",
92+
"ADMIN : cjlvi91a41aab0714677xp87h\n",
93+
"NONE : cjmb6xy80f5vz0780u3mw2rj4\n"
94+
]
95+
}
96+
],
97+
"source": "roles = client.get_roles()\nfor name, role in roles.items():\n print(role.name, \":\", role.uid)"
98+
},
99+
{
100+
"cell_type": "markdown",
101+
"id": "superb-exploration",
102+
"metadata": {},
103+
"source": [
104+
"* Above we printed out all of the roles available to the current org.\n",
105+
"* Notice the `NONE`. That is for project level roles"
106+
]
107+
},
108+
{
109+
"cell_type": "markdown",
110+
"id": "romantic-martin",
111+
"metadata": {},
112+
"source": [
113+
"### Create\n",
114+
"* Users are created by sending an invite\n",
115+
"* An email will be sent to them and they will be asked to join your organization"
116+
]
117+
},
118+
{
119+
"cell_type": "markdown",
120+
"id": "harmful-state",
121+
"metadata": {},
122+
"source": [
123+
"#### Organization Level Permissions\n",
124+
"* Invite a new labeler with labeling permissions on all projects"
125+
]
126+
},
127+
{
128+
"cell_type": "code",
129+
"execution_count": 7,
130+
"id": "analyzed-partition",
131+
"metadata": {},
132+
"outputs": [
133+
{
134+
"data": {
135+
"text/plain": [
136+
"InviteLimit(remaining=2, used=3, limit=5)"
137+
]
138+
},
139+
"execution_count": 6,
140+
"metadata": {},
141+
"output_type": "execute_result"
142+
}
143+
],
144+
"source": "# First make sure that you have enough seats:\norganization.invite_limit()"
145+
},
146+
{
147+
"cell_type": "code",
148+
"execution_count": 8,
149+
"id": "ready-housing",
150+
"metadata": {},
151+
"outputs": [],
152+
"source": "invite = organization.invite_user(DUMMY_EMAIL, roles[\"LABELER\"])"
153+
},
154+
{
155+
"cell_type": "code",
156+
"execution_count": 9,
157+
"id": "touched-quarter",
158+
"metadata": {},
159+
"outputs": [
160+
{
161+
"name": "stdout",
162+
"output_type": "stream",
163+
"text": [
164+
"2021-04-20 22:11:55.897000+00:00\n",
165+
"Labeler\n",
166+
"< SET THIS >\n"
167+
]
168+
}
169+
],
170+
"source": "print(invite.created_at)\nprint(invite.organization_role_name)\nprint(invite.email)"
171+
},
172+
{
173+
"cell_type": "markdown",
174+
"id": "disabled-evidence",
175+
"metadata": {},
176+
"source": [
177+
"#### Project Level Permissions\n",
178+
"* Invite a new labeler with labeling permissions specific to a set of projects\n",
179+
"* Here we set organization level permissions to Roles.NONE to indicate that the user only has project level permissions"
180+
]
181+
},
182+
{
183+
"cell_type": "code",
184+
"execution_count": 10,
185+
"id": "nervous-firmware",
186+
"metadata": {},
187+
"outputs": [],
188+
"source": "project = client.create_project(name=\"test_user_management\")\nproject_role = ProjectRole(project=project, role=roles[\"REVIEWER\"])\ninvite = organization.invite_user(DUMMY_EMAIL,\n roles[\"NONE\"],\n project_roles=[project_role])"
189+
},
190+
{
191+
"cell_type": "markdown",
192+
"id": "greatest-halifax",
193+
"metadata": {},
194+
"source": [
195+
"### Read\n",
196+
"* Outstanding invites cannot be queried for at this time. This information can be found in the members tab of the web app.\n",
197+
"* You are able to query for members once they have joined."
198+
]
199+
},
200+
{
201+
"cell_type": "code",
202+
"execution_count": 11,
203+
"id": "amateur-egyptian",
204+
"metadata": {},
205+
"outputs": [
206+
{
207+
"name": "stdout",
208+
"output_type": "stream",
209+
"text": [
210+
"<User {'created_at': datetime.datetime(2021, 1, 20, 1, 2, 31, tzinfo=datetime.timezone.utc), 'email': '[email protected]', 'intercom_hash': '050b8b292bd66abf88ea9a279c6ee80a530e0f9cf98a06e1d5372ef13697f46b', 'is_external_user': False, 'is_viewer': True, 'nickname': 'msokoloff', 'name': 'Matt Sokoloff', 'picture': 'https://lh6.googleusercontent.com/-gO94Mcw4PGs/AAAAAAAAAAI/AAAAAAAAAAA/AMZuuclv_5P5WICzV1aImhxGADj_OS5c7w/s96-c/photo.jpg', 'uid': 'ckk4q1vgwc0vp0704xhx7m4vk', 'updated_at': datetime.datetime(2021, 4, 1, 15, 48, 27, tzinfo=datetime.timezone.utc)}>\n"
211+
]
212+
}
213+
],
214+
"source": "users = list(organization.users())\nprint(users[0])"
215+
},
216+
{
217+
"cell_type": "markdown",
218+
"id": "bottom-reply",
219+
"metadata": {},
220+
"source": [
221+
"### Update\n",
222+
"* There is no update on invites. Instead you must delete and resend them\n",
223+
"* You can update User roles"
224+
]
225+
},
226+
{
227+
"cell_type": "code",
228+
"execution_count": 12,
229+
"id": "atlantic-maria",
230+
"metadata": {},
231+
"outputs": [
232+
{
233+
"name": "stdout",
234+
"output_type": "stream",
235+
"text": [
236+
"<OrgRole {'name': 'Labeler', 'uid': 'cjlvi914y1aa20714372uvzjv'}>\n",
237+
"<OrgRole {'name': 'None', 'uid': 'cjmb6xy80f5vz0780u3mw2rj4'}>\n",
238+
"<OrgRole {'name': 'None', 'uid': 'cjmb6xy80f5vz0780u3mw2rj4'}>\n"
239+
]
240+
}
241+
],
242+
"source": "user = client._get_single(User, DUMMY_USER_ACCOUNT_ID)\n\n# Give the user organization level permissions\nuser.update_org_role(roles[\"LABELER\"])\nprint(user.org_role())\n# Restore project level permissions\nuser.update_org_role(roles[\"NONE\"])\nprint(user.org_role())\n# Make the user a labeler for the current project\nuser.upsert_project_role(project, roles[\"LABELER\"])\nprint(user.org_role())"
243+
},
244+
{
245+
"cell_type": "code",
246+
"execution_count": 13,
247+
"id": "liquid-beast",
248+
"metadata": {},
249+
"outputs": [],
250+
"source": "# Remove the user from a project (Same as setting the project role to `roles.NONE`)\nuser.remove_from_project(project)"
251+
},
252+
{
253+
"cell_type": "markdown",
254+
"id": "portuguese-harvard",
255+
"metadata": {},
256+
"source": [
257+
"### Delete"
258+
]
259+
},
260+
{
261+
"cell_type": "markdown",
262+
"id": "adjacent-partnership",
263+
"metadata": {},
264+
"source": [
265+
"* Invites can only be deleted from the ui at this time. \n",
266+
"* Deleting invites can be done in the members tab of the web app."
267+
]
268+
},
269+
{
270+
"cell_type": "markdown",
271+
"id": "desperate-shield",
272+
"metadata": {},
273+
"source": [
274+
"* Delete the User\n",
275+
"* Make sure you want to remove the user from the org:\n",
276+
"* `>>> organization.remove_user(user)`"
277+
]
278+
},
279+
{
280+
"cell_type": "markdown",
281+
"id": "oriented-demand",
282+
"metadata": {},
283+
"source": [
284+
"### Cleanup\n",
285+
"* We created an extra project. Let's delete it"
286+
]
287+
},
288+
{
289+
"cell_type": "code",
290+
"execution_count": 14,
291+
"id": "veterinary-repository",
292+
"metadata": {},
293+
"outputs": [],
294+
"source": "project.delete()"
295+
}
296+
],
297+
"metadata": {
298+
"kernelspec": {
299+
"display_name": "Python 3",
300+
"language": "python",
301+
"name": "python3"
302+
},
303+
"language_info": {
304+
"codemirror_mode": {
305+
"name": "ipython",
306+
"version": 3
307+
},
308+
"file_extension": ".py",
309+
"mimetype": "text/x-python",
310+
"name": "python",
311+
"nbconvert_exporter": "python",
312+
"pygments_lexer": "ipython3",
313+
"version": "3.8.2"
314+
}
315+
},
316+
"nbformat": 4,
317+
"nbformat_minor": 5
318+
}

labelbox/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@
1616
from labelbox.schema.webhook import Webhook
1717
from labelbox.schema.prediction import Prediction, PredictionModel
1818
from labelbox.schema.ontology import Ontology
19+
from labelbox.schema.role import Role, ProjectRole
20+
from labelbox.schema.invite import Invite, InviteLimit

0 commit comments

Comments
 (0)