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 new API endpoints for file manager/consume page #63

Merged
merged 3 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
22 changes: 14 additions & 8 deletions src/Aquifer.API/Modules/Bibles/BibleResponse.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
namespace Aquifer.API.Modules.Bibles;

public class BibleBookResponse
public class BibleResponse
{
public int LanguageId { get; set; }
public int Id { get; set; }
public string Name { get; set; } = null!;
public string Abbreviation { get; set; } = null!;

public IEnumerable<BibleBookResponseContent> Contents { get; set; } =
new List<BibleBookResponseContent>();
public IEnumerable<BibleResponseBook> Books { get; set; } =
new List<BibleResponseBook>();
}

public class BibleBookResponseContent
public class BibleResponseBook
{
public int BookId { get; set; }
public string BookCode { get; set; }
public string DisplayName { get; set; } = null!;
public string TextUrl { get; set; } = null!;
public object? AudioUrls { get; set; }
public int TextSize { get; set; }
public int AudioSize { get; set; }
public int ChapterCount { get; set; }
}

public class BibleBookDetailsResponse : BibleResponseBook
{
public string TextUrl { get; set; } = null!;
public object? AudioUrls { get; set; }
}
68 changes: 52 additions & 16 deletions src/Aquifer.API/Modules/Bibles/BiblesModule.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Aquifer.API.Utilities;
using Aquifer.Data;
using Aquifer.Data;
using Aquifer.Data.Enums;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.EntityFrameworkCore;

Expand All @@ -10,31 +10,67 @@ public class BiblesModule : IModule
public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints)
{
var group = endpoints.MapGroup("bibles");
group.MapGet("language/{languageId:int}", GetBibleContentsByLanguage);
group.MapGet("language/{languageId:int}", GetBibleByLanguage);
group.MapGet("{bibleId:int}/book/{bookCode}", GetBibleBookDetails);

return endpoints;
}

