diff --git a/.github/workflows/nightly-docker.yml b/.github/workflows/nightly-docker.yml index 680015afe..45621456a 100644 --- a/.github/workflows/nightly-docker.yml +++ b/.github/workflows/nightly-docker.yml @@ -1,9 +1,7 @@ name: Build Nightly Docker on: - push: - branches: - - 'develop' + workflow_dispatch: jobs: docker: @@ -13,6 +11,8 @@ jobs: - name: Check Out Repo uses: actions/checkout@v2 + with: + ref: develop - name: NodeJS to Compile WebUI uses: actions/setup-node@v2.1.5 @@ -28,7 +28,7 @@ jobs: echo 'Copying back to Kavita wwwroot' rsync -a dist/ ../../API/wwwroot/ - + cd ../ || exit - name: Get csproj Version @@ -38,14 +38,14 @@ jobs: proj-path: Kavita.Common/Kavita.Common.csproj - name: Echo csproj version - run: echo "${{steps.get-version.outputs.assembly-version}}" + run: echo "${{steps.get-version.outputs.assembly-version}}" - name: Compile dotnet app uses: actions/setup-dotnet@v1 with: dotnet-version: '5.0.x' - run: ./monorepo-build.sh - + - name: Trigger Sentry workflow uses: benc-uk/workflow-dispatch@v1 with: @@ -77,12 +77,12 @@ jobs: - name: Image digest run: echo ${{ steps.docker_build.outputs.digest }} - + - name: Notify Discord uses: rjstone/discord-webhook-notify@v1 with: severity: info - description: + description: ${{ github.event.body }} details: 'https://hub.docker.com/r/kizaing/kavita/tags?page=1&ordering=last_updated' text: A new nightly build has been released for docker. webhookUrl: ${{ secrets.DISCORD_DOCKER_UPDATE_URL }} diff --git a/.github/workflows/sonar-scan.yml b/.github/workflows/sonar-scan.yml index b6dfdf351..fef98472e 100644 --- a/.github/workflows/sonar-scan.yml +++ b/.github/workflows/sonar-scan.yml @@ -2,14 +2,42 @@ name: .NET Build Test and Sonar Scan on: push: - branches: [ main, develop ] + branches: '**' pull_request: branches: [ main, develop ] types: [opened, synchronize, reopened] jobs: build: - name: Build and Scan + name: Build .Net + runs-on: windows-latest + steps: + - name: Checkout Repo + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 5.0.100 + + - name: Install dependencies + run: dotnet restore + + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 1.11 + + - uses: actions/upload-artifact@v2 + with: + name: csproj + path: Kavita.Common/Kavita.Common.csproj + + test: + name: Install Sonar & Test + needs: build runs-on: windows-latest steps: - name: Checkout Repo @@ -52,7 +80,7 @@ jobs: New-Item -Path .\.sonar\scanner -ItemType Directory dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner - - name: Build and analyze + - name: Sonar Scan env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} @@ -64,3 +92,56 @@ jobs: - name: Test run: dotnet test --no-restore --verbosity normal + + version: + name: Bump version on Develop push + needs: [ build, test ] + runs-on: ubuntu-latest + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }} + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 5.0.100 + + - name: Install dependencies + run: dotnet restore + + - name: Build + run: dotnet build --configuration Release --no-restore + + - name: Bump versions + uses: SiqiLu/dotnet-bump-version@master + with: + version_files: Kavita.Common/Kavita.Common.csproj + github_token: ${{ secrets.REPO_GHA_PAT }} + + develop: + name: Trigger Nightly Docker if Develop push + needs: [ build, test, version ] + runs-on: ubuntu-latest + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }} + steps: + + - name: If Push to Develop, Trigger Docker Stable + uses: benc-uk/workflow-dispatch@v1 + with: + workflow: Build Nightly Docker + token: ${{ secrets.REPO_GHA_PAT }} + + stable: + name: Trigger Stable Docker if Main push + needs: [ build, test ] + runs-on: ubuntu-latest + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + steps: + + - name: If Push to Main, Trigger Docker Stable + uses: benc-uk/workflow-dispatch@v1 + with: + workflow: Build Stable Docker + token: ${{ secrets.REPO_GHA_PAT }} diff --git a/.github/workflows/stable-docker.yml b/.github/workflows/stable-docker.yml index cbf5c14c6..9f4dc8363 100644 --- a/.github/workflows/stable-docker.yml +++ b/.github/workflows/stable-docker.yml @@ -1,9 +1,7 @@ name: Build Stable Docker on: - push: - branches: - - 'main' + workflow_dispatch: jobs: docker: @@ -12,6 +10,8 @@ jobs: - name: Check Out Repo uses: actions/checkout@v2 + with: + ref: main - name: NodeJS to Compile WebUI uses: actions/setup-node@v2.1.5 @@ -99,7 +99,7 @@ jobs: uses: rjstone/discord-webhook-notify@v1 with: severity: info - description: + description: ${{ github.event.body }} details: 'https://hub.docker.com/r/kizaing/kavita/tags?page=1&ordering=last_updated' text: A new stable build has been released for docker. webhookUrl: ${{ secrets.DISCORD_DOCKER_UPDATE_URL }} \ No newline at end of file diff --git a/API/Controllers/SeriesController.cs b/API/Controllers/SeriesController.cs index b739b62bd..7bf59c7e0 100644 --- a/API/Controllers/SeriesController.cs +++ b/API/Controllers/SeriesController.cs @@ -168,8 +168,17 @@ namespace API.Controllers [HttpPost("in-progress")] public async Task>> GetInProgress(FilterDto filterDto, [FromQuery] UserParams userParams, [FromQuery] int libraryId = 0) { + // NOTE: This has to be done manually like this due to the DisinctBy requirement var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); - return Ok((await _unitOfWork.SeriesRepository.GetInProgress(user.Id, libraryId, userParams, filterDto)).DistinctBy(s => s.Name)); + var results = await _unitOfWork.SeriesRepository.GetInProgress(user.Id, libraryId, userParams, filterDto); + + var listResults = results.DistinctBy(s => s.Name).Skip((userParams.PageNumber - 1) * userParams.PageSize) + .Take(userParams.PageSize).ToList(); + var pagedList = new PagedList(listResults, listResults.Count, userParams.PageNumber, userParams.PageSize); + + Response.AddPaginationHeader(pagedList.CurrentPage, pagedList.PageSize, pagedList.TotalCount, pagedList.TotalPages); + + return Ok(pagedList); } [Authorize(Policy = "RequireAdminRole")] diff --git a/API/Data/SeriesRepository.cs b/API/Data/SeriesRepository.cs index afaf17f5b..92d19042b 100644 --- a/API/Data/SeriesRepository.cs +++ b/API/Data/SeriesRepository.cs @@ -323,7 +323,6 @@ namespace API.Data var allQuery = _context.Series .Where(s => userLibraries.Contains(s.LibraryId) && formats.Contains(s.Format)) - .AsNoTracking() .OrderByDescending(s => s.Created) .ProjectTo(_mapper.ConfigurationProvider) .AsNoTracking(); @@ -333,7 +332,6 @@ namespace API.Data var query = _context.Series .Where(s => s.LibraryId == libraryId && formats.Contains(s.Format)) - .AsNoTracking() .OrderByDescending(s => s.Created) .ProjectTo(_mapper.ConfigurationProvider) .AsNoTracking(); @@ -349,48 +347,46 @@ namespace API.Data /// Pagination information /// Optional (default null) filter on query /// - public async Task> GetInProgress(int userId, int libraryId, UserParams userParams, FilterDto filter) + public async Task> GetInProgress(int userId, int libraryId, UserParams userParams, FilterDto filter) { var formats = filter.GetSqlFilter(); - var series = _context.Series - .Where(s => formats.Contains(s.Format)) - .Join(_context.AppUserProgresses, s => s.Id, progress => progress.SeriesId, (s, progress) => new - { - Series = s, - PagesRead = _context.AppUserProgresses.Where(s1 => s1.SeriesId == s.Id).Sum(s1 => s1.PagesRead), - progress.AppUserId, - LastModified = _context.AppUserProgresses.Where(p => p.Id == progress.Id).Max(p => p.LastModified) - }).AsNoTracking(); + IList userLibraries; if (libraryId == 0) { - var userLibraries = _context.Library + userLibraries = _context.Library .Include(l => l.AppUsers) .Where(library => library.AppUsers.Any(user => user.Id == userId)) .AsNoTracking() .Select(library => library.Id) .ToList(); - series = series.Where(s => s.AppUserId == userId - && s.PagesRead > 0 - && s.PagesRead < s.Series.Pages - && userLibraries.Contains(s.Series.LibraryId) - && formats.Contains(s.Series.Format)); } else { - series = series.Where(s => s.AppUserId == userId - && s.PagesRead > 0 - && s.PagesRead < s.Series.Pages - && s.Series.LibraryId == libraryId - && formats.Contains(s.Series.Format)); + userLibraries = new List() {libraryId}; } - var retSeries = series - .OrderByDescending(s => s.LastModified) - .Select(s => s.Series) - .ProjectTo(_mapper.ConfigurationProvider) + var series = _context.Series + .Where(s => formats.Contains(s.Format) && userLibraries.Contains(s.LibraryId)) + .Join(_context.AppUserProgresses, s => s.Id, progress => progress.SeriesId, (s, progress) => new + { + Series = s, + PagesRead = _context.AppUserProgresses.Where(s1 => s1.SeriesId == s.Id && s1.AppUserId == userId).Sum(s1 => s1.PagesRead), + progress.AppUserId, + LastModified = _context.AppUserProgresses.Where(p => p.Id == progress.Id && p.AppUserId == userId).Max(p => p.LastModified) + }) .AsNoTracking(); - return await PagedList.CreateAsync(retSeries, userParams.PageNumber, userParams.PageSize); + var retSeries = series.Where(s => s.AppUserId == userId + && s.PagesRead > 0 + && s.PagesRead < s.Series.Pages) + .OrderByDescending(s => s.LastModified) + .Select(s => s.Series) + .ProjectTo(_mapper.ConfigurationProvider) + .AsSplitQuery() + .AsNoTracking(); + + // Pagination does not work for this query as when we pull the data back, we get multiple rows of the same series. See controller for pagination code + return await retSeries.ToListAsync(); } public async Task GetSeriesMetadata(int seriesId) diff --git a/API/Extensions/FilterDtoExtensions.cs b/API/Extensions/FilterDtoExtensions.cs index 1b6689d49..7e5a818ec 100644 --- a/API/Extensions/FilterDtoExtensions.cs +++ b/API/Extensions/FilterDtoExtensions.cs @@ -7,7 +7,7 @@ namespace API.Extensions { public static class FilterDtoExtensions { - private static IList _allFormats = Enum.GetValues(); + private static readonly IList AllFormats = Enum.GetValues(); public static IList GetSqlFilter(this FilterDto filter) { @@ -19,10 +19,7 @@ namespace API.Extensions (MangaFormat) format }; } - else - { - return _allFormats; - } + return AllFormats; } } } diff --git a/API/Interfaces/ISeriesRepository.cs b/API/Interfaces/ISeriesRepository.cs index bedbf8b56..399bf4f1a 100644 --- a/API/Interfaces/ISeriesRepository.cs +++ b/API/Interfaces/ISeriesRepository.cs @@ -58,7 +58,7 @@ namespace API.Interfaces Task GetVolumeCoverImageAsync(int volumeId); Task GetSeriesCoverImageAsync(int seriesId); - Task> GetInProgress(int userId, int libraryId, UserParams userParams, FilterDto filter); + Task> GetInProgress(int userId, int libraryId, UserParams userParams, FilterDto filter); Task> GetRecentlyAdded(int libraryId, int userId, UserParams userParams, FilterDto filter); Task GetSeriesMetadata(int seriesId); Task> GetSeriesDtoForCollectionAsync(int collectionId, int userId, UserParams userParams); diff --git a/Kavita.Common/Kavita.Common.csproj b/Kavita.Common/Kavita.Common.csproj index b4bc5f86a..d8d7e51af 100644 --- a/Kavita.Common/Kavita.Common.csproj +++ b/Kavita.Common/Kavita.Common.csproj @@ -4,7 +4,7 @@ net5.0 kavitareader.com Kavita - 0.4.3.6 + 0.4.3.9 en @@ -19,4 +19,4 @@ - + \ No newline at end of file