mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 12:24:38 +03:00
Add delete scene button
This commit is contained in:
@@ -25,3 +25,7 @@ mutation SceneUpdate(
|
|||||||
...SceneData
|
...SceneData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutation SceneDestroy($id: ID!, $delete_file: Boolean) {
|
||||||
|
sceneDestroy(input: {id: $id, delete_file: $delete_file})
|
||||||
|
}
|
||||||
@@ -72,6 +72,7 @@ type Query {
|
|||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
sceneUpdate(input: SceneUpdateInput!): Scene
|
sceneUpdate(input: SceneUpdateInput!): Scene
|
||||||
|
sceneDestroy(input: SceneDestroyInput!): Boolean!
|
||||||
|
|
||||||
sceneMarkerCreate(input: SceneMarkerCreateInput!): SceneMarker
|
sceneMarkerCreate(input: SceneMarkerCreateInput!): SceneMarker
|
||||||
sceneMarkerUpdate(input: SceneMarkerUpdateInput!): SceneMarker
|
sceneMarkerUpdate(input: SceneMarkerUpdateInput!): SceneMarker
|
||||||
|
|||||||
@@ -53,6 +53,11 @@ input SceneUpdateInput {
|
|||||||
tag_ids: [ID!]
|
tag_ids: [ID!]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input SceneDestroyInput {
|
||||||
|
id: ID!
|
||||||
|
delete_file: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
type FindScenesResultType {
|
type FindScenesResultType {
|
||||||
count: Int!
|
count: Int!
|
||||||
scenes: [Scene!]!
|
scenes: [Scene!]!
|
||||||
|
|||||||
@@ -3,10 +3,13 @@ package api
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"github.com/stashapp/stash/pkg/database"
|
"os"
|
||||||
"github.com/stashapp/stash/pkg/models"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stashapp/stash/pkg/database"
|
||||||
|
"github.com/stashapp/stash/pkg/logger"
|
||||||
|
"github.com/stashapp/stash/pkg/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *mutationResolver) SceneUpdate(ctx context.Context, input models.SceneUpdateInput) (*models.Scene, error) {
|
func (r *mutationResolver) SceneUpdate(ctx context.Context, input models.SceneUpdateInput) (*models.Scene, error) {
|
||||||
@@ -101,6 +104,59 @@ func (r *mutationResolver) SceneUpdate(ctx context.Context, input models.SceneUp
|
|||||||
return scene, nil
|
return scene, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *mutationResolver) SceneDestroy(ctx context.Context, input models.SceneDestroyInput) (bool, error) {
|
||||||
|
qb := models.NewSceneQueryBuilder()
|
||||||
|
jqb := models.NewJoinsQueryBuilder()
|
||||||
|
tx := database.DB.MustBeginTx(ctx, nil)
|
||||||
|
|
||||||
|
sceneID, _ := strconv.Atoi(input.ID)
|
||||||
|
|
||||||
|
scene, err := qb.Find(sceneID)
|
||||||
|
if err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := jqb.DestroyScenesTags(sceneID, tx); err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := jqb.DestroyPerformersScenes(sceneID, tx); err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := jqb.DestroyScenesMarkers(sceneID, tx); err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := jqb.DestroyScenesGalleries(sceneID, tx); err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := qb.Destroy(input.ID, tx); err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// if delete file is true, then delete the file as well
|
||||||
|
// if it fails, just log a message
|
||||||
|
if input.DeleteFile != nil && *input.DeleteFile {
|
||||||
|
err = os.Remove(scene.Path)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warnf("Could not delete file %s: %s", scene.Path, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *mutationResolver) SceneMarkerCreate(ctx context.Context, input models.SceneMarkerCreateInput) (*models.SceneMarker, error) {
|
func (r *mutationResolver) SceneMarkerCreate(ctx context.Context, input models.SceneMarkerCreateInput) (*models.SceneMarker, error) {
|
||||||
primaryTagID, _ := strconv.Atoi(input.PrimaryTagID)
|
primaryTagID, _ := strconv.Atoi(input.PrimaryTagID)
|
||||||
sceneID, _ := strconv.Atoi(input.SceneID)
|
sceneID, _ := strconv.Atoi(input.SceneID)
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ type ComplexityRoot struct {
|
|||||||
ConfigureGeneral func(childComplexity int, input ConfigGeneralInput) int
|
ConfigureGeneral func(childComplexity int, input ConfigGeneralInput) int
|
||||||
PerformerCreate func(childComplexity int, input PerformerCreateInput) int
|
PerformerCreate func(childComplexity int, input PerformerCreateInput) int
|
||||||
PerformerUpdate func(childComplexity int, input PerformerUpdateInput) int
|
PerformerUpdate func(childComplexity int, input PerformerUpdateInput) int
|
||||||
|
SceneDestroy func(childComplexity int, input SceneDestroyInput) int
|
||||||
SceneMarkerCreate func(childComplexity int, input SceneMarkerCreateInput) int
|
SceneMarkerCreate func(childComplexity int, input SceneMarkerCreateInput) int
|
||||||
SceneMarkerDestroy func(childComplexity int, id string) int
|
SceneMarkerDestroy func(childComplexity int, id string) int
|
||||||
SceneMarkerUpdate func(childComplexity int, input SceneMarkerUpdateInput) int
|
SceneMarkerUpdate func(childComplexity int, input SceneMarkerUpdateInput) int
|
||||||
@@ -283,6 +284,7 @@ type GalleryResolver interface {
|
|||||||
}
|
}
|
||||||
type MutationResolver interface {
|
type MutationResolver interface {
|
||||||
SceneUpdate(ctx context.Context, input SceneUpdateInput) (*Scene, error)
|
SceneUpdate(ctx context.Context, input SceneUpdateInput) (*Scene, error)
|
||||||
|
SceneDestroy(ctx context.Context, input SceneDestroyInput) (bool, error)
|
||||||
SceneMarkerCreate(ctx context.Context, input SceneMarkerCreateInput) (*SceneMarker, error)
|
SceneMarkerCreate(ctx context.Context, input SceneMarkerCreateInput) (*SceneMarker, error)
|
||||||
SceneMarkerUpdate(ctx context.Context, input SceneMarkerUpdateInput) (*SceneMarker, error)
|
SceneMarkerUpdate(ctx context.Context, input SceneMarkerUpdateInput) (*SceneMarker, error)
|
||||||
SceneMarkerDestroy(ctx context.Context, id string) (bool, error)
|
SceneMarkerDestroy(ctx context.Context, id string) (bool, error)
|
||||||
@@ -610,6 +612,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Mutation.PerformerUpdate(childComplexity, args["input"].(PerformerUpdateInput)), true
|
return e.complexity.Mutation.PerformerUpdate(childComplexity, args["input"].(PerformerUpdateInput)), true
|
||||||
|
|
||||||
|
case "Mutation.sceneDestroy":
|
||||||
|
if e.complexity.Mutation.SceneDestroy == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
args, err := ec.field_Mutation_sceneDestroy_args(context.TODO(), rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Mutation.SceneDestroy(childComplexity, args["input"].(SceneDestroyInput)), true
|
||||||
|
|
||||||
case "Mutation.sceneMarkerCreate":
|
case "Mutation.sceneMarkerCreate":
|
||||||
if e.complexity.Mutation.SceneMarkerCreate == nil {
|
if e.complexity.Mutation.SceneMarkerCreate == nil {
|
||||||
break
|
break
|
||||||
@@ -1833,6 +1847,7 @@ type Query {
|
|||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
sceneUpdate(input: SceneUpdateInput!): Scene
|
sceneUpdate(input: SceneUpdateInput!): Scene
|
||||||
|
sceneDestroy(input: SceneDestroyInput!): Boolean!
|
||||||
|
|
||||||
sceneMarkerCreate(input: SceneMarkerCreateInput!): SceneMarker
|
sceneMarkerCreate(input: SceneMarkerCreateInput!): SceneMarker
|
||||||
sceneMarkerUpdate(input: SceneMarkerUpdateInput!): SceneMarker
|
sceneMarkerUpdate(input: SceneMarkerUpdateInput!): SceneMarker
|
||||||
@@ -2158,6 +2173,11 @@ input SceneUpdateInput {
|
|||||||
tag_ids: [ID!]
|
tag_ids: [ID!]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input SceneDestroyInput {
|
||||||
|
id: ID!
|
||||||
|
delete_file: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
type FindScenesResultType {
|
type FindScenesResultType {
|
||||||
count: Int!
|
count: Int!
|
||||||
scenes: [Scene!]!
|
scenes: [Scene!]!
|
||||||
@@ -2284,6 +2304,20 @@ func (ec *executionContext) field_Mutation_performerUpdate_args(ctx context.Cont
|
|||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) field_Mutation_sceneDestroy_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
var err error
|
||||||
|
args := map[string]interface{}{}
|
||||||
|
var arg0 SceneDestroyInput
|
||||||
|
if tmp, ok := rawArgs["input"]; ok {
|
||||||
|
arg0, err = ec.unmarshalNSceneDestroyInput2githubᚗcomᚋstashappᚋstashᚋpkgᚋmodelsᚐSceneDestroyInput(ctx, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args["input"] = arg0
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) field_Mutation_sceneMarkerCreate_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
func (ec *executionContext) field_Mutation_sceneMarkerCreate_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
args := map[string]interface{}{}
|
args := map[string]interface{}{}
|
||||||
@@ -3467,6 +3501,40 @@ func (ec *executionContext) _Mutation_sceneUpdate(ctx context.Context, field gra
|
|||||||
return ec.marshalOScene2ᚖgithubᚗcomᚋstashappᚋstashᚋpkgᚋmodelsᚐScene(ctx, field.Selections, res)
|
return ec.marshalOScene2ᚖgithubᚗcomᚋstashappᚋstashᚋpkgᚋmodelsᚐScene(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Mutation_sceneDestroy(ctx context.Context, field graphql.CollectedField) graphql.Marshaler {
|
||||||
|
ctx = ec.Tracer.StartFieldExecution(ctx, field)
|
||||||
|
defer func() { ec.Tracer.EndFieldExecution(ctx) }()
|
||||||
|
rctx := &graphql.ResolverContext{
|
||||||
|
Object: "Mutation",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: true,
|
||||||
|
}
|
||||||
|
ctx = graphql.WithResolverContext(ctx, rctx)
|
||||||
|
rawArgs := field.ArgumentMap(ec.Variables)
|
||||||
|
args, err := ec.field_Mutation_sceneDestroy_args(ctx, rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
rctx.Args = args
|
||||||
|
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
|
||||||
|
resTmp := ec.FieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return ec.resolvers.Mutation().SceneDestroy(rctx, args["input"].(SceneDestroyInput))
|
||||||
|
})
|
||||||
|
if resTmp == nil {
|
||||||
|
if !ec.HasError(rctx) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(bool)
|
||||||
|
rctx.Result = res
|
||||||
|
ctx = ec.Tracer.StartFieldChildExecution(ctx)
|
||||||
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Mutation_sceneMarkerCreate(ctx context.Context, field graphql.CollectedField) graphql.Marshaler {
|
func (ec *executionContext) _Mutation_sceneMarkerCreate(ctx context.Context, field graphql.CollectedField) graphql.Marshaler {
|
||||||
ctx = ec.Tracer.StartFieldExecution(ctx, field)
|
ctx = ec.Tracer.StartFieldExecution(ctx, field)
|
||||||
defer func() { ec.Tracer.EndFieldExecution(ctx) }()
|
defer func() { ec.Tracer.EndFieldExecution(ctx) }()
|
||||||
@@ -8269,6 +8337,30 @@ func (ec *executionContext) unmarshalInputPerformerUpdateInput(ctx context.Conte
|
|||||||
return it, nil
|
return it, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalInputSceneDestroyInput(ctx context.Context, v interface{}) (SceneDestroyInput, error) {
|
||||||
|
var it SceneDestroyInput
|
||||||
|
var asMap = v.(map[string]interface{})
|
||||||
|
|
||||||
|
for k, v := range asMap {
|
||||||
|
switch k {
|
||||||
|
case "id":
|
||||||
|
var err error
|
||||||
|
it.ID, err = ec.unmarshalNID2string(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "delete_file":
|
||||||
|
var err error
|
||||||
|
it.DeleteFile, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return it, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalInputSceneFilterType(ctx context.Context, v interface{}) (SceneFilterType, error) {
|
func (ec *executionContext) unmarshalInputSceneFilterType(ctx context.Context, v interface{}) (SceneFilterType, error) {
|
||||||
var it SceneFilterType
|
var it SceneFilterType
|
||||||
var asMap = v.(map[string]interface{})
|
var asMap = v.(map[string]interface{})
|
||||||
@@ -9032,6 +9124,11 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
|||||||
out.Values[i] = graphql.MarshalString("Mutation")
|
out.Values[i] = graphql.MarshalString("Mutation")
|
||||||
case "sceneUpdate":
|
case "sceneUpdate":
|
||||||
out.Values[i] = ec._Mutation_sceneUpdate(ctx, field)
|
out.Values[i] = ec._Mutation_sceneUpdate(ctx, field)
|
||||||
|
case "sceneDestroy":
|
||||||
|
out.Values[i] = ec._Mutation_sceneDestroy(ctx, field)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
case "sceneMarkerCreate":
|
case "sceneMarkerCreate":
|
||||||
out.Values[i] = ec._Mutation_sceneMarkerCreate(ctx, field)
|
out.Values[i] = ec._Mutation_sceneMarkerCreate(ctx, field)
|
||||||
case "sceneMarkerUpdate":
|
case "sceneMarkerUpdate":
|
||||||
@@ -11065,6 +11162,10 @@ func (ec *executionContext) marshalNScene2ᚖgithubᚗcomᚋstashappᚋstashᚋp
|
|||||||
return ec._Scene(ctx, sel, v)
|
return ec._Scene(ctx, sel, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalNSceneDestroyInput2githubᚗcomᚋstashappᚋstashᚋpkgᚋmodelsᚐSceneDestroyInput(ctx context.Context, v interface{}) (SceneDestroyInput, error) {
|
||||||
|
return ec.unmarshalInputSceneDestroyInput(ctx, v)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) marshalNSceneFileType2githubᚗcomᚋstashappᚋstashᚋpkgᚋmodelsᚐSceneFileType(ctx context.Context, sel ast.SelectionSet, v SceneFileType) graphql.Marshaler {
|
func (ec *executionContext) marshalNSceneFileType2githubᚗcomᚋstashappᚋstashᚋpkgᚋmodelsᚐSceneFileType(ctx context.Context, sel ast.SelectionSet, v SceneFileType) graphql.Marshaler {
|
||||||
return ec._SceneFileType(ctx, sel, &v)
|
return ec._SceneFileType(ctx, sel, &v)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,6 +136,11 @@ type PerformerUpdateInput struct {
|
|||||||
Image *string `json:"image"`
|
Image *string `json:"image"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SceneDestroyInput struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
DeleteFile *bool `json:"delete_file"`
|
||||||
|
}
|
||||||
|
|
||||||
type SceneFileType struct {
|
type SceneFileType struct {
|
||||||
Size *string `json:"size"`
|
Size *string `json:"size"`
|
||||||
Duration *float64 `json:"duration"`
|
Duration *float64 `json:"duration"`
|
||||||
|
|||||||
@@ -33,6 +33,14 @@ func (qb *JoinsQueryBuilder) UpdatePerformersScenes(sceneID int, updatedJoins []
|
|||||||
return qb.CreatePerformersScenes(updatedJoins, tx)
|
return qb.CreatePerformersScenes(updatedJoins, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (qb *JoinsQueryBuilder) DestroyPerformersScenes(sceneID int, tx *sqlx.Tx) error {
|
||||||
|
ensureTx(tx)
|
||||||
|
|
||||||
|
// Delete the existing joins
|
||||||
|
_, err := tx.Exec("DELETE FROM performers_scenes WHERE scene_id = ?", sceneID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (qb *JoinsQueryBuilder) CreateScenesTags(newJoins []ScenesTags, tx *sqlx.Tx) error {
|
func (qb *JoinsQueryBuilder) CreateScenesTags(newJoins []ScenesTags, tx *sqlx.Tx) error {
|
||||||
ensureTx(tx)
|
ensureTx(tx)
|
||||||
for _, join := range newJoins {
|
for _, join := range newJoins {
|
||||||
@@ -58,6 +66,15 @@ func (qb *JoinsQueryBuilder) UpdateScenesTags(sceneID int, updatedJoins []Scenes
|
|||||||
return qb.CreateScenesTags(updatedJoins, tx)
|
return qb.CreateScenesTags(updatedJoins, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (qb *JoinsQueryBuilder) DestroyScenesTags(sceneID int, tx *sqlx.Tx) error {
|
||||||
|
ensureTx(tx)
|
||||||
|
|
||||||
|
// Delete the existing joins
|
||||||
|
_, err := tx.Exec("DELETE FROM scenes_tags WHERE scene_id = ?", sceneID)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (qb *JoinsQueryBuilder) CreateSceneMarkersTags(newJoins []SceneMarkersTags, tx *sqlx.Tx) error {
|
func (qb *JoinsQueryBuilder) CreateSceneMarkersTags(newJoins []SceneMarkersTags, tx *sqlx.Tx) error {
|
||||||
ensureTx(tx)
|
ensureTx(tx)
|
||||||
for _, join := range newJoins {
|
for _, join := range newJoins {
|
||||||
@@ -82,3 +99,32 @@ func (qb *JoinsQueryBuilder) UpdateSceneMarkersTags(sceneMarkerID int, updatedJo
|
|||||||
}
|
}
|
||||||
return qb.CreateSceneMarkersTags(updatedJoins, tx)
|
return qb.CreateSceneMarkersTags(updatedJoins, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (qb *JoinsQueryBuilder) DestroySceneMarkersTags(sceneMarkerID int, updatedJoins []SceneMarkersTags, tx *sqlx.Tx) error {
|
||||||
|
ensureTx(tx)
|
||||||
|
|
||||||
|
// Delete the existing joins
|
||||||
|
_, err := tx.Exec("DELETE FROM scene_markers_tags WHERE scene_marker_id = ?", sceneMarkerID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *JoinsQueryBuilder) DestroyScenesGalleries(sceneID int, tx *sqlx.Tx) error {
|
||||||
|
ensureTx(tx)
|
||||||
|
|
||||||
|
// Unset the existing scene id from galleries
|
||||||
|
_, err := tx.Exec("UPDATE galleries SET scene_id = null WHERE scene_id = ?", sceneID)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *JoinsQueryBuilder) DestroyScenesMarkers(sceneID int, tx *sqlx.Tx) error {
|
||||||
|
ensureTx(tx)
|
||||||
|
|
||||||
|
// Delete the scene marker tags
|
||||||
|
_, err := tx.Exec("DELETE t FROM scene_markers_tags t join scene_markers m on t.scene_marker_id = m.id WHERE m.scene_id = ?", sceneID)
|
||||||
|
|
||||||
|
// Delete the existing joins
|
||||||
|
_, err = tx.Exec("DELETE FROM scene_markers WHERE scene_id = ?", sceneID)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ package models
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"github.com/jmoiron/sqlx"
|
|
||||||
"github.com/stashapp/stash/pkg/database"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
"github.com/stashapp/stash/pkg/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
const scenesForPerformerQuery = `
|
const scenesForPerformerQuery = `
|
||||||
@@ -76,6 +77,9 @@ func (qb *SceneQueryBuilder) Update(updatedScene Scene, tx *sqlx.Tx) (*Scene, er
|
|||||||
return &updatedScene, nil
|
return &updatedScene, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (qb *SceneQueryBuilder) Destroy(id string, tx *sqlx.Tx) error {
|
||||||
|
return executeDeleteQuery("scenes", id, tx)
|
||||||
|
}
|
||||||
func (qb *SceneQueryBuilder) Find(id int) (*Scene, error) {
|
func (qb *SceneQueryBuilder) Find(id int) (*Scene, error) {
|
||||||
query := "SELECT * FROM scenes WHERE id = ? LIMIT 1"
|
query := "SELECT * FROM scenes WHERE id = ? LIMIT 1"
|
||||||
args := []interface{}{id}
|
args := []interface{}{id}
|
||||||
|
|||||||
@@ -82,7 +82,12 @@ export const Scene: FunctionComponent<ISceneProps> = (props: ISceneProps) => {
|
|||||||
<Tab
|
<Tab
|
||||||
id="scene-edit-panel"
|
id="scene-edit-panel"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
panel={<SceneEditPanel scene={modifiedScene} onUpdate={(newScene) => setScene(newScene)} />}
|
panel={
|
||||||
|
<SceneEditPanel
|
||||||
|
scene={modifiedScene}
|
||||||
|
onUpdate={(newScene) => setScene(newScene)}
|
||||||
|
onDelete={() => props.history.push("/scenes")}
|
||||||
|
/>}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
Alert,
|
||||||
Button,
|
Button,
|
||||||
FormGroup,
|
FormGroup,
|
||||||
HTMLSelect,
|
HTMLSelect,
|
||||||
@@ -19,6 +20,7 @@ import { ValidGalleriesSelect } from "../../select/ValidGalleriesSelect";
|
|||||||
interface IProps {
|
interface IProps {
|
||||||
scene: GQL.SceneDataFragment;
|
scene: GQL.SceneDataFragment;
|
||||||
onUpdate: (scene: GQL.SceneDataFragment) => void;
|
onUpdate: (scene: GQL.SceneDataFragment) => void;
|
||||||
|
onDelete: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SceneEditPanel: FunctionComponent<IProps> = (props: IProps) => {
|
export const SceneEditPanel: FunctionComponent<IProps> = (props: IProps) => {
|
||||||
@@ -33,10 +35,14 @@ export const SceneEditPanel: FunctionComponent<IProps> = (props: IProps) => {
|
|||||||
const [performerIds, setPerformerIds] = useState<string[] | undefined>(undefined);
|
const [performerIds, setPerformerIds] = useState<string[] | undefined>(undefined);
|
||||||
const [tagIds, setTagIds] = useState<string[] | undefined>(undefined);
|
const [tagIds, setTagIds] = useState<string[] | undefined>(undefined);
|
||||||
|
|
||||||
|
const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState<boolean>(false);
|
||||||
|
const [deleteFile, setDeleteFile] = useState<boolean>(false);
|
||||||
|
|
||||||
// Network state
|
// Network state
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const updateScene = StashService.useSceneUpdate(getSceneInput());
|
const updateScene = StashService.useSceneUpdate(getSceneInput());
|
||||||
|
const deleteScene = StashService.useSceneDestroy(getSceneDeleteInput());
|
||||||
|
|
||||||
function updateSceneEditState(state: Partial<GQL.SceneDataFragment>) {
|
function updateSceneEditState(state: Partial<GQL.SceneDataFragment>) {
|
||||||
const perfIds = !!state.performers ? state.performers.map((performer) => performer.id) : undefined;
|
const perfIds = !!state.performers ? state.performers.map((performer) => performer.id) : undefined;
|
||||||
@@ -89,6 +95,27 @@ export const SceneEditPanel: FunctionComponent<IProps> = (props: IProps) => {
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSceneDeleteInput(): GQL.SceneDestroyInput {
|
||||||
|
return {
|
||||||
|
id: props.scene.id,
|
||||||
|
delete_file: deleteFile
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onDelete() {
|
||||||
|
setIsDeleteAlertOpen(false);
|
||||||
|
setIsLoading(true);
|
||||||
|
try {
|
||||||
|
await deleteScene();
|
||||||
|
ToastUtils.success("Deleted scene");
|
||||||
|
} catch (e) {
|
||||||
|
ErrorUtils.handle(e);
|
||||||
|
}
|
||||||
|
setIsLoading(false);
|
||||||
|
|
||||||
|
props.onDelete();
|
||||||
|
}
|
||||||
|
|
||||||
function renderMultiSelect(type: "performers" | "tags", initialIds: string[] | undefined) {
|
function renderMultiSelect(type: "performers" | "tags", initialIds: string[] | undefined) {
|
||||||
return (
|
return (
|
||||||
<FilterMultiSelect
|
<FilterMultiSelect
|
||||||
@@ -105,8 +132,27 @@ export const SceneEditPanel: FunctionComponent<IProps> = (props: IProps) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderDeleteAlert() {
|
||||||
|
return (
|
||||||
|
<Alert
|
||||||
|
cancelButtonText="Cancel"
|
||||||
|
confirmButtonText="Delete"
|
||||||
|
icon="trash"
|
||||||
|
intent="danger"
|
||||||
|
isOpen={isDeleteAlertOpen}
|
||||||
|
onCancel={() => setIsDeleteAlertOpen(false)}
|
||||||
|
onConfirm={() => onDelete()}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
Are you sure you want to delete this scene? Unless the file is also deleted, this scene will be re-added when scan is performed.
|
||||||
|
</p>
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{renderDeleteAlert()}
|
||||||
{isLoading ? <Spinner size={Spinner.SIZE_LARGE} /> : undefined}
|
{isLoading ? <Spinner size={Spinner.SIZE_LARGE} /> : undefined}
|
||||||
<div className="form-container " style={{width: "50%"}}>
|
<div className="form-container " style={{width: "50%"}}>
|
||||||
<FormGroup label="Title">
|
<FormGroup label="Title">
|
||||||
@@ -171,6 +217,7 @@ export const SceneEditPanel: FunctionComponent<IProps> = (props: IProps) => {
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
</div>
|
</div>
|
||||||
<Button text="Save" intent="primary" onClick={() => onSave()}/>
|
<Button text="Save" intent="primary" onClick={() => onSave()}/>
|
||||||
|
<Button text="Delete" intent="danger" onClick={() => setIsDeleteAlertOpen(true)}/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -138,6 +138,10 @@ export class StashService {
|
|||||||
return GQL.useSceneUpdate({ variables: input });
|
return GQL.useSceneUpdate({ variables: input });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static useSceneDestroy(input: GQL.SceneDestroyInput) {
|
||||||
|
return GQL.useSceneDestroy({ variables: input });
|
||||||
|
}
|
||||||
|
|
||||||
public static useStudioCreate(input: GQL.StudioCreateInput) {
|
public static useStudioCreate(input: GQL.StudioCreateInput) {
|
||||||
return GQL.useStudioCreate({ variables: input });
|
return GQL.useStudioCreate({ variables: input });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// Generated in 2019-05-27T11:23:10-07:00
|
// Generated in 2019-08-15T13:55:54+10:00
|
||||||
export type Maybe<T> = T | undefined;
|
export type Maybe<T> = T | undefined;
|
||||||
|
|
||||||
export interface SceneFilterType {
|
export interface SceneFilterType {
|
||||||
@@ -88,6 +88,12 @@ export interface SceneUpdateInput {
|
|||||||
tag_ids?: Maybe<string[]>;
|
tag_ids?: Maybe<string[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SceneDestroyInput {
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
delete_file?: Maybe<boolean>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SceneMarkerCreateInput {
|
export interface SceneMarkerCreateInput {
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
@@ -390,6 +396,17 @@ export type SceneUpdateMutation = {
|
|||||||
|
|
||||||
export type SceneUpdateSceneUpdate = SceneDataFragment;
|
export type SceneUpdateSceneUpdate = SceneDataFragment;
|
||||||
|
|
||||||
|
export type SceneDestroyVariables = {
|
||||||
|
id: string;
|
||||||
|
delete_file?: Maybe<boolean>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SceneDestroyMutation = {
|
||||||
|
__typename?: "Mutation";
|
||||||
|
|
||||||
|
sceneDestroy: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type StudioCreateVariables = {
|
export type StudioCreateVariables = {
|
||||||
name: string;
|
name: string;
|
||||||
url?: Maybe<string>;
|
url?: Maybe<string>;
|
||||||
@@ -1774,6 +1791,22 @@ export function useSceneUpdate(
|
|||||||
SceneUpdateVariables
|
SceneUpdateVariables
|
||||||
>(SceneUpdateDocument, baseOptions);
|
>(SceneUpdateDocument, baseOptions);
|
||||||
}
|
}
|
||||||
|
export const SceneDestroyDocument = gql`
|
||||||
|
mutation SceneDestroy($id: ID!, $delete_file: Boolean) {
|
||||||
|
sceneDestroy(input: { id: $id, delete_file: $delete_file })
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export function useSceneDestroy(
|
||||||
|
baseOptions?: ReactApolloHooks.MutationHookOptions<
|
||||||
|
SceneDestroyMutation,
|
||||||
|
SceneDestroyVariables
|
||||||
|
>
|
||||||
|
) {
|
||||||
|
return ReactApolloHooks.useMutation<
|
||||||
|
SceneDestroyMutation,
|
||||||
|
SceneDestroyVariables
|
||||||
|
>(SceneDestroyDocument, baseOptions);
|
||||||
|
}
|
||||||
export const StudioCreateDocument = gql`
|
export const StudioCreateDocument = gql`
|
||||||
mutation StudioCreate($name: String!, $url: String, $image: String!) {
|
mutation StudioCreate($name: String!, $url: String, $image: String!) {
|
||||||
studioCreate(input: { name: $name, url: $url, image: $image }) {
|
studioCreate(input: { name: $name, url: $url, image: $image }) {
|
||||||
|
|||||||
Reference in New Issue
Block a user