mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-06-01 04:34:50 -04:00
Add delete route that allow recursive delete for directories
This commit is contained in:
parent
fccc5b6ad9
commit
9e089b21ed
@ -84,6 +84,27 @@ public class MiscRepository(
|
|||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<int> DeletePath(string path, bool recurse)
|
||||||
|
{
|
||||||
|
// Make sure to include a path separator to prevents deletions from things like:
|
||||||
|
// DeletePath("/video/abc", true) -> /video/abdc (should not be deleted)
|
||||||
|
string dirPath = path.EndsWith("/") ? path : $"{path}/";
|
||||||
|
|
||||||
|
int count = await context
|
||||||
|
.Episodes.Where(x => x.Path == path || (recurse && x.Path.StartsWith(dirPath)))
|
||||||
|
.ExecuteDeleteAsync();
|
||||||
|
count += await context
|
||||||
|
.Movies.Where(x => x.Path == path || (recurse && x.Path.StartsWith(dirPath)))
|
||||||
|
.ExecuteDeleteAsync();
|
||||||
|
await context
|
||||||
|
.Issues.Where(x =>
|
||||||
|
x.Domain == "scanner"
|
||||||
|
&& (x.Cause == path || (recurse && x.Cause.StartsWith(dirPath)))
|
||||||
|
)
|
||||||
|
.ExecuteDeleteAsync();
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<ICollection<RefreshableItem>> GetRefreshableItems(DateTime end)
|
public async Task<ICollection<RefreshableItem>> GetRefreshableItems(DateTime end)
|
||||||
{
|
{
|
||||||
IQueryable<RefreshableItem> GetItems<T>()
|
IQueryable<RefreshableItem> GetItems<T>()
|
||||||
|
@ -30,7 +30,7 @@ namespace Kyoo.Core.Api;
|
|||||||
/// Private APIs only used for other services. Can change at any time without notice.
|
/// Private APIs only used for other services. Can change at any time without notice.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Permission(nameof(Misc), Kind.Read, Group = Group.Admin)]
|
[PartialPermission(nameof(Misc), Group = Group.Admin)]
|
||||||
public class Misc(MiscRepository repo) : BaseApi
|
public class Misc(MiscRepository repo) : BaseApi
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -38,18 +38,40 @@ public class Misc(MiscRepository repo) : BaseApi
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The list of paths known to Kyoo.</returns>
|
/// <returns>The list of paths known to Kyoo.</returns>
|
||||||
[HttpGet("/paths")]
|
[HttpGet("/paths")]
|
||||||
|
[PartialPermission(Kind.Read)]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public Task<ICollection<string>> GetAllPaths()
|
public Task<ICollection<string>> GetAllPaths()
|
||||||
{
|
{
|
||||||
return repo.GetRegisteredPaths();
|
return repo.GetRegisteredPaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete item at path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to delete.</param>
|
||||||
|
/// <param name="recursive">
|
||||||
|
/// If true, the path will be considered as a directory and every children will be removed.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>Nothing</returns>
|
||||||
|
[HttpDelete("/paths")]
|
||||||
|
[PartialPermission(Kind.Delete)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
|
public async Task<IActionResult> DeletePath(
|
||||||
|
[FromQuery] string path,
|
||||||
|
[FromQuery] bool recursive = false
|
||||||
|
)
|
||||||
|
{
|
||||||
|
await repo.DeletePath(path, recursive);
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// List items to refresh.
|
/// List items to refresh.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="date">The upper limit for the refresh date.</param>
|
/// <param name="date">The upper limit for the refresh date.</param>
|
||||||
/// <returns>The items that should be refreshed before the given date</returns>
|
/// <returns>The items that should be refreshed before the given date</returns>
|
||||||
[HttpGet("/refreshables")]
|
[HttpGet("/refreshables")]
|
||||||
|
[PartialPermission(Kind.Read)]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public Task<ICollection<RefreshableItem>> GetAllPaths([FromQuery] DateTime? date)
|
public Task<ICollection<RefreshableItem>> GetAllPaths([FromQuery] DateTime? date)
|
||||||
{
|
{
|
||||||
|
@ -104,29 +104,16 @@ class KyooClient:
|
|||||||
async def delete(
|
async def delete(
|
||||||
self,
|
self,
|
||||||
path: str,
|
path: str,
|
||||||
type: Literal["episode", "movie"] | None = None,
|
|
||||||
):
|
):
|
||||||
logger.info("Deleting %s", path)
|
logger.info("Deleting %s", path)
|
||||||
|
|
||||||
if type is None or type == "movie":
|
async with self.client.delete(
|
||||||
async with self.client.delete(
|
f'{self._url}/paths?recursive=true&path={quote(path)}',
|
||||||
f'{self._url}/movies?filter=path eq "{quote(path)}"',
|
headers={"X-API-Key": self._api_key},
|
||||||
headers={"X-API-Key": self._api_key},
|
) as r:
|
||||||
) as r:
|
if not r.ok:
|
||||||
if not r.ok:
|
logger.error(f"Request error: {await r.text()}")
|
||||||
logger.error(f"Request error: {await r.text()}")
|
r.raise_for_status()
|
||||||
r.raise_for_status()
|
|
||||||
|
|
||||||
if type is None or type == "episode":
|
|
||||||
async with self.client.delete(
|
|
||||||
f'{self._url}/episodes?filter=path eq "{quote(path)}"',
|
|
||||||
headers={"X-API-Key": self._api_key},
|
|
||||||
) as r:
|
|
||||||
if not r.ok:
|
|
||||||
logger.error(f"Request error: {await r.text()}")
|
|
||||||
r.raise_for_status()
|
|
||||||
|
|
||||||
await self.delete_issue(path)
|
|
||||||
|
|
||||||
async def get(self, path: str):
|
async def get(self, path: str):
|
||||||
async with self.client.get(
|
async with self.client.get(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user