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

Cwdoe 1300 end event #89

Merged
merged 3 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion Blueprint.Api/Blueprint.Api.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<Version>1.0.1</Version>
<Version>1.0.2-rc1</Version>
<TargetFramework>net6.0</TargetFramework>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
<NoWarn>CS1591</NoWarn>
Expand Down
23 changes: 21 additions & 2 deletions Blueprint.Api/Controllers/MselController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ public async Task<IActionResult> PushIntegrations(Guid id, CancellationToken ct)
/// <remarks>
/// Pulls all Integrations from the associated applications
/// <para />
/// Accessible only to a ContentDeveloper or an Administrator
/// Accessible only to a ContentDeveloper or Msel Owner
/// </remarks>
/// <param name="id">The id of the MSEL</param>
/// <param name="ct"></param>
Expand All @@ -382,7 +382,26 @@ public async Task<IActionResult> PushIntegrations(Guid id, CancellationToken ct)
[SwaggerOperation(OperationId = "pullIntegrations")]
public async Task<IActionResult> PullIntegrations(Guid id, CancellationToken ct)
{
var msel = await _mselService.PullIntegrationsAsync(id, ct);
var msel = await _mselService.PullIntegrationsAsync(id, ItemStatus.Approved, ct);
return Ok(msel);
}

/// <summary>
/// End the MSEL deployment and archive it
/// </summary>
/// <remarks>
/// Pulls all Integrations from the associated applications and changes MSEL staus to Archived
/// <para />
/// Accessible only to a ContentDeveloper or MSEL Owner
/// </remarks>
/// <param name="id">The id of the MSEL</param>
/// <param name="ct"></param>
[HttpDelete("msels/{id}/archive")]
[ProducesResponseType(typeof(ViewModels.Msel), (int)HttpStatusCode.NoContent)]
[SwaggerOperation(OperationId = "archive")]
public async Task<IActionResult> Archive(Guid id, CancellationToken ct)
{
var msel = await _mselService.ArchiveAsync(id, ct);
return Ok(msel);
}

Expand Down
20 changes: 20 additions & 0 deletions Blueprint.Api/Controllers/PlayerApplicationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,26 @@ public async Task<IActionResult> Create([FromBody] PlayerApplication playerAppli
return CreatedAtAction(nameof(this.Get), new { id = createdPlayerApplication.Id }, createdPlayerApplication);
}

/// <summary>
/// Creates a new PlayerApplication and pushes to a Player View
/// </summary>
/// <remarks>
/// Creates a new PlayerApplication with the attributes specified
/// <para />
/// Accessible only to a ContentDeveloper or MSEL owner
/// </remarks>
/// <param name="playerApplication">The data used to create the PlayerApplication</param>
/// <param name="ct"></param>
[HttpPost("playerApplications/push")]
[ProducesResponseType(typeof(PlayerApplication), (int)HttpStatusCode.Created)]
[SwaggerOperation(OperationId = "createAndPushPlayerApplication")]
public async Task<IActionResult> CreateAndPush([FromBody] PlayerApplication playerApplication, CancellationToken ct)
{
playerApplication.CreatedBy = User.GetId();
var createdPlayerApplication = await _playerApplicationService.CreateAndPushAsync(playerApplication, ct);
return CreatedAtAction(nameof(this.Get), new { id = createdPlayerApplication.Id }, createdPlayerApplication);
}

/// <summary>
/// Updates a PlayerApplication
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,5 +201,13 @@ public static async Task CreateActionsAsync(MselEntity msel, CiteApiClient citeA
}
}

// Add User to Cite Team
public static async Task AddUserToTeamAsync(Guid userId, Guid teamId, CiteApiClient citeApiClient, BlueprintContext blueprintContext, CancellationToken ct)
{
// create Cite TeamUsers
var citeTeamUser = new TeamUser(){TeamId = teamId, UserId = userId};
await citeApiClient.CreateTeamUserAsync(citeTeamUser, ct);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -244,5 +244,13 @@ public static string GetArticleValue(string key, ICollection<DataValueEntity> da
return dataValue == null ? "" : dataValue.Value;
}

// Add User to Gallery Team
public static async Task AddUserToTeamAsync(Guid userId, Guid teamId, GalleryApiClient galleryApiClient, BlueprintContext blueprintContext, CancellationToken ct)
{
// create Gallery TeamUsers
var galleryTeamUser = new TeamUser(){TeamId = teamId, UserId = userId};
await galleryApiClient.CreateTeamUserAsync(galleryTeamUser, ct);
}

}
}
4 changes: 2 additions & 2 deletions Blueprint.Api/Services/IntegrationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using Blueprint.Api.Data.Models;
using Blueprint.Api.Hubs;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -227,7 +226,7 @@ private async void ProcessTheMsel(Object integrationInformationObject)
}
await hubGroup.SendAsync(MainHubMethods.MselPushStatusChange, msel.Id + "", null, ct);
// set the MSEL status
msel.Status = Data.Enumerations.ItemStatus.Approved;
msel.Status = integrationInformation.FinalStatus;
await blueprintContext.SaveChangesAsync(ct);
}

