mail based rss feed aggregator
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

split LoggedIn into User and Admin and add fetching subscriptions and users

ollie ec97c224 545224e8

+177 -11
+177 -11
src/eater/ui/main_ui.gleam
··· 18 18 19 19 import eater/configuration 20 20 import eater/database 21 + import eater/feed/rss 21 22 import eater/smtp 22 23 import eater/ui/toaster 23 24 import eater/user ··· 73 74 SignUpForm(..) -> SignUpForm(..model, data:) 74 75 ConfirmOneTimePassword(..) -> ConfirmOneTimePassword(..model, data:) 75 76 LoginForm(..) -> LoginForm(..model, data:) 76 - LoggedIn(..) -> LoggedIn(..model, data:) 77 + User(..) -> User(..model, data:) 78 + Admin(..) -> Admin(..model, data:) 77 79 } 78 80 } 79 81 ··· 105 107 106 108 /// 107 109 pub opaque type Model { 110 + // signup 108 111 SignUpForm(data: ModelData, form: form.Form(FormUser)) 109 112 ConfirmOneTimePassword( 110 113 data: ModelData, ··· 113 116 password_to_confirm: String, 114 117 attempts_left: Int, 115 118 ) 119 + // login 116 120 LoginForm(data: ModelData, form: form.Form(FormUser)) 117 - LoggedIn(data: ModelData, user: user.User) 121 + 122 + // logged in 123 + User(data: ModelData, self: user.User, subscriptions: List(rss.Location)) 124 + Admin( 125 + data: ModelData, 126 + self: user.User, 127 + subscriptions: List(rss.Location), 128 + users: List(user.User), 129 + ) 118 130 } 119 131 120 132 /// describe a model using structured data ··· 140 152 woof.field("model", "LoginForm"), 141 153 woof.field("form-email", form.field_value(form, "email")), 142 154 ] 143 - LoggedIn(data: _, user:) -> [ 144 - woof.field("model", "LoggedIn"), 145 - woof.field("user-email", user.email), 155 + User(data: _, self:, subscriptions:) -> [ 156 + woof.field("model", "User"), 157 + woof.field("user-email", self.email), 158 + woof.int_field("subscription-count", subscriptions |> list.length()), 159 + ] 160 + Admin(data: _, self:, subscriptions:, users: _) -> [ 161 + woof.field("model", "Admin"), 162 + woof.field("user-email", self.email), 163 + woof.int_field("subscription-count", subscriptions |> list.length()), 146 164 ] 147 165 } 148 166 } ··· 177 195 ServerCreatedNewUser(user: user.User) 178 196 DatabasePersistedNewUser(Result(user.User, sqlight.Error)) 179 197 UserClickedGotoLogIn 198 + DatabaseReturnedAllUsers(Result(List(user.User), sqlight.Error)) 199 + DatabaseReturnedSubscriptions(Result(List(rss.Location), sqlight.Error)) 180 200 } 181 201 182 202 /// describe a message using structured data ··· 265 285 TimerDismissedToast -> [ 266 286 woof.field("message", "TimerDismissedToast"), 267 287 ] 288 + DatabaseReturnedAllUsers(Ok(_)) -> [ 289 + woof.field("message", "DatabaseReturnedAllUsers"), 290 + woof.field("status", "ok"), 291 + ] 292 + DatabaseReturnedAllUsers(Error(db_error)) -> [ 293 + woof.field("message", "DatabaseReturnedAllUsers"), 294 + woof.field("status", "error"), 295 + woof.field("details", string.inspect(db_error)), 296 + ] 297 + DatabaseReturnedSubscriptions(Ok(_)) -> [ 298 + woof.field("message", "DatabaseReturnedSubscriptions"), 299 + woof.field("status", "ok"), 300 + ] 301 + DatabaseReturnedSubscriptions(Error(db_error)) -> [ 302 + woof.field("message", "DatabaseReturnedSubscriptions"), 303 + woof.field("status", "error"), 304 + woof.field("details", string.inspect(db_error)), 305 + ] 268 306 } 269 307 } 270 308 ··· 325 363 ) 326 364 } 327 365 ServerSentPassword(Error(_), password_to_confirm: _, user: _), _ -> { 366 + log_model_n_message( 367 + model:, 368 + message:, 369 + at: woof.Error, 370 + with: "Database error", 371 + ) 372 + 328 373 let toast = 329 374 toaster.Toast( 330 375 title: None, ··· 336 381 337 382 // one time password matches, add a new user 338 383 UserSubmittedOneTimePassword(Ok(password)), 339 - ConfirmOneTimePassword(password_to_confirm:, data:, user:, ..) 384 + ConfirmOneTimePassword(password_to_confirm:, data: _, user:, ..) 340 385 if password == password_to_confirm 341 386 -> #(model, create_new_user(user)) 342 387 ··· 345 390 persist_new_user(user, model.data.database), 346 391 ) 347 392 DatabasePersistedNewUser(Ok(user)), _ -> #( 348 - LoggedIn(model.data, user), 349 - effect.none(), 393 + User(model.data, user, []), 394 + fetch_logged_in_data(model.data.database, user), 350 395 ) 351 396 DatabasePersistedNewUser(Error(_)), _ -> { 397 + log_model_n_message( 398 + model:, 399 + message:, 400 + at: woof.Error, 401 + with: "Database error", 402 + ) 403 + 352 404 let toast = 353 405 toaster.Toast( 354 406 title: Some("Something went wrong"), ··· 453 505 } 454 506 } 455 507 DatabaseReturnedUser(Error(_), _), _ -> { 508 + log_model_n_message( 509 + model:, 510 + message:, 511 + at: woof.Error, 512 + with: "Database error", 513 + ) 514 + 456 515 let toast = 457 516 toaster.Toast( 458 517 title: None, ··· 462 521 do_toast(toast, model) 463 522 } 464 523 ServerVerifiedLogin(valid: True, user:), _ -> #( 465 - LoggedIn(model.data, user), 466 - effect.none(), 524 + User(model.data, user, []), 525 + fetch_logged_in_data(model.data.database, user), 467 526 ) 468 527 ServerVerifiedLogin(valid: False, user: _), _ -> { 469 528 let toast = ··· 475 534 do_toast(toast, model) 476 535 } 477 536 537 + // toast stuff -------------------------------------------------------------- 478 538 TimerDismissedToast, _ -> { 479 539 // the amount of toasts should stay small enough that this isnt an issue 480 540 let toasts = ··· 486 546 487 547 #(model, effect.none()) 488 548 } 549 + 550 + // main ui bits ------------------------------------------------------------- 551 + // user data arrived 552 + DatabaseReturnedSubscriptions(Ok(subscriptions)), User(..) -> #( 553 + User(..model, subscriptions:), 554 + effect.none(), 555 + ) 556 + DatabaseReturnedSubscriptions(Ok(subscriptions)), Admin(..) -> #( 557 + Admin(..model, subscriptions:), 558 + effect.none(), 559 + ) 560 + // nu uh 561 + DatabaseReturnedSubscriptions(Ok(_)), _ -> #(model, effect.none()) 562 + 563 + // user data didnt arrive 564 + // nu uh 565 + DatabaseReturnedSubscriptions(Error(_)), _ -> { 566 + log_model_n_message( 567 + model:, 568 + message:, 569 + at: woof.Error, 570 + with: "Database error", 571 + ) 572 + 573 + let toast = 574 + toaster.Toast( 575 + title: Some("Failed to fetch subscriptions"), 576 + message: "I failed to get your subscriptions. Try again in a bit.", 577 + options: toast.default_options(toast.Warning), 578 + ) 579 + 580 + do_toast(toast, model) 581 + } 582 + 583 + DatabaseReturnedAllUsers(Ok(users)), Admin(..) -> #( 584 + Admin(..model, users:), 585 + effect.none(), 586 + ) 587 + DatabaseReturnedAllUsers(Error(_)), Admin(..) -> { 588 + log_model_n_message( 589 + model:, 590 + message:, 591 + at: woof.Error, 592 + with: "Database error", 593 + ) 594 + 595 + let toast = 596 + toaster.Toast( 597 + title: Some("Failed to fetch users"), 598 + message: "I failed to fetch all users. Try again in a bit.", 599 + options: toast.default_options(toast.Warning), 600 + ) 601 + 602 + do_toast(toast, model) 603 + } 604 + // nu uh 605 + DatabaseReturnedAllUsers(_), _ -> #(model, effect.none()) 489 606 } 490 607 } 491 608 609 + /// fetch data required when logged in 610 + /// user stuff and admin stuff if applicaple 611 + /// 612 + fn fetch_logged_in_data( 613 + database: sqlight.Connection, 614 + user: user.User, 615 + ) -> Effect(Message) { 616 + let admin_data = case user.is_admin { 617 + True -> fetch_user_list(database) 618 + False -> effect.none() 619 + } 620 + 621 + effect.batch([ 622 + fetch_user_subscriptions(database, user), 623 + admin_data, 624 + ]) 625 + } 626 + 627 + /// fetch all subscriptions for a given user 628 + /// 629 + /// `DatabaseReturnedSubscriptions` 630 + /// 631 + fn fetch_user_subscriptions( 632 + database: sqlight.Connection, 633 + user: user.User, 634 + ) -> Effect(Message) { 635 + use dispatch <- effect.from 636 + 637 + database.feeds_for_user(user, database) 638 + |> DatabaseReturnedSubscriptions 639 + |> dispatch 640 + } 641 + 642 + /// fetch a list of all users 643 + /// 644 + /// `DatabaseReturnedAllUsers` 645 + /// 646 + fn fetch_user_list(database: sqlight.Connection) -> Effect(Message) { 647 + use dispatch <- effect.from 648 + 649 + database.all_users(database) 650 + |> DatabaseReturnedAllUsers 651 + |> dispatch 652 + } 653 + 492 654 /// create a new user from a `FormUser` 493 655 /// 494 656 /// `ServerCreatedNewUser` ··· 516 678 |> dispatch 517 679 } 518 680 681 + /// check if a given `FormUser` matches a given `user.User` 682 + /// 683 + /// `ServerVerifiedLogin` 684 + /// 519 685 fn verify_login(user: user.User, from_form: FormUser) -> Effect(Message) { 520 686 use dispatch <- effect.from 521 687 ··· 600 766 busy: False, 601 767 allow_signups: data.configuration.allow_signups, 602 768 ) 603 - LoggedIn(data:, user:) -> view_logged_in(data, user) 769 + User(data:, user:) -> view_logged_in(data, user) 604 770 }, 605 771 // button.button([event.on_click(SpawnToast)], [element.text("spawn toast")]), 606 772 portal.to("body", [], [