This commit is contained in:
@@ -12,6 +12,7 @@ type Bundle struct {
|
||||
Changes *ChangeService
|
||||
Logs *LogService
|
||||
Channels *ChannelService
|
||||
Stories *StoryService
|
||||
}
|
||||
|
||||
// NewBundle creates a new bundle.
|
||||
@@ -38,6 +39,13 @@ func NewBundle(db database.Database) *Bundle {
|
||||
channelService: bundle.Channels,
|
||||
characterService: bundle.Characters,
|
||||
}
|
||||
bundle.Stories = &StoryService{
|
||||
stories: db.Stories(),
|
||||
chapters: db.Chapters(),
|
||||
comments: db.Comments(),
|
||||
changeService: bundle.Changes,
|
||||
characterService: bundle.Characters,
|
||||
}
|
||||
|
||||
return bundle
|
||||
}
|
||||
|
||||
+281
-15
@@ -13,16 +13,25 @@ import (
|
||||
|
||||
// StoryService is a service governing all operations on stories and child objects.
|
||||
type StoryService struct {
|
||||
stories repositories.StoryRepository
|
||||
chapters repositories.ChapterRepository
|
||||
comments repositories.CommentRepository
|
||||
changeService *ChangeService
|
||||
stories repositories.StoryRepository
|
||||
chapters repositories.ChapterRepository
|
||||
comments repositories.CommentRepository
|
||||
changeService *ChangeService
|
||||
characterService *CharacterService
|
||||
}
|
||||
|
||||
func (s *StoryService) FindStory(ctx context.Context, id string) (*models.Story, error) {
|
||||
return s.stories.Find(ctx, id)
|
||||
}
|
||||
|
||||
func (s *StoryService) FindChapter(ctx context.Context, id string) (*models.Chapter, error) {
|
||||
return s.chapters.Find(ctx, id)
|
||||
}
|
||||
|
||||
func (s *StoryService) FindComment(ctx context.Context, id string) (*models.Comment, error) {
|
||||
return s.comments.Find(ctx, id)
|
||||
}
|
||||
|
||||
func (s *StoryService) ListStories(ctx context.Context, filter models.StoryFilter) ([]*models.Story, error) {
|
||||
return s.stories.List(ctx, filter)
|
||||
}
|
||||
@@ -35,10 +44,19 @@ func (s *StoryService) ListComments(ctx context.Context, chapter models.Chapter,
|
||||
return s.comments.List(ctx, models.CommentFilter{ChapterID: &chapter.ID, Limit: limit})
|
||||
}
|
||||
|
||||
func (s *StoryService) CreateStory(ctx context.Context, name, author string, category models.StoryCategory, listed, open bool, tags []models.Tag, createdDate, fictionalDate time.Time) (*models.Story, error) {
|
||||
func (s *StoryService) CreateStory(ctx context.Context, name string, author *string, category models.StoryCategory, listed, open bool, tags []models.Tag, createdDate, fictionalDate time.Time) (*models.Story, error) {
|
||||
if author == nil {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if token == nil {
|
||||
return nil, auth.ErrUnauthenticated
|
||||
}
|
||||
|
||||
author = &token.UserID
|
||||
}
|
||||
|
||||
story := &models.Story{
|
||||
Name: name,
|
||||
Author: author,
|
||||
Author: *author,
|
||||
Category: category,
|
||||
Listed: listed,
|
||||
Open: open,
|
||||
@@ -62,12 +80,21 @@ func (s *StoryService) CreateStory(ctx context.Context, name, author string, cat
|
||||
return story, nil
|
||||
}
|
||||
|
||||
func (s *StoryService) CreateChapter(ctx context.Context, story models.Story, title, author, source string, createdDate time.Time, fictionalDate *time.Time, commentMode models.ChapterCommentMode) (*models.Chapter, error) {
|
||||
func (s *StoryService) CreateChapter(ctx context.Context, story models.Story, title, source string, author *string, createdDate time.Time, fictionalDate *time.Time, commentMode models.ChapterCommentMode) (*models.Chapter, error) {
|
||||
if author == nil {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if token == nil {
|
||||
return nil, auth.ErrUnauthenticated
|
||||
}
|
||||
|
||||
author = &token.UserID
|
||||
}
|
||||
|
||||
chapter := &models.Chapter{
|
||||
ID: generate.ChapterID(),
|
||||
StoryID: story.ID,
|
||||
Title: title,
|
||||
Author: author,
|
||||
Author: *author,
|
||||
Source: source,
|
||||
CreatedDate: createdDate,
|
||||
EditedDate: createdDate,
|
||||
@@ -102,11 +129,13 @@ func (s *StoryService) CreateChapter(ctx context.Context, story models.Story, ti
|
||||
return chapter, nil
|
||||
}
|
||||
|
||||
// CreateComment adds a comment.
|
||||
func (s *StoryService) CreateComment(ctx context.Context, chapter models.Chapter, subject, author, source, characterName string, character *models.Character, createdDate time.Time, fictionalDate time.Time) (*models.Comment, error) {
|
||||
characterID := ""
|
||||
if character != nil {
|
||||
characterID = character.ID
|
||||
func (s *StoryService) CreateComment(ctx context.Context, chapter models.Chapter, subject, author, source, characterName string, characterID *string, createdDate time.Time, fictionalDate time.Time) (*models.Comment, error) {
|
||||
if characterID != nil {
|
||||
if err := s.permittedCharacter(ctx, "comment", *characterID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
characterID = new(string)
|
||||
}
|
||||
|
||||
if !chapter.CanComment() {
|
||||
@@ -127,7 +156,7 @@ func (s *StoryService) CreateComment(ctx context.Context, chapter models.Chapter
|
||||
Subject: subject,
|
||||
Author: author,
|
||||
CharacterName: characterName,
|
||||
CharacterID: characterID,
|
||||
CharacterID: *characterID,
|
||||
FictionalDate: fictionalDate,
|
||||
CreatedDate: createdDate,
|
||||
EditedDate: createdDate,
|
||||
@@ -145,8 +174,245 @@ func (s *StoryService) CreateComment(ctx context.Context, chapter models.Chapter
|
||||
if story, err := s.stories.Find(ctx, chapter.StoryID); err == nil {
|
||||
s.changeService.Submit(ctx, "Comment", "add", story.Listed, changekeys.Many(story, chapter, comment), comment)
|
||||
} else {
|
||||
s.changeService.Submit(ctx, "Comment", "add", false, changekeys.Many(chapter, comment), comment)
|
||||
s.changeService.Submit(ctx, "Comment", "add", false, changekeys.Many(models.Story{ID: chapter.StoryID}, chapter, comment), comment)
|
||||
}
|
||||
|
||||
return comment, nil
|
||||
}
|
||||
|
||||
func (s *StoryService) EditStory(ctx context.Context, story *models.Story, name *string, category *models.StoryCategory, listed, open *bool, fictionalDate *time.Time) (*models.Story, error) {
|
||||
if story == nil {
|
||||
panic("StoryService.Edit called with nil story")
|
||||
}
|
||||
|
||||
if err := auth.CheckPermission(ctx, "edit", story); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
story, err := s.stories.Update(ctx, *story, models.StoryUpdate{
|
||||
Name: name,
|
||||
Open: open,
|
||||
Listed: listed,
|
||||
Category: category,
|
||||
FictionalDate: fictionalDate,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.changeService.Submit(ctx, "Story", "edit", story.Listed, changekeys.Listed(story), story)
|
||||
|
||||
return story, nil
|
||||
}
|
||||
|
||||
func (s *StoryService) AddStoryTag(ctx context.Context, story models.Story, tag models.Tag) (*models.Story, error) {
|
||||
if err := auth.CheckPermission(ctx, "edit", &story); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err := s.stories.AddTag(ctx, story, tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
story.Tags = append(story.Tags, tag)
|
||||
|
||||
s.changeService.Submit(ctx, "Story", "tag", story.Listed, changekeys.Listed(story), story, tag)
|
||||
|
||||
return &story, nil
|
||||
}
|
||||
|
||||
func (s *StoryService) RemoveStoryTag(ctx context.Context, story models.Story, tag models.Tag) (*models.Story, error) {
|
||||
if err := auth.CheckPermission(ctx, "edit", &story); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err := s.stories.RemoveTag(ctx, story, tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i, tag2 := range story.Tags {
|
||||
if tag2 == tag {
|
||||
story.Tags = append(story.Tags[:i], story.Tags[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
s.changeService.Submit(ctx, "Story", "untag", story.Listed, changekeys.Listed(story), story, tag)
|
||||
|
||||
return &story, nil
|
||||
}
|
||||
|
||||
func (s *StoryService) EditChapter(ctx context.Context, chapter *models.Chapter, title, source *string, fictionalDate *time.Time, commentMode *models.ChapterCommentMode, commentsLocked *bool) (*models.Chapter, error) {
|
||||
if chapter == nil {
|
||||
panic("StoryService.EditChapter called with nil chapter")
|
||||
}
|
||||
|
||||
if err := auth.CheckPermission(ctx, "edit", chapter); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chapter, err := s.chapters.Update(ctx, *chapter, models.ChapterUpdate{
|
||||
Title: title,
|
||||
Source: source,
|
||||
FictionalDate: fictionalDate,
|
||||
CommentMode: commentMode,
|
||||
CommentsLocked: commentsLocked,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if story, err := s.stories.Find(ctx, chapter.StoryID); err == nil {
|
||||
s.changeService.Submit(ctx, "Comment", "add", story.Listed, changekeys.Many(story, chapter), chapter)
|
||||
} else {
|
||||
s.changeService.Submit(ctx, "Comment", "add", false, changekeys.Many(models.Story{ID: chapter.StoryID}, chapter), chapter)
|
||||
}
|
||||
|
||||
return chapter, nil
|
||||
}
|
||||
|
||||
func (s *StoryService) MoveChapter(ctx context.Context, chapter *models.Chapter, from, to models.Story) (*models.Chapter, error) {
|
||||
if err := auth.CheckPermission(ctx, "move", chapter); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if to.Open {
|
||||
if !auth.TokenFromContext(ctx).Permitted("member", "chapter.add") {
|
||||
return nil, auth.ErrUnauthorized
|
||||
}
|
||||
} else {
|
||||
if err := auth.CheckPermission(ctx, "add", chapter); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
chapter, err := s.chapters.Move(ctx, *chapter, from, to)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.changeService.Submit(ctx, "Chapter", "move-out", from.Listed, changekeys.Listed(from), chapter)
|
||||
s.changeService.Submit(ctx, "Chapter", "move-in", to.Listed, changekeys.Listed(to), chapter)
|
||||
|
||||
return chapter, nil
|
||||
}
|
||||
|
||||
func (s *StoryService) EditComment(ctx context.Context, comment *models.Comment, source, characterName, characterID, subject *string, fictionalDate *time.Time) (*models.Comment, error) {
|
||||
if comment == nil {
|
||||
panic("StoryService.EditChapter called with nil chapter")
|
||||
}
|
||||
|
||||
if err := auth.CheckPermission(ctx, "edit", comment); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if characterID != nil && *characterID != "" && *characterID != comment.CharacterID {
|
||||
if err := s.permittedCharacter(ctx, "comment", *characterID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
chapter, err := s.chapters.Find(ctx, comment.ChapterID)
|
||||
if err != nil {
|
||||
return nil, errors.New("could not find chapter")
|
||||
}
|
||||
if !chapter.CanComment() {
|
||||
return nil, errors.New("comments are locked or disabled")
|
||||
}
|
||||
|
||||
comment, err = s.comments.Update(ctx, *comment, models.CommentUpdate{
|
||||
Source: source,
|
||||
CharacterName: characterName,
|
||||
CharacterID: characterID,
|
||||
FictionalDate: fictionalDate,
|
||||
Subject: subject,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if story, err := s.stories.Find(ctx, chapter.StoryID); err == nil {
|
||||
s.changeService.Submit(ctx, "Comment", "edit", story.Listed, changekeys.Many(story, chapter, comment), comment)
|
||||
} else {
|
||||
s.changeService.Submit(ctx, "Comment", "edit", false, changekeys.Many(models.Story{ID: chapter.StoryID}, chapter, comment), comment)
|
||||
}
|
||||
|
||||
return comment, nil
|
||||
}
|
||||
|
||||
func (s *StoryService) RemoveStory(ctx context.Context, story *models.Story) error {
|
||||
if err := auth.CheckPermission(ctx, "add", story); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := s.stories.Delete(ctx, *story)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.changeService.Submit(ctx, "Story", "remove", story.Listed, changekeys.Listed(story), story)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StoryService) RemoveChapter(ctx context.Context, chapter *models.Chapter) error {
|
||||
if err := auth.CheckPermission(ctx, "remove", chapter); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := s.chapters.Delete(ctx, *chapter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if story, err := s.stories.Find(ctx, chapter.StoryID); err == nil {
|
||||
s.changeService.Submit(ctx, "Chapter", "remove", story.Listed, changekeys.Many(story, chapter), chapter)
|
||||
} else {
|
||||
s.changeService.Submit(ctx, "Chapter", "remove", false, changekeys.Many(models.Story{ID: chapter.StoryID}, chapter), chapter)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StoryService) RemoveComment(ctx context.Context, comment *models.Comment) error {
|
||||
if err := auth.CheckPermission(ctx, "remove", comment); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
chapter, err := s.chapters.Find(ctx, comment.ChapterID)
|
||||
if err != nil {
|
||||
return errors.New("could not find parent chapter")
|
||||
}
|
||||
if !chapter.CanComment() {
|
||||
return errors.New("comments are locked or disabled")
|
||||
}
|
||||
|
||||
err = s.comments.Delete(ctx, *comment)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if story, err := s.stories.Find(ctx, chapter.StoryID); err == nil {
|
||||
s.changeService.Submit(ctx, "Chapter", "remove", story.Listed, changekeys.Many(story, chapter, comment), comment)
|
||||
} else {
|
||||
s.changeService.Submit(ctx, "Chapter", "remove", false, changekeys.Many(models.Story{ID: chapter.StoryID}, chapter, comment), comment)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StoryService) permittedCharacter(ctx context.Context, permissionKind, characterID string) error {
|
||||
character, err := s.characterService.Find(ctx, characterID)
|
||||
if err != nil {
|
||||
return errors.New("character could not be found")
|
||||
}
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if character.Author != token.UserID && !token.Permitted(permissionKind+".edit") {
|
||||
return errors.New("you are not permitted to use others' character")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user