How do I create a people, groups and, permissions CSV template?

Watershed’s Import Data feature enables you to import CSV files containing people, groups and permissions data. The templates map the columns of a CSV file to properties of Watershed people, groups and permissions configuration objects. You’ll need an import template for each type of CSV file you upload, and once the mapping has been created new CSVs following the same structure can be uploaded as often as required. A single CSV file can contain a combination of people, groups and permissions data, or this data may be contained in separate files.

Templates are created using the Import Templates settings page. Creating import templates is a complex task and is normally completed for you by the Watershed team. This guide explains how to create Import Templates. It has 6 sections

Creating a New Import Template

To create a new Import Template, click the Add Import Template button on the Settings / Import Templates page. Enter a name for the template and then upload an example CSV source file which the template will be based on.

In the next two steps you specify template variables and create a template. We recommend that rather than specifying template variables up front, that you dive straight into creating the template, scrolling back up to specify template variables if and when you need them.

How the Template Works

The template is a JSON object with ‘people’, ‘groups’ and/or ‘permissions’ properties. Each of these properties contains an array of configuration objects with placeholder values and functions that are filled in using data from each row of the CSV. The template can also have a statements property which templates the import of xAPI statements based on the same CSV. Statement templates are explained here.

The template uses the Handlebarsjs templating language. See CSV Templates Functions and Variables for a list of available functions. Values are inserted using the handlebars syntax {{columns.[Name of Column]}}. For example, the below syntax inserts the value of the Email Address field into the mbox property of a persona.

{
    "name": "foo",
    "mbox": "mailto:{{columns.[Email Address]}}"
}

You can also insert values using template variables using the syntax {{NameOfTemplateVariable}}.

The People Template

The template’s people property contains an array of person objects to be created. If a person with the same customId as the one to be imported already exists, then the person will be updated.

Please note: the personas property of the person being added is expected to contain a complete list of personas for that person. If a person already exists then any existing personas will be overwritten when the person is updated by the CSV import. If you need to add a single persona to an existing person, this can be done either via the user interface or via API.

Person objects have the following properties:

Property

Details

customId

String

A unique identifier for the person. Must be unique. Often this will be an account name from another system or an email address.

name

String

Name of the person to be used by Watershed. For example, a learner might have personas named “Mike” and “Michael”; the person name is what Watershed will use.

imageUrl

URI

Link to a profile image for a person. This image will be downloaded and stored in Watershed when the CSV is uploaded, so the image does not need to be permanently available at this url.

If not provided and one of the personas contains an email address linked to a Gravatar account, the Gravatar image will be used. Images can also be uploaded directly to Watershed via the UI or API.

personas

array

List of xAPI agents associated with the person. Each agent object takes the format defined by the xAPI specification.

parentGroupCustomIds

array

List of custom ids of groups the person belongs to. Use this property to add people to groups.

preserve

array

List of properties that should not be overwritten by the template if they already exist. Currently only supports the "name" property.

 

What are personas and xAPI agents?

Agents are the objects within xAPI statements that identify the person involved in the experience, normally the learner. They don’t just identify a person, but a persona of that person, such as their work email address or a personal social media account.

For example, the email addresses bob@example.com and bobby@example.net are both personas, which may refer ultimately to the same person, Bob. Another example might be bob12 at twitter.com, which would be considered an "account on a system" in xAPI terms.

The Groups Template

Groups are collections of people or other groups. They provide a way to model organization hierarchies, groups defined by roles or locations, and many other use cases for filtering and aggregating report data. Groups have some associated metadata, like name, and type. Permissions granting access to group data can be granted to specific people or other groups.

The template’s groups property contains an array of group objects to be created. If a group with the same customId as the one to be imported already exists, then the group will be updated.

Group objects have the following properties:

Property

Details

customId

String

A custom identifier for the Group Type, e.g. the identifier used in another system. Must be unique.

name

String

The display name of the Group Type e.g. “Job Role”.

description

String

A longer description for the group.

type

GroupType

The type of Group. See below for details of the GroupType object.

imageUrl

URI

A url for an image associated with this group.

parentGroupCustomIds

array

A list of custom ids that contain this group, both directly and indirectly.

preserve

array

List of properties that should not be overwritten by the template if they already exist. Currently only supports the "name" property.

All groups have a group type, e.g. ‘Nashville’ might be a group of type ‘City’, or ‘Accountant’ might be a group of type ‘Job Role’. Group Types have the following properties:

Property

Details

name

String

The display name of the Group Type e.g. “Job Role”. Must be unique.

pluralName

String

The plural display name for a collection of the Group Type. E.g. “Job Roles”

DispldayOrder

Integer

The order the group type will be displayed in relative to other group types in a list.

Group Membership Behavior

