Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LtiAdvantage submodule, update LineItems view #8

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9dd3872
Fix project references. Fix null reference errors in Tool.cshtml
steelheaddigital Mar 16, 2021
93ea2e0
Include LtiAdvantage as submodule and adjust references
willwm Apr 5, 2021
9f70f45
Update project references
willwm Apr 5, 2021
353565a
Convert to relative link
willwm Apr 5, 2021
56d34b1
Remove broken URL
willwm Apr 5, 2021
40c0700
Merge pull request #1 from learningcom/submodule-ltiadvantage
steelheaddigital Apr 5, 2021
c81e649
Add links to README.md
willwm Apr 6, 2021
4a24e40
Fix error when platform doesn't return line items. Add a way to submi…
steelheaddigital Apr 27, 2021
4e74875
Merge pull request #3 from learningcom/submit-score
willwm Apr 27, 2021
1456c8c
Retrieve and display any context members on load
steelheaddigital May 4, 2021
688583e
Merge pull request #4 from learningcom/display-context-members
willwm May 8, 2021
20468c0
Show results on load
steelheaddigital May 10, 2021
3743e93
Merge pull request #5 from learningcom/display-context-members
willwm May 10, 2021
c938739
Retrieve line item data on load
steelheaddigital May 12, 2021
f0d4160
Merge pull request #6 from learningcom/line-item-details
willwm May 12, 2021
ba1cfae
Allow the resourcelinkid for a new line item to be specified
steelheaddigital May 14, 2021
65c7334
Merge pull request #7 from learningcom/add-line-item
willwm May 14, 2021
bac40f9
Allow for deletion of line items
steelheaddigital May 17, 2021
41d4de5
Merge pull request #8 from learningcom/delete-line-item
willwm May 17, 2021
7182a46
Fix the redirect to the /Catalog page on a DeepLinkRequest launch. Ch…
steelheaddigital May 21, 2021
40d029a
Merge pull request #9 from learningcom/catalog-fix
willwm May 24, 2021
cfd3565
Generate correct tool Url when assigning a deep link item
steelheaddigital Jun 2, 2021
e4c37d8
Merge pull request #10 from learningcom/deep-link-assign-fix
willwm Jun 2, 2021
b697007
Add PowerShell convenience script for console startup
willwm Jun 12, 2021
e3cb912
Display custom params from launch request
steelheaddigital Jul 7, 2021
7b7414e
Merge pull request #11 from learningcom/custom-param-display
willwm Jul 7, 2021
860cc24
Allow invalid certificates in HttpCleint
steelheaddigital Aug 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "shared/LtiAdvantage"]
path = shared/LtiAdvantage
url = https://github.com/learningcom/LtiAdvantage
24 changes: 12 additions & 12 deletions AdvantageTool.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2019
# Visual Studio Version 16
VisualStudioVersion = 16.0.30804.86
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{777D9453-8256-4AD3-ADDF-BE34047DFFEB}"
ProjectSection(SolutionItems) = preProject
Expand All @@ -10,9 +10,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdvantageTool", "src\AdvantageTool.csproj", "{4EBF015D-9B8C-4A2E-8A72-658F931718C0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LtiAdvantage", "..\..\LTI\LtiAdvantage\src\LtiAdvantage\LtiAdvantage.csproj", "{097C6757-60C8-44C2-B378-F9A8E3A08377}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LtiAdvantage", "shared\LtiAdvantage\src\LtiAdvantage\LtiAdvantage.csproj", "{52E66378-7670-4E6E-978C-D3B16883506C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LtiAdvantage.IdentityModel", "..\..\LTI\LtiAdvantage\src\LtiAdvantage.IdentityModel\LtiAdvantage.IdentityModel.csproj", "{C55CD2BF-0A0E-43F2-A285-E82904CCD727}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LtiAdvantage.IdentityModel", "shared\LtiAdvantage\src\LtiAdvantage.IdentityModel\LtiAdvantage.IdentityModel.csproj", "{B04A07BC-C551-478E-8B6C-377D219EC8FF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -24,14 +24,14 @@ Global
{4EBF015D-9B8C-4A2E-8A72-658F931718C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EBF015D-9B8C-4A2E-8A72-658F931718C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EBF015D-9B8C-4A2E-8A72-658F931718C0}.Release|Any CPU.Build.0 = Release|Any CPU
{097C6757-60C8-44C2-B378-F9A8E3A08377}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{097C6757-60C8-44C2-B378-F9A8E3A08377}.Debug|Any CPU.Build.0 = Debug|Any CPU
{097C6757-60C8-44C2-B378-F9A8E3A08377}.Release|Any CPU.ActiveCfg = Release|Any CPU
{097C6757-60C8-44C2-B378-F9A8E3A08377}.Release|Any CPU.Build.0 = Release|Any CPU
{C55CD2BF-0A0E-43F2-A285-E82904CCD727}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C55CD2BF-0A0E-43F2-A285-E82904CCD727}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C55CD2BF-0A0E-43F2-A285-E82904CCD727}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C55CD2BF-0A0E-43F2-A285-E82904CCD727}.Release|Any CPU.Build.0 = Release|Any CPU
{52E66378-7670-4E6E-978C-D3B16883506C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{52E66378-7670-4E6E-978C-D3B16883506C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{52E66378-7670-4E6E-978C-D3B16883506C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{52E66378-7670-4E6E-978C-D3B16883506C}.Release|Any CPU.Build.0 = Release|Any CPU
{B04A07BC-C551-478E-8B6C-377D219EC8FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B04A07BC-C551-478E-8B6C-377D219EC8FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B04A07BC-C551-478E-8B6C-377D219EC8FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B04A07BC-C551-478E-8B6C-377D219EC8FF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

# LTI Advantage Tool

Sample LTI Advantage Tool for .NET Core. See https://advantagetool.azurewebsites.net/
Most of the interesting stuff is in [src/Pages/Tool.cshtml.cs](src/Pages/Tool.cshtml.cs)

Most of the interesting stuff is in https://github.com/andyfmiller/LtiAdvantageTool/blob/master/src/Pages/Tool.cshtml.cs
## Useful Links

Debugging Tools

* [OpenID Connect debugger](https://oidcdebugger.com/)

LTI Specifications
* [Learning Tools Interoperability Core Specification 1.3 | IMS Global Learning Consortium](https://www.imsglobal.org/spec/lti/v1p3/)
* [Learning Tools Interoperability Names and Role Provisioning Services Version 2.0 | IMS Global Learning Consortium](https://www.imsglobal.org/spec/lti-nrps/v2p0)
* [Learning Tools Interoperability Assignment and Grade Services Version 2.0 | IMS Global Learning Consortium](https://www.imsglobal.org/spec/lti-ags/v2p0)
1 change: 1 addition & 0 deletions Start-AdvantageTool.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dotnet run --project .\src\AdvantageTool.csproj
1 change: 1 addition & 0 deletions shared/LtiAdvantage
Submodule LtiAdvantage added at b6272d
4 changes: 2 additions & 2 deletions src/AdvantageTool.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\LTI\LtiAdvantage\src\LtiAdvantage.IdentityModel\LtiAdvantage.IdentityModel.csproj" />
<ProjectReference Include="..\..\..\LTI\LtiAdvantage\src\LtiAdvantage\LtiAdvantage.csproj" />
<ProjectReference Include="..\shared\LtiAdvantage\src\LtiAdvantage.IdentityModel\LtiAdvantage.IdentityModel.csproj" />
<ProjectReference Include="..\shared\LtiAdvantage\src\LtiAdvantage\LtiAdvantage.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
8 changes: 5 additions & 3 deletions src/Pages/Catalog.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,18 @@ public async Task<IActionResult> OnPostAssignActivities()

var contentItems = new List<ContentItem>();
var customParameters = LtiRequest.Custom;
var platform = await _context.GetPlatformByIssuerAsync(LtiRequest.Iss);

foreach (var activity in Activities)
{
if (activity.Selected)
{
var url = Url.Page("/Tool", null, new { platformId = platform.PlatformId }, Request.Scheme);
var contentItem = new LtiLinkItem
{
Title = activity.Title,
Text = activity.Description,
Url = Url.Page("./Tool", null, null, Request.Scheme),
Url = url,
Custom = new Dictionary<string, string>
{
{ "activity_id", activity.Id.ToString() }
Expand Down Expand Up @@ -143,11 +146,10 @@ public async Task<IActionResult> OnPostAssignActivities()
response.AddClaim(new Claim(JwtRegisteredClaimNames.Exp, EpochTime.GetIntDate(DateTime.UtcNow.AddMinutes(5)).ToString()));
response.AddClaim(new Claim(JwtRegisteredClaimNames.Nonce, IdentityModel.CryptoRandom.CreateRandomKeyString(8)));

var platform = await _context.GetPlatformByIssuerAsync(LtiRequest.Iss);
var credentials = PemHelper.SigningCredentialsFromPemString(platform.PrivateKey);
var jwt = handler.WriteToken(new JwtSecurityToken(new JwtHeader(credentials), response));

return Post("id_token", jwt, LtiRequest.DeepLinkingSettings.DeepLinkReturnUrl);
return Post("JWT", jwt, LtiRequest.DeepLinkingSettings.DeepLinkReturnUrl);
}

/// <summary>
Expand Down
63 changes: 57 additions & 6 deletions src/Pages/Components/LineItems/Default.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@
@if (Model != null)
{
<div class="row">
<div class="col-12">
<div class="col-12 mb-3">
<div class="card bg-transparent">
<form method="post">
<input type="hidden" name="id_token" value="@Model.IdToken" />
<h5 class="card-header">
Gradebook
<button type="submit" class="btn btn-light btn-sm float-right" asp-page-handler="CreateLineItem">
Add a line item for <span class="font-italic">@Model.LtiRequest.ResourceLink.Title</span>
</button>
</h5>

<div class="card-body">
<div class="form-group">
<label>Resource Link ID</label>
<input type="text" name="resource_link_id" value="@Model.LtiRequest.ResourceLink.Title" class="form-control mb-3 w-25"/>
<button type="submit" class="btn btn-light btn-sm form-control w-25" asp-page-handler="CreateLineItem">
Add a line item
</button>
</div>
@Model.Status
@if (Model.LineItems == null)
{
Expand All @@ -29,7 +34,16 @@
<th scope="col" class="border-left-0 border-top-0"></th>
@foreach (var lineItem in Model.LineItems.OrderBy(l => l.Header))
{
<th scope="col" class="text-center">@lineItem.Header</th>
<th scope="col" class="text-center">
@lineItem.Header
@{var deleteRouteData = new Dictionary<string, string> { { "lineItemUrl", lineItem.AgsLineItem.Id } };}
<button type="submit" class="btn btn-sm btn-link"
data-toggle="tooltip" title="Delete line item"
asp-page-handler="DeleteLineItem"
asp-all-route-data="@deleteRouteData">
<i class="fa fa-minus-square fa-lg text-light"></i>
</button>
</th>
}
</tr>
</thead>
Expand Down Expand Up @@ -74,4 +88,41 @@
</div>
</div>
</div>
}
<div class="row">
<div class="col-4 mb-3">
<div class="card bg-transparent">
<h5 class="card-header">
Members
</h5>
<div class="card-body">
@if (Model.Members == null)
{
<p>
This context does not have any members.
</p>
}
else
{
<table class="table table-bordered table-responsive-sm border-0">
<thead>
<tr>
<th scope="col" class="text-center">UserId</th>
</tr>
</thead>
<tbody>
@foreach (var member in Model.Members)
{
<tr>
<td>
@member.Key
</td>
</tr>
}
</tbody>
</table>
}
</div>
</div>
</div>
</div>
}
46 changes: 23 additions & 23 deletions src/Pages/Components/LineItems/LineItemsViewComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,19 @@ public async Task<IViewComponentResult> InvokeAsync(string idToken)
return View(model);
}

// Get all the line items
// Get all the members of the course
model.Members = new Dictionary<string, string>();

try
{
var httpClient = _httpClientFactory.CreateClient();
httpClient.SetBearerToken(tokenResponse.AccessToken);

httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept
.Add(new MediaTypeWithQualityHeaderValue(Constants.MediaTypes.LineItemContainer));
.Add(new MediaTypeWithQualityHeaderValue(Constants.MediaTypes.MembershipContainer));

using (var response = await httpClient.GetAsync(model.LtiRequest.AssignmentGradeServices?.LineItemsUrl))
using (var response = await httpClient.GetAsync(model.LtiRequest.NamesRoleService.ContextMembershipUrl))
{
if (!response.IsSuccessStatusCode)
{
Expand All @@ -80,34 +83,32 @@ public async Task<IViewComponentResult> InvokeAsync(string idToken)
}

var content = await response.Content.ReadAsStringAsync();
model.LineItems = JsonConvert.DeserializeObject<List<LineItem>>(content)
.Select(i => new MyLineItem
var membership = JsonConvert.DeserializeObject<MembershipContainer>(content);
foreach (var member in membership.Members.OrderBy(m => m.FamilyName).ThenBy(m => m.GivenName))
{
if (!model.Members.ContainsKey(member.UserId))
{
AgsLineItem = i,
Header = i.Label ?? $"Tag: {i.Tag}"
})
.ToList();
model.Members.Add(member.UserId, $"{member.FamilyName}, {member.GivenName}");
}
}
}
}
catch (Exception e)
{
model.Status = e.Message;
return View();
return View(model);
}

// Get all the members of the course
model.Members = new Dictionary<string, string>();

// Get all the line items
try
{
var httpClient = _httpClientFactory.CreateClient();
httpClient.SetBearerToken(tokenResponse.AccessToken);

httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept
.Add(new MediaTypeWithQualityHeaderValue(Constants.MediaTypes.MembershipContainer));
.Add(new MediaTypeWithQualityHeaderValue(Constants.MediaTypes.LineItemContainer));

using (var response = await httpClient.GetAsync(model.LtiRequest.NamesRoleService.ContextMembershipUrl))
using (var response = await httpClient.GetAsync(model.LtiRequest.AssignmentGradeServices?.LineItemsUrl))
{
if (!response.IsSuccessStatusCode)
{
Expand All @@ -116,14 +117,13 @@ public async Task<IViewComponentResult> InvokeAsync(string idToken)
}

var content = await response.Content.ReadAsStringAsync();
var membership = JsonConvert.DeserializeObject<MembershipContainer>(content);
foreach (var member in membership.Members.OrderBy(m => m.FamilyName).ThenBy(m => m.GivenName))
{
if (!model.Members.ContainsKey(member.UserId))
model.LineItems = JsonConvert.DeserializeObject<List<LineItem>>(content)
.Select(i => new MyLineItem
{
model.Members.Add(member.UserId, $"{member.FamilyName}, {member.GivenName}");
}
}
AgsLineItem = i,
Header = i.Label ?? $"Tag: {i.Tag}"
})
.ToList();
}
}
catch (Exception e)
Expand Down
Loading