private async Task<Ok<List<BibleBookResponse>>> GetBibleContentsByLanguage(int languageId,
private async Task<Ok<List<BibleResponse>>> GetBibleByLanguage(int languageId,
AquiferDbContext dbContext,
CancellationToken cancellationToken)
{
var bibles = await dbContext.Bibles.Where(x => x.LanguageId == languageId)
.Select(x => new BibleBookResponse
.Select(bible => new BibleResponse
{
LanguageId = x.LanguageId,
Name = x.Name,
Contents = x.BibleBookContents.Select(y => new BibleBookResponseContent
{
BookId = y.BookId,
DisplayName = y.DisplayName,
TextUrl = y.TextUrl,
TextSize = y.TextSize,
AudioUrls = JsonUtilities.DefaultSerialize(y.AudioUrls),
AudioSize = y.AudioSize
})
Name = bible.Name,
Abbreviation = bible.Abbreviation,
Id = bible.Id,
Books = bible.BibleBookContents.OrderBy(book => book.BookId).Select(book =>
new BibleResponseBook
{
BookCode = book.BookId.ToCode(),
DisplayName = book.DisplayName,
TextSize = book.TextSize,
AudioSize = book.AudioSize,
ChapterCount = book.ChapterCount
})
}).ToListAsync(cancellationToken);

return TypedResults.Ok(bibles);
}

private async Task<Results<Ok<BibleBookDetailsResponse>, NotFound>> GetBibleBookDetails(
int bibleId,
string bookCode,
AquiferDbContext dbContext,
CancellationToken cancellationToken)
{
var bookId = BookIdSerializer.FromCode(bookCode);
if (bookId == null)
{
return TypedResults.NotFound();
}

var book = await dbContext.BibleBookContents
.SingleOrDefaultAsync(b => b.BibleId == bibleId && b.BookId == bookId, cancellationToken);

if (book == null)
{
return TypedResults.NotFound();
}

var response = new BibleBookDetailsResponse
{
AudioSize = book.AudioSize,
AudioUrls = book.AudioUrls,
BookCode = book.BookId.ToCode(),
ChapterCount = book.ChapterCount,
DisplayName = book.DisplayName,
TextSize = book.TextSize,
TextUrl = book.TextUrl
};

return TypedResults.Ok(response);
}
}
43 changes: 0 additions & 43 deletions src/Aquifer.API/Modules/Passages/PassageResourcesResponse.cs

This file was deleted.

14 changes: 0 additions & 14 deletions src/Aquifer.API/Modules/Passages/PassageResponse.cs

This file was deleted.

144 changes: 93 additions & 51 deletions src/Aquifer.API/Modules/Passages/PassagesModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,67 +8,109 @@ namespace Aquifer.API.Modules.Passages;

public class PassagesModule : IModule
{
private static readonly ResourceEntityType[] AllowedResourceTypes = { ResourceEntityType.CBBTER };

public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints)
{
var group = endpoints.MapGroup("passages");
group.MapGet("/resources/language/{languageId:int}", GetPassageResourcesByLanguage);
group.MapGet("language/{languageId:int}/resource/{resourceType}", GetPassagesByLanguageAndResource);
group.MapGet("{passageId:int}/language/{languageId:int}", GetPassageDetailsForLanguage);
return endpoints;
}

public async Task<Ok<List<PassageResourcesResponse>>> GetPassageResourcesByLanguage(int languageId,
private async Task<Results<Ok<List<PassagesBookResponse>>, NotFound>> GetPassagesByLanguageAndResource(
int languageId,
ResourceEntityType resourceType,
AquiferDbContext dbContext,
CancellationToken cancellationToken)
{
if (!AllowedResourceTypes.Contains(resourceType))
{
return TypedResults.NotFound();
}

var passagesByBook = (await dbContext.Passages
.Where(p => p.PassageResources.Any(pr =>
pr.Resource.Type == resourceType &&
pr.Resource.ResourceContents.Any(rc => rc.LanguageId == languageId)))
.Select(passage =>
new PassagesResponsePassage
{
Id = passage.Id,
PassageStartDetails = BibleUtilities.TranslateVerseId(passage.StartVerseId),
PassageEndDetails = BibleUtilities.TranslateVerseId(passage.EndVerseId)
}
).ToListAsync(cancellationToken))
.GroupBy(passage => passage.BookId)
.Select(grouped => new PassagesBookResponse
{
BookId = grouped.Key, Passages = grouped.OrderBy(p => p.StartChapter).ThenBy(p => p.StartVerse)
})
.OrderBy(book => book.BookId).ToList();

return TypedResults.Ok(passagesByBook);
}

private async Task<Results<Ok<PassageDetailsResponse>, NotFound>> GetPassageDetailsForLanguage(
int passageId,
int languageId,
AquiferDbContext dbContext,
CancellationToken cancellationToken)
{
var passageContent = (await dbContext.Passages.Select(passage =>
new PassageResourcesResponse
var passage = await dbContext.Passages.FindAsync(passageId, cancellationToken);
if (passage == null)
{
return TypedResults.NotFound();
}

var passageResourceContent = await dbContext.PassageResources
// find all passages that overlap with the current passage
.Where(pr => (pr.Passage.StartVerseId >= passage.StartVerseId &&
pr.Passage.StartVerseId <= passage.EndVerseId) ||
(pr.Passage.EndVerseId >= passage.StartVerseId &&
pr.Passage.EndVerseId <= passage.EndVerseId))
.SelectMany(pr => pr.Resource.ResourceContents.Where(rc => rc.LanguageId == languageId).Select(rc =>
new PassageDetailsResponseContent
{
PassageStartDetails = BibleUtilities.TranslateVerseId(passage.StartVerseId),
PassageEndDetails = BibleUtilities.TranslateVerseId(passage.EndVerseId),
Resources = passage.PassageResources
.Where(pr => pr.Resource.Type != ResourceEntityType.TyndaleBibleDictionary)
.Select(passageResource =>
new PassageResourcesResponseResource
{
Type = (int)passageResource.Resource.Type,
MediaType = (int)passageResource.Resource.MediaType,
EnglishLabel = passageResource.Resource.EnglishLabel,
Tag = passageResource.Resource.Tag,
Content =
passageResource.Resource.ResourceContents
.Select(resourceContent =>
new PassageResourcesResponseResourceContent
{
LanguageId = resourceContent.LanguageId,
DisplayName = resourceContent.DisplayName,
Summary = resourceContent.Summary,
Content = JsonUtilities.DefaultSerialize(resourceContent.Content),
ContentSize = resourceContent.ContentSize
}).FirstOrDefault(content => content.LanguageId == languageId),
SupportingResources = passageResource.Resource.SupportingResources
.Where(sr => sr.Type != ResourceEntityType.TyndaleBibleDictionary)
.Select(
supportingResource => new PassageResourcesResponseResource
{
Type = (int)supportingResource.Type,
MediaType = (int)supportingResource.MediaType,
EnglishLabel = supportingResource.EnglishLabel,
Tag = supportingResource.Tag,
Content = supportingResource.ResourceContents.Select(resourceContent =>
new PassageResourcesResponseResourceContent
{
LanguageId = resourceContent.LanguageId,
DisplayName = resourceContent.DisplayName,
Summary = resourceContent.Summary,
Content =
JsonUtilities.DefaultSerialize(resourceContent.Content),
ContentSize = resourceContent.ContentSize
}).FirstOrDefault(content => content.LanguageId == languageId)
})
})
}).ToListAsync(cancellationToken))
.OrderBy(passage => passage.BookId)
.ThenBy(passage => passage.StartChapter).ThenBy(passage => passage.StartVerse).ToList();
ContentId = rc.Id,
ContentSize = rc.ContentSize,
MediaTypeName = rc.MediaType,
TypeName = pr.Resource.Type
}))
.ToListAsync(cancellationToken);

var verseResourceContent = await dbContext.VerseResources
// find all verses contained within the current passage
.Where(vr => vr.VerseId >= passage.StartVerseId && vr.VerseId <= passage.EndVerseId)
.SelectMany(vr => vr.Resource.ResourceContents.Where(rc => rc.LanguageId == languageId).Select(rc =>
new PassageDetailsResponseContent
{
ContentId = rc.Id,
ContentSize = rc.ContentSize,
MediaTypeName = rc.MediaType,
TypeName = vr.Resource.Type
}))
.ToListAsync(cancellationToken);

var supportingResourceContent = await dbContext.PassageResources.Where(pr => pr.PassageId == passageId)
.SelectMany(pr => pr.Resource.SupportingResources
.SelectMany(sr => sr.ResourceContents.Where(rc => rc.LanguageId == languageId)
.Select(rc => new PassageDetailsResponseContent
{
ContentId = rc.Id,
ContentSize = rc.ContentSize,
MediaTypeName = rc.MediaType,
TypeName = sr.Type
})))
.ToListAsync(cancellationToken);

return TypedResults.Ok(passageContent);
return TypedResults.Ok(new PassageDetailsResponse
{
Id = passage.Id,
PassageStartDetails = BibleUtilities.TranslateVerseId(passage.StartVerseId),
PassageEndDetails = BibleUtilities.TranslateVerseId(passage.EndVerseId),
Contents = passageResourceContent.Concat(verseResourceContent).Concat(supportingResourceContent)
.DistinctBy(rc => rc.ContentId)
});
MrGrinst marked this conversation as resolved.
Show resolved Hide resolved
}
}
39 changes: 39 additions & 0 deletions src/Aquifer.API/Modules/Passages/PassagesResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Aquifer.Data.Entities;
using System.Text.Json.Serialization;

namespace Aquifer.API.Modules.Passages;

public class PassagesBookResponse
{
public int BookId { get; set; }
public IEnumerable<PassagesResponsePassage> Passages { get; set; } = null!;
}

public class PassagesResponsePassage
{
public int Id { get; set; }
public int BookId => PassageStartDetails.BookId;
public int StartChapter => PassageStartDetails.Chapter;
public int EndChapter => PassageEndDetails.Chapter;
public int StartVerse => PassageStartDetails.Verse;
public int EndVerse => PassageEndDetails.Verse;

[JsonIgnore]
public (int BookId, int Chapter, int Verse) PassageStartDetails { get; set; }

[JsonIgnore]
public (int BookId, int Chapter, int Verse) PassageEndDetails { get; set; }
}

public class PassageDetailsResponse : PassagesResponsePassage
{
public IEnumerable<PassageDetailsResponseContent> Contents { get; set; } = null!;
}

public class PassageDetailsResponseContent
{
public int ContentId { get; set; }
public ResourceEntityType TypeName { get; set; }
public ResourceContentMediaType MediaTypeName { get; set; }
public int ContentSize { get; set; }
}
Loading