Add nested posts UI (#5)
## Summary - Cut hunt, question, submission, voting, hiding, and profile flows over to unified posts - Render nested replies with permission-aware inline Reply/Edit controls and edited markers - Add post profile queries and the author index migration they depend on Co-authored-by: codegirl-007 <s.raide@gmail.com>
This commit was merged in pull request #5.
This commit is contained in:
@@ -438,6 +438,21 @@ func (m *Memory) GetPostThread(_ context.Context, rootID string) (*Post, error)
|
||||
return buildPostTree(posts, rootID)
|
||||
}
|
||||
|
||||
func (m *Memory) GetPostThreadForViewer(ctx context.Context, rootID, viewerID string) (*Post, error) {
|
||||
root, err := m.GetPostThread(ctx, rootID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
for _, value := range m.postVotes[rootID] {
|
||||
root.Score += value
|
||||
}
|
||||
root.UserVote = m.postVotes[rootID][viewerID]
|
||||
root.Answered = m.threadContainsAdminReply(rootID)
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func (m *Memory) UpdatePost(_ context.Context, post *Post) error {
|
||||
if post == nil {
|
||||
return fmt.Errorf("%w: post is nil", ErrInvalidPost)
|
||||
@@ -489,6 +504,73 @@ func (m *Memory) ListRootPosts(_ context.Context, postDate, viewerID string) ([]
|
||||
return posts, nil
|
||||
}
|
||||
|
||||
func (m *Memory) ListRootPostsByAuthor(_ context.Context, authorID string) ([]Post, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
posts := make([]Post, 0)
|
||||
for _, post := range m.posts {
|
||||
if post.ParentID != nil ||
|
||||
post.AuthorID != authorID ||
|
||||
post.PostState == PostStateHidden {
|
||||
continue
|
||||
}
|
||||
posts = append(posts, *clonePostWithAuthor(post, m.users))
|
||||
}
|
||||
return sortProfilePosts(posts), nil
|
||||
}
|
||||
|
||||
func (m *Memory) ListRootPostsAnsweredBy(_ context.Context, adminID string) ([]Post, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
posts := make([]Post, 0)
|
||||
for _, root := range m.posts {
|
||||
if root.ParentID != nil || root.PostState == PostStateHidden {
|
||||
continue
|
||||
}
|
||||
participated := false
|
||||
for _, post := range m.posts {
|
||||
if post.AuthorID == adminID && m.postIsDescendantOf(post, root.ID) {
|
||||
participated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if participated {
|
||||
posts = append(posts, *clonePostWithAuthor(root, m.users))
|
||||
}
|
||||
}
|
||||
return sortProfilePosts(posts), nil
|
||||
}
|
||||
|
||||
func (m *Memory) SetRootPostState(_ context.Context, id string, state PostState) error {
|
||||
switch state {
|
||||
case PostStateVisible, PostStateHidden, PostStateLocked:
|
||||
default:
|
||||
return fmt.Errorf("%w: invalid post state", ErrInvalidPost)
|
||||
}
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
post, ok := m.posts[id]
|
||||
if !ok || post.ParentID != nil {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
post.PostState = state
|
||||
post.UpdatedAt = time.Now().UTC().Format(time.RFC3339Nano)
|
||||
return nil
|
||||
}
|
||||
|
||||
func sortProfilePosts(posts []Post) []Post {
|
||||
sort.Slice(posts, func(i, j int) bool {
|
||||
if posts[i].CreatedAt != posts[j].CreatedAt {
|
||||
return posts[i].CreatedAt > posts[j].CreatedAt
|
||||
}
|
||||
return posts[i].ID > posts[j].ID
|
||||
})
|
||||
if len(posts) > ProfileListLimit {
|
||||
posts = posts[:ProfileListLimit]
|
||||
}
|
||||
return posts
|
||||
}
|
||||
|
||||
func (m *Memory) VotePost(_ context.Context, userID, postID string, value int) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
Reference in New Issue
Block a user