Manage team sharing in your Dropbox app

Welcome back, professor. This article is a follow-up to “3 ways to add sharing to your Dropbox App”. We’re going to dive deeper into more advanced sharing use cases that are possible with the Dropbox API. Let’s get to it.

As you may remember, you’re a professor for a large university. Besides teaching, you run a multifaceted research lab. It’s a busy job, but with some creative use of the Dropbox API, you’re able to spend most of your time focused on the parts you enjoy. That’s because Dropbox Business accounts allow you to closely manage team sharing.

Creating an App with Team member management access

There are four distinct Business access types outlined in the the Access types section of the Dropbox Business API documentation. You can start with team member management, which will allow you to sort professors, teaching assistants, and students into groups to easily control file access for the entire lab.
1. Create a new app from your App console
2. Select ‘Dropbox Business API’
3. Select ‘Team member management’
4. Name your app and click ‘Create app’
5. Click ‘Generate access token’ and copy the token into your app

team_member_token = 'your_team_member_management_token'
dbx_team_members = dropbox.DropboxTeam(team_member_token)

Organizing your new students

Your research lab consists of one giant team split into many smaller groups of students. The whole lab has some files they need to share, but each respective groups need more granular control over their specific files and file access.

Adding students to team

A new wave of students joined your lab for the fall semester. Inviting each student to your Dropbox Business team is a good place to start:

students = [('Amy', 'Smith', 'Amy@college.edu'), ('Bill', 'Jones', 'Bill@college.edu', 'Varna', 'Patel', 'Varna@college.edu')]
students_to_add = []
for first_name, last_name, email in students:
    member = dropbox.team.MemberAddArg(
        member_email=email, 
        member_given_name=first_name,  
        member_surname=last_name, 
        send_welcome_email=True
    )
    students_to_add.append(member)
team_add_request = dbx_team_members.team_members_add(students_to_add)
print(team_add_request)

Note: we’re using the /team/members/add endpoint

Sorting students into groups

The lab work is split up into distinct groups so students can focus on one area at a time. This is an excellent use case for the Dropbox groups feature because, after they’re sorted, whole groups of students can be referenced by a group_id.

During the first class of the semester students choose their preferred groups. One of the most popular groups is the Field Research Group, which will be doing lots of hands-on research.

First, you create the new group with a group_external_id, which is an optional field used to define your own key:

create_request = dbx_team_members.team_groups_create(
    group_name='Field Research Group', 
    group_external_id='field_research_group_fall_2019'
)
print(create_request)

Next, you add a teaching assistant as the designated owner for each respective group so they’re able to add or remove members in case students move between groups:

selected_group = dropbox.team.GroupSelector.group_external_id('field_research_group_fall_2019')
selected_user = dropbox.team.UserSelectorArg.email('Paul+TA@college.edu')
# access_type defaults to viewer if left blank
selected_access_type = dropbox.team.GroupAccessType.owner
member_access = dropbox.team.MemberAccess(
    user=selected_user,
    access_type=selected_access_type
)
owner_add_request = dbx_team_members.team_groups_members_add(
    group=selected_group,
    members=[member_access]
)
print(owner_add_request)

Finally, you bulk add each group of the student to their chosen groups:

field_research_group = ['Amy@college.edu', 'Bill@college.edu']
new_group_members = []
selected_group = dropbox.team.GroupSelector.group_external_id('field_research_group_fall_2019')
for member_email in field_research_group:
    selected_user = dropbox.team.UserSelectorArg.email(member_email)
    selected_access_type = dropbox.team.GroupAccessType.member
    member_access = dropbox.team.MemberAccess(
        user=selected_user,
        access_type=selected_access_type
    )
    new_group_members.append(member_access)
    
group_add_request = dbx_team_members.team_groups_members_add(
    group=selected_group,
    members=new_group_members
)
print(group_add_request)

Note: managing users & groups requires the team member management permission. However, reading this information with /teams/members/list and /teams/groups/list only requires team information permission, allowing them to be used with any Dropbox Business application. Many teams use will manage users & groups in the Admin Console, identity management tool, or connector. In many cases your app may only need to read this data from Dropbox.

Excellent! New students have been added to your Dropbox team, a teaching assistant was assigned to the Field Research Group as a group owner, and you’ve sorted students into their own respective groups (like the Field Research Group).

Administering student accounts

Dropbox Business team administrators may sign in as members of their team to organize accounts and troubleshoot. Admin-authorized apps with Member file access permission may do so via API, and use the User Endpoints on behalf of specific members on the team.

Creating an App with Team member file access

1. Create a second new app from your App console
2. Select ‘Dropbox Business API’
3. Select ‘Team member file access’
4. Name your app and click ‘Create app’
5. Click ‘Generate access token’ and copy the token into your app

team_file_token = 'your_team_file_access_token

Because you’re using a team-linked app, you’ll need to use the Dropbox-API-Select-User header in order to assume the role of a user to call Dropbox User Endpoints.

The first thing you’ll need is a team_member_id:

user = dropbox.team.UserSelectorArg.email('Paul+TA@college.edu')
member = dbx_team_members.team_members_get_info([user])
if member[0].is_member_info():
    member_info = member[0].get_member_info()
    team_member_id = member_info.profile.team_member_id
print(f'You grabbed {member_info.profile.name}s team member id:{team_member_id}')

Now you can instantiate the Dropbox SDK to act on behalf of that user:

dbx_as_user = dropbox.DropboxTeam(team_file_token).as_user(team_member_id)
# a quick test call to verify our assume user calls work:
print(dbx_as_user.sharing_list_folders())

If the above call was successful, you’re ready to start administering sharing! We’ll be using dbx_as_user to make calls in some of the upcoming example snippets.

Sharing folders with groups

Since all your students have been sorted, you can share folder access with an entire group at once instead of enumerating over all students! Members can also be added or removed from that group and the share will stay the same.

There are two important pieces of information you need to grab in order to share a folder with a group. Note that the calls use different access types, and, accordingly, different access tokens.

1. group_id — unique to each group
2. shared_folder_id — unique to each shared folder

To get the group_id for the Field Research Group you created earlier:

selected_group = dropbox.team.GroupsSelector.group_external_ids(['field_research_group_fall_2019'])
groups = dbx_team_members.team_groups_get_info(selected_group)
if groups[0].is_group_info():
    group = groups[0].get_group_info()
    target_group_id = group.group_id
print(f'grabbed {group.group_name} with group id {target_group_id}')

To get the shared_folder_id for the existing folder the Field Research Group will share:

shared_folders = dbx_as_user.sharing_list_folders()
for folder in shared_folders.entries:
    # filter out your target folder by name
    if folder.name == "field_research_team_folder":
        target_shared_folder_id = folder.shared_folder_id
        print(f'grabbed {folder.name}, shared folder id: {target_shared_folder_id}')

Note: this snippet only works for an existing shared folder. An alternative would be /sharing/share_folder, which would create a new shared folder if one didn’t exist.

Now you can grant the entire Field Research Group access to the shared folder and all content inside… without enumerating!

selected_group = dropbox.sharing.MemberSelector.dropbox_id(target_group_id)
# leaving out access level defaults to viewer
target_access_level = dropbox.sharing.AccessLevel.editor
add_group_member = dropbox.sharing.AddMember(
    member=selected_group,
    access_level=target_access_level
)
dbx_as_user.sharing_add_folder_member(
    shared_folder_id=target_shared_folder_id,
    members=[add_group_member]
)
print("successfully shared to group")

Some other benefits of using group shares:

  • Groups can be reused on multiple folders and at different access levels — making it much easier to control access in bulk.
  • Adding or removing members to a group means they’re automatically included or removed from that group’s existing shares — greatly increasing ease of access and security when members join or leave.

Granting shared folder access in bulk certainly saves a lot of time, but it’s not the only way to share files in Dropbox. Sometimes your students may prefer to use shared links.

Sharing links in a team setting

Creating team-only shared links

After completing a major milestone, the Field Research Group compiled their research into a spreadsheet, which will be a useful resource for other groups in the lab. The spreadsheet should be visible to everyone else on the team (other groups) but not the outside world. You can do this by creating a team-only shared link.

You create a shared link scoped to team-only access by calling /sharing/create_shared_link_with_settings with an extra parameter in the settings:

team_audience = dropbox.sharing.LinkAudience.team
link_settings = dropbox.sharing.SharedLinkSettings(audience=team_audience)
file_path = '/field_research_team_folder/field_data.xls'
link = dbx_as_user.sharing_create_shared_link_with_settings(
    file_path=path,
    settings=link_settings
)
print(link)

The team-only shared link worked great for a little while. Unfortunately, as the lab has grown in size students have become a little too careless about how they’re using shared links. You decide to lock things down a bit.

Updating a folder’s sharing policy

The Field Research Group often needs to share links to files with other members in the group, but you don’t want that content shared with other groups in the lab. Rather than relying on individuals to change that setting for themselves every time a shared link is created, you update the folder’s sharing policy.

Note: in a team context, a shared folder can be owned by either a member or a team. As the owner, a team member can directly update a shared folder’s settings. However, for a shared folder owned by a team, the settings must be changed from the Admin Console.

Imagine the Field Research Group’s shared folder was created by their teaching assistant, Paul. Since he’s the owner, you assume the role of Paul in order to update the folder’s sharing policy:

dbx_as_user = dropbox.DropboxTeam(team_file_token).as_user('pauls_team_member_id')

Some variables used in the snippet below, Paul’s team_member_id and the target_shared_folder_id, are from code snippets in above sections.

Now you can update the shared folder’s policy:

new_link_policy = dropbox.sharing.SharedLinkPolicy.members
policy_update_request = dbx_as_user.sharing_update_folder_policy(
    shared_folder_id=target_shared_folder_id, 
    shared_link_policy=new_link_policy
)
print(policy_update_request)

