Interfacing with MS Teams and related services (Microsoft Graph)
The xooauth package support a basic interface for the Microsoft Graph API, which can be used e.g. with Microsoft Teams.
These interface classes support conversion from/to JSON and to the url-encoded calling patterns on the fly, just by specifying the Tcl variable names with minor annotations (somewhat similar to the export_vars interface). Furthermore, the interface supports pagination: some Microsoft Graph API calls return per default just a partial number of results (e.g. first 100). To obtain all results, multiple REST calls have to be issued to get the full result set. Over this interface, one can specify the desired maximum number of entries.
Furthermore, the API supports async operations (create/clone/archive/unarchive teams), where the behavior can be tailored via the options "-wait" and "-donecallback".
To use the Microsoft Graph API, an "app" has to be registered/configured/authorized/...[1,2,3] by an administrator of the organization before an access token [4] can be obtained token from the Microsoft identity platform. The access token contains information about your app and the permissions it has for the resources and APIs available through Microsoft Graph. This interface is based on access tokens [4] and the /token endpoint [1] ("Get access without a user") and assumes, one has already obtained the client_id and client_secret to configure this service this way. In theory, this API will allow later to switch to newer versions of the Graph API when newer versions (currently post 1.0) of the Microsoft Graph API will come out.
The interface is written in an ensemble style where commands with the same kind of objects share a common prefix (examples are "group", "team", "user", "application", ... see below for more details). It follows strictly to the Microsoft naming conventions and makes it straightforward to extend the interface in the future. The implementation is part of the xooauth package (see also [5]).
[1] https://docs.microsoft.com/en-us/graph/auth-v2-service
[2] https://docs.microsoft.com/en-us/graph/auth/auth-concepts
[3] https://docs.microsoft.com/en-us/graph/auth-register-app-v2
[4] https://oauth.net/id-tokens-vs-access-tokens/
[5] https://openacs.org/api-doc/package-view?version_id=5659574&public_p=1&about_package_key=&kind=procs
[5] https://openacs.org/api-doc/package-view?version_id=5659574&public_p=1&about_package_key=&kind=procs
===========================================================================
ms::app pp ?-list? ?-prefix /value/? /dict/ ms::app application get /application_id/ ?-select /value/? ms::app application list ?-count /value/? ?-expand /value/? ?-filter /value/? ?-orderby /value/? ?-search /value/? ?-select /value/? ?-top /integer/? ms::app chat get /chat_id/ ms::app chat messages /chat_id/ ?-top /integer/? ms::app group deleted ?-count /value/? ?-expand /value/? ?-filter /value/? ?-orderby /value/? ?-search /value/? ?-select /value/? ?-top /integer/? ms::app group get /group_id/ ?-select /value/? ms::app group list ?-count /value/? ?-expand /value/? ?-filter /value/? ?-orderby /value/? ?-search /value/? ?-select /value/? ?-max_entries /value/? ?-top /integer/? ms::app group member add /group_id/ /principals/ ms::app group member list /group_id/ ?-count /value/? ?-filter /value/? ?-search /value/? ?-max_entries /value/? ?-top /integer/? ms::app group member remove /group_id/ /principal/ ms::app group memberof /group_id/ ?-count /value/? ?-filter /value/? ?-orderby /value/? ?-search /value/? ms::app group owner add /group_id/ /principal/ ms::app group owner list /group_id/ ms::app group owner remove /group_id/ /user_id/ ms::app team archive /team_id/ ?-shouldSetSpoSiteReadOnlyForMembers /value/? ?-donecallback /value/? ?-wait? ms::app team channel list /team_id/ ?-filter /value/? ?-select /value/? ?-expand /value/? ms::app team clone /team_id/ ?-classification /value/? ?-description /value/? -displayName /value/ ?-mailNickname /value/? -partsToClone /value/ ?-visibility /value/? ?-donecallback /value/? ?-wait? ms::app team create ?-description /value/? -displayName /value/ ?-visibility /value/? -owner /value/ ?-donecallback /value/? ?-wait? ms::app team delete /team_id/ ms::app team get /team_id/ ?-expand /value/? ?-select /value/? ms::app team member add /team_id/ /principal/ ?-roles /value/? ms::app team member list /team_id/ ?-filter /value/? ?-select /value/? ms::app team member remove /team_id/ /principal/ ms::app team unarchive /team_id/ ?-donecallback /value/? ?-wait? ms::app user get /principal/ ?-select /value/? ms::app user list ?-select /value/? ?-filter /value/? ?-max_entries /value/? ?-top /value/? ms::app user me ?-select /value/? ?-token /value/? ms::app user memberof /principal/ ?-count /value/? ?-filter /value/? ?-orderby /value/? ?-search /value/? ms::app run_donecallback /location/ /callback/ ms::app schedule_donecallback /secs/ /location/ /callback/ ms::app token ?-grant_type /value/? ?-scope /value/? ?-assertion /value/? ?-requested_token_use /value/?
Example Usage
# # Create the interface object for a tenant (named here ms::app). # For interacting with multiple tenant, define multiple application # interface objects. # ::ms::Graph create ms::app \ -tenant ... \ -client_id ... \ -client_secret ... \ -version v1.0 # # get the Teams UID for a user (here via email, actual userPrincipalName) # set user_info [ms::app user get gustaf.neumann@wu.ac.at] set user_id [dict get $user_info id] : ba34495a-fd40-4c82-bc7b-1f7c778fec34 # # Get information about a user. We use for output formatting a # pretty-printer to provide a more readable format pf the dict # structures returned by the Microsoft graph API: # ms::app pp [ms::app user get gustaf.neumann@wu.ac.at] : @odata.context: https://graph.microsoft.com/v1.0/$metadata#users/$entity : businessPhones: {...} : displayName: Neumann, Gustaf : givenName: Gustaf : jobTitle: null : mail: Gustaf.Neumann@wu.ac.at : mobilePhone: .... : officeLocation: D2.2.034 : preferredLanguage: null : surname: Neumann : userPrincipalName: gustaf.neumann@wu.ac.at : id: ba34495a-fd40-4c82-bc7b-1f7c778fec34 # # One can get more information by specifying additional "select" # attributes, such as e.g. "department" and others (for details, see # https://docs.microsoft.com/en-us/graph/api/resources/user?view=graph-rest-1.0#properties) ms::app pp [ms::app user get gustaf.neumann@wu.ac.at -select id,department,companyName,identities,mySite,streetAddress] : @odata.context: https://graph.microsoft.com/v1.0/$metadata#users(id,department,companyName,identities,mySite,streetAddress)/$entity : id: ba34495a-fd40-4c82-bc7b-1f7c778fec34 : department: Wirtschaftsinformatik und Neue Medien : companyName: WU-WIEN : streetAddress: Welthandelsplatz 1 : mySite: https://wu-my.sharepoint.com/personal/gustaf_neumann_wu_ac_at/ : identities: {signInType userPrincipalName issuer wu.onmicrosoft.com issuerAssignedId gustaf.neumann@wu.ac.at} # # Get a list of certain users. We use for output formatting a # pretty-printer to provide a more readable format of the dict # structures returned by the Microsoft graph API: # ms::app pp [ms::app user list -select id,displayName,userPrincipalName -filter "startsWith(displayName,'Neumann')"] : @odata.context: https://graph.microsoft.com/v1.0/$metadata#users(id,displayName,userPrincipalName) : value: : id: ba34495a-fd40-4c82-bc7b-1f7c778fec34 : displayName: Neumann, Gustaf : userPrincipalName: gustaf.neumann@wu.ac.at : : id: 4e2b2b37-6c50-4367-9209-bd7392f2e115 : displayName: Neumann, Lore : userPrincipalName: lore.neumann@wu.ac.at # # Return the first 10 users. Per default, Microsoft Graph returns the # first 100 entries. By specifying -max_entries, the interface issues # potentially several requests for returning the desired amount. # ms::app pp [ms::app user list -select id,displayName,userPrincipalName -max_entries 10] # # List the first 10 teams/groups # ms::app pp [ms::app group list -select id,displayName -max_entries 10] # # Get some attributes about a set of teams # ms::app pp [ms::app group list -select id,displayName -filter "startsWith(displayName,'TLF')"] : : @odata.context: https://graph.microsoft.com/beta/$metadata#groups(id,displayName) : value: : id: b78e7642-... : displayName: TLF-TEAM # # Get detail info from a team # set team_id b78e7642-... ms::app pp [ms::app team get $team_id] # # Get members of a team # ms::app pp [ms::app group member list $team_id] # # Get owners of a team # ms::app pp [ms::app group owner list $team_id] # # Add member to a team # ms::app group member add $team_id gustaf.neumann@wu.ac.at # # Get channels of a team # ms::app pp [ms::app team channel list $team_id] # # Delete a team # ms::app team delete 85f3d2d2-c2d3-... # # List deleted groups/teams # ms::app pp [ms::app group deleted -filter "startsWith(displayName,'Testing community')"] : @odata.context: https://graph.microsoft.com/v1.0/$metadata#groups(id,displayName,deletedDateTime) : value: : id: c0030714-656d-4bbe-8d4e-507e73d6f643 : displayName: Testing community 3 : deletedDateTime: 2021-10-22T09:14:08Z