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:
@@ -258,6 +258,39 @@ func GetPostThread(ctx context.Context, db *sql.DB, rootID string) (*Post, error
|
||||
return buildPostTree(posts, rootID)
|
||||
}
|
||||
|
||||
// GetPostThreadForViewer includes root voting and answered annotations.
|
||||
func GetPostThreadForViewer(
|
||||
ctx context.Context,
|
||||
db *sql.DB,
|
||||
rootID string,
|
||||
viewerID string,
|
||||
) (*Post, error) {
|
||||
root, err := GetPostThread(ctx, db, rootID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
summary, err := sqlc.New(db).GetRootPostVoteSummary(ctx, sqlc.GetRootPostVoteSummaryParams{
|
||||
ViewerID: viewerID,
|
||||
RootID: rootID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
root.Score = int(summary.Score)
|
||||
root.UserVote = int(summary.UserVote)
|
||||
root.Answered = postTreeContainsRole(root, RoleAdmin)
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func postTreeContainsRole(post *Post, role Role) bool {
|
||||
for _, reply := range post.Replies {
|
||||
if reply.AuthorRole == role || postTreeContainsRole(reply, role) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func buildPostTree(posts []Post, rootID string) (*Post, error) {
|
||||
byID := make(map[string]*Post, len(posts))
|
||||
for i := range posts {
|
||||
@@ -334,6 +367,89 @@ func ListRootPosts(ctx context.Context, db *sql.DB, postDate, viewerID string) (
|
||||
return posts, nil
|
||||
}
|
||||
|
||||
// ListRootPostsByAuthor returns visible roots created by an author, newest first.
|
||||
func ListRootPostsByAuthor(ctx context.Context, db *sql.DB, authorID string) ([]Post, error) {
|
||||
rows, err := sqlc.New(db).ListRootPostsByAuthor(ctx, sqlc.ListRootPostsByAuthorParams{
|
||||
AuthorID: authorID,
|
||||
HiddenState: string(PostStateHidden),
|
||||
RowLimit: ProfileListLimit,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
posts := make([]Post, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
posts = append(posts, postFromValues(
|
||||
db,
|
||||
r.ID,
|
||||
r.ParentID,
|
||||
r.AuthorID,
|
||||
r.AuthorName,
|
||||
r.AuthorRole,
|
||||
r.Title,
|
||||
r.Body,
|
||||
r.City,
|
||||
r.PostDate,
|
||||
r.PostState,
|
||||
r.CreatedAt,
|
||||
r.UpdatedAt,
|
||||
))
|
||||
}
|
||||
return posts, nil
|
||||
}
|
||||
|
||||
// ListRootPostsAnsweredBy returns visible roots containing a reply by adminID.
|
||||
func ListRootPostsAnsweredBy(ctx context.Context, db *sql.DB, adminID string) ([]Post, error) {
|
||||
rows, err := sqlc.New(db).ListRootPostsAnsweredBy(ctx, sqlc.ListRootPostsAnsweredByParams{
|
||||
HiddenState: string(PostStateHidden),
|
||||
AdminID: adminID,
|
||||
RowLimit: ProfileListLimit,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
posts := make([]Post, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
posts = append(posts, postFromValues(
|
||||
db,
|
||||
r.ID,
|
||||
r.ParentID,
|
||||
r.AuthorID,
|
||||
r.AuthorName,
|
||||
r.AuthorRole,
|
||||
r.Title,
|
||||
r.Body,
|
||||
r.City,
|
||||
r.PostDate,
|
||||
r.PostState,
|
||||
r.CreatedAt,
|
||||
r.UpdatedAt,
|
||||
))
|
||||
}
|
||||
return posts, nil
|
||||
}
|
||||
|
||||
// SetRootPostState changes a root post's state.
|
||||
func SetRootPostState(ctx context.Context, db *sql.DB, id string, state PostState) error {
|
||||
switch state {
|
||||
case PostStateVisible, PostStateHidden, PostStateLocked:
|
||||
default:
|
||||
return fmt.Errorf("%w: invalid post state", ErrInvalidPost)
|
||||
}
|
||||
n, err := sqlc.New(db).UpdateRootPostState(ctx, sqlc.UpdateRootPostStateParams{
|
||||
PostState: string(state),
|
||||
UpdatedAt: time.Now().UTC().Format(time.RFC3339Nano),
|
||||
ID: id,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == 0 {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetPostVote sets value to 1, -1, or 0 on a visible root post.
|
||||
func SetPostVote(ctx context.Context, db *sql.DB, userID, postID string, value int) error {
|
||||
if value != 1 && value != -1 && value != 0 {
|
||||
|
||||
Reference in New Issue
Block a user