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 over 2 years 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;
+ }
}