From a7113d5efed4465780e7c76bbd55ec2b9ec9ab81 Mon Sep 17 00:00:00 2001 From: Gisle Aune Date: Sat, 7 Jul 2018 17:45:24 +0200 Subject: [PATCH] Added add/edit/remove mutations for Chapter --- resolver/chapter.go | 143 ++++++++++++++++++++++++++++++++++- schema/root.graphql | 10 +++ schema/types/chapter.graphql | 36 +++++++++ 3 files changed, 187 insertions(+), 2 deletions(-) diff --git a/resolver/chapter.go b/resolver/chapter.go index 972d2c1..94b86f9 100644 --- a/resolver/chapter.go +++ b/resolver/chapter.go @@ -4,18 +4,20 @@ import ( "context" "time" + "git.aiterp.net/rpdata/api/internal/session" + "git.aiterp.net/rpdata/api/model/change" "git.aiterp.net/rpdata/api/model/story" ) // ChapterResolver for the Chapter graphql type type ChapterResolver struct{ C story.Chapter } -// ChapterArgs is args for channel query +// ChapterArgs is args for chapter query type ChapterArgs struct { ID string } -// Chapter implements the channel query +// Chapter implements the chapter query func (r *QueryResolver) Chapter(ctx context.Context, args *ChapterArgs) (*ChapterResolver, error) { chapter, err := story.FindChapterID(args.ID) if err != nil { @@ -25,6 +27,143 @@ func (r *QueryResolver) Chapter(ctx context.Context, args *ChapterArgs) (*Chapte return &ChapterResolver{C: chapter}, nil } +// AddChapterArgs is args for the addChapter mutation +type AddChapterArgs struct { + Input *AddChapterInput +} + +// AddChapterInput is input for the addChapter mutation +type AddChapterInput struct { + StoryID string + Title string + Author *string + Source string + FictionalDate *string +} + +// AddChapter implements the addChapter mutation +func (r *MutationResolver) AddChapter(ctx context.Context, args *AddChapterArgs) (*ChapterResolver, error) { + user := session.FromContext(ctx).User() + if user == nil || !user.Permitted("member", "chapter.add") { + return nil, ErrUnauthorized + } + + story, err := story.FindID(args.Input.StoryID) + if err != nil { + return nil, err + } + + author := user.ID + if args.Input.Author != nil { + author = *args.Input.Author + + if user.ID != author && !user.Permitted("chapter.add") { + return nil, ErrPermissionDenied + } + } + + fictionalDate := time.Time{} + if args.Input.FictionalDate != nil { + fictionalDate, err = time.Parse(time.RFC3339Nano, *args.Input.FictionalDate) + if err != nil { + return nil, err + } + } + + chapter, err := story.AddChapter(args.Input.Title, author, args.Input.Source, time.Now(), fictionalDate) + if err != nil { + return nil, err + } + + change.Submit("Chapter", "add", user.ID, chapter.ID, map[string]interface{}{ + "title": args.Input.Title, + "author": author, + "fictionalDate": fictionalDate, + }) + + return &ChapterResolver{C: chapter}, nil +} + +// EditChapterArgs is args for the addChapter mutation +type EditChapterArgs struct { + Input *EditChapterInput +} + +// EditChapterInput is input for the addChapter mutation +type EditChapterInput struct { + ID string + Title *string + Source *string + FictionalDate *string +} + +// EditChapter implements the editChapter mutation +func (r *MutationResolver) EditChapter(ctx context.Context, args *EditChapterArgs) (*ChapterResolver, error) { + user := session.FromContext(ctx).User() + if user == nil || !user.Permitted("member", "chapter.edit") { + return nil, ErrUnauthorized + } + + chapter, err := story.FindChapterID(args.Input.ID) + if err != nil { + return nil, err + } + + if chapter.Author != user.ID && !user.Permitted("chapter.edit") { + return nil, ErrPermissionDenied + } + + var fictionalDate *time.Time + if args.Input.FictionalDate != nil { + date, err := time.Parse(time.RFC3339Nano, *args.Input.FictionalDate) + if err != nil { + return nil, err + } + + fictionalDate = &date + } + + err = chapter.Edit(args.Input.Title, args.Input.Source, fictionalDate) + if err != nil { + return nil, err + } + + change.Submit("Chapter", "edit", user.ID, chapter.ID, map[string]interface{}{ + "title": args.Input.Title, + "source": args.Input.Source, + "fictionalDate": fictionalDate, + }) + + return &ChapterResolver{C: chapter}, nil +} + +// DeleteChapterArgs is args for the addChapter mutation +type DeleteChapterArgs struct { + ID string +} + +// RemoveChapter implements the removeChapter mutation +func (r *MutationResolver) RemoveChapter(ctx context.Context, args *DeleteChapterArgs) (*ChapterResolver, error) { + user := session.FromContext(ctx).User() + if user == nil || !user.Permitted("member", "chapter.edit") { + return nil, ErrUnauthorized + } + + chapter, err := story.FindChapterID(args.ID) + if err != nil { + return nil, err + } + + err = chapter.Remove() + if err != nil { + return nil, err + } + + change.Submit("Chapter", "remove", user.ID, chapter.ID, nil) + + return &ChapterResolver{C: chapter}, nil +} + // ID resolves Chapter.id func (r *ChapterResolver) ID() string { return r.C.ID diff --git a/schema/root.graphql b/schema/root.graphql index 6f7b463..7396897 100644 --- a/schema/root.graphql +++ b/schema/root.graphql @@ -113,6 +113,16 @@ type Mutation { removeFile(id: String!): File + # Add a chapter to a story + addChapter(input: ChapterAddInput!): Chapter! + + # Edit a chapter + editChapter(input: ChapterEditInput!): Chapter! + + # Remove a chapter + removeChapter(id: String!): Chapter! + + # Log in login(username: String!, password: String!): Session! diff --git a/schema/types/chapter.graphql b/schema/types/chapter.graphql index f7a796b..ede4723 100644 --- a/schema/types/chapter.graphql +++ b/schema/types/chapter.graphql @@ -20,4 +20,40 @@ type Chapter { # The date of edit. editedDate: String! +} + +# Input for addChapter mutation +input ChapterAddInput { + # The story to add a chapter to + storyId: String! + + # The title to give the chapter. It can not be left empty + title: String! + + # The author to set for the chapter. It will use the logged in user ID, and only + # users with appropriate permissions can post as another author. Even then, it's only + # for importing/moving content. This author name will not be used when logging the + # submission + author: String + + # The markdown source for the content + source: String! + + # Optionally, assign a fictional date for the chapter + fictionalDate: String +} + +# Input for editChapter mutation +input ChapterEditInput { + # The chapter to edit + id: String! + + # Change the chapter's title + title: String + + # Change the source + source: String + + # Set the fictional date for a chapter + fictionalDate: String } \ No newline at end of file