@@ -13,10 +13,14 @@ import (
|
|||||||
"git.aiterp.net/rpdata/api/models/chapters"
|
"git.aiterp.net/rpdata/api/models/chapters"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Queries
|
||||||
|
|
||||||
func (r *resolver) Chapter(ctx context.Context, id string) (models.Chapter, error) {
|
func (r *resolver) Chapter(ctx context.Context, id string) (models.Chapter, error) {
|
||||||
return chapters.FindID(id)
|
return chapters.FindID(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mutations
|
||||||
|
|
||||||
func (r *mutationResolver) AddChapter(ctx context.Context, input input.ChapterAddInput) (models.Chapter, error) {
|
func (r *mutationResolver) AddChapter(ctx context.Context, input input.ChapterAddInput) (models.Chapter, error) {
|
||||||
story, err := stories.FindID(input.StoryID)
|
story, err := stories.FindID(input.StoryID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package queries
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/graph2/input"
|
||||||
"git.aiterp.net/rpdata/api/internal/auth"
|
"git.aiterp.net/rpdata/api/internal/auth"
|
||||||
"git.aiterp.net/rpdata/api/models"
|
"git.aiterp.net/rpdata/api/models"
|
||||||
"git.aiterp.net/rpdata/api/models/stories"
|
"git.aiterp.net/rpdata/api/models/stories"
|
||||||
@@ -29,3 +31,95 @@ func (r *resolver) Stories(ctx context.Context, filter *stories.Filter) ([]model
|
|||||||
|
|
||||||
return stories.List(filter)
|
return stories.List(filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mutations
|
||||||
|
|
||||||
|
func (r *mutationResolver) AddStory(ctx context.Context, input input.StoryAddInput) (models.Story, error) {
|
||||||
|
token := auth.TokenFromContext(ctx)
|
||||||
|
if token == nil || !token.Permitted("member", "story.add") {
|
||||||
|
return models.Story{}, errors.New("Permission denied")
|
||||||
|
}
|
||||||
|
|
||||||
|
author := token.UserID
|
||||||
|
if input.Author != nil && *input.Author != author {
|
||||||
|
if !token.Permitted("story.add") {
|
||||||
|
return models.Story{}, errors.New("You are not permitted to add a story in another author's name")
|
||||||
|
}
|
||||||
|
|
||||||
|
author = *input.Author
|
||||||
|
}
|
||||||
|
|
||||||
|
fictionalDate := time.Time{}
|
||||||
|
if input.FictionalDate != nil {
|
||||||
|
fictionalDate = *input.FictionalDate
|
||||||
|
}
|
||||||
|
|
||||||
|
listed := input.Listed != nil && *input.Listed
|
||||||
|
open := input.Open != nil && *input.Open
|
||||||
|
|
||||||
|
return stories.Add(input.Name, author, input.Category, listed, open, input.Tags, time.Now(), fictionalDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *mutationResolver) AddStoryTag(ctx context.Context, input input.StoryTagAddInput) (models.Story, error) {
|
||||||
|
token := auth.TokenFromContext(ctx)
|
||||||
|
|
||||||
|
story, err := stories.FindID(input.ID)
|
||||||
|
if err != nil {
|
||||||
|
return models.Story{}, errors.New("Story not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if token.PermittedUser(story.Author, "member", "story.edit") {
|
||||||
|
return models.Story{}, errors.New("You are not permitted to edit this story")
|
||||||
|
}
|
||||||
|
|
||||||
|
return stories.AddTag(story, input.Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *mutationResolver) RemoveStoryTag(ctx context.Context, input input.StoryTagRemoveInput) (models.Story, error) {
|
||||||
|
token := auth.TokenFromContext(ctx)
|
||||||
|
|
||||||
|
story, err := stories.FindID(input.ID)
|
||||||
|
if err != nil {
|
||||||
|
return models.Story{}, errors.New("Story not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if token.PermittedUser(story.Author, "member", "story.edit") {
|
||||||
|
return models.Story{}, errors.New("You are not permitted to edit this story")
|
||||||
|
}
|
||||||
|
|
||||||
|
return stories.RemoveTag(story, input.Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *mutationResolver) EditStory(ctx context.Context, input input.StoryEditInput) (models.Story, error) {
|
||||||
|
token := auth.TokenFromContext(ctx)
|
||||||
|
|
||||||
|
story, err := stories.FindID(input.ID)
|
||||||
|
if err != nil {
|
||||||
|
return models.Story{}, errors.New("Story not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if token.PermittedUser(story.Author, "member", "story.edit") {
|
||||||
|
return models.Story{}, errors.New("You are not permitted to remove this story")
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.ClearFictionalDate != nil && *input.ClearFictionalDate {
|
||||||
|
input.FictionalDate = &time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stories.Edit(story, input.Name, input.Category, input.Listed, input.Open, input.FictionalDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *mutationResolver) RemoveStory(ctx context.Context, input input.StoryRemoveInput) (models.Story, error) {
|
||||||
|
token := auth.TokenFromContext(ctx)
|
||||||
|
|
||||||
|
story, err := stories.FindID(input.ID)
|
||||||
|
if err != nil {
|
||||||
|
return models.Story{}, errors.New("Story not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if token.PermittedUser(story.Author, "member", "story.remove") {
|
||||||
|
return models.Story{}, errors.New("You are not permitted to remove this story")
|
||||||
|
}
|
||||||
|
|
||||||
|
return stories.Remove(story)
|
||||||
|
}
|
||||||
|
|||||||
@@ -59,6 +59,22 @@ type Query {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
|
# Add a story
|
||||||
|
addStory(input: StoryAddInput!): Story!
|
||||||
|
|
||||||
|
# Add a story tag
|
||||||
|
addStoryTag(input: StoryTagAddInput!): Story!
|
||||||
|
|
||||||
|
# Remove a story tag
|
||||||
|
removeStoryTag(input: StoryTagRemoveInput!): Story!
|
||||||
|
|
||||||
|
# Edit a story
|
||||||
|
editStory(input: StoryEditInput!): Story!
|
||||||
|
|
||||||
|
# Remove a story
|
||||||
|
removeStory(input: StoryRemoveInput!): Story!
|
||||||
|
|
||||||
|
|
||||||
# Add a chapter to a story
|
# Add a chapter to a story
|
||||||
addChapter(input: ChapterAddInput!): Chapter!
|
addChapter(input: ChapterAddInput!): Chapter!
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,9 @@ input StoryEditInput {
|
|||||||
|
|
||||||
# Set the fictional date of the story.
|
# Set the fictional date of the story.
|
||||||
fictionalDate: Date
|
fictionalDate: Date
|
||||||
|
|
||||||
|
# Clear the fictional date of the story.
|
||||||
|
clearFictionalDate: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
# Input for the addStoryTag mutation
|
# Input for the addStoryTag mutation
|
||||||
@@ -132,6 +135,12 @@ input StoryTagRemoveInput {
|
|||||||
tag: TagInput!
|
tag: TagInput!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Input for the removeStory mutation
|
||||||
|
input StoryRemoveInput {
|
||||||
|
# What story to remove.
|
||||||
|
id: String!
|
||||||
|
}
|
||||||
|
|
||||||
# Possible values for Story.category
|
# Possible values for Story.category
|
||||||
enum StoryCategory {
|
enum StoryCategory {
|
||||||
# General information
|
# General information
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package stories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/models"
|
||||||
|
"github.com/globalsign/mgo/bson"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrTagAlreadyExists is an error returned by Story.AddTag
|
||||||
|
var ErrTagAlreadyExists = errors.New("Tag already exists on story")
|
||||||
|
|
||||||
|
// AddTag adds a tag to the story. It returns ErrTagAlreadyExists if the tag is already there
|
||||||
|
func AddTag(story models.Story, tag models.Tag) (models.Story, error) {
|
||||||
|
for i := range story.Tags {
|
||||||
|
if story.Tags[i].Equal(tag) {
|
||||||
|
return models.Story{}, ErrTagAlreadyExists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := collection.UpdateId(story.ID, bson.M{"$push": bson.M{"tags": tag}})
|
||||||
|
if err != nil {
|
||||||
|
return models.Story{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
story.Tags = append(story.Tags, tag)
|
||||||
|
|
||||||
|
return story, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package stories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Add creates a new story.
|
||||||
|
func Add(name, author string, category models.StoryCategory, listed, open bool, tags []models.Tag, createdDate, fictionalDate time.Time) (models.Story, error) {
|
||||||
|
story := models.Story{
|
||||||
|
ID: makeStoryID(),
|
||||||
|
Name: name,
|
||||||
|
Author: author,
|
||||||
|
Category: category,
|
||||||
|
Listed: listed,
|
||||||
|
Open: open,
|
||||||
|
Tags: tags,
|
||||||
|
CreatedDate: createdDate,
|
||||||
|
FictionalDate: fictionalDate,
|
||||||
|
UpdatedDate: createdDate,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := collection.Insert(story)
|
||||||
|
if err != nil {
|
||||||
|
return models.Story{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return story, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package stories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/models"
|
||||||
|
"github.com/globalsign/mgo/bson"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Edit edits the story and returns the edited story if it succeeds.
|
||||||
|
func Edit(story models.Story, name *string, category *models.StoryCategory, listed, open *bool, fictionalDate *time.Time) (models.Story, error) {
|
||||||
|
changes := bson.M{}
|
||||||
|
|
||||||
|
if name != nil && *name != story.Name {
|
||||||
|
changes["name"] = *name
|
||||||
|
story.Name = *name
|
||||||
|
}
|
||||||
|
if category != nil && *category != story.Category {
|
||||||
|
changes["category"] = *category
|
||||||
|
story.Category = *category
|
||||||
|
}
|
||||||
|
if listed != nil && *listed != story.Listed {
|
||||||
|
changes["listed"] = *listed
|
||||||
|
story.Listed = *listed
|
||||||
|
}
|
||||||
|
if open != nil && *open != story.Open {
|
||||||
|
changes["open"] = *open
|
||||||
|
story.Open = *open
|
||||||
|
}
|
||||||
|
if fictionalDate != nil && !fictionalDate.Equal(story.FictionalDate) {
|
||||||
|
changes["fictionalDate"] = *fictionalDate
|
||||||
|
story.FictionalDate = *fictionalDate
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(changes) == 0 {
|
||||||
|
return story, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := collection.UpdateId(story.ID, bson.M{"$set": changes})
|
||||||
|
if err != nil {
|
||||||
|
return models.Story{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return story, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package stories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/models"
|
||||||
|
"github.com/globalsign/mgo/bson"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrTagNotExists is an error returned by Story.RemoveTag
|
||||||
|
var ErrTagNotExists = errors.New("Tag does not exist on story")
|
||||||
|
|
||||||
|
// RemoveTag removes a tag to the story. It returns ErrTagNotExists if the tag does not exist.
|
||||||
|
func RemoveTag(story models.Story, tag models.Tag) (models.Story, error) {
|
||||||
|
index := -1
|
||||||
|
for i := range story.Tags {
|
||||||
|
if story.Tags[i].Equal(tag) {
|
||||||
|
index = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if index == -1 {
|
||||||
|
return models.Story{}, ErrTagNotExists
|
||||||
|
}
|
||||||
|
|
||||||
|
err := collection.UpdateId(story.ID, bson.M{"$pull": bson.M{"tags": tag}})
|
||||||
|
if err != nil {
|
||||||
|
return models.Story{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
story.Tags = append(story.Tags[:index], story.Tags[index+1:]...)
|
||||||
|
|
||||||
|
return story, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package stories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.aiterp.net/rpdata/api/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Remove the story from the database
|
||||||
|
func Remove(story models.Story) (models.Story, error) {
|
||||||
|
return story, collection.RemoveId(story.ID)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user