Expand Down Expand Up @@ -360,6 +359,7 @@ public class IntegrationInformation
{
public Guid MselId { get; set; }
public Guid? PlayerViewId { get; set; }
public Data.Enumerations.ItemStatus FinalStatus { get; set; }
}

}
5 changes: 3 additions & 2 deletions Blueprint.Api/Services/JoinQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ public JoinInformation Take(CancellationToken cancellationToken)
public class JoinInformation
{
public Guid UserId { get; set; }
public Guid PlayerViewId { get; set; }
public Guid PlayerTeamId { get; set; }
public Guid? PlayerTeamId { get; set; }
public Guid? GalleryTeamId { get; set; }
public Guid? CiteTeamId { get; set; }
}

}
42 changes: 35 additions & 7 deletions Blueprint.Api/Services/JoinService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using System.Threading.Tasks;
using Blueprint.Api.Infrastructure.Extensions;
using Blueprint.Api.Data;
using Blueprint.Api.ViewModels;

namespace Blueprint.Api.Services
{
Expand Down Expand Up @@ -85,22 +86,49 @@ private async void ProcessTheJoin(Object joinInformationObject)
{
var ct = new CancellationToken();
var joinInformation = (JoinInformation)joinInformationObject;
var loggerInformation = $"Join for User: {joinInformation.UserId}, PlayerView: {joinInformation.PlayerViewId}, PlayerTeam: {joinInformation.PlayerTeamId}";
var loggerInformation = $"Join for User: {joinInformation.UserId}, PlayerTeam: {joinInformation.PlayerTeamId}";
var currentProcessStep = "Begin processing";
_logger.LogDebug($"{currentProcessStep} {loggerInformation}");
try
{
using (var scope = _scopeFactory.CreateScope())
using (var blueprintContext = scope.ServiceProvider.GetRequiredService<BlueprintContext>())
{
// get auth token
var tokenResponse = await ApiClientsExtensions.GetToken(scope);
// Get Player API client
currentProcessStep = "Player - get API client";
var playerApiClient = IntegrationPlayerExtensions.GetPlayerApiClient(_httpClientFactory, _clientOptions.CurrentValue.PlayerApiUrl, tokenResponse);
// Join Player
if (joinInformation.PlayerTeamId != null)
{
// Get Player API client
currentProcessStep = "Player - get API client";
var playerApiClient = IntegrationPlayerExtensions.GetPlayerApiClient(_httpClientFactory, _clientOptions.CurrentValue.PlayerApiUrl, tokenResponse);

// add user to team
currentProcessStep = "Player - add user to team";
await IntegrationPlayerExtensions.AddUserToTeamAsync(joinInformation.UserId, (Guid)joinInformation.PlayerTeamId, playerApiClient, blueprintContext, ct);
}
// Join Gallery
if (joinInformation.GalleryTeamId != null)
{
// Get Gallery API client
currentProcessStep = "Gallery - get API client";
var galleryApiClient = IntegrationGalleryExtensions.GetGalleryApiClient(_httpClientFactory, _clientOptions.CurrentValue.GalleryApiUrl, tokenResponse);

// add user to team
currentProcessStep = "Player - add user to team";
await IntegrationPlayerExtensions.AddUserToTeamAsync(joinInformation.UserId, joinInformation.PlayerTeamId, playerApiClient, blueprintContext, ct);
// add user to team
currentProcessStep = "Gallery - add user to team";
await IntegrationGalleryExtensions.AddUserToTeamAsync(joinInformation.UserId, (Guid)joinInformation.GalleryTeamId, galleryApiClient, blueprintContext, ct);
}
// Join Cite
if (joinInformation.CiteTeamId != null)
{
// Get Cite API client
currentProcessStep = "Cite - get API client";
var citeApiClient = IntegrationCiteExtensions.GetCiteApiClient(_httpClientFactory, _clientOptions.CurrentValue.CiteApiUrl, tokenResponse);

// add user to team
currentProcessStep = "Cite - add user to team";
await IntegrationCiteExtensions.AddUserToTeamAsync(joinInformation.UserId, (Guid)joinInformation.CiteTeamId, citeApiClient, blueprintContext, ct);
}
}
}
catch (System.Exception ex)
Expand Down
49 changes: 37 additions & 12 deletions Blueprint.Api/Services/MselService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ public interface IMselService
Task<Tuple<MemoryStream, string>> DownloadJsonAsync(Guid mselId, CancellationToken ct);
Task<DataTable> GetDataTableAsync(Guid mselId, CancellationToken ct);
Task<ViewModels.Msel> PushIntegrationsAsync(Guid mselId, CancellationToken ct);
Task<ViewModels.Msel> PullIntegrationsAsync(Guid mselId, CancellationToken ct);
Task<ViewModels.Msel> PullIntegrationsAsync(Guid mselId, ItemStatus finalStatus, CancellationToken ct);
Task<ViewModels.Msel> ArchiveAsync(Guid mselId, CancellationToken ct);
Task<IEnumerable<ViewModels.Msel>> GetMyJoinInvitationMselsAsync(CancellationToken ct);
Task<IEnumerable<ViewModels.Msel>> GetMyLaunchInvitationMselsAsync(CancellationToken ct);
Task<Guid> JoinMselByInvitationAsync(Guid mselId, CancellationToken ct); // returns the Player View ID
Expand Down Expand Up @@ -597,6 +598,9 @@ public async Task<bool> DeleteAsync(Guid id, CancellationToken ct)
!( await MselOwnerRequirement.IsMet(_user.GetId(), id, _context)))
throw new ForbiddenException();

// pull integrations if there are any
await PullIntegrationsAsync(id, ItemStatus.Approved, ct);
// delete the MSEL
var mselToDelete = await _context.Msels.SingleOrDefaultAsync(v => v.Id == id, ct);
if (mselToDelete == null)
throw new EntityNotFoundException<Msel>();
Expand Down Expand Up @@ -1661,12 +1665,12 @@ public async Task<Msel> UploadJsonAsync(FileForm form, CancellationToken ct)
var userVerificationErrorMessage = await FindDuplicateMselUsersAsync(mselId, ct);
if (!String.IsNullOrWhiteSpace(userVerificationErrorMessage))
throw new InvalidOperationException(userVerificationErrorMessage);
_integrationQueue.Add(new IntegrationInformation{MselId = mselId, PlayerViewId = null});
_integrationQueue.Add(new IntegrationInformation{MselId = mselId, PlayerViewId = null, FinalStatus = ItemStatus.Deployed});

return _mapper.Map<ViewModels.Msel>(msel);
}

