a mini social media app for small communities

add user deletion

Changed files
+124 -2
doc
src
templates
+20
doc/database_spec.md
··· 60 60 | `id` | int | identifier for this entry | 61 61 | `post_id` | int | the post this entry is for | 62 62 | `likes` | int | the net amount of likes this post has | 63 + 64 + ## `Site` 65 + 66 + > stores mutable, site-wide data. there should only ever be one entry here 67 + 68 + | name | type | desc | 69 + |--------|--------|----------------------------------------------| 70 + | `id` | int | identifier for this (should always be 0) | 71 + | `motd` | string | the message of the day displayed on `/index` | 72 + 73 + ## `Notification` 74 + 75 + > represents a notification sent to a user 76 + 77 + | name | type | desc | 78 + |-----------|--------|------------------------------------------| 79 + | `id` | int | identifier for this notification | 80 + | `user_id` | int | the user that receives this notification | 81 + | `summary` | string | the summary for this notification | 82 + | `body` | string | the full text for this notification |
+1 -1
doc/todo.md
··· 10 10 - [ ] post:tags ('hashtags') 11 11 - [ ] post:images (should have a config.maple toggle to enable/disable) 12 12 - [ ] post:saving (add the post to a list of saved posts that a user can view later) 13 - - [ ] user:deletion 14 13 15 14 ## ideas 16 15 ··· 23 22 - [x] user:bio/about me 24 23 - [x] user:listed pronouns 25 24 - [x] user:notifications 25 + - [x] user:deletion 26 26 - [x] post:likes/dislikes 27 27 - [x] post:mentioning ('tagging') other users in posts 28 28 - [x] post:mentioning:who mentioned you (send notifications when a user mentions you)
+5
readme.md
··· 28 28 ``` 29 29 30 30 then go to the configured url to view (default is `http://localhost:8008`). 31 + 32 + if you do not have a database, you can either self-host a postgresql database on 33 + your machine, or you can find a free one online. i use and like 34 + [neon.tech](https://neon.tech), their free plan is pretty comfortable for a 35 + small beep instance!
+61
src/api.v
··· 318 318 return ctx.redirect('/inbox') 319 319 } 320 320 321 + @['/api/user/delete'] 322 + fn (mut app App) api_user_delete(mut ctx Context, id int) veb.Result { 323 + user := app.whoami(mut ctx) or { 324 + ctx.error('you are not logged in!') 325 + return ctx.redirect('/login') 326 + } 327 + 328 + println('attempting to delete ${id} as ${user.id}') 329 + 330 + if user.admin || user.id == id { 331 + // yeet 332 + sql app.db { 333 + delete from User where id == id 334 + delete from Like where user_id == id 335 + delete from Notification where user_id == id 336 + } or { 337 + ctx.error('failed to delete user: ${id}') 338 + return ctx.redirect('/') 339 + } 340 + 341 + // delete posts and their likes 342 + posts_from_this_user := sql app.db { 343 + select from Post where author_id == id 344 + } or { [] } 345 + 346 + for post in posts_from_this_user { 347 + sql app.db { 348 + delete from Like where post_id == post.id 349 + delete from LikeCache where post_id == post.id 350 + } or { 351 + eprintln('failed to delete like cache for post during user deletion: ${post.id}') 352 + } 353 + } 354 + 355 + sql app.db { 356 + delete from Post where author_id == id 357 + } or { 358 + eprintln('failed to delete posts by deleting user: ${user.id}') 359 + } 360 + 361 + app.auth.delete_tokens_for_user(id) or { 362 + eprintln('failed to delete tokens for user during deletion: ${id}') 363 + } 364 + // log out 365 + if user.id == id { 366 + ctx.set_cookie( 367 + name: 'token' 368 + value: '' 369 + same_site: .same_site_none_mode 370 + secure: true 371 + path: '/' 372 + ) 373 + } 374 + println('deleted user ${id}') 375 + } else { 376 + ctx.error('be nice. deleting other users is off-limits.') 377 + } 378 + 379 + return ctx.redirect('/') 380 + } 381 + 321 382 ////// post ////// 322 383 323 384 @['/api/post/new_post'; post]
+37 -1
src/templates/user.html
··· 132 132 <input type="submit" value="save"> 133 133 </form> 134 134 @end 135 + <br> 136 + <details> 137 + <summary>dangerous settings (click to reveal)</summary> 138 + <div> 139 + <form action="/api/user/delete" autocomplete="off"> 140 + <input 141 + type="number" 142 + name="id" 143 + id="id" 144 + value="@user.id" 145 + required 146 + readonly 147 + hidden 148 + aria-hidden 149 + > 150 + <p><strong>there is NO GOING BACK after deleting your account.</strong></p> 151 + <p><strong>EVERY ONE of your posts, notifications, likes, dislikes, and ALL OTHER USER DATA WILL BE PERMANENTLY DELETED</strong></p> 152 + <div> 153 + <input type="checkbox" name="are-you-sure" id="are-you-sure" required> 154 + <label for="are-you-sure">click to confirm</label> 155 + </div> 156 + <br> 157 + <div> 158 + <input type="checkbox" name="are-you-really-sure" id="are-you-really-sure" required> 159 + <label for="are-you-really-sure">click to doubly confirm</label> 160 + </div> 161 + <br> 162 + <div> 163 + <input type="checkbox" name="are-you-absolutely-sure" id="are-you-absolutely-sure" required> 164 + <label for="are-you-absolutely-sure">click to triply confirm</label> 165 + </div> 166 + <br> 167 + <input type="submit" value="delete your account"> 168 + </form> 169 + </div> 170 + </details> 135 171 </div> 136 172 @end 137 173 ··· 140 176 <h2>admin powers:</h2> 141 177 <form action="/api/user/set_muted" method="post"> 142 178 <input 143 - type="text" 179 + type="number" 144 180 name="id" 145 181 id="id" 146 182 value="@user.id"