mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Correctly delete files when specified (#2804)
This commit is contained in:
@@ -181,7 +181,7 @@ func Destroy(ctx context.Context, destroyer Destroyer, f File, fileDeleter *Dele
|
|||||||
}
|
}
|
||||||
|
|
||||||
// don't delete files in zip files
|
// don't delete files in zip files
|
||||||
if deleteFile && f.Base().ZipFileID != nil {
|
if deleteFile && f.Base().ZipFileID == nil {
|
||||||
if err := fileDeleter.Files([]string{f.Base().Path}); err != nil {
|
if err := fileDeleter.Files([]string{f.Base().Path}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -190,17 +190,24 @@ func Destroy(ctx context.Context, destroyer Destroyer, f File, fileDeleter *Dele
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type FolderGetterDestroyer interface {
|
|
||||||
FolderGetter
|
|
||||||
FolderDestroyer
|
|
||||||
}
|
|
||||||
|
|
||||||
type ZipDestroyer struct {
|
type ZipDestroyer struct {
|
||||||
FileDestroyer Destroyer
|
FileDestroyer GetterDestroyer
|
||||||
FolderDestroyer FolderGetterDestroyer
|
FolderDestroyer FolderGetterDestroyer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *ZipDestroyer) DestroyZip(ctx context.Context, f File, fileDeleter *Deleter, deleteFile bool) error {
|
func (d *ZipDestroyer) DestroyZip(ctx context.Context, f File, fileDeleter *Deleter, deleteFile bool) error {
|
||||||
|
// destroy contained files
|
||||||
|
files, err := d.FileDestroyer.FindByZipFileID(ctx, f.Base().ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ff := range files {
|
||||||
|
if err := d.FileDestroyer.Destroy(ctx, ff.Base().ID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// destroy contained folders
|
// destroy contained folders
|
||||||
folders, err := d.FolderDestroyer.FindByZipFileID(ctx, f.Base().ID)
|
folders, err := d.FolderDestroyer.FindByZipFileID(ctx, f.Base().ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -177,6 +177,11 @@ type Destroyer interface {
|
|||||||
Destroy(ctx context.Context, id ID) error
|
Destroy(ctx context.Context, id ID) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GetterDestroyer interface {
|
||||||
|
Getter
|
||||||
|
Destroyer
|
||||||
|
}
|
||||||
|
|
||||||
// Store provides methods to find, create and update Files.
|
// Store provides methods to find, create and update Files.
|
||||||
type Store interface {
|
type Store interface {
|
||||||
Getter
|
Getter
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ type FolderDestroyer interface {
|
|||||||
Destroy(ctx context.Context, id FolderID) error
|
Destroy(ctx context.Context, id FolderID) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FolderGetterDestroyer interface {
|
||||||
|
FolderGetter
|
||||||
|
FolderDestroyer
|
||||||
|
}
|
||||||
|
|
||||||
// FolderStore provides methods to find, create and update Folders.
|
// FolderStore provides methods to find, create and update Folders.
|
||||||
type FolderStore interface {
|
type FolderStore interface {
|
||||||
FolderGetter
|
FolderGetter
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { useToast } from "src/hooks";
|
|||||||
import { ConfigurationContext } from "src/hooks/Config";
|
import { ConfigurationContext } from "src/hooks/Config";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
import { faTrashAlt } from "@fortawesome/free-solid-svg-icons";
|
import { faTrashAlt } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { galleryPath } from "src/core/galleries";
|
|
||||||
|
|
||||||
interface IDeleteGalleryDialogProps {
|
interface IDeleteGalleryDialogProps {
|
||||||
selected: GQL.SlimGalleryDataFragment[];
|
selected: GQL.SlimGalleryDataFragment[];
|
||||||
@@ -74,8 +73,14 @@ export const DeleteGalleriesDialog: React.FC<IDeleteGalleryDialogProps> = (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fsGalleries = props.selected.filter((g) => galleryPath(g));
|
const deletedFiles: string[] = [];
|
||||||
if (fsGalleries.length === 0) {
|
|
||||||
|
props.selected.forEach((s) => {
|
||||||
|
const paths = s.files.map((f) => f.path);
|
||||||
|
deletedFiles.push(...paths);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (deletedFiles.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +89,7 @@ export const DeleteGalleriesDialog: React.FC<IDeleteGalleryDialogProps> = (
|
|||||||
<p className="font-weight-bold">
|
<p className="font-weight-bold">
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
values={{
|
values={{
|
||||||
count: fsGalleries.length,
|
count: deletedFiles.length,
|
||||||
singularEntity: intl.formatMessage({ id: "file" }),
|
singularEntity: intl.formatMessage({ id: "file" }),
|
||||||
pluralEntity: intl.formatMessage({ id: "files" }),
|
pluralEntity: intl.formatMessage({ id: "files" }),
|
||||||
}}
|
}}
|
||||||
@@ -92,13 +97,13 @@ export const DeleteGalleriesDialog: React.FC<IDeleteGalleryDialogProps> = (
|
|||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
{fsGalleries.slice(0, 5).map((s) => (
|
{deletedFiles.slice(0, 5).map((s) => (
|
||||||
<li key={galleryPath(s)}>{galleryPath(s)}</li>
|
<li key={s}>{s}</li>
|
||||||
))}
|
))}
|
||||||
{fsGalleries.length > 5 && (
|
{deletedFiles.length > 5 && (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
values={{
|
values={{
|
||||||
count: fsGalleries.length - 5,
|
count: deletedFiles.length - 5,
|
||||||
singularEntity: intl.formatMessage({ id: "file" }),
|
singularEntity: intl.formatMessage({ id: "file" }),
|
||||||
pluralEntity: intl.formatMessage({ id: "files" }),
|
pluralEntity: intl.formatMessage({ id: "files" }),
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { useToast } from "src/hooks";
|
|||||||
import { ConfigurationContext } from "src/hooks/Config";
|
import { ConfigurationContext } from "src/hooks/Config";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
import { faTrashAlt } from "@fortawesome/free-solid-svg-icons";
|
import { faTrashAlt } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { objectPath } from "src/core/files";
|
|
||||||
|
|
||||||
interface IDeleteImageDialogProps {
|
interface IDeleteImageDialogProps {
|
||||||
selected: GQL.SlimImageDataFragment[];
|
selected: GQL.SlimImageDataFragment[];
|
||||||
@@ -74,12 +73,19 @@ export const DeleteImagesDialog: React.FC<IDeleteImageDialogProps> = (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deletedFiles: string[] = [];
|
||||||
|
|
||||||
|
props.selected.forEach((s) => {
|
||||||
|
const paths = s.files.map((f) => f.path);
|
||||||
|
deletedFiles.push(...paths);
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="delete-dialog alert alert-danger text-break">
|
<div className="delete-dialog alert alert-danger text-break">
|
||||||
<p className="font-weight-bold">
|
<p className="font-weight-bold">
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
values={{
|
values={{
|
||||||
count: props.selected.length,
|
count: deletedFiles.length,
|
||||||
singularEntity: intl.formatMessage({ id: "file" }),
|
singularEntity: intl.formatMessage({ id: "file" }),
|
||||||
pluralEntity: intl.formatMessage({ id: "files" }),
|
pluralEntity: intl.formatMessage({ id: "files" }),
|
||||||
}}
|
}}
|
||||||
@@ -87,13 +93,13 @@ export const DeleteImagesDialog: React.FC<IDeleteImageDialogProps> = (
|
|||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
{props.selected.slice(0, 5).map((s) => (
|
{deletedFiles.slice(0, 5).map((s) => (
|
||||||
<li key={objectPath(s)}>{objectPath(s)}</li>
|
<li key={s}>{s}</li>
|
||||||
))}
|
))}
|
||||||
{props.selected.length > 5 && (
|
{deletedFiles.length > 5 && (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
values={{
|
values={{
|
||||||
count: props.selected.length - 5,
|
count: deletedFiles.length - 5,
|
||||||
singularEntity: intl.formatMessage({ id: "file" }),
|
singularEntity: intl.formatMessage({ id: "file" }),
|
||||||
pluralEntity: intl.formatMessage({ id: "files" }),
|
pluralEntity: intl.formatMessage({ id: "files" }),
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ export const DeleteScenesDialog: React.FC<IDeleteSceneDialogProps> = (
|
|||||||
<p className="font-weight-bold">
|
<p className="font-weight-bold">
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
values={{
|
values={{
|
||||||
count: props.selected.length,
|
count: deletedFiles.length,
|
||||||
singularEntity: intl.formatMessage({ id: "file" }),
|
singularEntity: intl.formatMessage({ id: "file" }),
|
||||||
pluralEntity: intl.formatMessage({ id: "files" }),
|
pluralEntity: intl.formatMessage({ id: "files" }),
|
||||||
}}
|
}}
|
||||||
|
|||||||
Reference in New Issue
Block a user