Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Chapters for Galleries #3289

Merged
merged 32 commits into from
Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
804c261
Chapters for Galleries: Frontend
yoshnopa Dec 14, 2022
5bc0e4c
Chapters for Galleries: Add current Chapter to the Header
yoshnopa Dec 15, 2022
fa0b8c0
Chapters for Galleries: Add Backend Entries and GraphQL, frontend for…
yoshnopa Dec 17, 2022
352fc3a
Merge branch 'stashapp:develop' into develop
yoshnopa Dec 17, 2022
6d591eb
Chapters for Galleries: Add Import and export, linting, handle pagebu…
yoshnopa Dec 18, 2022
68feffe
Chapters for Galleries: Integration Tests
yoshnopa Dec 18, 2022
9da4142
Chapters for Galleries: Fix Chapter header for Galleries > 40
yoshnopa Dec 18, 2022
41900ce
Chapters for Galleries: Update Dtatbase Version due to #3015 push
yoshnopa Dec 21, 2022
062cb26
Chapters for Galleries: Frontend
yoshnopa Dec 14, 2022
11144ab
Chapters for Galleries: Add current Chapter to the Header
yoshnopa Dec 15, 2022
6c0544d
Chapters for Galleries: Add Backend Entries and GraphQL, frontend for…
yoshnopa Dec 17, 2022
9e226c8
Chapters for Galleries: Add Import and export, linting, handle pagebu…
yoshnopa Dec 18, 2022
30a693a
Chapters for Galleries: Integration Tests
yoshnopa Dec 18, 2022
9419a8f
Chapters for Galleries: Fix Chapter header for Galleries > 40
yoshnopa Dec 18, 2022
93727a6
Chapters for Galleries: Update Dtatbase Version due to #3015 push
yoshnopa Dec 21, 2022
0a164b8
Merge branch 'develop' of https://github.com/yoshnopa/stash into develop
yoshnopa Dec 21, 2022
94ac199
Chapters for Galleries: Handle custom number of Images on Image wall/…
yoshnopa Jan 3, 2023
a016b45
Chapters for Galleries: Linting
yoshnopa Jan 3, 2023
4adb103
Chapters for Galleries: Fix a bug, change label to Index, show chapte…
yoshnopa Jan 3, 2023
91cae04
Chapters for Galleries: Change page number to gallery index, some fro…
yoshnopa Mar 8, 2023
1bb5e45
Merge branch 'develop' into develop
yoshnopa Mar 9, 2023
9efa4fa
Chapters for Galleries // Merging Corrections, image index check, no …
yoshnopa Mar 9, 2023
9c568fa
Merge branch 'develop' into develop
yoshnopa Mar 15, 2023
832a30a
Chapters for Galleries // Review use backend validation, naming, sql …
yoshnopa Mar 15, 2023
c84c041
Merge branch 'develop' of https://github.com/yoshnopa/stash into develop
yoshnopa Mar 15, 2023
12fef6d
Delete chapters via relationship
WithoutPants Mar 15, 2023
8053f8a
Improve chapter form
WithoutPants Mar 16, 2023
0fae8e5
Use CountByGalleryID for chapter validation
WithoutPants Mar 16, 2023
616a197
Refactor lightbox
WithoutPants Mar 16, 2023
1fd7376
Refactor chapter menu
WithoutPants Mar 16, 2023
3b64acc
Merge remote-tracking branch 'upstream/develop' into prs/3289
WithoutPants Mar 16, 2023
bf3ad75
Add changelog entry
WithoutPants Mar 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions graphql/documents/data/gallery-chapter.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fragment GalleryChapterData on GalleryChapter {
id
title
image_index

gallery {
id
}
}
5 changes: 5 additions & 0 deletions graphql/documents/data/gallery-slim.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ fragment SlimGalleryData on Gallery {
thumbnail
}
}
chapters {
id
title
image_index
}
studio {
id
name
Expand Down
3 changes: 3 additions & 0 deletions graphql/documents/data/gallery.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ fragment GalleryData on Gallery {
...FolderData
}

chapters {
...GalleryChapterData
}
cover {
...SlimImageData
}
Expand Down
31 changes: 31 additions & 0 deletions graphql/documents/mutations/gallery-chapter.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
mutation GalleryChapterCreate(
$title: String!,
$image_index: Int!,
$gallery_id: ID!) {
galleryChapterCreate(input: {
title: $title,
image_index: $image_index,
gallery_id: $gallery_id,
}) {
...GalleryChapterData
}
}

mutation GalleryChapterUpdate(
$id: ID!,
$title: String!,
$image_index: Int!,
$gallery_id: ID!) {
galleryChapterUpdate(input: {
id: $id,
title: $title,
image_index: $image_index,
gallery_id: $gallery_id,
}) {
...GalleryChapterData
}
}

mutation GalleryChapterDestroy($id: ID!) {
galleryChapterDestroy(id: $id)
}
4 changes: 4 additions & 0 deletions graphql/schema/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ type Mutation {
addGalleryImages(input: GalleryAddInput!): Boolean!
removeGalleryImages(input: GalleryRemoveInput!): Boolean!

galleryChapterCreate(input: GalleryChapterCreateInput!): GalleryChapter
galleryChapterUpdate(input: GalleryChapterUpdateInput!): GalleryChapter
galleryChapterDestroy(id: ID!): Boolean!

performerCreate(input: PerformerCreateInput!): Performer
performerUpdate(input: PerformerUpdateInput!): Performer
performerDestroy(input: PerformerDestroyInput!): Boolean!
Expand Down
2 changes: 2 additions & 0 deletions graphql/schema/types/filters.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ input GalleryFilterType {
organized: Boolean
"""Filter by average image resolution"""
average_resolution: ResolutionCriterionInput
"""Filter to only include galleries that have chapters. `true` or `false`"""
has_chapters: String
"""Filter to only include galleries with this studio"""
studios: HierarchicalMultiCriterionInput
"""Filter to only include galleries with these tags"""
Expand Down
26 changes: 26 additions & 0 deletions graphql/schema/types/gallery-chapter.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
type GalleryChapter {
id: ID!
gallery: Gallery!
title: String!
image_index: Int!
created_at: Time!
updated_at: Time!
}

input GalleryChapterCreateInput {
gallery_id: ID!
title: String!
image_index: Int!
}

input GalleryChapterUpdateInput {
id: ID!
gallery_id: ID!
title: String!
image_index: Int!
}

type FindGalleryChaptersResultType {
count: Int!
chapters: [GalleryChapter!]!
}
1 change: 1 addition & 0 deletions graphql/schema/types/gallery.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type Gallery {
files: [GalleryFile!]!
folder: Folder

chapters: [GalleryChapter!]!
scenes: [Scene!]!
studio: Studio
image_count: Int!
Expand Down
4 changes: 4 additions & 0 deletions internal/api/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ func (r *Resolver) scraperCache() *scraper.Cache {
func (r *Resolver) Gallery() GalleryResolver {
return &galleryResolver{r}
}
func (r *Resolver) GalleryChapter() GalleryChapterResolver {
return &galleryChapterResolver{r}
}
func (r *Resolver) Mutation() MutationResolver {
return &mutationResolver{r}
}
Expand Down Expand Up @@ -83,6 +86,7 @@ type queryResolver struct{ *Resolver }
type subscriptionResolver struct{ *Resolver }

type galleryResolver struct{ *Resolver }
type galleryChapterResolver struct{ *Resolver }
type performerResolver struct{ *Resolver }
type sceneResolver struct{ *Resolver }
type sceneMarkerResolver struct{ *Resolver }
Expand Down
11 changes: 11 additions & 0 deletions internal/api/resolver_model_gallery.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,14 @@ func (r *galleryResolver) ImageCount(ctx context.Context, obj *models.Gallery) (

return ret, nil
}

func (r *galleryResolver) Chapters(ctx context.Context, obj *models.Gallery) (ret []*models.GalleryChapter, err error) {
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
ret, err = r.repository.GalleryChapter.FindByGalleryID(ctx, obj.ID)
return err
}); err != nil {
return nil, err
}

return ret, nil
}
32 changes: 32 additions & 0 deletions internal/api/resolver_model_gallery_chapter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package api

import (
"context"
"time"

"github.com/stashapp/stash/pkg/models"
)

func (r *galleryChapterResolver) Gallery(ctx context.Context, obj *models.GalleryChapter) (ret *models.Gallery, err error) {
if !obj.GalleryID.Valid {
panic("Invalid gallery id")
}

if err := r.withReadTxn(ctx, func(ctx context.Context) error {
galleryID := int(obj.GalleryID.Int64)
ret, err = r.repository.Gallery.Find(ctx, galleryID)
return err
}); err != nil {
return nil, err
}

return ret, nil
}

func (r *galleryChapterResolver) CreatedAt(ctx context.Context, obj *models.GalleryChapter) (*time.Time, error) {
return &obj.CreatedAt.Timestamp, nil
}

func (r *galleryChapterResolver) UpdatedAt(ctx context.Context, obj *models.GalleryChapter) (*time.Time, error) {
return &obj.UpdatedAt.Timestamp, nil
}
149 changes: 149 additions & 0 deletions internal/api/resolver_mutation_gallery.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package api

import (
"context"
"database/sql"
"errors"
"fmt"
"os"
Expand All @@ -10,6 +11,7 @@ import (

"github.com/stashapp/stash/internal/manager"
"github.com/stashapp/stash/pkg/file"
"github.com/stashapp/stash/pkg/gallery"
"github.com/stashapp/stash/pkg/image"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/plugin"
Expand Down Expand Up @@ -489,3 +491,150 @@ func (r *mutationResolver) RemoveGalleryImages(ctx context.Context, input Galler

return true, nil
}

func (r *mutationResolver) getGalleryChapter(ctx context.Context, id int) (ret *models.GalleryChapter, err error) {
if err := r.withTxn(ctx, func(ctx context.Context) error {
ret, err = r.repository.GalleryChapter.Find(ctx, id)
return err
}); err != nil {
return nil, err
}

return ret, nil
}

func (r *mutationResolver) GalleryChapterCreate(ctx context.Context, input GalleryChapterCreateInput) (*models.GalleryChapter, error) {
galleryID, err := strconv.Atoi(input.GalleryID)
if err != nil {
return nil, err
}

var imageCount int
if err := r.withTxn(ctx, func(ctx context.Context) error {
imageCount, err = r.repository.Image.CountByGalleryID(ctx, galleryID)
return err
}); err != nil {
return nil, err
}
// Sanity Check of Index
if input.ImageIndex > imageCount || input.ImageIndex < 1 {
return nil, errors.New("Image # must greater than zero and in range of the gallery images")
}

currentTime := time.Now()
newGalleryChapter := models.GalleryChapter{
Title: input.Title,
ImageIndex: input.ImageIndex,
GalleryID: sql.NullInt64{Int64: int64(galleryID), Valid: galleryID != 0},
CreatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
UpdatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
}

if err != nil {
return nil, err
}

ret, err := r.changeChapter(ctx, create, newGalleryChapter)
if err != nil {
return nil, err
}

r.hookExecutor.ExecutePostHooks(ctx, ret.ID, plugin.GalleryChapterCreatePost, input, nil)
return r.getGalleryChapter(ctx, ret.ID)
}

func (r *mutationResolver) GalleryChapterUpdate(ctx context.Context, input GalleryChapterUpdateInput) (*models.GalleryChapter, error) {
// Populate gallery chapter from the input
galleryChapterID, err := strconv.Atoi(input.ID)
if err != nil {
return nil, err
}

galleryID, err := strconv.Atoi(input.GalleryID)
if err != nil {
return nil, err
}

var imageCount int
if err := r.withTxn(ctx, func(ctx context.Context) error {
imageCount, err = r.repository.Image.CountByGalleryID(ctx, galleryID)
return err
}); err != nil {
return nil, err
}
// Sanity Check of Index
if input.ImageIndex > imageCount || input.ImageIndex < 1 {
return nil, errors.New("Image # must greater than zero and in range of the gallery images")
}

updatedGalleryChapter := models.GalleryChapter{
ID: galleryChapterID,
Title: input.Title,
ImageIndex: input.ImageIndex,
GalleryID: sql.NullInt64{Int64: int64(galleryID), Valid: galleryID != 0},
UpdatedAt: models.SQLiteTimestamp{Timestamp: time.Now()},
}

ret, err := r.changeChapter(ctx, update, updatedGalleryChapter)
if err != nil {
return nil, err
}

translator := changesetTranslator{
inputMap: getUpdateInputMap(ctx),
}
r.hookExecutor.ExecutePostHooks(ctx, ret.ID, plugin.GalleryChapterUpdatePost, input, translator.getFields())
return r.getGalleryChapter(ctx, ret.ID)
}

func (r *mutationResolver) GalleryChapterDestroy(ctx context.Context, id string) (bool, error) {
chapterID, err := strconv.Atoi(id)
if err != nil {
return false, err
}

if err := r.withTxn(ctx, func(ctx context.Context) error {
qb := r.repository.GalleryChapter

chapter, err := qb.Find(ctx, chapterID)

if err != nil {
return err
}

if chapter == nil {
return fmt.Errorf("Chapter with id %d not found", chapterID)
}

return gallery.DestroyChapter(ctx, chapter, qb)
}); err != nil {
return false, err
}

r.hookExecutor.ExecutePostHooks(ctx, chapterID, plugin.GalleryChapterDestroyPost, id, nil)

return true, nil
}

func (r *mutationResolver) changeChapter(ctx context.Context, changeType int, changedChapter models.GalleryChapter) (*models.GalleryChapter, error) {
var galleryChapter *models.GalleryChapter

// Start the transaction and save the gallery chapter
var err = r.withTxn(ctx, func(ctx context.Context) error {
qb := r.repository.GalleryChapter
var err error

switch changeType {
case create:
galleryChapter, err = qb.Create(ctx, changedChapter)
case update:
galleryChapter, err = qb.Update(ctx, changedChapter)
if err != nil {
return err
}
}
return err
})

return galleryChapter, err
}
Loading