package services import ( "context" "errors" "git.aiterp.net/rpdata/api/internal/auth" "git.aiterp.net/rpdata/api/internal/generate" "git.aiterp.net/rpdata/api/models" "git.aiterp.net/rpdata/api/models/changekeys" "git.aiterp.net/rpdata/api/repositories" "time" ) // 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 } func (s *StoryService) FindStory(ctx context.Context, id string) (*models.Story, error) { return s.stories.Find(ctx, id) } func (s *StoryService) ListStories(ctx context.Context, filter models.StoryFilter) ([]*models.Story, error) { return s.stories.List(ctx, filter) } func (s *StoryService) ListChapters(ctx context.Context, story models.Story) ([]*models.Chapter, error) { return s.chapters.List(ctx, models.ChapterFilter{StoryID: &story.ID, Limit: 0}) } func (s *StoryService) ListComments(ctx context.Context, chapter models.Chapter, limit int) ([]*models.Comment, error) { 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) { story := &models.Story{ Name: name, Author: author, Category: category, Listed: listed, Open: open, Tags: tags, CreatedDate: createdDate, FictionalDate: fictionalDate, UpdatedDate: createdDate, } if err := auth.CheckPermission(ctx, "add", story); err != nil { return nil, err } story, err := s.stories.Insert(ctx, *story) if err != nil { return nil, err } s.changeService.Submit(ctx, "Story", "add", story.Listed, changekeys.Listed(story), story) 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) { chapter := &models.Chapter{ ID: generate.ChapterID(), StoryID: story.ID, Title: title, Author: author, Source: source, CreatedDate: createdDate, EditedDate: createdDate, CommentMode: commentMode, CommentsLocked: false, } if fictionalDate != nil { chapter.FictionalDate = *fictionalDate } if story.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.Insert(ctx, *chapter) if err != nil { return nil, err } if createdDate.After(story.UpdatedDate) { _, _ = s.stories.Update(ctx, story, models.StoryUpdate{UpdatedDate: &createdDate}) } s.changeService.Submit(ctx, "Chapter", "add", story.Listed, changekeys.Many(story, chapter), chapter) 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 } if !chapter.CanComment() { return nil, errors.New("comments are locked or disabled") } if author == "" { if token := auth.TokenFromContext(ctx); token != nil { author = token.UserID } else { return nil, auth.ErrUnauthenticated } } comment := &models.Comment{ ID: generate.CommentID(), ChapterID: chapter.ID, Subject: subject, Author: author, CharacterName: characterName, CharacterID: characterID, FictionalDate: fictionalDate, CreatedDate: createdDate, EditedDate: createdDate, Source: source, } if err := auth.CheckPermission(ctx, "add", comment); err != nil { return nil, err } comment, err := s.comments.Insert(ctx, *comment) 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, comment), comment) } else { s.changeService.Submit(ctx, "Comment", "add", false, changekeys.Many(chapter, comment), comment) } return comment, nil }