public async Task<ViewModels.Msel> PullIntegrationsAsync(Guid mselId, CancellationToken ct)
public async Task<ViewModels.Msel> PullIntegrationsAsync(Guid mselId, ItemStatus finalStatus, CancellationToken ct)
{
// user must be a Content Developer or a MSEL owner
if (!(await _authorizationService.AuthorizeAsync(_user, null, new ContentDeveloperRequirement())).Succeeded &&
Expand All @@ -1675,11 +1679,21 @@ public async Task<Msel> UploadJsonAsync(FileForm form, CancellationToken ct)
// get the MSEL and verify data state
var msel = await _context.Msels.FindAsync(mselId);
if (msel == null)
throw new EntityNotFoundException<MselEntity>($"MSEL {mselId} was not found when attempting to remove from Player.");
if (msel.PlayerViewId == null)
throw new InvalidOperationException($"MSEL {mselId} is not associated to a Player View.");
throw new EntityNotFoundException<MselEntity>($"MSEL {mselId} was not found.");
// add msel to process queue
_integrationQueue.Add(new IntegrationInformation{MselId = mselId, PlayerViewId = null});
_integrationQueue.Add(new IntegrationInformation{MselId = mselId, PlayerViewId = null, FinalStatus = finalStatus});

return _mapper.Map<ViewModels.Msel>(msel);
}

public async Task<ViewModels.Msel> ArchiveAsync(Guid mselId, CancellationToken ct)
{
// permissions will be checked in PullIntegrationsAsync
await PullIntegrationsAsync(mselId, ItemStatus.Archived, ct);
// get the MSEL and set status to aarchived
var msel = await _context.Msels.FindAsync(mselId);
msel.Status = ItemStatus.Archived;
await _context.SaveChangesAsync(ct);

return _mapper.Map<ViewModels.Msel>(msel);
}
Expand Down Expand Up @@ -1741,7 +1755,8 @@ private async Task<string> FindDuplicateMselUsersAsync(Guid mselId, Cancellation
.Select(mt => mt.Msel)
.ToListAsync(ct);
// get deployed msels with an invitation
var email = _user.Claims.First(c => c.Type == "email")?.Value;
var emailClaim = _user.Claims.SingleOrDefault(c => c.Type == "email");
var email = emailClaim == null ? "" : emailClaim.Value;
var now = DateTime.UtcNow;
var invitationList = await _context.Invitations
.Where(i =>
Expand Down Expand Up @@ -1772,7 +1787,8 @@ private async Task<string> FindDuplicateMselUsersAsync(Guid mselId, Cancellation
throw new ForbiddenException();

// get template msels with an invitation
var email = _user.Claims.First(c => c.Type == "email")?.Value;
var emailClaim = _user.Claims.SingleOrDefault(c => c.Type == "email");
var email = emailClaim == null ? "" : emailClaim.Value;
var now = DateTime.UtcNow;
var invitationList = await _context.Invitations
.Where(i =>
Expand Down Expand Up @@ -1834,12 +1850,16 @@ public async Task<Guid> JoinMselByInvitationAsync(Guid mselId, CancellationToken
);
if (invitation != null)
{
// increment the invitation use count
invitation.UserCount++;
await _context.SaveChangesAsync(ct);
// add the join data to the join queue
var joinInformation = new JoinInformation{
UserId = _user.GetId(),
PlayerViewId = (Guid)msel.PlayerViewId,
PlayerTeamId = (Guid)invitation.Team.PlayerTeamId
PlayerTeamId = invitation.Team.PlayerTeamId,
GalleryTeamId = invitation.Team.GalleryTeamId,
CiteTeamId = invitation.Team.CiteTeamId
};
// add the join data to the join queue
_joinQueue.Add(joinInformation);
}
}
Expand Down Expand Up @@ -1869,6 +1889,11 @@ public async Task<Msel> LaunchMselByInvitationAsync(Guid mselId, CancellationTok

// clone the template MSEL
var mselEntity = await privateMselCopyAsync(mselId, invitation.TeamId, ct);
// set the start time to the current time
mselEntity.StartTime = DateTime.UtcNow;
// increment the invitation use count
invitation.UserCount++;
await _context.SaveChangesAsync(ct);
// create the new player view ID, so that the UI will be able to look for it to be created
var playerViewId = Guid.NewGuid();
// add the launch data to the launch queue
Expand Down
14 changes: 14 additions & 0 deletions Blueprint.Api/Services/PlayerApplicationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public interface IPlayerApplicationService
Task<IEnumerable<ViewModels.PlayerApplication>> GetByMselAsync(Guid mselId, CancellationToken ct);
Task<ViewModels.PlayerApplication> GetAsync(Guid id, CancellationToken ct);
Task<ViewModels.PlayerApplication> CreateAsync(ViewModels.PlayerApplication playerApplication, CancellationToken ct);
Task<ViewModels.PlayerApplication> CreateAndPushAsync(ViewModels.PlayerApplication playerApplication, CancellationToken ct);
Task<ViewModels.PlayerApplication> UpdateAsync(Guid id, ViewModels.PlayerApplication playerApplication, CancellationToken ct);
Task<bool> DeleteAsync(Guid id, CancellationToken ct);
}
Expand All @@ -33,17 +34,20 @@ public class PlayerApplicationService : IPlayerApplicationService
{
private readonly BlueprintContext _context;
private readonly IAuthorizationService _authorizationService;
private readonly IPlayerService _playerService;
private readonly ClaimsPrincipal _user;
private readonly IMapper _mapper;

public PlayerApplicationService(
BlueprintContext context,
IAuthorizationService authorizationService,
IPlayerService playerService,
IPrincipal user,
IMapper mapper)
{
_context = context;
_authorizationService = authorizationService;
_playerService = playerService;
_user = user as ClaimsPrincipal;
_mapper = mapper;
}
Expand Down Expand Up @@ -100,6 +104,16 @@ public PlayerApplicationService(
return playerApplication;
}

public async Task<ViewModels.PlayerApplication> CreateAndPushAsync(ViewModels.PlayerApplication playerApplication, CancellationToken ct)
{
// authorization will be checked in CreateAsync
var item = await CreateAsync(playerApplication, ct);
// push the application to Player
await _playerService.PushApplication(item, ct);

return item;
}

public async Task<ViewModels.PlayerApplication> UpdateAsync(Guid id, ViewModels.PlayerApplication playerApplication, CancellationToken ct)
{
if (!(await _authorizationService.AuthorizeAsync(_user, null, new ContentDeveloperRequirement())).Succeeded &&
Expand Down
Loading
Loading