Invite & Library Edit - Missing SideNav Code (#2322)

This commit is contained in:
Joe Milazzo 2023-10-17 14:08:56 -05:00 committed by GitHub
parent 7c8fdd9ea8
commit a3afa04be4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 139 additions and 66 deletions

View File

@ -459,7 +459,7 @@ public class AccountController : BaseApiController
if (adminUser == null) return Unauthorized();
if (!await _unitOfWork.UserRepository.IsUserAdminAsync(adminUser)) return Unauthorized(await _localizationService.Translate(User.GetUserId(), "permission-denied"));
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(dto.UserId);
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(dto.UserId, AppUserIncludes.SideNavStreams);
if (user == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "no-user"));
// Check if username is changing
@ -509,6 +509,7 @@ public class AccountController : BaseApiController
{
lib.AppUsers ??= new List<AppUser>();
lib.AppUsers.Remove(user);
user.RemoveSideNavFromLibrary(lib);
}
libraries = (await _unitOfWork.LibraryRepository.GetLibraryForIdsAsync(dto.Libraries, LibraryIncludes.AppUser)).ToList();
@ -518,6 +519,7 @@ public class AccountController : BaseApiController
{
lib.AppUsers ??= new List<AppUser>();
lib.AppUsers.Add(user);
user.CreateSideNavFromLibrary(lib);
}
user.AgeRestriction = hasAdminRole ? AgeRating.NotApplicable : dto.AgeRestriction.AgeRating;
@ -528,6 +530,9 @@ public class AccountController : BaseApiController
if (!_unitOfWork.HasChanges() || await _unitOfWork.CommitAsync())
{
await _eventHub.SendMessageToAsync(MessageFactory.UserUpdate, MessageFactory.UserUpdateEvent(user.Id, user.UserName), user.Id);
await _eventHub.SendMessageToAsync(MessageFactory.SideNavUpdate, MessageFactory.SideNavUpdateEvent(user.Id), user.Id);
// If we adjust library access, dashboards should re-render
await _eventHub.SendMessageToAsync(MessageFactory.DashboardUpdate, MessageFactory.DashboardUpdateEvent(user.Id), user.Id);
return Ok();
}
@ -627,8 +632,10 @@ public class AccountController : BaseApiController
{
lib.AppUsers ??= new List<AppUser>();
lib.AppUsers.Add(user);
user.CreateSideNavFromLibrary(lib);
}
_unitOfWork.UserRepository.Update(user);
user.AgeRestriction = hasAdminRole ? AgeRating.NotApplicable : dto.AgeRestriction.AgeRating;
user.AgeRestrictionIncludeUnknowns = hasAdminRole || dto.AgeRestriction.IncludeUnknowns;
@ -649,6 +656,7 @@ public class AccountController : BaseApiController
await _unitOfWork.CommitAsync();
}
try
{
var emailLink = await _accountService.GenerateEmailLink(Request, user.ConfirmationToken, "confirm-email", dto.Email);

View File

@ -109,16 +109,7 @@ public class LibraryController : BaseApiController
foreach (var user in userNeedingNewLibrary)
{
var maxCount = user.SideNavStreams.Select(s => s.Order).Max();
user.SideNavStreams.Add(new AppUserSideNavStream()
{
Name = library.Name,
Order = maxCount + 1,
IsProvided = false,
StreamType = SideNavStreamType.Library,
LibraryId = library.Id,
Visible = true,
});
user.CreateSideNavFromLibrary(library);
_unitOfWork.UserRepository.Update(user);
}
@ -201,7 +192,7 @@ public class LibraryController : BaseApiController
[HttpPost("grant-access")]
public async Task<ActionResult<MemberDto>> UpdateUserLibraries(UpdateLibraryForUserDto updateLibraryForUserDto)
{
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(updateLibraryForUserDto.Username);
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(updateLibraryForUserDto.Username, AppUserIncludes.SideNavStreams);
if (user == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "user-doesnt-exist"));
var libraryString = string.Join(',', updateLibraryForUserDto.SelectedLibraries.Select(x => x.Name));
@ -217,10 +208,12 @@ public class LibraryController : BaseApiController
{
// Remove
library.AppUsers.Remove(user);
user.RemoveSideNavFromLibrary(library);
}
else if (!libraryContainsUser && libraryIsSelected)
{
library.AppUsers.Add(user);
user.CreateSideNavFromLibrary(library);
}
}
@ -235,6 +228,11 @@ public class LibraryController : BaseApiController
_logger.LogInformation("Added: {SelectedLibraries} to {Username}",libraryString, updateLibraryForUserDto.Username);
// Bust cache
await _libraryCacheProvider.RemoveByPrefixAsync(CacheKey);
// TODO: Update a user's SideNav based on library access
_unitOfWork.UserRepository.Update(user);
return Ok(_mapper.Map<MemberDto>(user));
}