When importing data about groups and people that already exist, Watershed needs to know how to handle that information. For example, if a person is in the group 'Nashville' and is assigned to another group of the same type, such as 'New York', what should be the resulting group memberships for that person? Should they be in both 'Nashville' and 'New York' groups, or just 'New York'?

This decision is governed by the action property of people and group configuration objects. This has three possible values:

create_update is the default value. It will create groups where they don't exist and add people and groups to parents as defined in the template. With this setting the outcome of the example above would be that the person belongs to both 'Nashville' and 'New York' groups.

add_memberships works in the same way as create_update except that it will only add people to groups that already exist. So in the example above, if 'New York' did not already exist as a group, the person would remain in 'Nashville' only. An error that 'New York' was not found would be recorded. 

add_memberships_if_existing works in the same way as add_memberships except that it will not log an error if the group is not found. You should only use add_memberships when a group not existing would be a genuine error that you want to flag to the person importing the file. Use add_memberships_if_existing when you don't want to generate an error. 

create_replace will replace group memberships, creating groups where they don't exist. So in the example above, the person would only belong to 'New York' group after the import. This value should be used at template level for imports where the CSV is intended to represent the complete state of the world. 

replace_memberships works in the same way as create_replace except that it will only add people to groups that already exist.

The action property can be applied to the template as a whole and to individual people and group objects. When applied to people and group objects, this will override the value on the template.

Here's an example of the syntax:

"people": [
        {
            "name": "{{columns.[name]}}",
            "customId": "{{columns.[email]}}",
            "personas": [
                ...
            ],
            "parentGroupCustomIds": [
                ...
            ],
            "action": "create_update"
        }
    ],

The Permissions Template

Permissions control who can see data about a group of people. Permissions can be assigned to individual people or groups of people. Permissions apply to everybody inside the group that the permission is applied to, including any sub groups.

The template’s permissions property contains an array of permission objects to be created. Permission objects have the following properties:

Property

Details

target

Group

The group whose data the permission relates to. The value of this property is an object with a customId property.

person

Person

The person who should be able to see data about the target group. The value of this property is an object with a customId property.

Permissions include either a person or group property, not both.

group

Group

The group who should be able to see data about the target group. The value of this property is an object with a customId property.

Permissions include either a person or group property, not both.

Complete Example

Below is a complete example CSV template used to populate people, groups and permissions.

{
    "people": [
        {
            "name": "{{columns.[name]}}",
            "customId": "{{columns.[email]}}",
            "personas": [
                {
                    "name": "{{columns.[name]}}",
                    "mbox": "mailto:{{columns.[email]}}"
                }, 
                {
                    "name": "{{columns.[name]}}",
                    "account": {
                        "homePage": "https://watershedlrs.com/fake-hr-system",
                        "name": "{{columns.[emp id]}}"
                    }
                }
            ],
            "parentGroupCustomIds": [
                "whole-company"{{#if columns.[region]}},
                "{{slugify columns.[region]}}"{{/if}}{{#if columns.[division]}},
                "{{slugify columns.[division]}}"{{/if}}
            ]
        }
    ],
    "groups": [
        {
            "name": "Whole Company",
            "customId": "whole-company",
            "type": {
                "name": "Whole Company",
                "pluralName": "Whole Company"
            }
        }
        {{#if columns.[region]}},
        {
            "name": "{{columns.[region]}}",
            "customId": "{{slugify columns.[region]}}",
            "parentGroupCustomIds": ["whole-company"],
            "type": {
                "name": "Region",
                "pluralName": "Regions"
            }
        }{{/if}}{{#if columns.[division]}},
        {
            "name": "{{columns.[division]}}",
            "customId": "{{slugify columns.[division]}}",
            "type": {
                "name": "Division",
                "pluralName": "Divisions"
            }
            {{#if columns.[region]}},
                "parentGroupCustomIds": ["{{slugify columns.[region]}}"]
            {{/if}}
        }{{/if}}
    ],
    "permissions": [
        {{#ifEquals columns.[manager] 'yes'}}
            {{#if columns.[region]}}
                {{#if columns.[division]}}
                    {
                        "target": {
                            "customId": "{{slugify columns.[division]}}"
                        },
                        "person": {
                            "customId": "{{columns.[email]}}"
                        }
                    }
                {{else}}
                    {
                        "target": {
                            "customId": "{{slugify columns.[region]}}"
                        },
                        "person": {
                            "customId": "{{columns.[email]}}"
                        }
                    }
                {{/if}}
            {{else}}
                {
                    "target": {
                        "customId": "whole-company"
                    },
                    "person": {
                        "customId": "{{columns.[email]}}"
                    }
                }
            {{/if}}
        {{/ifEquals}}
    ]
}
Was this article helpful?
0 out of 0 found this helpful
Have more questions? Submit a request

If you can't find what you need or you want to ask a real person a question, please contact customer support.