Delete cascading enrollments - desire2learn

How to delete user's enrollments from cascading structure of org units?
In my app I use the following path to create enrollments:
POST /d2l/api/lp/1.4/enrollments/
with request body:
{
"OrgUnitId": 123,
"UserId": 4,
"RoleId": 5
}
this call creates 3 enrollments:
OrgUnitId=123 -> Course offering
OrgUnitId=124 -> Section
OrgUnitId=125 -> Group
So, I know only top level orgUnitId (related to Course offering). Others enrollments are created automatically.
When I try to delete enrollments I use the following DELETE call:
/d2l/api/lp/1.4/enrollments/orgUnits/123/users/4
After this call I still see "enrollments children":
OrgUnitId=124 -> Section
OrgUnitId=125 -> Group
How can I remove them?

Ideally, the API could handle this, but here's an alternative:
The DELETE call will return an EnrollmentData block showing the status pre-deletion:
{
"OrgUnitId": <number:D2LID>,
"UserId": <number:D2LID>,
"RoleId": <number:D2LID>,
"IsCascading": <boolean>
}
If IsCascading is true, retrieve the children using the request below, and iterate your original DELETE statement on the children OrgUnits.
GET /d2l/api/lp/(version)/orgstructure/(orgUnitId)/descendants/
(See http://docs.valence.desire2learn.com/res/orgunit.html#get--d2l-api-lp-%28version%29-orgstructure-%28orgUnitId%29-descendants-)

Related

Planner Plan URL or creating a Planner Tab in Teams

I've been trying to create a plan using the Graph REST API for .Net and Microsoft Planner. Following the provided documentation, I was able to create a plan. However, I've seen that after creating it, no URL in order to access that plan is provided.
I was wondering if there was a way of getting or constructing this URL having the planId.
Following this, I also want to link the created Plan to a Tab in Microsoft Plan, but could not find anything useful in the documentation. Is there even a way to create a Planner Tab in Ms Teams using the Graph API?
These are the documentation pages for adding tabs:
https://learn.microsoft.com/en-us/graph/api/channel-post-tabs?view=graph-rest-1.0
https://learn.microsoft.com/en-us/graph/teams-configuring-builtin-tabs
The URL for the Planner Tab page is as follows. You'll need to put your plan id there, but other variables in curly braces are part of the URL as variables, and get filled in by Teams when someone is viewing the tab. https://tasks.teams.microsoft.com/teamsui/{tid}/Home/PlannerFrame?page=7&auth_pvr=OrgId&auth_upn={userPrincipalName}&groupId={groupId}&planId=<YourPlanId>&channelId={channelId}&entityId={entityId}&tid={tid}&userObjectId={userObjectId}&subEntityId={subEntityId}&sessionId={sessionId}&theme={theme}&mkt={locale}&ringId={ringId}&PlannerRouteHint={tid}&tabVersion=20200228.1_s
The full request looks like:
{
"displayName": "<Name of the tab>",
"teamsApp#odata.bind" : "https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/com.microsoft.teamspace.tab.planner",
"configuration":{
"entityId": "<combined channel and plan id>",
"contentUrl": "https://tasks.teams.microsoft.com/teamsui/{tid}/Home/PlannerFrame?page=7&auth_pvr=OrgId&auth_upn={userPrincipalName}&groupId={groupId}&planId=<Your plan Id>&channelId={channelId}&entityId={entityId}&tid={tid}&userObjectId={userObjectId}&subEntityId={subEntityId}&sessionId={sessionId}&theme={theme}&mkt={locale}&ringId={ringId}&PlannerRouteHint={tid}&tabVersion=20200228.1_s"
}
}
3 values need to be replaced there, the display name, the entity id and the plan id in the URL.
The entity id value looks like tt.c_<channel id>_p_<plan id> For example for Channel ID = ABC, and Plan ID = 123, you'd get literal string tt.c_ABC_p_123
The plans can be accessed to through this API:https://developer.microsoft.com/graph/graph-explorer?request=groups/%7Bid%7D/planner/plans&version=v1.0
Please refer this document:Top Planner API tasks
You should only need the Planner Id and Channel Id to create a Planner tab in Teams.
Here is my complete request body:
{
"displayName": "<Name of the tab>",
"teamsApp#odata.bind" : "https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/com.microsoft.teamspace.tab.planner",
"configuration":{
"entityId": "tt.c_<Channel Id>_p_<Plan Id>",
"contentUrl": "https://tasks.teams.microsoft.com/teamsui/{tid}/Home/PlannerFrame?page=7&auth_pvr=OrgId&auth_upn={userPrincipalName}&groupId={groupId}&planId=<Plan Id>&channelId={channelId}&entityId={entityId}&tid={tid}&userObjectId={userObjectId}&subEntityId={subEntityId}&sessionId={sessionId}&theme={theme}&mkt={locale}&ringId={ringId}&PlannerRouteHint={tid}&tabVersion=20200228.1_s",
"removeUrl": "https://tasks.teams.microsoft.com/teamsui/{tid}/Home/PlannerFrame?page=13&auth_pvr=OrgId&auth_upn={userPrincipalName}&groupId={groupId}&planId=<Plan Id>&channelId={channelId}&entityId={entityId}&tid={tid}&userObjectId={userObjectId}&subEntityId={subEntityId}&sessionId={sessionId}&theme={theme}&mkt={locale}&ringId={ringId}&PlannerRouteHint={tid}&tabVersion=20200228.1_s",
"websiteUrl": "https://tasks.office.com/d3ee719b-9e5c-478b-87c9-c4ffbfd27c96/Home/PlanViews/<Plan Id>?Type=PlanLink&Channel=TeamsTab"
}
}
The following attributes need values replaced:
displayName: Tab Title
entityId: Channel Id & Plan Id
contentUrl: Plan Id
removeUrl: Plan Id
websiteUrl: Plan Id

Create a documentSet using graph API - configuration

I implemented with Graph API several calls to create a document set.
I followed the answer posted here concerning the possibility of creating a DocumentSet in SharePoint here : Is it possible to create a project documentset using graph API?
For this i followed those steps :
1. Getting the library driveId :
`GET https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${listId}?$expand=drive`
2. Creating the folder:
POST https://graph.microsoft.com/v1.0/drives/${driveId}/root/children
I have to pass an object:
{
"name": ${nameOfTheFolder},
"folder": {},
}
3. Getting the Sharepoint itemId:
4. Updating the document library:
`PATCH https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${listId}/items/${sharepointIds.listItemId}`
and passing a body:
{
"contentType": {
"id": "content-type-id-of-the-document-set"
},
"fields": {
//whatever fields you want to set
}
}
I have questions concerning the folder creation and the updating:
What is expected in the folder object ?
{
"name": ${nameOfTheFolder},
"folder": {},
}
Concerning the path step:
{
"contentType": {
"id": "content-type-id-of-the-document-set"
},
"fields": {
//whatever fields you want to set
}
}
I have several questions :
Let's consider i have a document type called invoices. Which id is expected for document type id ?
finally how do i pass the fields ? let's say i want to pass 3 fields : invoiceId, claimId, clientId.
Graph API is great but some more information would be helpful. thanks !
I have questions concerning the folder creation and the updating: What is expected in the folder object ?
The folder object (sent as {}) is there to tell graph API that you are creating a folder and not a file. It is a property of the drive item
Let's consider i have a document type called invoices. Which id is expected for document type id ?
This is the id contentType subfield of the list item you are patching
ally how do i pass the fields ? let's say i want to pass 3 fields : invoiceId, claimId, clientId.
You just pass them with repective values like below. See Update listItem
{
"invoiceId": "value",
"claimId": "value"
...
}
One point I didn't express correctly was to know what id is expected here :
{
"contentType": {
"id": "content-type-id-of-the-document-set"
},
"fields": {
//whatever fields you want to set
}
}
I retrieved the different content types of my site by calling this kind of URL and check if the content type exists.
https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${listId}/contentTypes
From the result i retrieve in a Value object the id.
The id looks like this :
0x0120D5200082903AB771604546844DB2AC483D905B00E58445A7D..........
In modern SharePoint, you can also get the Content Type ID from the UI by browsing to SharePoint Site > Site Settings > Site content types > <ContentTypeName> > Content Type ID.
Content Type ID
Not sure if this is easier than via graph, but it's another option at least.

Query in firebase Database in iOS

I work with firebase database, I have the following data,
I need to get all groups names (GName) of a user by his phoneNum, i.e. all groups of specific user, How can I get that in swift 4?
You should consider restructuring your data. If a user belongs to more than one group in your application then you'll probably have to duplicate your user node for every group the user belongs to in your data structure. You can create another JSON object that holds all of the groups that a user belongs to. Here is a sample JSON for you:
{
"users": [{
"xyz123": {
"userId": "xyz123",
"username": "user1",
"phoneNum": "123456",
"groups": [{
"groupId": 1,
"groupName": "aaa"
}, {
"groupId": 2,
"groupName": "bbb"
}]
}
}]
}
As for filtering with the phone number, you can get all users inside a list and filter the result with the phone number criteria
result = result.filter({item.phoneNum == "123456"})
or get phone number of the user to a upper level, call .child() method with the phone number criteria and fetch the specific user.
Also take a look at structuring data part at firebase documentation.
https://firebase.google.com/docs/database/ios/structure-data
Hope that helps.

Microsoft graph batch requests

I have the following requirement :
create an office 365 unified group
add members to it
add each of the members to the accepted senders list of the group
fetch the following IDS for local storage (sql server)
The group ID
The group's main thread ID
The group's main planner plan ID
The group's main planner bucket ID
Can I batch this using the following : https://developer.microsoft.com/en-us/graph/docs/concepts/json_batching
The way I am doing it, I have a request object (in the JSON batch) for each api request.
Logically, I can't proceed with any of my requests without having created the group. So the first one will be the POST to the groups endpoint.
What I would like is a way for subsequent requests to use the newly created group ID to, for example, add members.
Is that doable in the same batch (same JSON batch object)?
If yes, how?
You can use dependsOn to sequence requests as specific order but it will be easier to run them as separated batches, one after another.
Create group
Add members
...
For adding users in a batch try json like this (replace id's with group and userIds):
`
{
"requests": [
{
"id": "1",
"method": "POST",
"url": "/v1.0/groups/{id}/members/$ref"
"body": {
"#odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/{id}"
}
}
{
"id": "2",
"method": "POST",
"url": "/v1.0/groups/{id}/members/$ref"
"body": {
"#odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/{id}"
}
}
]
}
`

Returning a custom field where value depends on the query in elasticsearch

I have some data like so in elasticsearch:
account (http://localhost:9200/myapp/account/1)
========
name
state
groups //groups is an array containing objects like so {id: 1, starred: true}
//the id is the id of the group type
email (http://localhost:9200/myapp/email/1?parent=1)
========
email
primary //just a boolean to denote whether this email is primary or not
group
========
name
description
emails are children of account.
Based on imotov's excellent answer, I am able to run a search on account.name and email.email and return ALL accounts where the searched prefix matches the above 2 fields:
{
"query": {
"bool": {
"must": [
{
"term": {
"statuses": "active"
}
}
],
"should": [
{
"prefix": {
"name": "a"
}
},
{
"has_child": {
"type": "email",
"query": {
"prefix": {
"email": "a"
}
}
}
}
],
"minimum_number_should_match" : 1
}
}
}
What I would like to do now is to return 2 custom fields for each result:
For each result return a field called email, if the search was matched on the email type (which is a child of account), return that email, otherwise return the primary email linked to the account, if none, null can be returned.
For each result return a field called group. The value of the field should contain the name of the starred group whose id is stored in the groups array. Essentially: Find group.id where group.starred is true in each account.groups, then return the matching group.name from the group type base on the id we found.
I have been looking at script fields, but I am not sure if it is able to return fields for each hit. I am also not sure if the above is actually accomplishable in ES.
Could someone provide some pointers as to whether this is possible and how to get started?
Currently, there is simply no way to get to access the data in a has_child or nested clause.
The only solution is to get some data, make some decisions on the client and then get more data.
Here's what I did to achieve it:
Run the query above and get back the data.
To deal with showing the match emails or the primary email (run on the email type):
{"query":
{"bool":{
"should":{
{
"prefix":{
"email" : "the query"
}
},
{
"terms":{
"_parent" : ["list", "of", "account", "ids"]
}
}
}
}
}
}
Base on the above query, we can get any email addresses that were matched by the search term. Remember to set the fields in the above query to include _parent.
We can then use array_diff() or a similiar function in languages other than PHP to diff the parent ids from above and and original query. This should then give us a list of accounts where no email was matched. Simply then send another request to get the primary emails for those accounts.
For the groups, send a query to type account and:
Constrain _id to the list of account ids.
Constrain group.starred to true.
This should get you a list of starred groups. To get more information (name etc), send a query to type group and:
Constrain _id to the group ids above.
Finally, do some client side processing to put it together so that it is easier for the next part of your program to use.

Resources