diff --git a/Gallery.Api/Controllers/CollectionController.cs b/Gallery.Api/Controllers/CollectionController.cs index 58c23cf..73d5bcd 100755 --- a/Gallery.Api/Controllers/CollectionController.cs +++ b/Gallery.Api/Controllers/CollectionController.cs @@ -103,6 +103,25 @@ public async Task Create([FromBody] Collection collection, Cancel return CreatedAtAction(nameof(this.Get), new { id = createdCollection.Id }, createdCollection); } + /// + /// Creates a new Collection by copying an existing Collection + /// + /// + /// Creates a new Collection from the specified existing Collection + /// + /// Accessible only to a ContentDeveloper or an Administrator + /// + /// The ID of the Collection to be copied + /// + [HttpPost("collections/{id}/copy")] + [ProducesResponseType(typeof(Collection), (int)HttpStatusCode.Created)] + [SwaggerOperation(OperationId = "copyCollection")] + public async Task Copy(Guid id, CancellationToken ct) + { + var createdCollection = await _collectionService.CopyAsync(id, ct); + return CreatedAtAction(nameof(this.Get), new { id = createdCollection.Id }, createdCollection); + } + /// /// Updates a Collection /// @@ -144,6 +163,32 @@ public async Task Delete(Guid id, CancellationToken ct) return NoContent(); } + /// Upload a json Collection file + /// The files to upload and their settings + /// + [HttpPost("collections/json")] + [ProducesResponseType(typeof(Collection), (int)HttpStatusCode.OK)] + [SwaggerOperation(OperationId = "uploadJsonFiles")] + public async Task UploadJsonAsync([FromForm] FileForm form, CancellationToken ct) + { + var result = await _collectionService.UploadJsonAsync(form, ct); + return Ok(result); + } + + /// Download a Collection by id as json file + /// The id of the collection + /// + [HttpGet("collections/{id}/json")] + [ProducesResponseType(typeof(FileResult), (int)HttpStatusCode.OK)] + [SwaggerOperation(OperationId = "downloadJson")] + public async Task DownloadJsonAsync(Guid id, CancellationToken ct) + { + (var stream, var fileName) = await _collectionService.DownloadJsonAsync(id, ct); + + // If this is wrapped in an Ok, it throws an exception + return File(stream, "application/octet-stream", fileName); + } + } } diff --git a/Gallery.Api/Controllers/ExhibitController.cs b/Gallery.Api/Controllers/ExhibitController.cs index afd4e24..6bd3747 100755 --- a/Gallery.Api/Controllers/ExhibitController.cs +++ b/Gallery.Api/Controllers/ExhibitController.cs @@ -157,6 +157,25 @@ public async Task Create([FromBody] Exhibit exhibit, Cancellation return CreatedAtAction(nameof(this.Get), new { id = createdExhibit.Id }, createdExhibit); } + /// + /// Creates a new Exhibit by copying an existing Exhibit + /// + /// + /// Creates a new Exhibit from the specified existing Exhibit + /// + /// Accessible only to a ContentDeveloper or an Administrator + /// + /// The ID of the Exhibit to be copied + /// + [HttpPost("exhibits/{id}/copy")] + [ProducesResponseType(typeof(Exhibit), (int)HttpStatusCode.Created)] + [SwaggerOperation(OperationId = "copyExhibit")] + public async Task Copy(Guid id, CancellationToken ct) + { + var createdExhibit = await _exhibitService.CopyAsync(id, ct); + return CreatedAtAction(nameof(this.Get), new { id = createdExhibit.Id }, createdExhibit); + } + /// /// Updates an Exhibit /// @@ -217,6 +236,32 @@ public async Task Delete(Guid id, CancellationToken ct) return NoContent(); } + /// Upload a json Exhibit file + /// The files to upload and their settings + /// + [HttpPost("exhibits/json")] + [ProducesResponseType(typeof(Exhibit), (int)HttpStatusCode.OK)] + [SwaggerOperation(OperationId = "uploadJsonFiles")] + public async Task UploadJsonAsync([FromForm] FileForm form, CancellationToken ct) + { + var result = await _exhibitService.UploadJsonAsync(form, ct); + return Ok(result); + } + + /// Download a Exhibit by id as json file + /// The id of the exhibit + /// + [HttpGet("exhibits/{id}/json")] + [ProducesResponseType(typeof(FileResult), (int)HttpStatusCode.OK)] + [SwaggerOperation(OperationId = "downloadJson")] + public async Task DownloadJsonAsync(Guid id, CancellationToken ct) + { + (var stream, var fileName) = await _exhibitService.DownloadJsonAsync(id, ct); + + // If this is wrapped in an Ok, it throws an exception + return File(stream, "application/octet-stream", fileName); + } + } } diff --git a/Gallery.Api/Gallery.Api.csproj b/Gallery.Api/Gallery.Api.csproj index aebe991..fea806e 100755 --- a/Gallery.Api/Gallery.Api.csproj +++ b/Gallery.Api/Gallery.Api.csproj @@ -1,7 +1,7 @@  - 1.5.2-rc1 + 1.6.0-rc1 net6.0 bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml CS1591 diff --git a/Gallery.Api/Services/CollectionService.cs b/Gallery.Api/Services/CollectionService.cs index ae4eda6..45a0e40 100755 --- a/Gallery.Api/Services/CollectionService.cs +++ b/Gallery.Api/Services/CollectionService.cs @@ -3,9 +3,13 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Security.Claims; using System.Security.Principal; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using AutoMapper; @@ -26,6 +30,9 @@ public interface ICollectionService Task> GetMineAsync(CancellationToken ct); Task GetAsync(Guid id, CancellationToken ct); Task CreateAsync(ViewModels.Collection collection, CancellationToken ct); + Task CopyAsync(Guid collectionId, CancellationToken ct); + Task> DownloadJsonAsync(Guid collectionId, CancellationToken ct); + Task UploadJsonAsync(FileForm form, CancellationToken ct); Task UpdateAsync(Guid id, ViewModels.Collection collection, CancellationToken ct); Task DeleteAsync(Guid id, CancellationToken ct); } @@ -103,6 +110,148 @@ public CollectionService( return collection; } + public async Task CopyAsync(Guid collectionId, CancellationToken ct) + { + if (!(await _authorizationService.AuthorizeAsync(_user, null, new ContentDeveloperRequirement())).Succeeded) + throw new ForbiddenException(); + + var collectionEntity = await _context.Collections + .AsNoTracking() + .SingleOrDefaultAsync(m => m.Id == collectionId); + if (collectionEntity == null) + throw new EntityNotFoundException("Collection not found with ID=" + collectionId.ToString()); + + var cards = await _context.Cards + .AsNoTracking() + .Where(c => c.CollectionId == collectionId) + .ToListAsync(ct); + var articles = await _context.Articles + .AsNoTracking() + .Where(c => c.CollectionId == collectionId) + .ToListAsync(ct); + var newCollectionEntity = await privateCollectionCopyAsync(collectionEntity, cards, articles, ct); + var collection = _mapper.Map(newCollectionEntity); + + return collection; + } + + private async Task privateCollectionCopyAsync( + CollectionEntity collectionEntity, + List cards, + List articles, + CancellationToken ct) + { + var currentUserId = _user.GetId(); + var username = (await _context.Users.SingleOrDefaultAsync(u => u.Id == _user.GetId())).Name; + var oldCollectionId = collectionEntity.Id; + var newCollectionId = Guid.NewGuid(); + var dateCreated = DateTime.UtcNow; + collectionEntity.Id = newCollectionId; + collectionEntity.DateCreated = dateCreated; + collectionEntity.CreatedBy = currentUserId; + collectionEntity.DateModified = collectionEntity.DateCreated; + collectionEntity.ModifiedBy = collectionEntity.CreatedBy; + collectionEntity.Name = collectionEntity.Name + " - " + username; + await _context.Collections.AddAsync(collectionEntity, ct); + // copy cards + var newCardIds = new Dictionary(); + foreach (var cardEntity in cards) + { + newCardIds[cardEntity.Id] = Guid.NewGuid(); + cardEntity.Id = newCardIds[cardEntity.Id]; + cardEntity.CollectionId = collectionEntity.Id; + cardEntity.Collection = null; + cardEntity.DateCreated = collectionEntity.DateCreated; + cardEntity.CreatedBy = collectionEntity.CreatedBy; + await _context.Cards.AddAsync(cardEntity, ct); + } + // copy articles + foreach (var articleEntity in articles) + { + articleEntity.Id = Guid.NewGuid(); + articleEntity.CollectionId = newCollectionId; + articleEntity.Collection = null; + articleEntity.CardId = articleEntity.CardId == null ? null : newCardIds[(Guid)articleEntity.CardId]; + articleEntity.Card = null; + articleEntity.DateCreated = collectionEntity.DateCreated; + articleEntity.CreatedBy = collectionEntity.CreatedBy; + await _context.Articles.AddAsync(articleEntity, ct); + } + await _context.SaveChangesAsync(ct); + + // get the new Collection to return + collectionEntity = await _context.Collections + .SingleOrDefaultAsync(sm => sm.Id == newCollectionId, ct); + + return collectionEntity; + } + + public async Task> DownloadJsonAsync(Guid collectionId, CancellationToken ct) + { + // user must be a Content Developer + if (!(await _authorizationService.AuthorizeAsync(_user, null, new ContentDeveloperRequirement())).Succeeded) + throw new ForbiddenException(); + + var collection = await _context.Collections + .SingleOrDefaultAsync(sm => sm.Id == collectionId, ct); + if (collection == null) + { + throw new EntityNotFoundException("Collection not found " + collectionId); + } + // get the cards + var cards = await _context.Cards + .AsNoTracking() + .Where(c => c.CollectionId == collectionId) + .ToListAsync(ct); + //get the articles + var articles = await _context.Articles + .AsNoTracking() + .Where(c => c.CollectionId == collectionId) + .ToListAsync(ct); + // create the whole object + var collectionFileObject = new CollectionFileFormat(){ + Collection = collection, + Cards = cards, + Articles = articles + }; + var collectionFileJson = ""; + var options = new JsonSerializerOptions() + { + ReferenceHandler = ReferenceHandler.Preserve + }; + collectionFileJson = JsonSerializer.Serialize(collectionFileObject, options); + // convert string to stream + byte[] byteArray = Encoding.ASCII.GetBytes(collectionFileJson); + MemoryStream memoryStream = new MemoryStream(byteArray); + var filename = collection.Description.ToLower().EndsWith(".json") ? collection.Description : collection.Description + ".json"; + + return System.Tuple.Create(memoryStream, filename); + } + + public async Task UploadJsonAsync(FileForm form, CancellationToken ct) + { + // user must be a Content Developer + if (!(await _authorizationService.AuthorizeAsync(_user, null, new ContentDeveloperRequirement())).Succeeded) + throw new ForbiddenException(); + + var uploadItem = form.ToUpload; + var collectionJson = ""; + using (StreamReader reader = new StreamReader(uploadItem.OpenReadStream())) + { + // convert stream to string + collectionJson = reader.ReadToEnd(); + } + var options = new JsonSerializerOptions() + { + ReferenceHandler = ReferenceHandler.Preserve + }; + var collectionFileObject = JsonSerializer.Deserialize(collectionJson, options); + // make a copy and add it to the database + var collectionEntity = await privateCollectionCopyAsync(collectionFileObject.Collection, collectionFileObject.Cards, collectionFileObject.Articles, ct); + + return _mapper.Map(collectionEntity); + } + public async Task UpdateAsync(Guid id, ViewModels.Collection collection, CancellationToken ct) { if (!(await _authorizationService.AuthorizeAsync(_user, null, new ContentDeveloperRequirement())).Succeeded) @@ -144,5 +293,12 @@ public async Task DeleteAsync(Guid id, CancellationToken ct) } } + + class CollectionFileFormat + { + public CollectionEntity Collection { get; set; } + public List Cards { get; set; } + public List Articles { get; set; } + } } diff --git a/Gallery.Api/Services/ExhibitService.cs b/Gallery.Api/Services/ExhibitService.cs index cdad0a8..8bb9fd2 100755 --- a/Gallery.Api/Services/ExhibitService.cs +++ b/Gallery.Api/Services/ExhibitService.cs @@ -3,9 +3,13 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Security.Claims; using System.Security.Principal; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using AutoMapper; @@ -29,6 +33,9 @@ public interface IExhibitService Task> GetMineByCollectionAsync(Guid collectionId, CancellationToken ct); Task GetAsync(Guid id, CancellationToken ct); Task CreateAsync(ViewModels.Exhibit exhibit, CancellationToken ct); + Task CopyAsync(Guid exhibitId, CancellationToken ct); + Task> DownloadJsonAsync(Guid exhibitId, CancellationToken ct); + Task UploadJsonAsync(FileForm form, CancellationToken ct); Task UpdateAsync(Guid id, ViewModels.Exhibit exhibit, CancellationToken ct); Task SetMoveAndInjectAsync(Guid id, int move, int inject, CancellationToken ct); Task DeleteAsync(Guid id, CancellationToken ct); @@ -151,6 +158,217 @@ public ExhibitService( return exhibit; } + public async Task CopyAsync(Guid exhibitId, CancellationToken ct) + { + if (!(await _authorizationService.AuthorizeAsync(_user, null, new ContentDeveloperRequirement())).Succeeded) + throw new ForbiddenException(); + + var exhibitFileObject = await BuildExhibitFileObject(exhibitId, ct); + var newExhibitEntity = await privateExhibitCopyAsync(exhibitFileObject, false, ct); + var exhibit = _mapper.Map(newExhibitEntity); + + return exhibit; + } + + private async Task BuildExhibitFileObject(Guid exhibitId, CancellationToken ct) + { + var exhibitEntity = await _context.Exhibits + .AsNoTracking() + .Include(m => m.Teams) + .AsSingleQuery() + .SingleOrDefaultAsync(m => m.Id == exhibitId); + if (exhibitEntity == null) + throw new EntityNotFoundException("Exhibit not found with ID=" + exhibitId.ToString()); + + var collection = await _context.Collections + .AsNoTracking() + .Where(m => m.Id == exhibitEntity.CollectionId) + .SingleOrDefaultAsync(ct); + var cards = await _context.Cards + .AsNoTracking() + .Where(m => m.CollectionId == exhibitEntity.CollectionId) + .ToListAsync(ct); + var articles = await _context.Articles + .AsNoTracking() + .Where(m => m.CollectionId == exhibitEntity.CollectionId) + .ToListAsync(ct); + var teams = await _context.Teams + .AsNoTracking() + .Where(m => m.ExhibitId == exhibitEntity.Id) + .ToListAsync(ct); + var teamCards = await _context.TeamCards + .AsNoTracking() + .Where(m => m.Card.CollectionId == exhibitEntity.CollectionId && m.Team.ExhibitId == exhibitEntity.Id) + .ToListAsync(ct); + var teamArticles = await _context.TeamArticles + .AsNoTracking() + .Where(m => m.Article.CollectionId == exhibitEntity.CollectionId && m.Team.ExhibitId == exhibitEntity.Id) + .ToListAsync(ct); + var exhibitFileObject = new ExhibitFileFormat() { + Collection = collection, + Cards = cards, + Articles = articles, + Exhibit = exhibitEntity, + Teams = teams, + TeamCards = teamCards, + TeamArticles = teamArticles + }; + + return exhibitFileObject; + } + + private async Task privateExhibitCopyAsync(ExhibitFileFormat exhibitFileObject, bool copyTheCollection, CancellationToken ct) + { + var currentUserId = _user.GetId(); + var username = (await _context.Users.SingleOrDefaultAsync(u => u.Id == _user.GetId())).Name; + var dateCreated = DateTime.UtcNow; + var oldCollectionId = exhibitFileObject.Collection.Id; + var newCollectionId = Guid.NewGuid(); + var cardMap = new Dictionary(); + var articleMap = new Dictionary(); + if (copyTheCollection) + { + // copy the collection + exhibitFileObject.Collection.Id = newCollectionId; + exhibitFileObject.Collection.DateCreated = dateCreated; + exhibitFileObject.Collection.CreatedBy = currentUserId; + exhibitFileObject.Collection.DateModified = exhibitFileObject.Collection.DateCreated; + exhibitFileObject.Collection.ModifiedBy = exhibitFileObject.Collection.CreatedBy; + exhibitFileObject.Collection.Name = exhibitFileObject.Collection.Name + " - " + username; + await _context.Collections.AddAsync(exhibitFileObject.Collection, ct); + // copy cards + foreach (var cardEntity in exhibitFileObject.Cards) + { + cardMap[cardEntity.Id] = Guid.NewGuid(); + cardEntity.Id = cardMap[cardEntity.Id]; + cardEntity.CollectionId = exhibitFileObject.Collection.Id; + cardEntity.Collection = null; + cardEntity.DateCreated = exhibitFileObject.Collection.DateCreated; + cardEntity.CreatedBy = exhibitFileObject.Collection.CreatedBy; + await _context.Cards.AddAsync(cardEntity, ct); + } + // copy articles + foreach (var articleEntity in exhibitFileObject.Articles) + { + articleMap[articleEntity.Id] = Guid.NewGuid(); + articleEntity.Id = articleMap[articleEntity.Id]; + articleEntity.CollectionId = newCollectionId; + articleEntity.Collection = null; + articleEntity.CardId = articleEntity.CardId == null ? null : cardMap[(Guid)articleEntity.CardId]; + articleEntity.Card = null; + articleEntity.DateCreated = exhibitFileObject.Collection.DateCreated; + articleEntity.CreatedBy = exhibitFileObject.Collection.CreatedBy; + await _context.Articles.AddAsync(articleEntity, ct); + } + } + + var oldExhibitId = exhibitFileObject.Exhibit.Id; + var newExhibitId = Guid.NewGuid(); + exhibitFileObject.Exhibit.Id = newExhibitId; + exhibitFileObject.Exhibit.CollectionId = copyTheCollection ? newCollectionId : oldCollectionId; + exhibitFileObject.Exhibit.DateCreated = DateTime.UtcNow; + exhibitFileObject.Exhibit.CreatedBy = currentUserId; + exhibitFileObject.Exhibit.DateModified = exhibitFileObject.Exhibit.DateCreated; + exhibitFileObject.Exhibit.ModifiedBy = exhibitFileObject.Exhibit.CreatedBy; + exhibitFileObject.Exhibit.Teams = null; + exhibitFileObject.Exhibit.CurrentMove = 0; + exhibitFileObject.Exhibit.CurrentInject = 0; + exhibitFileObject.Exhibit.ScenarioId = null; + await _context.Exhibits.AddAsync(exhibitFileObject.Exhibit, ct); + // copy teams + var teamMap = new Dictionary(); + foreach (var team in exhibitFileObject.Teams) + { + teamMap[team.Id] = Guid.NewGuid(); + team.Id = teamMap[team.Id]; + team.ExhibitId = exhibitFileObject.Exhibit.Id; + team.Exhibit = null; + team.DateCreated = exhibitFileObject.Exhibit.DateCreated; + team.CreatedBy = exhibitFileObject.Exhibit.CreatedBy; + await _context.Teams.AddAsync(team, ct); + } + // copy team cards + foreach (var teamCard in exhibitFileObject.TeamCards) + { + teamCard.Id = Guid.NewGuid(); + teamCard.TeamId = teamMap[teamCard.TeamId]; + teamCard.Team = null; + teamCard.CardId = copyTheCollection ? cardMap[teamCard.CardId] : teamCard.CardId; + teamCard.Card = null; + teamCard.DateCreated = dateCreated; + teamCard.CreatedBy = currentUserId; + await _context.TeamCards.AddAsync(teamCard, ct); + } + // copy team articles + foreach (var teamArticle in exhibitFileObject.TeamArticles) + { + teamArticle.Id = Guid.NewGuid(); + teamArticle.ExhibitId = newExhibitId; + teamArticle.Exhibit = null; + teamArticle.TeamId = teamMap[teamArticle.TeamId]; + teamArticle.Team = null; + teamArticle.ArticleId = copyTheCollection ? articleMap[teamArticle.ArticleId] : teamArticle.ArticleId; + teamArticle.Article = null; + teamArticle.DateCreated = dateCreated; + teamArticle.CreatedBy = currentUserId; + await _context.TeamArticles.AddAsync(teamArticle, ct); + } + await _context.SaveChangesAsync(ct); + + // get the new Exhibit to return + var exhibitEntity = await _context.Exhibits + .SingleOrDefaultAsync(sm => sm.Id == exhibitFileObject.Exhibit.Id, ct); + + return exhibitEntity; + } + + public async Task> DownloadJsonAsync(Guid exhibitId, CancellationToken ct) + { + // user must be a Content Developer + if (!(await _authorizationService.AuthorizeAsync(_user, null, new ContentDeveloperRequirement())).Succeeded) + throw new ForbiddenException(); + + var exhibitFileObject = await BuildExhibitFileObject(exhibitId, ct); + var createdBy = (await _context.Users.SingleOrDefaultAsync(m => m.Id == exhibitFileObject.Exhibit.CreatedBy, ct)).Name; + var dateCreated = exhibitFileObject.Exhibit.DateCreated.ToString("-YYYYmmDD-"); + var exhibitJson = ""; + var options = new JsonSerializerOptions() + { + ReferenceHandler = ReferenceHandler.Preserve + }; + exhibitJson = JsonSerializer.Serialize(exhibitFileObject, options); + // convert string to stream + byte[] byteArray = Encoding.ASCII.GetBytes(exhibitJson); + MemoryStream memoryStream = new MemoryStream(byteArray); + var filename = exhibitFileObject.Collection.Name + dateCreated + createdBy + ".json"; + + return System.Tuple.Create(memoryStream, filename); + } + + public async Task UploadJsonAsync(FileForm form, CancellationToken ct) + { + // user must be a Content Developer + if (!(await _authorizationService.AuthorizeAsync(_user, null, new ContentDeveloperRequirement())).Succeeded) + throw new ForbiddenException(); + + var uploadItem = form.ToUpload; + var exhibitJson = ""; + using (StreamReader reader = new StreamReader(uploadItem.OpenReadStream())) + { + // convert stream to string + exhibitJson = reader.ReadToEnd(); + } + var options = new JsonSerializerOptions() + { + ReferenceHandler = ReferenceHandler.Preserve + }; + var exhibitFileObject = JsonSerializer.Deserialize(exhibitJson, options); + // make a copy and add it to the database + var exhibitEntity = await privateExhibitCopyAsync(exhibitFileObject, true, ct); + + return _mapper.Map(exhibitEntity); + } + public async Task UpdateAsync(Guid id, ViewModels.Exhibit exhibit, CancellationToken ct) { if (!(await _authorizationService.AuthorizeAsync(_user, null, new ContentDeveloperRequirement())).Succeeded) @@ -214,5 +432,15 @@ public async Task DeleteAsync(Guid id, CancellationToken ct) } } + class ExhibitFileFormat + { + public CollectionEntity Collection { get; set; } + public List Cards { get; set; } + public List Articles { get; set; } + public ExhibitEntity Exhibit { get; set; } + public List Teams { get; set; } + public List TeamCards { get; set; } + public List TeamArticles { get; set; } + } } diff --git a/Gallery.Api/ViewModels/FileForm.cs b/Gallery.Api/ViewModels/FileForm.cs new file mode 100644 index 0000000..5c9079d --- /dev/null +++ b/Gallery.Api/ViewModels/FileForm.cs @@ -0,0 +1,13 @@ +// Copyright 2024 Carnegie Mellon University. All Rights Reserved. +// Released under a MIT (SEI)-style license, please see LICENSE.md in the project root for license information or contact permission@sei.cmu.edu for full terms. + +using System; +using Microsoft.AspNetCore.Http; + +namespace Gallery.Api.ViewModels +{ + public class FileForm + { + public IFormFile ToUpload { get; set; } + } +} \ No newline at end of file diff --git a/Gallery.Api/appsettings.json b/Gallery.Api/appsettings.json index f032aba..ca70dbe 100755 --- a/Gallery.Api/appsettings.json +++ b/Gallery.Api/appsettings.json @@ -34,16 +34,16 @@ "SeedFile": "seed-data.json" }, "Authorization": { - "Authority": "http://localhost:5000", - "AuthorizationUrl": "http://localhost:5000/connect/authorize", - "TokenUrl": "http://localhost:5000/connect/token", + "Authority": "http://localhost:8080/realms/crucible", + "AuthorizationUrl": "http://localhost:8080/realms/crucible/protocol/openid-connect/auth", + "TokenUrl": "http://localhost:8080/realms/crucible/protocol/openid-connect/token", "AuthorizationScope": "gallery", - "ClientId": "gallery.swagger", - "ClientName": "Gallery Swagger UI", + "ClientId": "gallery-api", + "ClientName": "gallery-api", "ClientSecret": "", "RequireHttpsMetadata": false, "ValidateAudience": true, - "ValidAudiences": [] + "ValidAudiences": [] // Defaults to AuthorizationScope if null or empty }, "ClientSettings": { "SteamfitterApiUrl": "http://localhost:4400/", @@ -53,15 +53,15 @@ "Endpoint": "http://localhost/xapi", "Username": "", "Password": "", - "IssuerUrl": "http://localhost:5000", + "IssuerUrl": "http://localhost:8080/realms/crucible", "ApiUrl": "http://localhost:4722/api/", "UiUrl": "http://localhost:4723", "EmailDomain": "", "Platform": "Gallery" }, "ResourceOwnerAuthorization": { - "Authority": "http://localhost:5000", - "ClientId": "gallery.api", + "Authority": "http://localhost:8080/realms/crucible", + "ClientId": "gallery-admin", "ClientSecret": "", "UserName": "", "Password": "",