a mini social media app for small communities

refactors in preparation for search

Changed files
+182 -79
src
+26
src/database/like.v
··· 2 2 3 3 import entity { Like, LikeCache } 4 4 5 + // add_like adds a like to the database, returns true if this succeeds and false 6 + // otherwise. 7 + pub fn (app &DatabaseAccess) add_like(like &Like) bool { 8 + sql app.db { 9 + insert like into Like 10 + // yeet the old cached like value 11 + delete from LikeCache where post_id == like.post_id 12 + } or { 13 + return false 14 + } 15 + return true 16 + } 17 + 5 18 // get_net_likes_for_post returns the net likes of the given post. 6 19 pub fn (app &DatabaseAccess) get_net_likes_for_post(post_id int) int { 7 20 // check cache ··· 43 56 44 57 return likes 45 58 } 59 + 60 + // unlike_post removes a (dis)like from the given post, returns true if this 61 + // succeeds and false otherwise. 62 + pub fn (app &DatabaseAccess) unlike_post(post_id int, user_id int) bool { 63 + sql app.db { 64 + delete from Like where user_id == user_id && post_id == post_id 65 + // yeet the old cached like value 66 + delete from LikeCache where post_id == post_id 67 + } or { 68 + return false 69 + } 70 + return true 71 + }
+34
src/database/notification.v
··· 2 2 3 3 import entity { Notification } 4 4 5 + // get_notification_by_id gets a notification by its given id, returns none if 6 + // the notification does not exist. 7 + pub fn (app &DatabaseAccess) get_notification_by_id(id int) ?Notification { 8 + notifications := sql app.db { 9 + select from Notification where id == id 10 + } or { [] } 11 + if notifications.len != 1 { 12 + return none 13 + } 14 + return notifications[0] 15 + } 16 + 17 + // delete_notification deletes the given notification, returns true if this 18 + // succeeded and false otherwise. 19 + pub fn (app &DatabaseAccess) delete_notification(id int) bool { 20 + sql app.db { 21 + delete from Notification where id == id 22 + } or { 23 + return false 24 + } 25 + return true 26 + } 27 + 28 + // delete_notifications_for_user deletes all notifications for the given user, 29 + // returns true if this succeeded and false otherwise. 30 + pub fn (app &DatabaseAccess) delete_notifications_for_user(user_id int) bool { 31 + sql app.db { 32 + delete from Notification where user_id == user_id 33 + } or { 34 + return false 35 + } 36 + return true 37 + } 38 + 5 39 // get_notifications_for gets a list of notifications for the given user. 6 40 pub fn (app &DatabaseAccess) get_notifications_for(user_id int) []Notification { 7 41 notifications := sql app.db {
+46
src/database/post.v
··· 3 3 import time 4 4 import entity { Post, Like, LikeCache } 5 5 6 + // add_post adds a new post to the database, returns true if this succeeded and 7 + // false otherwise. 8 + pub fn (app &DatabaseAccess) add_post(post &Post) bool { 9 + sql app.db { 10 + insert post into Post 11 + } or { 12 + return false 13 + } 14 + return true 15 + } 16 + 6 17 // get_post_by_id gets a post by its id, returns none if it does not exist. 7 18 pub fn (app &DatabaseAccess) get_post_by_id(id int) ?Post { 8 19 posts := sql app.db { ··· 84 95 } or { [] } 85 96 return posts 86 97 } 98 + 99 + // pin_post pins the given post, returns true if this succeeds and false 100 + // otherwise. 101 + pub fn (app &DatabaseAccess) pin_post(post_id int) bool { 102 + sql app.db { 103 + update Post set pinned = true where id == post_id 104 + } or { 105 + return false 106 + } 107 + return true 108 + } 109 + 110 + // update_post updates the given post's title and body with the given title and 111 + // body, returns true if this succeeds and false otherwise. 112 + pub fn (app &DatabaseAccess) update_post(post_id int, new_title string, new_body string) bool { 113 + sql app.db { 114 + update Post set body = new_body, title = new_title where id == post_id 115 + } or { 116 + return false 117 + } 118 + return true 119 + } 120 + 121 + // delete_post deletes the given post and all likes associated with it, returns 122 + // true if this succeeds and false otherwise. 123 + pub fn (app &DatabaseAccess) delete_post(id int) bool { 124 + sql app.db { 125 + delete from Post where id == id 126 + delete from Like where post_id == id 127 + delete from LikeCache where post_id == id 128 + } or { 129 + return false 130 + } 131 + return true 132 + }
+11
src/database/site.v
··· 18 18 } 19 19 return configs[0] 20 20 } 21 + 22 + // set_motd sets the site's current message of the day, returns true if this 23 + // succeeds and false otherwise. 24 + pub fn (app &DatabaseAccess) set_motd(motd string) bool { 25 + sql app.db { 26 + update Site set motd = motd where id == 1 27 + } or { 28 + return false 29 + } 30 + return true 31 + }
+35 -1
src/database/user.v
··· 1 1 module database 2 2 3 - import entity { User, Notification, Like, Post } 3 + import entity { User, Notification, Like, LikeCache, Post } 4 4 5 5 // new_user creates a new user and returns their struct after creation. 6 6 pub fn (app &DatabaseAccess) new_user(user User) ?User { ··· 172 172 } 173 173 return likes.len == 1 174 174 } 175 + 176 + // delete_user deletes the given user and their data, returns true if this 177 + // succeeded and false otherwise. 178 + pub fn (app &DatabaseAccess) delete_user(user_id int) bool { 179 + sql app.db { 180 + delete from User where id == user_id 181 + delete from Like where user_id == user_id 182 + delete from Notification where user_id == user_id 183 + } or { 184 + return false 185 + } 186 + 187 + // delete posts and their likes 188 + posts_from_this_user := sql app.db { 189 + select from Post where author_id == id 190 + } or { [] } 191 + 192 + for post in posts_from_this_user { 193 + sql app.db { 194 + delete from Like where post_id == post.id 195 + delete from LikeCache where post_id == post.id 196 + } or { 197 + eprintln('failed to delete like cache for post during user deletion: ${post.id}') 198 + } 199 + } 200 + 201 + sql app.db { 202 + delete from Post where author_id == id 203 + } or { 204 + eprintln('failed to delete posts by deleting user: ${user_id}') 205 + } 206 + 207 + return true 208 + }
+30 -78
src/webapp/api.v
··· 329 329 330 330 @['/api/user/notification/clear'] 331 331 fn (mut app App) api_user_notification_clear(mut ctx Context, id int) veb.Result { 332 - if !ctx.is_logged_in() { 332 + user := app.whoami(mut ctx) or { 333 333 ctx.error('you are not logged in!') 334 334 return ctx.redirect('/login') 335 335 } 336 - sql app.db { 337 - delete from Notification where id == id 338 - } or { 339 - ctx.error('failed to delete notification') 340 - return ctx.redirect('/inbox') 336 + 337 + if notification := app.get_notification_by_id(id) { 338 + if notification.user_id != user.id { 339 + ctx.error('no such notification for user') 340 + return ctx.redirect('/inbox') 341 + } else { 342 + if !app.delete_notification(id) { 343 + ctx.error('failed to delete notification') 344 + return ctx.redirect('/inbox') 345 + } 346 + } 347 + } else { 348 + ctx.error('no such notification for user') 341 349 } 350 + 342 351 return ctx.redirect('/inbox') 343 352 } 344 353 ··· 348 357 ctx.error('you are not logged in!') 349 358 return ctx.redirect('/login') 350 359 } 351 - sql app.db { 352 - delete from Notification where user_id == user.id 353 - } or { 360 + if !app.delete_notifications_for_user(user.id) { 354 361 ctx.error('failed to delete notifications') 355 362 return ctx.redirect('/inbox') 356 363 } ··· 368 375 369 376 if user.admin || user.id == id { 370 377 // yeet 371 - sql app.db { 372 - delete from User where id == id 373 - delete from Like where user_id == id 374 - delete from Notification where user_id == id 375 - } or { 378 + if !app.delete_user(user.id) { 376 379 ctx.error('failed to delete user: ${id}') 377 380 return ctx.redirect('/') 378 - } 379 - 380 - // delete posts and their likes 381 - posts_from_this_user := sql app.db { 382 - select from Post where author_id == id 383 - } or { [] } 384 - 385 - for post in posts_from_this_user { 386 - sql app.db { 387 - delete from Like where post_id == post.id 388 - delete from LikeCache where post_id == post.id 389 - } or { 390 - eprintln('failed to delete like cache for post during user deletion: ${post.id}') 391 - } 392 - } 393 - 394 - sql app.db { 395 - delete from Post where author_id == id 396 - } or { 397 - eprintln('failed to delete posts by deleting user: ${user.id}') 398 381 } 399 382 400 383 app.auth.delete_tokens_for_user(id) or { ··· 459 442 post.replying_to = replying_to 460 443 } 461 444 462 - sql app.db { 463 - insert post into Post 464 - } or { 445 + if !app.add_post(post) { 465 446 ctx.error('failed to post!') 466 447 println('failed to post: ${post} from user ${user.id}') 467 448 return ctx.redirect('/post/new') ··· 490 471 } 491 472 492 473 if user.admin || user.id == post.author_id { 493 - sql app.db { 494 - delete from Post where id == id 495 - delete from Like where post_id == id 496 - } or { 474 + if !app.delete_post(post.id) { 497 475 ctx.error('failed to delete post') 498 476 eprintln('failed to delete post: ${id}') 499 477 return ctx.redirect('/') ··· 514 492 post := app.get_post_by_id(id) or { return ctx.server_error('post does not exist') } 515 493 516 494 if app.does_user_like_post(user.id, post.id) { 517 - sql app.db { 518 - delete from Like where user_id == user.id && post_id == post.id 519 - // yeet the old cached like value 520 - delete from LikeCache where post_id == post.id 521 - } or { 495 + if !app.unlike_post(post.id, user.id) { 522 496 eprintln('user ${user.id} failed to unlike post ${id}') 523 497 return ctx.server_error('failed to unlike post') 524 498 } ··· 526 500 } else { 527 501 // remove the old dislike, if it exists 528 502 if app.does_user_dislike_post(user.id, post.id) { 529 - sql app.db { 530 - delete from Like where user_id == user.id && post_id == post.id 531 - } or { 503 + if !app.unlike_post(post.id, user.id) { 532 504 eprintln('user ${user.id} failed to remove dislike on post ${id} when liking it') 533 505 } 534 506 } ··· 538 510 post_id: post.id 539 511 is_like: true 540 512 } 541 - sql app.db { 542 - insert like into Like 543 - // yeet the old cached like value 544 - delete from LikeCache where post_id == post.id 545 - } or { 513 + if !app.add_like(like) { 546 514 eprintln('user ${user.id} failed to like post ${id}') 547 515 return ctx.server_error('failed to like post') 548 516 } ··· 557 525 post := app.get_post_by_id(id) or { return ctx.server_error('post does not exist') } 558 526 559 527 if app.does_user_dislike_post(user.id, post.id) { 560 - sql app.db { 561 - delete from Like where user_id == user.id && post_id == post.id 562 - // yeet the old cached like value 563 - delete from LikeCache where post_id == post.id 564 - } or { 565 - eprintln('user ${user.id} failed to unlike post ${id}') 566 - return ctx.server_error('failed to unlike post') 528 + if !app.unlike_post(post.id, user.id) { 529 + eprintln('user ${user.id} failed to undislike post ${id}') 530 + return ctx.server_error('failed to undislike post') 567 531 } 568 532 return ctx.ok('undisliked post') 569 533 } else { 570 534 // remove the old like, if it exists 571 535 if app.does_user_like_post(user.id, post.id) { 572 - sql app.db { 573 - delete from Like where user_id == user.id && post_id == post.id 574 - } or { 536 + if !app.unlike_post(post.id, user.id) { 575 537 eprintln('user ${user.id} failed to remove like on post ${id} when disliking it') 576 538 } 577 539 } ··· 581 543 post_id: post.id 582 544 is_like: false 583 545 } 584 - sql app.db { 585 - insert like into Like 586 - // yeet the old cached like value 587 - delete from LikeCache where post_id == post.id 588 - } or { 546 + if !app.add_like(like) { 589 547 eprintln('user ${user.id} failed to dislike post ${id}') 590 548 return ctx.server_error('failed to dislike post') 591 549 } ··· 614 572 return ctx.redirect('/') 615 573 } 616 574 617 - sql app.db { 618 - update Post set body = body, title = title where id == id 619 - } or { 575 + if !app.update_post(id, title, body) { 620 576 eprintln('failed to update post') 621 577 ctx.error('failed to update post') 622 578 return ctx.redirect('/') ··· 633 589 } 634 590 635 591 if user.admin { 636 - sql app.db { 637 - update Post set pinned = true where id == id 638 - } or { 592 + if !app.pin_post(id) { 639 593 eprintln('failed to pin post: ${id}') 640 594 ctx.error('failed to pin post') 641 595 return ctx.redirect('/post/${id}') ··· 658 612 } 659 613 660 614 if user.admin { 661 - sql app.db { 662 - update Site set motd = motd where id == 1 663 - } or { 615 + if !app.set_motd(motd) { 664 616 ctx.error('failed to set motd') 665 617 eprintln('failed to set motd: ${motd}') 666 618 return ctx.redirect('/')