AmendHub

jcs

/

subtext

/

amendments

/

130

board: Support deleting posts

Depending on whether the post has replies, either delete the post or
just edit it to say it's been deleted

jcs made amendment 130 5 months ago
--- board.c Sat Jun 4 15:52:07 2022 +++ board.c Thu Jun 9 16:03:02 2022 @@ -119,6 +119,8 @@ size_t board_find_post_ids(struct board *board, size_t unsigned long **post_ids, size_t offset, size_t limit); short board_post_create(struct board *board, struct board_thread *thread, struct board_post *post); +void board_delete_post(struct session *s, struct board *board, + struct board_post *post, struct board_thread *thread); void board_show(struct session *s, short id) @@ -507,8 +509,9 @@ board_post_read(struct session *s, struct board *board { static struct session_menu_option opts[] = { { '#', "#0123456789", "Read post [#]" }, - { 'r', "Rr", "Post reply to this message" }, - { 'q', "QqXx", "Return to message list" }, + { 'd', "Dd", "Delete this post (if permitted)" }, + { 'r', "Rr", "Reply to this post" }, + { 'q', "QqXx", "Return to threads" }, { '?', "?", "List these options" }, }; char time[32]; @@ -521,6 +524,7 @@ board_post_read(struct session *s, struct board *board short ret = POST_READ_RETURN_DONE; char c; char *data; + short cc; bool done = false, show_help = false; size = bile_read_alloc(board->bile, BOARD_POST_RTYPE, id, &data); @@ -536,7 +540,6 @@ board_post_read(struct session *s, struct board *board if (size == 0) panic("failed fetching thread %ld: %d", post.thread_id, bile_error(board->bile)); - bile_unmarshall_object(board->bile, board_thread_object_fields, nboard_thread_object_fields, data, size, &thread, true); free(data); @@ -566,6 +569,37 @@ board_post_read(struct session *s, struct board *board show_help = false; switch (c) { + case 'd': + if (!(s->user && (s->user->is_sysop || + s->user->id == post.id))) { + session_output_string(s, "Invalid option\r\n"); + session_flush(s); + break; + } + + session_printf(s, "Are you sure you want to permanently " + "delete this post? [y/N] "); + session_flush(s); + + cc = session_input_char(s); + if (cc == 'y' || c == 'Y') { + session_printf(s, "%c\r\n", cc); + session_flush(s); + + board_delete_post(s, board, &post, &thread); + + session_log(s, "Deleted post %ld (thread %ld)", post.id, + thread.thread_id); + + session_printf(s, "\r\n{{B}}Post deleted!{{/B}}\r\n"); + session_flush(s); + ret = POST_READ_RETURN_FIND; + done = true; + } else { + session_printf(s, "\r\Post not deleted.\r\n"); + session_flush(s); + } + break; case 'r': new_id = board_compose(s, board, &thread, &post, NULL, NULL); if (new_id) { @@ -771,4 +805,102 @@ board_post_create(struct board *board, struct board_th done: return (post->id == 0 ? -1 : 0); +} + +void +board_delete_post(struct session *s, struct board *board, + struct board_post *post, struct board_thread *thread) +{ + size_t size, n, nn; + char *data; + char del[50]; + short ret; + bool childs = false; + unsigned long *new_post_ids; + unsigned long *new_parent_post_ids; + + if (thread->nposts == 1) { + bile_delete(board->bile, BOARD_THREAD_RTYPE, thread->thread_id); + bile_delete(board->bile, BOARD_POST_RTYPE, post->id); + return; + } + + for (n = 0; n < thread->nposts; n++) { + if (thread->parent_post_ids[n] == post->id) { + childs = true; + break; + } + } + + if (!childs) { + /* just zap this off the end of the tree */ + new_post_ids = xcalloc(thread->nposts - 1, sizeof(unsigned long)); + new_parent_post_ids = xcalloc(thread->nposts - 1, + sizeof(unsigned long)); + + for (n = 0, nn = 0; n < thread->nposts; n++) { + if (thread->post_ids[n] == post->id) + continue; + + new_post_ids[nn] = thread->post_ids[n]; + nn++; + } + + for (n = 0, nn = 0; n < thread->nposts; n++) { + if (thread->post_ids[n] == post->id) + continue; + + new_parent_post_ids[nn] = thread->parent_post_ids[n]; + nn++; + } + + thread->nposts--; + + free(thread->post_ids); + thread->post_ids = new_post_ids; + free(thread->parent_post_ids); + thread->parent_post_ids = new_parent_post_ids; + + ret = bile_marshall_object(board->bile, board_thread_object_fields, + nboard_thread_object_fields, thread, &data, &size); + if (ret != 0 || size == 0) { + warn("failed to marshall thread object during post delete"); + return; + } + if (bile_write(board->bile, BOARD_THREAD_RTYPE, thread->thread_id, + data, size) != size) { + warn("bile_write of updated thread after post delete failed! " + "%d", bile_error(board->bile)); + free(data); + return; + } + free(data); + + bile_delete(board->bile, BOARD_POST_RTYPE, post->id); + + bile_flush(board->bile, true); + return; + } + + /* all we can do is change the post to say deleted */ + if (post->body != NULL) + free(post->body); + snprintf(del, sizeof(del), "[ Post deleted by %s ]", + s->user ? s->user->username : "unknown"); + post->body = xstrdup(del); + post->body_size = strlen(post->body) + 1; + + ret = bile_marshall_object(board->bile, board_post_object_fields, + nboard_post_object_fields, post, &data, &size); + if (ret != 0 || size == 0) { + warn("failed to marshall updated post object"); + return; + } + if (bile_write(board->bile, BOARD_POST_RTYPE, post->id, data, + size) != size) { + warn("bile_write of updated post failed! %d", + bile_error(board->bile)); + free(data); + return; + } }