Student Subject and Course Completion - desire2learn

Would someone be able to direct me to the correct API that I could use to mark a Student Subject and Course to ‘Complete’?
I found out ‘Grade.CourseCompletion’ API could serve the purpose, but not sure if that's correct understanding.
Also, where could I find below highlighted fields and how I can change their value?
"OrgUnitId": <number:D2LID>,
**"CompletionId": <number:D2LID>,**
"UserId": <number:D2LID>,
**"CompletedDate": <string:UTCDateTime>,**
"ExpiryDate": <string:UTCDateTime>|null
Thanks
Vivek

You cannot change a CompletionId; it's an entity identifier for the completion record that gets created by Brightspace when the completion record gets created. (I believe you could, however, delete a completion record and create a new one.)
You use the POST and PUT routes for course completion to create new (or update existing) course completion records. The JSON structure you provide when you do a create or update operation allows you to specify a CompletedDate.
I would also point out that D2L has a developer-specific community to support clients and partners and you may find that answers to your questions are more timely there.

Related

ASP.NET Model Id in ViewModel - is it safe?

Scenario:
(with an ASP.NET web app - Core or MVC)
I have a database with Users and Items for each user.
That means the UserId is a foreign key in the Items table.
From the browser I login as a User. I get my Items as a list of ItemViewModels, which are mapped (AutoMapper) to ItemViewModels via a simple api GET request.
I want to update one of the items (which should belong to me - the logged in user) via a simple API call. So I send the modified item back to the server via a PUT request as an ItemViewModel.
First approach:
The simplest approach would be to include the Item's database ID, ItemId, in the ItemViewModel - so when I receive the item to be updated as an ItemViewModel, I can map it back to the existing item in the database.
This however sounds pretty unsafe to me, as anyone could modify the PUT request with any ItemId and affect items which don't belong to the user who executed the request. Is there anything I'm missing about this approach?
Second approach:
Don't pass the database PK ItemId in the ItemViewModel.
Instead use an additional form of identification: let's say that user X has 10 items. And they are numbered from 1 to 10 using a property named UserItemId(which also exists in the database).
I can then pass this UserItemId in the ItemViewModel and when I get it back I can map it to an existing Item in the database (if all was ok with the request) or discard it and reject the request if the UserItemId didn't match anything from the logged in user's items.
Is anyone using this approach?
Pros:
The user only has access to it's own items and can't affect anyone else's since it doesn't know the actual Item ID (primary key), and any modifications are restricted to it's items.
Cons:
A great deal of extra management must be implemented on the server side for this approach to work.
Any other approaches ?
Please consider that the case mentioned above applies to all entities in the database which a client side implementation can CRUD, so it's not just the simple case described above.
The proposed solution should work for the entire app data.
I know this question has been asked here and here but the first one doesn't have a satisfying answer and I don't think the second one really applies to my situation, since it just deals with the UserId.
Thanks.
EDIT
Please consider the Item above as an aggregate root which contains multiple complex subItems each with a table in the db. And the question applies for them as much as for the main Item. That means that each subItem is passed as a ViewModel to the client.
I should mention that regarding further securing the update request:
For the first approach I can easily check if the user is allowed to change the item. But I should do this for all subItems too.
For the second approach I can check if the user can update the Item as follows: I get the userItemId of the incoming ViewModel -> I get all the logged in user's items from the database and try to find a match with the same userItemId, if I get a hit then I proceed with the update.
I think your application is not secure, if you only hide the Id.
You must check, before changing the database entity, if the user is allowed to change the entity.
In your case you should check, if your Id from the authenticated user is the UserId in your item.
If your ViewModel ist similar or identical for your API you could use a FilterAttribute in your controller.

JSON API implmentation for service object in Rails

As you know, service object is used to create data for multiple domains, or connect 3rd party APIs in one procedure.
So in this case, resource interface and domain model are not exactly matched.
For example, you want to create Subscription.
The procedure is following,
create User
create choose the Plan
create Subscription (connecting third party API)
(If something fails, the rollback occurs.)
The business logic is across more than one domain.
So I could do POST with those JSON data.
{"plan_id": 1,
"user_info":{"uuid": "644e1dd7-2a7f-18fb-b8ed-ed78c3f92c2b",
"name": "John Doe",
"email": "john#gmailcom"},
"user_card_info": {"object":"card",
"exp_month": 12,
"exp_year": 2020,
"number": 4242424242424242}
}
In this case, how should I handle this situation in JSON API.
Maybe Should I create abstract resource?
Also How can I handle this within Controller in JSON API?
To do this in the front end, you would essentially need to duplicate rails validations for every single field, however it is much simpler to do this in rails within the controller action.
Firstly, all relevant models need to have the proper validations (generic and custom if necessary). This way, when you create an invalid object, you can catch the issue. Then, there's a class method called #transactions. I've listed the documentation below. This allows you to insert multiple records at once and rollback if any of them fail which should solve your issue. Be sure to use the #save! method over #save because the latter fails silently. Hopefully this was helpful :)
http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html

Ruby on Rails: When to add a new resource