With this policy in place, new shared links created by students in the Field Research Group can only be accessed by other members of their shared folder. Updating a folder’s shared link policy solves a second major challenge: shared links that are difficult to detect from your app. Because shared links to the same content are unique to each user, it can be a lot of work to retrieve them. By enforcing shared link creation at a policy level, you’ve ensured that student’s links will be created in a consistent way and you can look for them within your app.

Team managed shares

While organizing your courses this semester, you learned that Dropbox Business has team folders. Team folders allow the administrator to create folders and share with a group. Within the team folder, you can create additional nested shares to add or remove additional users. When members are added to a group, the new member has access to that group’s existing shares.

This enables you to take a folder structure like ‘/Field_Research/Lab Reports Spring 2020’ – and give the ‘Field_Research’ folder a different set of policies than the nested ‘Lab Reports Spring 2020’ folder. The ‘Field_Research’ folder may be read only for students for assignments, but the nested ‘Lab Reports Spring 2020’ be read-write for students to submit work.

The Dropbox Business APIs & headers will let you manage these team shares similar to standard user shares.

There are two types of managed team folders: Team Folders or Team Space. Which type is available depends on your account.

You can determine which type of account you’re on by checking visually (purple folder in your home directory means you’re on team space):

Shows a purple team member folder which only exists in team spaces
Your name will appear under a purple folder like this inside a team space

Or you can check programmatically using the API:

team_features = dropbox.team.Feature.has_team_shared_dropbox
is_team_space = dbx_team_members.team_features_get_values([team_features])
print(is_team_space)

If has_team_shared_dropbox resolves to True, then you’re using Dropbox team space!

There are some differences between the two team models:

Team Folders
  • Team Folders can be created with /team/team_folder/create and their membership managed with the sharing endpoints as described above.
  • Team folders automatically appear inside individual member’s home directories.
Team Spaces
  • Team managed shares are created in the team’s root space, using the /sharing/add_folder_member/ endpoint.
  • Each individual members directory is mounted inside the shared team space.
  • API callers will need to set the Dropbox-API-Path-Root header in order to read from & write to the team root space.

Regardless of which team account you are on, there are two behaviors shared by both patterns:
1. The folder is owned by a team (rather than member owned) so managing the creation, membership, or policies of these top level folders requires a Dropbox-API-Select-Admin header.
2. Users may create shares within these shares. By default, permissions are inherited, but the permission inheritance may be disabled. This opens some interested use cases for restrictive access control lists, or rACLs, which we’ll cover in the next blog post.

Calling the Dropbox API in a Team Space

Because your class is in a team space, there are a couple additional steps you need to take in order to update the ‘Lab Reports Spring 2020’ folder policy:

1. You need to use the Dropbox-API-Select-Admin header to perform the action as an admin.
You’ll need an admin’s account_id:

team_list = dbx_team_members.team_members_list()
for member in team_list.members:
    if member.role.is_team_admin():
        selected_admin = member.profile.account_id
        break

Note: this snippet grabs the first admin from your list of team members. A production app may instead specify the admin by email or team_member_id.

2. You’ll also need to set the root directory to the shared team space, which you can do by setting the Dropbox-API-Path-Root header.

Grab the root_namespace_id of the shared team space:

account_info = dbx_as_user.users_get_current_account()
root_namespace_id = account_info.root_info.root_namespace_id
team_root_namespace = dropbox.common.PathRoot.namespace_id(root_namespace_id)

Note: we’re selecting a user and getting current account info to find the root_namespace_id.

With those two variables set, you instantiate the Dropbox SDK as an admin and with a specific root folder (namespace):

dbx_as_admin_team_root = dropbox.DropboxTeam(team_file_token).with_path_root(team_root_namespace).as_admin(selected_admin)

Finally, you can update the folder’s sharing policy:

# Note: we're using the Dropbox-API-Select-User header to list folders
shared_folders = dbx_as_user.sharing_list_folders()
for folder in shared_folders.entries:
    if folder.name == "Lab Reports Spring 2020":
        student_reports_folder = folder.shared_folder_id 

new_link_policy = dropbox.sharing.SharedLinkPolicy.anyone
# Note: now we're using the Select-Admin and Path-Root header to update the policy
policy_update_request = dbx_as_admin_team_root.sharing_update_folder_policy(
    shared_folder_id=student_reports_folder, 
    shared_link_policy=new_link_policy
)
print(policy_update_request)

Hooray! You successfully updated the shared link policy for the ‘/Field_Research/Lab Reports Spring 2020’ folder.

Add sharing to your team-linked Dropbox app today!

The Dropbox API offers a great way to take control of how your files are shared and accessed. Combined with the features available to Dropbox Business teams, the Dropbox sharing APIs can save valuable time, streamline the sharing of content, and directly control the level of access applied to files and folders. Whether you’re managing a sales team, building an automated process for a digital design company, or a professor managing a multifaceted research lab, sharing can add a lot of value to your Dropbox App.

For additional technical information and guidance on this topic, we recommend reading our Namespace Guide, Content Access Guide, or the Business API Documentation. Keep an eye out for the next sharing article where we dive into rACLs and inherited permissions.

If you have any questions about this article or need help with anything else, you can always contact us here.

Build with Dropbox today at www.dropbox.com/developers