View File

@ -929,6 +929,12 @@ public class SeriesRepository : ISeriesRepository
query ??= _context.Series
.AsNoTracking();
// When the user has no access, just return instantly
if (userLibraries.Count == 0)
{
return query.Where(s => false);
}
// First setup any FilterField.Libraries in the statements, as these don't have any traditional query statements applied here

View File

@ -0,0 +1,46 @@
using System.Collections.Generic;
using System.Linq;
using API.Entities;
using API.Helpers;
namespace API.Extensions;
public static class AppUserExtensions
{
/// <summary>
/// Adds a new SideNavStream to the user's SideNavStreams. This user should have these streams already loaded
/// </summary>
/// <param name="user"></param>
/// <param name="library"></param>
public static void CreateSideNavFromLibrary(this AppUser user, Library library)
{
user.SideNavStreams ??= new List<AppUserSideNavStream>();
var maxCount = user.SideNavStreams.Select(s => s.Order).DefaultIfEmpty().Max();
if (user.SideNavStreams.FirstOrDefault(s => s.LibraryId == library.Id) != null) return;
user.SideNavStreams.Add(new AppUserSideNavStream()
{
Name = library.Name,
Order = maxCount + 1,
IsProvided = false,
StreamType = SideNavStreamType.Library,
LibraryId = library.Id,
Visible = true,
});
}
public static void RemoveSideNavFromLibrary(this AppUser user, Library library)
{
user.SideNavStreams ??= new List<AppUserSideNavStream>();
// Find the library and remove it
var item = user.SideNavStreams.FirstOrDefault(s => s.LibraryId == library.Id);
if (item == null) return;
user.SideNavStreams.Remove(item);
OrderableHelper.ReorderItems(user.SideNavStreams);
}
}

View File

@ -0,0 +1,60 @@
using System.Collections.Generic;
using API.Entities;
namespace API.Helpers;
public static class OrderableHelper
{
public static void ReorderItems(List<AppUserDashboardStream> items, int itemId, int toPosition)
{
var item = items.Find(r => r.Id == itemId);
if (item != null)
{
items.Remove(item);
items.Insert(toPosition, item);
}
for (var i = 0; i < items.Count; i++)
{
items[i].Order = i;
}
}
public static void ReorderItems(List<AppUserSideNavStream> items, int itemId, int toPosition)
{
var item = items.Find(r => r.Id == itemId);
if (item != null)
{
items.Remove(item);
items.Insert(toPosition, item);
}
for (var i = 0; i < items.Count; i++)
{
items[i].Order = i;
}
}
public static void ReorderItems(IList<AppUserSideNavStream> items)
{
for (var i = 0; i < items.Count; i++)
{
items[i].Order = i;
}
}
public static void ReorderItems(List<ReadingListItem> items, int readingListItemId, int toPosition)
{
var item = items.Find(r => r.Id == readingListItemId);
if (item != null)
{
items.Remove(item);
items.Insert(toPosition, item);
}
for (var i = 0; i < items.Count; i++)
{
items[i].Order = i;
}
}
}

View File

@ -236,28 +236,13 @@ public class ReadingListService : IReadingListService
public async Task<bool> UpdateReadingListItemPosition(UpdateReadingListPosition dto)
{
var items = (await _unitOfWork.ReadingListRepository.GetReadingListItemsByIdAsync(dto.ReadingListId)).ToList();
ReorderItems(items, dto.ReadingListItemId, dto.ToPosition);
OrderableHelper.ReorderItems(items, dto.ReadingListItemId, dto.ToPosition);
if (!_unitOfWork.HasChanges()) return true;
return await _unitOfWork.CommitAsync();
}
private static void ReorderItems(List<ReadingListItem> items, int readingListItemId, int toPosition)
{
var item = items.Find(r => r.Id == readingListItemId);
if (item != null)
{
items.Remove(item);
items.Insert(toPosition, item);
}
for (var i = 0; i < items.Count; i++)
{
items[i].Order = i;
}
}
/// <summary>
/// Removes a certain reading list item from a reading list
/// </summary>
@ -477,7 +462,7 @@ public class ReadingListService : IReadingListService
}
else
{
ReorderItems(items, readingListItem.Id, order);
OrderableHelper.ReorderItems(items, readingListItem.Id, order);
}
}

View File

@ -7,6 +7,7 @@ using API.DTOs.Dashboard;
using API.DTOs.SideNav;
using API.Entities;
using API.Entities.Enums;
using API.Helpers;
using API.SignalR;
using Kavita.Common;
using Kavita.Common.Helpers;
@ -127,7 +128,7 @@ public class StreamService : IStreamService
if (stream.Order == dto.ToPosition) return;
var list = user!.DashboardStreams.ToList();
ReorderItems(list, stream.Id, dto.ToPosition);
OrderableHelper.ReorderItems(list, stream.Id, dto.ToPosition);
user.DashboardStreams = list;
_unitOfWork.UserRepository.Update(user);
@ -263,7 +264,7 @@ public class StreamService : IStreamService
if (stream.Order == dto.ToPosition) return;
var list = user!.SideNavStreams.ToList();
ReorderItems(list, stream.Id, dto.ToPosition);
OrderableHelper.ReorderItems(list, stream.Id, dto.ToPosition);
user.SideNavStreams = list;
_unitOfWork.UserRepository.Update(user);
@ -340,33 +341,5 @@ public class StreamService : IStreamService
await _unitOfWork.CommitAsync();
}
private static void ReorderItems(List<AppUserDashboardStream> items, int itemId, int toPosition)
{
var item = items.Find(r => r.Id == itemId);
if (item != null)
{
items.Remove(item);
items.Insert(toPosition, item);
}
for (var i = 0; i < items.Count; i++)
{
items[i].Order = i;
}
}
private static void ReorderItems(List<AppUserSideNavStream> items, int itemId, int toPosition)
{
var item = items.Find(r => r.Id == itemId);
if (item != null)
{
items.Remove(item);
items.Insert(toPosition, item);
}
for (var i = 0; i < items.Count; i++)
{
items[i].Order = i;
}
}
}

View File

@ -1,7 +1,5 @@
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, OnInit} from '@angular/core';
import {ActivatedRoute, RouterLink} from '@angular/router';
import {ToastrService} from 'ngx-toastr';
import {ServerService} from 'src/app/_services/server.service';
import {Title} from '@angular/platform-browser';
import {NavService} from '../../_services/nav.service';
import {SentenceCasePipe} from '../../pipe/sentence-case.pipe';
@ -20,7 +18,7 @@ import {NgbNav, NgbNavContent, NgbNavItem, NgbNavItemRole, NgbNavLink, NgbNavOut
import {
SideNavCompanionBarComponent
} from '../../sidenav/_components/side-nav-companion-bar/side-nav-companion-bar.component';
import {TranslocoDirective, TranslocoService} from "@ngneat/transloco";
import {translate, TranslocoDirective, TranslocoService} from "@ngneat/transloco";
enum TabID {
General = '',
@ -66,8 +64,7 @@ export class DashboardComponent implements OnInit {
return TabID;
}
constructor(public route: ActivatedRoute, private serverService: ServerService,
private toastr: ToastrService, private titleService: Title, public navService: NavService) {
constructor(public route: ActivatedRoute, private titleService: Title, public navService: NavService) {
this.route.fragment.subscribe(frag => {
const tab = this.tabs.filter(item => item.fragment === frag);
if (tab.length > 0) {
@ -81,6 +78,6 @@ export class DashboardComponent implements OnInit {
}
ngOnInit() {
this.titleService.setTitle('Kavita - ' + this.translocoService.translate('admin-dashboard.title'));
this.titleService.setTitle('Kavita - ' + translate('admin-dashboard.title'));
}
}

View File

@ -7,7 +7,7 @@
"name": "GPL-3.0",
"url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE"
},
"version": "0.7.8.11"
"version": "0.7.8.12"
},
"servers": [
{