I have two questions on how the MVC works. I'm pretty sure I should add several resources, but I'm just coming to this conclusion and wanted to ask first to get a better understanding.
First question:
I have two models, user and subject. Users can enter subjects into the database. For each subject there are 5 data entry forms (Baseline, 3month, 6month,...) that are about 100-200 questions each (The relationship would be each subject has 1 of each data entry form). Should each data entry form be a new resource?
Second Question:
Lets say I want to randomize a few subjects into a group:
From the view, the user enters the amount of subjects to be randomized into a group, as well as the group name to be assigned. The form tag specifies an action I created, just for this function, called randomize.
From the controller, randomize uses the params sent from the view to query the database, and then to update each record to reflect the group. Instead of creating a new action for the randomize function, should I create a new resource for it? And as a side note, should any of these calculations be done in the model (other than defining the variables)?
Thank you for your time. Any help would be greatly appreciated. I am officially over-whelmed by all of the information I'm learning about this...but I feel that I'm really close to actually understanding the MVC.
I'll answer your second question first.
You should be creating controllers to handle CRUD tasks for resources. In this question you ask about creating a "Group". Regardless of whether this is an actual resource, or just a modification to a collection of other resources, you have the concept of creating a "Group", probably reading/updating a "group" and certainly deleting one.
Based on this, I would rather have a RandomGroup controller which I can call using a standard REST interface, rather than some #randomize action stuffed in the side of another controller.
As for your first question ... maybe, maybe not.
It really depends on whether an data entry form has any business logic of its own. If it doesn't then there's no harm it being part of a large object. But if your tests and code start to become too complex within the Subject model you may want to split it out into multiple models or at least multiple modules included into that model.
Perhaps you could consider that "Baseline", "3month", "6month" are all the same ... aside from their lead time. Perhaps that is a model in itself, and Subject could has_many :forms ??
Food for thought.

Modifing Desire2Learn Groups using the Valance REST API

I'm a bit confused on how we are supposed to update a group using the Valence API.
According to documentation, "Name,Code & Description" are required for updating, but the FETCH group block only returns "GroupID,Name, Description and Enrollments". If Group Code is not returned in the fetch, what value are we supposed to use in the update block if we only want to update the name? Since description is provided I can just feed that back, but what am I supposed to do about code ... just lose that data?
Perhaps there a way to send an update that will update only specific fields in the update block? When I omit fields from the update block I currently receive an error (ie in the case I only want to update the name).
The Code property for Groups is intended to be the "org-defined code" for the group (for a course offering, this is often called the "course code"), the one that might appear in the organization's SIS system, for example.
Because groups in Desire2Learn's Learning Suite are considered "org units", when you create one, you need to provide it with an appropriate org-defined code (Code) -- if your organization doesn't use org-defined codes for groups, then you can decide to systematically use some other kind of data by convention (a name, a descriptive string, and so on). You are correct that's inconvenient for the Fetch form of the GroupData structure not to provide this value for you, but the value will be accessible to callers through the organization structure routes (because the newly created group is just an special kind of org unit).
In Learning Suite v10.2 (LP API v1.3+) and later, you can use a single GET call to fetch back the properties for an org unit. In versions prior to v10.2, you will need to fetch the list of parents for the group to get a parent org unit ID, or if you already know the org unit ID for the course offering that owns the group you can use that; then you use that org unit ID to fetch its list of children: your group will be in that list. The OrgUnit and OrgUnitProperties structures both contain the Code property that you need here.

Deleting Entities and its Navigation Properties

I have something like a Customer object with up to 50000 order in an ICollection<Orders>.
Assume the Custome being in the local cache, the orders not. How can i delete the Cutomer and all of its related orders without loading all of the Customer orders into the cache and marking them with setDeleted()?
What is the best practice here. I assume extending the public SaveResult SaveChanges(JObject saveBundle) method is the best way. Any other possibilities here on the client side like a flag delete_all_navigation_too()?
Thanks
I must suppose that you do not have and do not want cascade delete on your database. Personally, I'm "terrified" of deletes in general and try to avoid them. I prefer a soft delete (marking a record as inactive). But not everyone agrees or can follow suit
I would consider adding a Web API method (say "DeleteCustomerAndOrders") to your controller to do it. You can call any API method from your client, not just a Breeze method.
In recommending this, I'm assuming that this kind of thing is a relative rarity in your app. You don't need a general purpose deleter, a deleter that takes an array of parent object IDs, a deleter that will delete some child objects and not others, ... etc., etc.
Follow this path and you will have moved the problem from the client to the server. That's good: you didn't have to load the orders on the client. Now you have to get rid of them on the server. If you're using Entity Framework, you face the same challenge of deleting the orders without loading them. Check out Alex James' solution: Bulk-deleting in LINQ to Entities.
Simplest approach that I can come up with is to create a cascade delete constraint on the database so that when a customer is deleted all of its orders get deleted as well. Then simply delete the customer on the client and call 'SaveChanges'. In addition, since Breeze does not yet support client side 'cascaded' deletes ( we are considering this one), you will need to iterate over any client side orders that are already loaded and 'detach' them.

Resources