mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Merge branch 'main' of github.com:Kareadita/Kavita into feature/code-quality-cleanup
This commit is contained in:
commit
4f93fef661
25
.github/workflows/dotnet-core.yml
vendored
Normal file
25
.github/workflows/dotnet-core.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
name: .NET Core
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- 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: Test
|
||||||
|
run: dotnet test --no-restore --verbosity normal
|
8
API/Constants/PolicyConstants.cs
Normal file
8
API/Constants/PolicyConstants.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace API.Constants
|
||||||
|
{
|
||||||
|
public static class PolicyConstants
|
||||||
|
{
|
||||||
|
public static readonly string AdminRole = "Admin";
|
||||||
|
public static readonly string PlebRole = "Pleb";
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using API.Constants;
|
||||||
using API.DTOs;
|
using API.DTOs;
|
||||||
using API.Entities;
|
using API.Entities;
|
||||||
using API.Interfaces;
|
using API.Interfaces;
|
||||||
@ -37,7 +38,6 @@ namespace API.Controllers
|
|||||||
[HttpPost("register")]
|
[HttpPost("register")]
|
||||||
public async Task<ActionResult<UserDto>> Register(RegisterDto registerDto)
|
public async Task<ActionResult<UserDto>> Register(RegisterDto registerDto)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Username: " + registerDto.Password);
|
|
||||||
if (await UserExists(registerDto.Username))
|
if (await UserExists(registerDto.Username))
|
||||||
{
|
{
|
||||||
return BadRequest("Username is taken.");
|
return BadRequest("Username is taken.");
|
||||||
@ -48,16 +48,18 @@ namespace API.Controllers
|
|||||||
var result = await _userManager.CreateAsync(user, registerDto.Password);
|
var result = await _userManager.CreateAsync(user, registerDto.Password);
|
||||||
|
|
||||||
if (!result.Succeeded) return BadRequest(result.Errors);
|
if (!result.Succeeded) return BadRequest(result.Errors);
|
||||||
|
|
||||||
|
|
||||||
var roleResult = await _userManager.AddToRoleAsync(user, "Pleb");
|
// TODO: Need a way to store Roles in enum and configure from there
|
||||||
|
var role = registerDto.IsAdmin ? PolicyConstants.AdminRole : PolicyConstants.PlebRole;
|
||||||
|
var roleResult = await _userManager.AddToRoleAsync(user, role);
|
||||||
|
|
||||||
if (!roleResult.Succeeded) return BadRequest(result.Errors);
|
if (!roleResult.Succeeded) return BadRequest(result.Errors);
|
||||||
|
|
||||||
return new UserDto()
|
return new UserDto
|
||||||
{
|
{
|
||||||
Username = user.UserName,
|
Username = user.UserName,
|
||||||
Token = await _tokenService.CreateToken(user),
|
Token = await _tokenService.CreateToken(user),
|
||||||
IsAdmin = user.IsAdmin
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,11 +81,10 @@ namespace API.Controllers
|
|||||||
_userRepository.Update(user);
|
_userRepository.Update(user);
|
||||||
await _userRepository.SaveAllAsync();
|
await _userRepository.SaveAllAsync();
|
||||||
|
|
||||||
return new UserDto()
|
return new UserDto
|
||||||
{
|
{
|
||||||
Username = user.UserName,
|
Username = user.UserName,
|
||||||
Token = await _tokenService.CreateToken(user),
|
Token = await _tokenService.CreateToken(user)
|
||||||
IsAdmin = user.IsAdmin
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using API.DTOs;
|
||||||
|
using API.Entities;
|
||||||
using API.Interfaces;
|
using API.Interfaces;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace API.Controllers
|
namespace API.Controllers
|
||||||
@ -7,17 +12,22 @@ namespace API.Controllers
|
|||||||
public class AdminController : BaseApiController
|
public class AdminController : BaseApiController
|
||||||
{
|
{
|
||||||
private readonly IUserRepository _userRepository;
|
private readonly IUserRepository _userRepository;
|
||||||
|
private readonly UserManager<AppUser> _userManager;
|
||||||
|
|
||||||
public AdminController(IUserRepository userRepository)
|
public AdminController(IUserRepository userRepository, UserManager<AppUser> userManager)
|
||||||
{
|
{
|
||||||
_userRepository = userRepository;
|
_userRepository = userRepository;
|
||||||
|
_userManager = userManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet("exists")]
|
||||||
public async Task<ActionResult<bool>> AdminExists()
|
public async Task<ActionResult<bool>> AdminExists()
|
||||||
{
|
{
|
||||||
return await _userRepository.AdminExists();
|
var users = await _userManager.GetUsersInRoleAsync("Admin");
|
||||||
|
return users.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -42,22 +42,20 @@ namespace API.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path"></param>
|
/// <param name="path"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
[Authorize(Policy = "RequireAdminRole")]
|
||||||
[HttpGet("list")]
|
[HttpGet("list")]
|
||||||
public ActionResult<IEnumerable<string>> GetDirectories(string path)
|
public ActionResult<IEnumerable<string>> GetDirectories(string path)
|
||||||
{
|
{
|
||||||
// TODO: We need some sort of validation other than our auth layer
|
|
||||||
_logger.Log(LogLevel.Debug, "Listing Directories for " + path);
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(path))
|
if (string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
return Ok(Directory.GetLogicalDrives());
|
return Ok(Directory.GetLogicalDrives());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Directory.Exists(@path)) return BadRequest("This is not a valid path");
|
if (!Directory.Exists(path)) return BadRequest("This is not a valid path");
|
||||||
|
|
||||||
return Ok(_directoryService.ListDirectory(path));
|
return Ok(_directoryService.ListDirectory(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<ActionResult<IEnumerable<LibraryDto>>> GetLibraries()
|
public async Task<ActionResult<IEnumerable<LibraryDto>>> GetLibraries()
|
||||||
{
|
{
|
||||||
@ -77,14 +75,13 @@ namespace API.Controllers
|
|||||||
// return Ok(await _libraryRepository.GetLibrariesForUserAsync(user));
|
// return Ok(await _libraryRepository.GetLibrariesForUserAsync(user));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
[Authorize(Policy = "RequireAdminRole")]
|
||||||
[HttpPut("update-for")]
|
[HttpPut("update-for")]
|
||||||
public async Task<ActionResult<MemberDto>> UpdateLibrary(UpdateLibraryDto updateLibraryDto)
|
public async Task<ActionResult<MemberDto>> UpdateLibrary(UpdateLibraryDto updateLibraryDto)
|
||||||
{
|
{
|
||||||
// TODO: Only admins can do this
|
|
||||||
var user = await _userRepository.GetUserByUsernameAsync(updateLibraryDto.Username);
|
var user = await _userRepository.GetUserByUsernameAsync(updateLibraryDto.Username);
|
||||||
|
|
||||||
if (user == null) return BadRequest("Could not validate user");
|
if (user == null) return BadRequest("Could not validate user");
|
||||||
if (!user.IsAdmin) return Unauthorized("Only admins are permitted");
|
|
||||||
|
|
||||||
user.Libraries = new List<Library>();
|
user.Libraries = new List<Library>();
|
||||||
|
|
||||||
|
@ -24,12 +24,6 @@ namespace API.Controllers
|
|||||||
_userRepository = userRepository;
|
_userRepository = userRepository;
|
||||||
_libraryRepository = libraryRepository;
|
_libraryRepository = libraryRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
public async Task<ActionResult<IEnumerable<MemberDto>>> GetUsers()
|
|
||||||
{
|
|
||||||
return Ok(await _userRepository.GetMembersAsync());
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("add-library")]
|
[HttpPost("add-library")]
|
||||||
public async Task<ActionResult> AddLibrary(CreateLibraryDto createLibraryDto)
|
public async Task<ActionResult> AddLibrary(CreateLibraryDto createLibraryDto)
|
||||||
@ -72,7 +66,27 @@ namespace API.Controllers
|
|||||||
|
|
||||||
return BadRequest("Not implemented");
|
return BadRequest("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Authorize(Policy = "RequireAdminRole")]
|
||||||
|
[HttpDelete("delete-user")]
|
||||||
|
public async Task<ActionResult> DeleteUser(string username)
|
||||||
|
{
|
||||||
|
var user = await _userRepository.GetUserByUsernameAsync(username);
|
||||||
|
_userRepository.Delete(user);
|
||||||
|
|
||||||
|
if (await _userRepository.SaveAllAsync())
|
||||||
|
{
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
return BadRequest("Could not delete the user.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "RequireAdminRole")]
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult<IEnumerable<MemberDto>>> GetUsers()
|
||||||
|
{
|
||||||
|
return Ok(await _userRepository.GetMembersAsync());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,7 +14,7 @@ namespace API.DTOs
|
|||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
public DateTime Created { get; set; }
|
public DateTime Created { get; set; }
|
||||||
public DateTime LastActive { get; set; }
|
public DateTime LastActive { get; set; }
|
||||||
public bool IsAdmin { get; set; }
|
|
||||||
public IEnumerable<LibraryDto> Libraries { get; set; }
|
public IEnumerable<LibraryDto> Libraries { get; set; }
|
||||||
|
public IEnumerable<string> Roles { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,8 +2,7 @@
|
|||||||
{
|
{
|
||||||
public class UserDto
|
public class UserDto
|
||||||
{
|
{
|
||||||
public string Username { get; set; }
|
public string Username { get; init; }
|
||||||
public string Token { get; set; }
|
public string Token { get; init; }
|
||||||
public bool IsAdmin { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
377
API/Data/Migrations/20201224155621_MiscCleanup.Designer.cs
generated
Normal file
377
API/Data/Migrations/20201224155621_MiscCleanup.Designer.cs
generated
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using API.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
namespace API.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
[Migration("20201224155621_MiscCleanup")]
|
||||||
|
partial class MiscCleanup
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "5.0.1");
|
||||||
|
|
||||||
|
modelBuilder.Entity("API.Entities.AppRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("RoleNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoles");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("API.Entities.AppUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AccessFailedCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Created")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("EmailConfirmed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsAdmin")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastActive")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("LockoutEnabled")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedEmail")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedUserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("PhoneNumber")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("PhoneNumberConfirmed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("RowVersion")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("SecurityStamp")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("TwoFactorEnabled")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedEmail")
|
||||||
|
.HasDatabaseName("EmailIndex");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedUserName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("UserNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUsers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("API.Entities.AppUserRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("RoleId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserRoles");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("API.Entities.FolderPath", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("LibraryId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Path")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("LibraryId");
|
||||||
|
|
||||||
|
b.ToTable("FolderPath");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("API.Entities.Library", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("CoverImage")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Library");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("AppUserLibrary", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AppUsersId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("LibrariesId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("AppUsersId", "LibrariesId");
|
||||||
|
|
||||||
|
b.HasIndex("LibrariesId");
|
||||||
|
|
||||||
|
b.ToTable("AppUserLibrary");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<int>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("RoleId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoleClaims");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<int>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserClaims");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<int>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderKey")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderDisplayName")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("LoginProvider", "ProviderKey");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserLogins");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<int>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "LoginProvider", "Name");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserTokens");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("API.Entities.AppUserRole", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("API.Entities.AppRole", "Role")
|
||||||
|
.WithMany("UserRoles")
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("API.Entities.AppUser", "User")
|
||||||
|
.WithMany("UserRoles")
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Role");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("API.Entities.FolderPath", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("API.Entities.Library", "Library")
|
||||||
|
.WithMany("Folders")
|
||||||
|
.HasForeignKey("LibraryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Library");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("AppUserLibrary", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("API.Entities.AppUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AppUsersId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("API.Entities.Library", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("LibrariesId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<int>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("API.Entities.AppRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<int>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("API.Entities.AppUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<int>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("API.Entities.AppUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<int>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("API.Entities.AppUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("API.Entities.AppRole", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("UserRoles");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("API.Entities.AppUser", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("UserRoles");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("API.Entities.Library", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Folders");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
API/Data/Migrations/20201224155621_MiscCleanup.cs
Normal file
42
API/Data/Migrations/20201224155621_MiscCleanup.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace API.Data.Migrations
|
||||||
|
{
|
||||||
|
public partial class MiscCleanup : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PasswordSalt",
|
||||||
|
table: "AspNetUsers");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "PasswordHash",
|
||||||
|
table: "AspNetUsers",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(byte[]),
|
||||||
|
oldType: "BLOB",
|
||||||
|
oldNullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterColumn<byte[]>(
|
||||||
|
name: "PasswordHash",
|
||||||
|
table: "AspNetUsers",
|
||||||
|
type: "BLOB",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "TEXT",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<byte[]>(
|
||||||
|
name: "PasswordSalt",
|
||||||
|
table: "AspNetUsers",
|
||||||
|
type: "BLOB",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using API.Constants;
|
||||||
using API.Entities;
|
using API.Entities;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
@ -11,8 +12,8 @@ namespace API.Data
|
|||||||
{
|
{
|
||||||
var roles = new List<AppRole>
|
var roles = new List<AppRole>
|
||||||
{
|
{
|
||||||
new AppRole {Name = "Admin"},
|
new AppRole {Name = PolicyConstants.AdminRole},
|
||||||
new AppRole {Name = "Pleb"}
|
new AppRole {Name = PolicyConstants.PlebRole}
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var role in roles)
|
foreach (var role in roles)
|
||||||
|
@ -6,6 +6,7 @@ using API.Entities;
|
|||||||
using API.Interfaces;
|
using API.Interfaces;
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using AutoMapper.QueryableExtensions;
|
using AutoMapper.QueryableExtensions;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace API.Data
|
namespace API.Data
|
||||||
@ -14,11 +15,13 @@ namespace API.Data
|
|||||||
{
|
{
|
||||||
private readonly DataContext _context;
|
private readonly DataContext _context;
|
||||||
private readonly IMapper _mapper;
|
private readonly IMapper _mapper;
|
||||||
|
private readonly UserManager<AppUser> _userManager;
|
||||||
|
|
||||||
public UserRepository(DataContext context, IMapper mapper)
|
public UserRepository(DataContext context, IMapper mapper, UserManager<AppUser> userManager)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_mapper = mapper;
|
_mapper = mapper;
|
||||||
|
_userManager = userManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(AppUser user)
|
public void Update(AppUser user)
|
||||||
@ -26,6 +29,11 @@ namespace API.Data
|
|||||||
_context.Entry(user).State = EntityState.Modified;
|
_context.Entry(user).State = EntityState.Modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Delete(AppUser user)
|
||||||
|
{
|
||||||
|
_context.Users.Remove(user);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<bool> SaveAllAsync()
|
public async Task<bool> SaveAllAsync()
|
||||||
{
|
{
|
||||||
return await _context.SaveChangesAsync() > 0;
|
return await _context.SaveChangesAsync() > 0;
|
||||||
@ -49,9 +57,26 @@ namespace API.Data
|
|||||||
|
|
||||||
public async Task<IEnumerable<MemberDto>> GetMembersAsync()
|
public async Task<IEnumerable<MemberDto>> GetMembersAsync()
|
||||||
{
|
{
|
||||||
return await _context.Users.Include(x => x.Libraries)
|
return await _userManager.Users
|
||||||
.Include(x => x.Libraries)
|
.Include(x => x.Libraries)
|
||||||
.ProjectTo<MemberDto>(_mapper.ConfigurationProvider)
|
.Include(r => r.UserRoles)
|
||||||
|
.ThenInclude(r => r.Role)
|
||||||
|
.OrderBy(u => u.UserName)
|
||||||
|
.Select(u => new MemberDto
|
||||||
|
{
|
||||||
|
Id = u.Id,
|
||||||
|
Username = u.UserName,
|
||||||
|
Created = u.Created,
|
||||||
|
LastActive = u.LastActive,
|
||||||
|
Roles = u.UserRoles.Select(r => r.Role.Name).ToList(),
|
||||||
|
Libraries = u.Libraries.Select(l => new LibraryDto
|
||||||
|
{
|
||||||
|
Name = l.Name,
|
||||||
|
CoverImage = l.CoverImage,
|
||||||
|
Type = l.Type,
|
||||||
|
Folders = l.Folders.Select(x => x.Path).ToList()
|
||||||
|
}).ToList()
|
||||||
|
})
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,11 +87,6 @@ namespace API.Data
|
|||||||
.ProjectTo<MemberDto>(_mapper.ConfigurationProvider)
|
.ProjectTo<MemberDto>(_mapper.ConfigurationProvider)
|
||||||
.SingleOrDefaultAsync();
|
.SingleOrDefaultAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> AdminExists()
|
|
||||||
{
|
|
||||||
return await _context.Users.AnyAsync(x => x.IsAdmin);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
using API.Constants;
|
||||||
using API.Data;
|
using API.Data;
|
||||||
using API.Entities;
|
using API.Entities;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
@ -35,6 +36,11 @@ namespace API.Extensions
|
|||||||
ValidateAudience = false
|
ValidateAudience = false
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
services.AddAuthorization(opt =>
|
||||||
|
{
|
||||||
|
opt.AddPolicy("RequireAdminRole", policy => policy.RequireRole(PolicyConstants.AdminRole));
|
||||||
|
});
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,6 @@ namespace API.Interfaces
|
|||||||
Task<AppUser> GetUserByUsernameAsync(string username);
|
Task<AppUser> GetUserByUsernameAsync(string username);
|
||||||
Task<IEnumerable<MemberDto>> GetMembersAsync();
|
Task<IEnumerable<MemberDto>> GetMembersAsync();
|
||||||
Task<MemberDto> GetMemberAsync(string username);
|
Task<MemberDto> GetMemberAsync(string username);
|
||||||
Task<bool> AdminExists();
|
public void Delete(AppUser user);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using API.Interfaces;
|
using API.Interfaces;
|
||||||
|
|
||||||
@ -7,15 +10,22 @@ namespace API.Services
|
|||||||
{
|
{
|
||||||
public class DirectoryService : IDirectoryService
|
public class DirectoryService : IDirectoryService
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Lists out top-level folders for a given directory. Filters out System and Hidden folders.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rootPath">Absolute path </param>
|
||||||
|
/// <returns>List of folder names</returns>
|
||||||
public IEnumerable<string> ListDirectory(string rootPath)
|
public IEnumerable<string> ListDirectory(string rootPath)
|
||||||
{
|
{
|
||||||
// TODO: Filter out Hidden and System folders
|
// TODO: Put some checks in here along with API to ensure that we aren't passed a file, folder exists, etc.
|
||||||
// DirectoryInfo di = new DirectoryInfo(@path);
|
|
||||||
// var dirs = di.GetDirectories()
|
var di = new DirectoryInfo(rootPath);
|
||||||
// .Where(dir => (dir.Attributes & FileAttributes.Hidden & FileAttributes.System) == 0).ToImmutableList();
|
var dirs = di.GetDirectories()
|
||||||
//
|
.Where(dir => !(dir.Attributes.HasFlag(FileAttributes.Hidden) || dir.Attributes.HasFlag(FileAttributes.System)))
|
||||||
|
.Select(d => d.Name).ToImmutableList();
|
||||||
return Directory.GetDirectories(@rootPath);
|
|
||||||
|
|
||||||
|
return dirs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user