Simply entities & seperate endpoints
This commit is contained in:
parent
41faa30e6f
commit
6d4dfcda67
22 changed files with 299 additions and 615 deletions
|
|
@ -935,7 +935,7 @@ public class SeriesFilterTests : AbstractDbTest
|
||||||
var zeroRating = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(2);
|
var zeroRating = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(2);
|
||||||
Assert.NotNull(zeroRating);
|
Assert.NotNull(zeroRating);
|
||||||
|
|
||||||
Assert.True(await ratingService.UpdateRating(user, new UpdateRatingDto()
|
Assert.True(await ratingService.UpdateSeriesRating(user, new UpdateRatingDto()
|
||||||
{
|
{
|
||||||
SeriesId = zeroRating.Id,
|
SeriesId = zeroRating.Id,
|
||||||
UserRating = 0
|
UserRating = 0
|
||||||
|
|
@ -944,7 +944,7 @@ public class SeriesFilterTests : AbstractDbTest
|
||||||
// Select 4.5 Rating
|
// Select 4.5 Rating
|
||||||
var partialRating = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(3);
|
var partialRating = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(3);
|
||||||
|
|
||||||
Assert.True(await ratingService.UpdateRating(user, new UpdateRatingDto()
|
Assert.True(await ratingService.UpdateSeriesRating(user, new UpdateRatingDto()
|
||||||
{
|
{
|
||||||
SeriesId = partialRating.Id,
|
SeriesId = partialRating.Id,
|
||||||
UserRating = 4.5f
|
UserRating = 4.5f
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ public class RatingServiceTests: AbstractDbTest
|
||||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Ratings);
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Ratings);
|
||||||
|
|
||||||
JobStorage.Current = new InMemoryStorage();
|
JobStorage.Current = new InMemoryStorage();
|
||||||
var result = await _ratingService.UpdateRating(user, new UpdateRatingDto
|
var result = await _ratingService.UpdateSeriesRating(user, new UpdateRatingDto
|
||||||
{
|
{
|
||||||
SeriesId = 1,
|
SeriesId = 1,
|
||||||
UserRating = 3,
|
UserRating = 3,
|
||||||
|
|
@ -79,7 +79,7 @@ public class RatingServiceTests: AbstractDbTest
|
||||||
|
|
||||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Ratings);
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Ratings);
|
||||||
|
|
||||||
var result = await _ratingService.UpdateRating(user, new UpdateRatingDto
|
var result = await _ratingService.UpdateSeriesRating(user, new UpdateRatingDto
|
||||||
{
|
{
|
||||||
SeriesId = 1,
|
SeriesId = 1,
|
||||||
UserRating = 3,
|
UserRating = 3,
|
||||||
|
|
@ -95,7 +95,7 @@ public class RatingServiceTests: AbstractDbTest
|
||||||
|
|
||||||
// Update the DB again
|
// Update the DB again
|
||||||
|
|
||||||
var result2 = await _ratingService.UpdateRating(user, new UpdateRatingDto
|
var result2 = await _ratingService.UpdateSeriesRating(user, new UpdateRatingDto
|
||||||
{
|
{
|
||||||
SeriesId = 1,
|
SeriesId = 1,
|
||||||
UserRating = 5,
|
UserRating = 5,
|
||||||
|
|
@ -129,7 +129,7 @@ public class RatingServiceTests: AbstractDbTest
|
||||||
|
|
||||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Ratings);
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Ratings);
|
||||||
|
|
||||||
var result = await _ratingService.UpdateRating(user, new UpdateRatingDto
|
var result = await _ratingService.UpdateSeriesRating(user, new UpdateRatingDto
|
||||||
{
|
{
|
||||||
SeriesId = 1,
|
SeriesId = 1,
|
||||||
UserRating = 10,
|
UserRating = 10,
|
||||||
|
|
@ -164,7 +164,7 @@ public class RatingServiceTests: AbstractDbTest
|
||||||
|
|
||||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Ratings);
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Ratings);
|
||||||
|
|
||||||
var result = await _ratingService.UpdateRating(user, new UpdateRatingDto
|
var result = await _ratingService.UpdateSeriesRating(user, new UpdateRatingDto
|
||||||
{
|
{
|
||||||
SeriesId = 2,
|
SeriesId = 2,
|
||||||
UserRating = 5,
|
UserRating = 5,
|
||||||
|
|
|
||||||
|
|
@ -399,7 +399,7 @@ public class ChapterController : BaseApiController
|
||||||
|
|
||||||
|
|
||||||
[HttpGet("chapter-detail-plus")]
|
[HttpGet("chapter-detail-plus")]
|
||||||
public async Task<ChapterDetailPlusDto> ChapterDetailPlus([FromQuery] int chapterId)
|
public async Task<ActionResult<ChapterDetailPlusDto>> ChapterDetailPlus([FromQuery] int chapterId)
|
||||||
{
|
{
|
||||||
var ret = new ChapterDetailPlusDto();
|
var ret = new ChapterDetailPlusDto();
|
||||||
|
|
||||||
|
|
@ -415,11 +415,10 @@ public class ChapterController : BaseApiController
|
||||||
ret.HasBeenRated = ownRating.HasBeenRated;
|
ret.HasBeenRated = ownRating.HasBeenRated;
|
||||||
}
|
}
|
||||||
|
|
||||||
var externalMetadata = await _unitOfWork.ExternalChapterMetadataRepository.Get(chapterId);
|
var externalReviews = await _unitOfWork.ChapterRepository.GetExternalChapterReviews(chapterId);
|
||||||
if (externalMetadata != null && externalMetadata.ExternalReviews.Count > 0)
|
if (externalReviews.Count > 0)
|
||||||
{
|
{
|
||||||
var dtos = externalMetadata.ExternalReviews.Select(ex => _mapper.Map<UserReviewDto>(ex)).ToList();
|
userReviews.AddRange(ReviewHelper.SelectSpectrumOfReviews(externalReviews));
|
||||||
userReviews.AddRange(ReviewHelper.SelectSpectrumOfReviews(dtos));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.Reviews = userReviews;
|
ret.Reviews = userReviews;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using API.Constants;
|
|
||||||
using API.Data;
|
using API.Data;
|
||||||
using API.Data.Repositories;
|
using API.Data.Repositories;
|
||||||
using API.DTOs;
|
using API.DTOs;
|
||||||
using API.Extensions;
|
using API.Extensions;
|
||||||
using API.Services;
|
using API.Services;
|
||||||
using API.Services.Plus;
|
using API.Services.Plus;
|
||||||
using EasyCaching.Core;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace API.Controllers;
|
namespace API.Controllers;
|
||||||
|
|
||||||
|
|
@ -33,13 +28,19 @@ public class RatingController : BaseApiController
|
||||||
_localizationService = localizationService;
|
_localizationService = localizationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
/// <summary>
|
||||||
public async Task<ActionResult> UpdateRating(UpdateRatingDto updateRating)
|
/// Update the users' rating of the given series
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="updateRating"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="UnauthorizedAccessException"></exception>
|
||||||
|
[HttpPost("series")]
|
||||||
|
public async Task<ActionResult> UpdateSeriesRating(UpdateRatingDto updateRating)
|
||||||
{
|
{
|
||||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId(), AppUserIncludes.Ratings | AppUserIncludes.ChapterRatings);
|
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId(), AppUserIncludes.Ratings | AppUserIncludes.ChapterRatings);
|
||||||
if (user == null) throw new UnauthorizedAccessException();
|
if (user == null) throw new UnauthorizedAccessException();
|
||||||
|
|
||||||
if (await _ratingService.UpdateRating(user, updateRating))
|
if (await _ratingService.UpdateSeriesRating(user, updateRating))
|
||||||
{
|
{
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
@ -47,24 +48,44 @@ public class RatingController : BaseApiController
|
||||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-error"));
|
return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-error"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("overall")]
|
/// <summary>
|
||||||
public async Task<ActionResult<RatingDto>> GetOverallRating(int seriesId, [FromQuery] int? chapterId)
|
/// Update the users' rating of the given chapter
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="updateRating">chapterId must be set</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="UnauthorizedAccessException"></exception>
|
||||||
|
[HttpPost("chapter")]
|
||||||
|
public async Task<ActionResult> UpdateChapterRating(UpdateRatingDto updateRating)
|
||||||
{
|
{
|
||||||
int average;
|
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId(), AppUserIncludes.Ratings | AppUserIncludes.ChapterRatings);
|
||||||
if (chapterId != null)
|
if (user == null) throw new UnauthorizedAccessException();
|
||||||
|
|
||||||
|
if (await _ratingService.UpdateChapterRating(user, updateRating))
|
||||||
{
|
{
|
||||||
average = await _unitOfWork.ChapterRepository.GetAverageUserRating(chapterId.Value, User.GetUserId());
|
return Ok();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
average = await _unitOfWork.SeriesRepository.GetAverageUserRating(seriesId, User.GetUserId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-error"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("overall-series")]
|
||||||
|
public async Task<ActionResult<RatingDto>> GetOverallSeriesRating(int seriesId)
|
||||||
|
{
|
||||||
return Ok(new RatingDto()
|
return Ok(new RatingDto()
|
||||||
{
|
{
|
||||||
Provider = ScrobbleProvider.Kavita,
|
Provider = ScrobbleProvider.Kavita,
|
||||||
AverageScore = average,
|
AverageScore = await _unitOfWork.SeriesRepository.GetAverageUserRating(seriesId, User.GetUserId()),
|
||||||
|
FavoriteCount = 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("overall-chapter")]
|
||||||
|
public async Task<ActionResult<RatingDto>> GetOverallChapterRating(int chapterId)
|
||||||
|
{
|
||||||
|
return Ok(new RatingDto()
|
||||||
|
{
|
||||||
|
Provider = ScrobbleProvider.Kavita,
|
||||||
|
AverageScore = await _unitOfWork.ChapterRepository.GetAverageUserRating(chapterId, User.GetUserId()),
|
||||||
FavoriteCount = 0,
|
FavoriteCount = 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,39 +33,16 @@ public class ReviewController : BaseApiController
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the review for a given series, or chapter
|
/// Updates the user's review for a given series
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dto"></param>
|
/// <param name="dto"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpPost]
|
[HttpPost("series")]
|
||||||
public async Task<ActionResult<UserReviewDto>> UpdateReview(UpdateUserReviewDto dto)
|
public async Task<ActionResult<UserReviewDto>> UpdateSeriesReview(UpdateUserReviewDto dto)
|
||||||
{
|
{
|
||||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId(), AppUserIncludes.Ratings | AppUserIncludes.ChapterRatings);
|
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId(), AppUserIncludes.Ratings);
|
||||||
if (user == null) return Unauthorized();
|
if (user == null) return Unauthorized();
|
||||||
|
|
||||||
UserReviewDto review;
|
|
||||||
if (dto.ChapterId != null)
|
|
||||||
{
|
|
||||||
review = await UpdateChapterReview(user, dto, dto.ChapterId.Value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
review = await UpdateSeriesReview(user, dto);
|
|
||||||
}
|
|
||||||
_unitOfWork.UserRepository.Update(user);
|
|
||||||
|
|
||||||
await _unitOfWork.CommitAsync();
|
|
||||||
|
|
||||||
if (dto.ChapterId == null)
|
|
||||||
{
|
|
||||||
BackgroundJob.Enqueue(() =>
|
|
||||||
_scrobblingService.ScrobbleReviewUpdate(user.Id, dto.SeriesId, string.Empty, dto.Body));
|
|
||||||
}
|
|
||||||
return Ok(review);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<UserReviewDto> UpdateSeriesReview(AppUser user, UpdateUserReviewDto dto)
|
|
||||||
{
|
|
||||||
var ratingBuilder = new RatingBuilder(await _unitOfWork.UserRepository.GetUserRatingAsync(dto.SeriesId, user.Id));
|
var ratingBuilder = new RatingBuilder(await _unitOfWork.UserRepository.GetUserRatingAsync(dto.SeriesId, user.Id));
|
||||||
|
|
||||||
var rating = ratingBuilder
|
var rating = ratingBuilder
|
||||||
|
|
@ -78,11 +55,31 @@ public class ReviewController : BaseApiController
|
||||||
{
|
{
|
||||||
user.Ratings.Add(rating);
|
user.Ratings.Add(rating);
|
||||||
}
|
}
|
||||||
return _mapper.Map<UserReviewDto>(rating);
|
|
||||||
|
_unitOfWork.UserRepository.Update(user);
|
||||||
|
|
||||||
|
await _unitOfWork.CommitAsync();
|
||||||
|
|
||||||
|
BackgroundJob.Enqueue(() =>
|
||||||
|
_scrobblingService.ScrobbleReviewUpdate(user.Id, dto.SeriesId, string.Empty, dto.Body));
|
||||||
|
return Ok(_mapper.Map<UserReviewDto>(rating));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<UserReviewDto> UpdateChapterReview(AppUser user, UpdateUserReviewDto dto, int chapterId)
|
/// <summary>
|
||||||
|
/// Update the user's review for a given chapter
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dto">chapterId must be set</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("chapter")]
|
||||||
|
public async Task<ActionResult<UserReviewDto>> UpdateChapterReview(UpdateUserReviewDto dto)
|
||||||
{
|
{
|
||||||
|
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId(), AppUserIncludes.ChapterRatings);
|
||||||
|
if (user == null) return Unauthorized();
|
||||||
|
|
||||||
|
if (dto.ChapterId == null) return BadRequest();
|
||||||
|
|
||||||
|
int chapterId = dto.ChapterId.Value;
|
||||||
|
|
||||||
var ratingBuilder = new ChapterRatingBuilder(await _unitOfWork.UserRepository.GetUserChapterRatingAsync(user.Id, chapterId));
|
var ratingBuilder = new ChapterRatingBuilder(await _unitOfWork.UserRepository.GetUserChapterRatingAsync(user.Id, chapterId));
|
||||||
|
|
||||||
var rating = ratingBuilder
|
var rating = ratingBuilder
|
||||||
|
|
@ -95,28 +92,45 @@ public class ReviewController : BaseApiController
|
||||||
{
|
{
|
||||||
user.ChapterRatings.Add(rating);
|
user.ChapterRatings.Add(rating);
|
||||||
}
|
}
|
||||||
return _mapper.Map<UserReviewDto>(rating);
|
|
||||||
|
_unitOfWork.UserRepository.Update(user);
|
||||||
|
|
||||||
|
await _unitOfWork.CommitAsync();
|
||||||
|
|
||||||
|
return Ok(_mapper.Map<UserReviewDto>(rating));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deletes the user's review for the given series, or chapter
|
/// Deletes the user's review for the given series
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpDelete]
|
[HttpDelete("series")]
|
||||||
public async Task<ActionResult> DeleteReview([FromQuery] int seriesId, [FromQuery] int? chapterId)
|
public async Task<ActionResult> DeleteSeriesReview([FromQuery] int seriesId)
|
||||||
{
|
{
|
||||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId(), AppUserIncludes.Ratings);
|
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId(), AppUserIncludes.Ratings);
|
||||||
if (user == null) return Unauthorized();
|
if (user == null) return Unauthorized();
|
||||||
|
|
||||||
if (chapterId != null)
|
user.Ratings = user.Ratings.Where(r => r.SeriesId != seriesId).ToList();
|
||||||
{
|
|
||||||
user.ChapterRatings = user.ChapterRatings.Where(r => r.ChapterId != chapterId).ToList();
|
_unitOfWork.UserRepository.Update(user);
|
||||||
}
|
|
||||||
else
|
await _unitOfWork.CommitAsync();
|
||||||
{
|
|
||||||
user.Ratings = user.Ratings.Where(r => r.SeriesId != seriesId).ToList();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes the user's review for the given chapter
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpDelete("chapter")]
|
||||||
|
public async Task<ActionResult> DeleteChapterReview([FromQuery] int chapterId)
|
||||||
|
{
|
||||||
|
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId(), AppUserIncludes.ChapterRatings);
|
||||||
|
if (user == null) return Unauthorized();
|
||||||
|
|
||||||
|
user.ChapterRatings = user.ChapterRatings.Where(r => r.ChapterId != chapterId).ToList();
|
||||||
|
|
||||||
_unitOfWork.UserRepository.Update(user);
|
_unitOfWork.UserRepository.Update(user);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,8 +79,6 @@ public sealed class DataContext : IdentityDbContext<AppUser, AppRole, int,
|
||||||
public DbSet<MetadataSettings> MetadataSettings { get; set; } = null!;
|
public DbSet<MetadataSettings> MetadataSettings { get; set; } = null!;
|
||||||
public DbSet<MetadataFieldMapping> MetadataFieldMapping { get; set; } = null!;
|
public DbSet<MetadataFieldMapping> MetadataFieldMapping { get; set; } = null!;
|
||||||
public DbSet<AppUserChapterRating> AppUserChapterRating { get; set; } = null!;
|
public DbSet<AppUserChapterRating> AppUserChapterRating { get; set; } = null!;
|
||||||
public DbSet<ExternalChapterReview> ExternalChapterReview { get; set; } = null!;
|
|
||||||
public DbSet<ExternalChapterMetadata> ExternalChapterMetadata { get; set; } = null!;
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder builder)
|
protected override void OnModelCreating(ModelBuilder builder)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,159 +0,0 @@
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace API.Data.Migrations
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public partial class ChapterRating : Migration
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "AppUserChapterRating",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
|
||||||
.Annotation("Sqlite:Autoincrement", true),
|
|
||||||
Rating = table.Column<float>(type: "REAL", nullable: false),
|
|
||||||
HasBeenRated = table.Column<bool>(type: "INTEGER", nullable: false),
|
|
||||||
Review = table.Column<string>(type: "TEXT", nullable: true),
|
|
||||||
SeriesId = table.Column<int>(type: "INTEGER", nullable: false),
|
|
||||||
ChapterId = table.Column<int>(type: "INTEGER", nullable: false),
|
|
||||||
AppUserId = table.Column<int>(type: "INTEGER", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_AppUserChapterRating", x => x.Id);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_AppUserChapterRating_AspNetUsers_AppUserId",
|
|
||||||
column: x => x.AppUserId,
|
|
||||||
principalTable: "AspNetUsers",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_AppUserChapterRating_Chapter_ChapterId",
|
|
||||||
column: x => x.ChapterId,
|
|
||||||
principalTable: "Chapter",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_AppUserChapterRating_Series_SeriesId",
|
|
||||||
column: x => x.SeriesId,
|
|
||||||
principalTable: "Series",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "ExternalChapterMetadata",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
|
||||||
.Annotation("Sqlite:Autoincrement", true),
|
|
||||||
ChapterId = table.Column<int>(type: "INTEGER", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_ExternalChapterMetadata", x => x.Id);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_ExternalChapterMetadata_Chapter_ChapterId",
|
|
||||||
column: x => x.ChapterId,
|
|
||||||
principalTable: "Chapter",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "ExternalChapterReview",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
|
||||||
.Annotation("Sqlite:Autoincrement", true),
|
|
||||||
Tagline = table.Column<string>(type: "TEXT", nullable: true),
|
|
||||||
Body = table.Column<string>(type: "TEXT", nullable: true),
|
|
||||||
BodyJustText = table.Column<string>(type: "TEXT", nullable: true),
|
|
||||||
RawBody = table.Column<string>(type: "TEXT", nullable: true),
|
|
||||||
Provider = table.Column<int>(type: "INTEGER", nullable: false),
|
|
||||||
Authority = table.Column<int>(type: "INTEGER", nullable: false),
|
|
||||||
SiteUrl = table.Column<string>(type: "TEXT", nullable: true),
|
|
||||||
Username = table.Column<string>(type: "TEXT", nullable: true),
|
|
||||||
Rating = table.Column<int>(type: "INTEGER", nullable: false),
|
|
||||||
Score = table.Column<int>(type: "INTEGER", nullable: false),
|
|
||||||
TotalVotes = table.Column<int>(type: "INTEGER", nullable: false),
|
|
||||||
ChapterId = table.Column<int>(type: "INTEGER", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_ExternalChapterReview", x => x.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "ExternalChapterMetadataExternalChapterReview",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
ExternalChapterMetadatasId = table.Column<int>(type: "INTEGER", nullable: false),
|
|
||||||
ExternalReviewsId = table.Column<int>(type: "INTEGER", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_ExternalChapterMetadataExternalChapterReview", x => new { x.ExternalChapterMetadatasId, x.ExternalReviewsId });
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_ExternalChapterMetadataExternalChapterReview_ExternalChapterMetadata_ExternalChapterMetadatasId",
|
|
||||||
column: x => x.ExternalChapterMetadatasId,
|
|
||||||
principalTable: "ExternalChapterMetadata",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_ExternalChapterMetadataExternalChapterReview_ExternalChapterReview_ExternalReviewsId",
|
|
||||||
column: x => x.ExternalReviewsId,
|
|
||||||
principalTable: "ExternalChapterReview",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AppUserChapterRating_AppUserId",
|
|
||||||
table: "AppUserChapterRating",
|
|
||||||
column: "AppUserId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AppUserChapterRating_ChapterId",
|
|
||||||
table: "AppUserChapterRating",
|
|
||||||
column: "ChapterId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AppUserChapterRating_SeriesId",
|
|
||||||
table: "AppUserChapterRating",
|
|
||||||
column: "SeriesId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_ExternalChapterMetadata_ChapterId",
|
|
||||||
table: "ExternalChapterMetadata",
|
|
||||||
column: "ChapterId",
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_ExternalChapterMetadataExternalChapterReview_ExternalReviewsId",
|
|
||||||
table: "ExternalChapterMetadataExternalChapterReview",
|
|
||||||
column: "ExternalReviewsId");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "AppUserChapterRating");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "ExternalChapterMetadataExternalChapterReview");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "ExternalChapterMetadata");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "ExternalChapterReview");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -11,7 +11,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
namespace API.Data.Migrations
|
namespace API.Data.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(DataContext))]
|
[DbContext(typeof(DataContext))]
|
||||||
[Migration("20250428151027_ChapterRating")]
|
[Migration("20250428180534_ChapterRating")]
|
||||||
partial class ChapterRating
|
partial class ChapterRating
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -1348,70 +1348,6 @@ namespace API.Data.Migrations
|
||||||
b.ToTable("MediaError");
|
b.ToTable("MediaError");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("API.Entities.Metadata.ExternalChapterMetadata", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("ChapterId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("ChapterId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("ExternalChapterMetadata");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("API.Entities.Metadata.ExternalChapterReview", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("Authority")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Body")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("BodyJustText")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("ChapterId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("Provider")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("Rating")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("RawBody")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("Score")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("SiteUrl")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("Tagline")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("TotalVotes")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Username")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.ToTable("ExternalChapterReview");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("API.Entities.Metadata.ExternalRating", b =>
|
modelBuilder.Entity("API.Entities.Metadata.ExternalRating", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
|
|
@ -1481,12 +1417,18 @@ namespace API.Data.Migrations
|
||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Authority")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<string>("Body")
|
b.Property<string>("Body")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<string>("BodyJustText")
|
b.Property<string>("BodyJustText")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("ChapterId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<int>("Provider")
|
b.Property<int>("Provider")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
|
@ -1516,6 +1458,8 @@ namespace API.Data.Migrations
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ChapterId");
|
||||||
|
|
||||||
b.ToTable("ExternalReview");
|
b.ToTable("ExternalReview");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -2550,21 +2494,6 @@ namespace API.Data.Migrations
|
||||||
b.ToTable("CollectionTagSeriesMetadata");
|
b.ToTable("CollectionTagSeriesMetadata");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("ExternalChapterMetadataExternalChapterReview", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("ExternalChapterMetadatasId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("ExternalReviewsId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.HasKey("ExternalChapterMetadatasId", "ExternalReviewsId");
|
|
||||||
|
|
||||||
b.HasIndex("ExternalReviewsId");
|
|
||||||
|
|
||||||
b.ToTable("ExternalChapterMetadataExternalChapterReview");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("ExternalRatingExternalSeriesMetadata", b =>
|
modelBuilder.Entity("ExternalRatingExternalSeriesMetadata", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("ExternalRatingsId")
|
b.Property<int>("ExternalRatingsId")
|
||||||
|
|
@ -3049,13 +2978,11 @@ namespace API.Data.Migrations
|
||||||
b.Navigation("Chapter");
|
b.Navigation("Chapter");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("API.Entities.Metadata.ExternalChapterMetadata", b =>
|
modelBuilder.Entity("API.Entities.Metadata.ExternalReview", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("API.Entities.Chapter", null)
|
b.HasOne("API.Entities.Chapter", null)
|
||||||
.WithOne("ExternalChapterMetadata")
|
.WithMany("ExternalReviews")
|
||||||
.HasForeignKey("API.Entities.Metadata.ExternalChapterMetadata", "ChapterId")
|
.HasForeignKey("ChapterId");
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("API.Entities.Metadata.ExternalSeriesMetadata", b =>
|
modelBuilder.Entity("API.Entities.Metadata.ExternalSeriesMetadata", b =>
|
||||||
|
|
@ -3365,21 +3292,6 @@ namespace API.Data.Migrations
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("ExternalChapterMetadataExternalChapterReview", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("API.Entities.Metadata.ExternalChapterMetadata", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("ExternalChapterMetadatasId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.HasOne("API.Entities.Metadata.ExternalChapterReview", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("ExternalReviewsId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("ExternalRatingExternalSeriesMetadata", b =>
|
modelBuilder.Entity("ExternalRatingExternalSeriesMetadata", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("API.Entities.Metadata.ExternalRating", null)
|
b.HasOne("API.Entities.Metadata.ExternalRating", null)
|
||||||
|
|
@ -3533,7 +3445,7 @@ namespace API.Data.Migrations
|
||||||
|
|
||||||
modelBuilder.Entity("API.Entities.Chapter", b =>
|
modelBuilder.Entity("API.Entities.Chapter", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("ExternalChapterMetadata");
|
b.Navigation("ExternalReviews");
|
||||||
|
|
||||||
b.Navigation("Files");
|
b.Navigation("Files");
|
||||||
|
|
||||||
113
API/Data/Migrations/20250428180534_ChapterRating.cs
Normal file
113
API/Data/Migrations/20250428180534_ChapterRating.cs
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace API.Data.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class ChapterRating : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "Authority",
|
||||||
|
table: "ExternalReview",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "ChapterId",
|
||||||
|
table: "ExternalReview",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AppUserChapterRating",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Rating = table.Column<float>(type: "REAL", nullable: false),
|
||||||
|
HasBeenRated = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
Review = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
SeriesId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
ChapterId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
AppUserId = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AppUserChapterRating", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AppUserChapterRating_AspNetUsers_AppUserId",
|
||||||
|
column: x => x.AppUserId,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AppUserChapterRating_Chapter_ChapterId",
|
||||||
|
column: x => x.ChapterId,
|
||||||
|
principalTable: "Chapter",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AppUserChapterRating_Series_SeriesId",
|
||||||
|
column: x => x.SeriesId,
|
||||||
|
principalTable: "Series",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ExternalReview_ChapterId",
|
||||||
|
table: "ExternalReview",
|
||||||
|
column: "ChapterId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AppUserChapterRating_AppUserId",
|
||||||
|
table: "AppUserChapterRating",
|
||||||
|
column: "AppUserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AppUserChapterRating_ChapterId",
|
||||||
|
table: "AppUserChapterRating",
|
||||||
|
column: "ChapterId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AppUserChapterRating_SeriesId",
|
||||||
|
table: "AppUserChapterRating",
|
||||||
|
column: "SeriesId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ExternalReview_Chapter_ChapterId",
|
||||||
|
table: "ExternalReview",
|
||||||
|
column: "ChapterId",
|
||||||
|
principalTable: "Chapter",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ExternalReview_Chapter_ChapterId",
|
||||||
|
table: "ExternalReview");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AppUserChapterRating");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_ExternalReview_ChapterId",
|
||||||
|
table: "ExternalReview");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Authority",
|
||||||
|
table: "ExternalReview");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ChapterId",
|
||||||
|
table: "ExternalReview");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1345,70 +1345,6 @@ namespace API.Data.Migrations
|
||||||
b.ToTable("MediaError");
|
b.ToTable("MediaError");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("API.Entities.Metadata.ExternalChapterMetadata", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("ChapterId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("ChapterId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("ExternalChapterMetadata");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("API.Entities.Metadata.ExternalChapterReview", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("Authority")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Body")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("BodyJustText")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("ChapterId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("Provider")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("Rating")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("RawBody")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("Score")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("SiteUrl")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("Tagline")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("TotalVotes")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Username")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.ToTable("ExternalChapterReview");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("API.Entities.Metadata.ExternalRating", b =>
|
modelBuilder.Entity("API.Entities.Metadata.ExternalRating", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
|
|
@ -1478,12 +1414,18 @@ namespace API.Data.Migrations
|
||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Authority")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<string>("Body")
|
b.Property<string>("Body")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<string>("BodyJustText")
|
b.Property<string>("BodyJustText")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("ChapterId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<int>("Provider")
|
b.Property<int>("Provider")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
|
@ -1513,6 +1455,8 @@ namespace API.Data.Migrations
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ChapterId");
|
||||||
|
|
||||||
b.ToTable("ExternalReview");
|
b.ToTable("ExternalReview");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -2547,21 +2491,6 @@ namespace API.Data.Migrations
|
||||||
b.ToTable("CollectionTagSeriesMetadata");
|
b.ToTable("CollectionTagSeriesMetadata");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("ExternalChapterMetadataExternalChapterReview", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("ExternalChapterMetadatasId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("ExternalReviewsId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.HasKey("ExternalChapterMetadatasId", "ExternalReviewsId");
|
|
||||||
|
|
||||||
b.HasIndex("ExternalReviewsId");
|
|
||||||
|
|
||||||
b.ToTable("ExternalChapterMetadataExternalChapterReview");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("ExternalRatingExternalSeriesMetadata", b =>
|
modelBuilder.Entity("ExternalRatingExternalSeriesMetadata", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("ExternalRatingsId")
|
b.Property<int>("ExternalRatingsId")
|
||||||
|
|
@ -3046,13 +2975,11 @@ namespace API.Data.Migrations
|
||||||
b.Navigation("Chapter");
|
b.Navigation("Chapter");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("API.Entities.Metadata.ExternalChapterMetadata", b =>
|
modelBuilder.Entity("API.Entities.Metadata.ExternalReview", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("API.Entities.Chapter", null)
|
b.HasOne("API.Entities.Chapter", null)
|
||||||
.WithOne("ExternalChapterMetadata")
|
.WithMany("ExternalReviews")
|
||||||
.HasForeignKey("API.Entities.Metadata.ExternalChapterMetadata", "ChapterId")
|
.HasForeignKey("ChapterId");
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("API.Entities.Metadata.ExternalSeriesMetadata", b =>
|
modelBuilder.Entity("API.Entities.Metadata.ExternalSeriesMetadata", b =>
|
||||||
|
|
@ -3362,21 +3289,6 @@ namespace API.Data.Migrations
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("ExternalChapterMetadataExternalChapterReview", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("API.Entities.Metadata.ExternalChapterMetadata", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("ExternalChapterMetadatasId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.HasOne("API.Entities.Metadata.ExternalChapterReview", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("ExternalReviewsId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("ExternalRatingExternalSeriesMetadata", b =>
|
modelBuilder.Entity("ExternalRatingExternalSeriesMetadata", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("API.Entities.Metadata.ExternalRating", null)
|
b.HasOne("API.Entities.Metadata.ExternalRating", null)
|
||||||
|
|
@ -3530,7 +3442,7 @@ namespace API.Data.Migrations
|
||||||
|
|
||||||
modelBuilder.Entity("API.Entities.Chapter", b =>
|
modelBuilder.Entity("API.Entities.Chapter", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("ExternalChapterMetadata");
|
b.Navigation("ExternalReviews");
|
||||||
|
|
||||||
b.Navigation("Files");
|
b.Navigation("Files");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||||
using API.DTOs;
|
using API.DTOs;
|
||||||
using API.DTOs.Metadata;
|
using API.DTOs.Metadata;
|
||||||
using API.DTOs.Reader;
|
using API.DTOs.Reader;
|
||||||
|
using API.DTOs.SeriesDetail;
|
||||||
using API.Entities;
|
using API.Entities;
|
||||||
using API.Entities.Enums;
|
using API.Entities.Enums;
|
||||||
using API.Extensions;
|
using API.Extensions;
|
||||||
|
|
@ -24,7 +25,8 @@ public enum ChapterIncludes
|
||||||
Files = 4,
|
Files = 4,
|
||||||
People = 8,
|
People = 8,
|
||||||
Genres = 16,
|
Genres = 16,
|
||||||
Tags = 32
|
Tags = 32,
|
||||||
|
ExternalReviews = 1 << 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IChapterRepository
|
public interface IChapterRepository
|
||||||
|
|
@ -49,6 +51,7 @@ public interface IChapterRepository
|
||||||
IEnumerable<Chapter> GetChaptersForSeries(int seriesId);
|
IEnumerable<Chapter> GetChaptersForSeries(int seriesId);
|
||||||
Task<IList<Chapter>> GetAllChaptersForSeries(int seriesId);
|
Task<IList<Chapter>> GetAllChaptersForSeries(int seriesId);
|
||||||
Task<int> GetAverageUserRating(int chapterId, int userId);
|
Task<int> GetAverageUserRating(int chapterId, int userId);
|
||||||
|
Task<IList<UserReviewDto>> GetExternalChapterReviews(int chapterId);
|
||||||
}
|
}
|
||||||
public class ChapterRepository : IChapterRepository
|
public class ChapterRepository : IChapterRepository
|
||||||
{
|
{
|
||||||
|
|
@ -327,4 +330,14 @@ public class ChapterRepository : IChapterRepository
|
||||||
.AverageAsync(r => (int?) r.Rating));
|
.AverageAsync(r => (int?) r.Rating));
|
||||||
return avg.HasValue ? (int) (avg.Value * 20) : 0;
|
return avg.HasValue ? (int) (avg.Value * 20) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IList<UserReviewDto>> GetExternalChapterReviews(int chapterId)
|
||||||
|
{
|
||||||
|
return await _context.Chapter
|
||||||
|
.Where(c => c.Id == chapterId)
|
||||||
|
.SelectMany(c => c.ExternalReviews)
|
||||||
|
// Don't use ProjectTo, it fails to map int to float (??)
|
||||||
|
.Select(r => _mapper.Map<UserReviewDto>(r))
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
#nullable enable
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using API.Entities.Metadata;
|
|
||||||
using API.Extensions.QueryExtensions;
|
|
||||||
using AutoMapper;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace API.Data.Repositories;
|
|
||||||
|
|
||||||
public enum ExternalChapterMetadataIncludes
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
ExternalReviews = 1 << 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IExternalChapterMetadataRepository
|
|
||||||
{
|
|
||||||
void Attach(ExternalChapterMetadata externalChapterMetadata);
|
|
||||||
void Remove(IEnumerable<ExternalChapterReview>? reviews);
|
|
||||||
|
|
||||||
Task<ExternalChapterMetadata?> Get(int chapterId, ExternalChapterMetadataIncludes includes = ExternalChapterMetadataIncludes.ExternalReviews);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ExternalChapterMetadataRepository(DataContext context, IMapper mapper): IExternalChapterMetadataRepository
|
|
||||||
{
|
|
||||||
|
|
||||||
public void Attach(ExternalChapterMetadata externalChapterMetadata)
|
|
||||||
{
|
|
||||||
context.ExternalChapterMetadata.Attach(externalChapterMetadata);
|
|
||||||
}
|
|
||||||
public void Remove(IEnumerable<ExternalChapterReview>? reviews)
|
|
||||||
{
|
|
||||||
if (reviews == null) return;
|
|
||||||
context.ExternalChapterReview.RemoveRange(reviews);
|
|
||||||
|
|
||||||
}
|
|
||||||
public async Task<ExternalChapterMetadata?> Get(int chapterId, ExternalChapterMetadataIncludes includes = ExternalChapterMetadataIncludes.ExternalReviews)
|
|
||||||
{
|
|
||||||
return await context.ExternalChapterMetadata
|
|
||||||
.Includes(includes)
|
|
||||||
.FirstOrDefaultAsync(c => c.ChapterId == chapterId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -33,7 +33,6 @@ public interface IUnitOfWork
|
||||||
IAppUserExternalSourceRepository AppUserExternalSourceRepository { get; }
|
IAppUserExternalSourceRepository AppUserExternalSourceRepository { get; }
|
||||||
IExternalSeriesMetadataRepository ExternalSeriesMetadataRepository { get; }
|
IExternalSeriesMetadataRepository ExternalSeriesMetadataRepository { get; }
|
||||||
IEmailHistoryRepository EmailHistoryRepository { get; }
|
IEmailHistoryRepository EmailHistoryRepository { get; }
|
||||||
IExternalChapterMetadataRepository ExternalChapterMetadataRepository { get; }
|
|
||||||
bool Commit();
|
bool Commit();
|
||||||
Task<bool> CommitAsync();
|
Task<bool> CommitAsync();
|
||||||
bool HasChanges();
|
bool HasChanges();
|
||||||
|
|
@ -75,7 +74,6 @@ public class UnitOfWork : IUnitOfWork
|
||||||
AppUserExternalSourceRepository = new AppUserExternalSourceRepository(_context, _mapper);
|
AppUserExternalSourceRepository = new AppUserExternalSourceRepository(_context, _mapper);
|
||||||
ExternalSeriesMetadataRepository = new ExternalSeriesMetadataRepository(_context, _mapper);
|
ExternalSeriesMetadataRepository = new ExternalSeriesMetadataRepository(_context, _mapper);
|
||||||
EmailHistoryRepository = new EmailHistoryRepository(_context, _mapper);
|
EmailHistoryRepository = new EmailHistoryRepository(_context, _mapper);
|
||||||
ExternalChapterMetadataRepository = new ExternalChapterMetadataRepository(_context, _mapper);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -105,7 +103,6 @@ public class UnitOfWork : IUnitOfWork
|
||||||
public IAppUserExternalSourceRepository AppUserExternalSourceRepository { get; }
|
public IAppUserExternalSourceRepository AppUserExternalSourceRepository { get; }
|
||||||
public IExternalSeriesMetadataRepository ExternalSeriesMetadataRepository { get; }
|
public IExternalSeriesMetadataRepository ExternalSeriesMetadataRepository { get; }
|
||||||
public IEmailHistoryRepository EmailHistoryRepository { get; }
|
public IEmailHistoryRepository EmailHistoryRepository { get; }
|
||||||
public IExternalChapterMetadataRepository ExternalChapterMetadataRepository { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Commits changes to the DB. Completes the open transaction.
|
/// Commits changes to the DB. Completes the open transaction.
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,7 @@ public class Chapter : IEntityDate, IHasReadTimeEstimate, IHasCoverImage
|
||||||
public Volume Volume { get; set; } = null!;
|
public Volume Volume { get; set; } = null!;
|
||||||
public int VolumeId { get; set; }
|
public int VolumeId { get; set; }
|
||||||
|
|
||||||
public ExternalChapterMetadata ExternalChapterMetadata { get; set; } = null!;
|
public ICollection<ExternalReview> ExternalReviews { get; set; } = [];
|
||||||
|
|
||||||
public void UpdateFrom(ParserInfo info)
|
public void UpdateFrom(ParserInfo info)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace API.Entities.Metadata;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// External Metadata from Kavita+ for a Chapter
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// As apposed to <see cref="ExternalSeriesMetadata"/>,
|
|
||||||
/// we do not have a ValidUntilUtc, as this is only matched together with the series.
|
|
||||||
/// </remarks>
|
|
||||||
public class ExternalChapterMetadata
|
|
||||||
{
|
|
||||||
public int Id { get; set; }
|
|
||||||
|
|
||||||
public int ChapterId { get; set; }
|
|
||||||
|
|
||||||
public ICollection<ExternalChapterReview> ExternalReviews { get; set; } = null!;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using API.Entities.Enums;
|
|
||||||
using API.Services.Plus;
|
|
||||||
|
|
||||||
namespace API.Entities.Metadata;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents an Externally supplied Review for a given Series
|
|
||||||
/// </summary>
|
|
||||||
public class ExternalChapterReview
|
|
||||||
{
|
|
||||||
public int Id { get; set; }
|
|
||||||
public string Tagline { get; set; }
|
|
||||||
public required string Body { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// Pure text version of the body
|
|
||||||
/// </summary>
|
|
||||||
public required string BodyJustText { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// Raw from the provider. Usually Markdown
|
|
||||||
/// </summary>
|
|
||||||
public string RawBody { get; set; }
|
|
||||||
public required ScrobbleProvider Provider { get; set; }
|
|
||||||
public RatingAuthority Authority { get; set; } = RatingAuthority.User;
|
|
||||||
public string SiteUrl { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// Reviewer's username
|
|
||||||
/// </summary>
|
|
||||||
public string Username { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// An Optional Rating coming from the Review
|
|
||||||
/// </summary>
|
|
||||||
public int Rating { get; set; } = 0;
|
|
||||||
/// <summary>
|
|
||||||
/// The media's overall Score
|
|
||||||
/// </summary>
|
|
||||||
public int Score { get; set; }
|
|
||||||
public int TotalVotes { get; set; }
|
|
||||||
|
|
||||||
public int ChapterId { get; set; }
|
|
||||||
|
|
||||||
// Relationships
|
|
||||||
public ICollection<ExternalChapterMetadata> ExternalChapterMetadatas { get; set; } = null!;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using API.Entities.Enums;
|
||||||
using API.Services.Plus;
|
using API.Services.Plus;
|
||||||
|
|
||||||
namespace API.Entities.Metadata;
|
namespace API.Entities.Metadata;
|
||||||
|
|
@ -20,6 +21,7 @@ public class ExternalReview
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string RawBody { get; set; }
|
public string RawBody { get; set; }
|
||||||
public required ScrobbleProvider Provider { get; set; }
|
public required ScrobbleProvider Provider { get; set; }
|
||||||
|
public RatingAuthority Authority { get; set; } = RatingAuthority.User;
|
||||||
public string SiteUrl { get; set; }
|
public string SiteUrl { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reviewer's username
|
/// Reviewer's username
|
||||||
|
|
@ -37,6 +39,7 @@ public class ExternalReview
|
||||||
|
|
||||||
|
|
||||||
public int SeriesId { get; set; }
|
public int SeriesId { get; set; }
|
||||||
|
public int? ChapterId { get; set; }
|
||||||
|
|
||||||
// Relationships
|
// Relationships
|
||||||
public ICollection<ExternalSeriesMetadata> ExternalSeriesMetadatas { get; set; } = null!;
|
public ICollection<ExternalSeriesMetadata> ExternalSeriesMetadatas { get; set; } = null!;
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,12 @@ public static class IncludesExtensions
|
||||||
.Include(c => c.Tags);
|
.Include(c => c.Tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (includes.HasFlag(ChapterIncludes.ExternalReviews))
|
||||||
|
{
|
||||||
|
queryable = queryable
|
||||||
|
.Include(c => c.ExternalReviews);
|
||||||
|
}
|
||||||
|
|
||||||
return queryable.AsSplitQuery();
|
return queryable.AsSplitQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,14 +315,4 @@ public static class IncludesExtensions
|
||||||
|
|
||||||
return query.AsSplitQuery();
|
return query.AsSplitQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IQueryable<ExternalChapterMetadata> Includes(this IQueryable<ExternalChapterMetadata> query, ExternalChapterMetadataIncludes includeFlags)
|
|
||||||
{
|
|
||||||
if (includeFlags.HasFlag(ExternalChapterMetadataIncludes.ExternalReviews))
|
|
||||||
{
|
|
||||||
query = query.Include(e => e.ExternalReviews);
|
|
||||||
}
|
|
||||||
|
|
||||||
return query.AsSplitQuery();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -344,19 +344,11 @@ public class AutoMapperProfiles : Profile
|
||||||
.ForMember(dest => dest.IsExternal,
|
.ForMember(dest => dest.IsExternal,
|
||||||
opt =>
|
opt =>
|
||||||
opt.MapFrom(src => true));
|
opt.MapFrom(src => true));
|
||||||
CreateMap<ExternalChapterReview, UserReviewDto>()
|
|
||||||
.ForMember(dest => dest.IsExternal,
|
|
||||||
opt =>
|
|
||||||
opt.MapFrom(src => true));
|
|
||||||
|
|
||||||
CreateMap<UserReviewDto, ExternalReview>()
|
CreateMap<UserReviewDto, ExternalReview>()
|
||||||
.ForMember(dest => dest.BodyJustText,
|
.ForMember(dest => dest.BodyJustText,
|
||||||
opt =>
|
opt =>
|
||||||
opt.MapFrom(src => ReviewHelper.GetCharacters(src.Body)));
|
opt.MapFrom(src => ReviewHelper.GetCharacters(src.Body)));
|
||||||
CreateMap<UserReviewDto, ExternalChapterReview>()
|
|
||||||
.ForMember(dest => dest.BodyJustText,
|
|
||||||
opt =>
|
|
||||||
opt.MapFrom(src => ReviewHelper.GetCharacters(src.Body)));
|
|
||||||
|
|
||||||
CreateMap<ExternalRecommendation, ExternalSeriesDto>();
|
CreateMap<ExternalRecommendation, ExternalSeriesDto>();
|
||||||
CreateMap<Series, ManageMatchSeriesDto>()
|
CreateMap<Series, ManageMatchSeriesDto>()
|
||||||
|
|
|
||||||
|
|
@ -1104,16 +1104,15 @@ public class ExternalMetadataService : IExternalMetadataService
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var exteralChapterMetadata = await GetOrCreateExternalChapterMetadataForChapter(chapter.Id, chapter);
|
_unitOfWork.ExternalSeriesMetadataRepository.Remove(chapter.ExternalReviews);
|
||||||
_unitOfWork.ExternalChapterMetadataRepository.Remove(exteralChapterMetadata.ExternalReviews);
|
|
||||||
|
|
||||||
List<ExternalChapterReview> externalReviews = [];
|
List<ExternalReview> externalReviews = [];
|
||||||
|
|
||||||
externalReviews.AddRange(metadata.CriticReviews
|
externalReviews.AddRange(metadata.CriticReviews
|
||||||
.Where(r => !string.IsNullOrWhiteSpace(r.Username) && !string.IsNullOrWhiteSpace(r.Body))
|
.Where(r => !string.IsNullOrWhiteSpace(r.Username) && !string.IsNullOrWhiteSpace(r.Body))
|
||||||
.Select(r =>
|
.Select(r =>
|
||||||
{
|
{
|
||||||
var review = _mapper.Map<ExternalChapterReview>(r);
|
var review = _mapper.Map<ExternalReview>(r);
|
||||||
review.ChapterId = chapter.Id;
|
review.ChapterId = chapter.Id;
|
||||||
review.Authority = RatingAuthority.Critic;
|
review.Authority = RatingAuthority.Critic;
|
||||||
return review;
|
return review;
|
||||||
|
|
@ -1122,13 +1121,13 @@ public class ExternalMetadataService : IExternalMetadataService
|
||||||
.Where(r => !string.IsNullOrWhiteSpace(r.Username) && !string.IsNullOrWhiteSpace(r.Body))
|
.Where(r => !string.IsNullOrWhiteSpace(r.Username) && !string.IsNullOrWhiteSpace(r.Body))
|
||||||
.Select(r =>
|
.Select(r =>
|
||||||
{
|
{
|
||||||
var review = _mapper.Map<ExternalChapterReview>(r);
|
var review = _mapper.Map<ExternalReview>(r);
|
||||||
review.ChapterId = chapter.Id;
|
review.ChapterId = chapter.Id;
|
||||||
review.Authority = RatingAuthority.User;
|
review.Authority = RatingAuthority.User;
|
||||||
return review;
|
return review;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
chapter.ExternalChapterMetadata.ExternalReviews = externalReviews;
|
chapter.ExternalReviews = externalReviews;
|
||||||
|
|
||||||
_logger.LogDebug("Added {Count} reviews for chapter {ChapterId}", externalReviews.Count, chapter.Id);
|
_logger.LogDebug("Added {Count} reviews for chapter {ChapterId}", externalReviews.Count, chapter.Id);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1588,28 +1587,6 @@ public class ExternalMetadataService : IExternalMetadataService
|
||||||
return externalSeriesMetadata;
|
return externalSeriesMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets from DB or creates a new one with just ChapterId
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="chapterId"></param>
|
|
||||||
/// <param name="chapter"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private async Task<ExternalChapterMetadata> GetOrCreateExternalChapterMetadataForChapter(int chapterId, Chapter chapter)
|
|
||||||
{
|
|
||||||
var externalChapterMetadata = await _unitOfWork.ExternalChapterMetadataRepository.Get(chapterId);
|
|
||||||
if (externalChapterMetadata != null) return externalChapterMetadata;
|
|
||||||
|
|
||||||
externalChapterMetadata = new ExternalChapterMetadata()
|
|
||||||
{
|
|
||||||
ChapterId = chapterId,
|
|
||||||
};
|
|
||||||
|
|
||||||
chapter.ExternalChapterMetadata = externalChapterMetadata;
|
|
||||||
_unitOfWork.ExternalChapterMetadataRepository.Attach(externalChapterMetadata);
|
|
||||||
|
|
||||||
return externalChapterMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<RecommendationDto> ProcessRecommendations(LibraryType libraryType, IEnumerable<MediaRecommendationDto> recs,
|
private async Task<RecommendationDto> ProcessRecommendations(LibraryType libraryType, IEnumerable<MediaRecommendationDto> recs,
|
||||||
ExternalSeriesMetadata externalSeriesMetadata)
|
ExternalSeriesMetadata externalSeriesMetadata)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,20 @@ namespace API.Services;
|
||||||
public interface IRatingService
|
public interface IRatingService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Updates the users' rating for a given series
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user">Should include ratings</param>
|
/// <param name="user">Should include ratings</param>
|
||||||
/// <param name="updateRatingDto"></param>
|
/// <param name="updateRatingDto"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<bool> UpdateRating(AppUser user, UpdateRatingDto updateRatingDto);
|
Task<bool> UpdateSeriesRating(AppUser user, UpdateRatingDto updateRatingDto);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the users' rating for a given chapter
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user">Should include ratings</param>
|
||||||
|
/// <param name="updateRatingDto">chapterId must be set</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<bool> UpdateChapterRating(AppUser user, UpdateRatingDto updateRatingDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RatingService: IRatingService
|
public class RatingService: IRatingService
|
||||||
|
|
@ -36,17 +44,7 @@ public class RatingService: IRatingService
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> UpdateRating(AppUser user, UpdateRatingDto updateRatingDto)
|
public async Task<bool> UpdateSeriesRating(AppUser user, UpdateRatingDto updateRatingDto)
|
||||||
{
|
|
||||||
if (updateRatingDto.ChapterId != null)
|
|
||||||
{
|
|
||||||
return await UpdateChapterRating(user, updateRatingDto);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await UpdateSeriesRating(user, updateRatingDto);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<bool> UpdateSeriesRating(AppUser user, UpdateRatingDto updateRatingDto)
|
|
||||||
{
|
{
|
||||||
var userRating =
|
var userRating =
|
||||||
await _unitOfWork.UserRepository.GetUserRatingAsync(updateRatingDto.SeriesId, user.Id) ??
|
await _unitOfWork.UserRepository.GetUserRatingAsync(updateRatingDto.SeriesId, user.Id) ??
|
||||||
|
|
@ -85,7 +83,7 @@ public class RatingService: IRatingService
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> UpdateChapterRating(AppUser user, UpdateRatingDto updateRatingDto)
|
public async Task<bool> UpdateChapterRating(AppUser user, UpdateRatingDto updateRatingDto)
|
||||||
{
|
{
|
||||||
if (updateRatingDto.ChapterId == null)
|
if (updateRatingDto.ChapterId == null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -15,35 +15,42 @@ export class ReviewService {
|
||||||
|
|
||||||
deleteReview(seriesId: number, chapterId?: number) {
|
deleteReview(seriesId: number, chapterId?: number) {
|
||||||
if (chapterId) {
|
if (chapterId) {
|
||||||
return this.httpClient.delete(this.baseUrl + `review?chapterId=${chapterId}&seriesId=${seriesId}`);
|
return this.httpClient.delete(this.baseUrl + `review/chapter?chapterId=${chapterId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.httpClient.delete(this.baseUrl + 'review?seriesId=' + seriesId);
|
return this.httpClient.delete(this.baseUrl + `review/series?seriesId=${seriesId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateReview(seriesId: number, body: string, chapterId?: number) {
|
updateReview(seriesId: number, body: string, chapterId?: number) {
|
||||||
if (chapterId) {
|
if (chapterId) {
|
||||||
return this.httpClient.post<UserReview>(this.baseUrl + `review`, {
|
return this.httpClient.post<UserReview>(this.baseUrl + `review/chapter`, {
|
||||||
seriesId, chapterId, body
|
seriesId, chapterId, body
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.httpClient.post<UserReview>(this.baseUrl + 'review', {
|
return this.httpClient.post<UserReview>(this.baseUrl + 'review/series', {
|
||||||
seriesId, body
|
seriesId, body
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRating(seriesId: number, userRating: number, chapterId?: number) {
|
updateRating(seriesId: number, userRating: number, chapterId?: number) {
|
||||||
return this.httpClient.post(this.baseUrl + 'rating', {
|
if (chapterId) {
|
||||||
seriesId, chapterId, userRating
|
return this.httpClient.post(this.baseUrl + 'rating/chapter', {
|
||||||
|
seriesId, chapterId, userRating
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.httpClient.post(this.baseUrl + 'rating/series', {
|
||||||
|
seriesId, userRating
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
overallRating(seriesId: number, chapterId?: number) {
|
overallRating(seriesId: number, chapterId?: number) {
|
||||||
if (chapterId) {
|
if (chapterId) {
|
||||||
return this.httpClient.get<Rating>(this.baseUrl + `rating/overall?chapterId=${chapterId}&seriesId=${seriesId}`);
|
return this.httpClient.get<Rating>(this.baseUrl + `rating/overall-chapter?chapterId=${chapterId}`);
|
||||||
}
|
}
|
||||||
return this.httpClient.get<Rating>(this.baseUrl + 'rating/overall?seriesId=' + seriesId);
|
|
||||||
|
return this.httpClient.get<Rating>(this.baseUrl + `rating/overall-series?seriesId=${seriesId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue