mail based rss feed aggregator
2
fork

Configure Feed

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

rename `main_ui.ModelData` to more fitting `main_ui.Context`

ollie b2c7b4cb ec97c224

+57 -54
+56 -53
src/eater/ui/main_ui.gleam
··· 48 48 49 49 // main ------------------------------------------------------------------------- 50 50 51 - pub fn component() -> lustre.App(ModelData, Model, Message) { 51 + pub fn component() -> lustre.App(Context, Model, Message) { 52 52 lustre.application(init:, update:, view:) 53 53 } 54 54 55 - fn init(data: ModelData) -> #(Model, Effect(Message)) { 55 + fn init(data: Context) -> #(Model, Effect(Message)) { 56 56 #(LoginForm(data, login_form()), effect.none()) 57 57 } 58 58 59 59 // model ------------------------------------------------------------------------ 60 60 61 - pub opaque type ModelData { 62 - ModelData( 61 + pub opaque type Context { 62 + Context( 63 63 csrf_token: String, 64 64 database: sqlight.Connection, 65 65 smtp_environment: smtp.SmtpEnvironment, ··· 69 69 ) 70 70 } 71 71 72 - fn update_data(data: ModelData, model: Model) -> Model { 72 + fn update_context(context: Context, model: Model) -> Model { 73 73 case model { 74 - SignUpForm(..) -> SignUpForm(..model, data:) 75 - ConfirmOneTimePassword(..) -> ConfirmOneTimePassword(..model, data:) 76 - LoginForm(..) -> LoginForm(..model, data:) 77 - User(..) -> User(..model, data:) 78 - Admin(..) -> Admin(..model, data:) 74 + SignUpForm(..) -> SignUpForm(..model, context:) 75 + ConfirmOneTimePassword(..) -> ConfirmOneTimePassword(..model, context:) 76 + LoginForm(..) -> LoginForm(..model, context:) 77 + User(..) -> User(..model, context:) 78 + Admin(..) -> Admin(..model, context:) 79 79 } 80 80 } 81 81 82 - /// create a new `ModelData` 82 + /// create a new `Context` 83 83 /// 84 - pub fn new_model_data( 84 + pub fn new_context( 85 85 csrf_token _csrf_token: String, 86 86 database database: sqlight.Connection, 87 87 smtp_environment smtp_environment: smtp.SmtpEnvironment, 88 88 configuration configuration: configuration.AppConfig, 89 - ) -> ModelData { 89 + ) -> Context { 90 90 // for some amount of per-session traceability; 91 91 // this should really be replaced with the csrf token, once that is properly implemented 92 92 let session_id = uuid.v7_string() |> string.slice(28, 6) 93 93 94 - ModelData( 94 + Context( 95 95 csrf_token: session_id, 96 96 database:, 97 97 smtp_environment:, ··· 108 108 /// 109 109 pub opaque type Model { 110 110 // signup 111 - SignUpForm(data: ModelData, form: form.Form(FormUser)) 111 + SignUpForm(context: Context, form: form.Form(FormUser)) 112 112 ConfirmOneTimePassword( 113 - data: ModelData, 113 + context: Context, 114 114 user: FormUser, 115 115 form: form.Form(String), 116 116 password_to_confirm: String, 117 117 attempts_left: Int, 118 118 ) 119 119 // login 120 - LoginForm(data: ModelData, form: form.Form(FormUser)) 120 + LoginForm(context: Context, form: form.Form(FormUser)) 121 121 122 122 // logged in 123 - User(data: ModelData, self: user.User, subscriptions: List(rss.Location)) 123 + User(context: Context, self: user.User, subscriptions: List(rss.Location)) 124 124 Admin( 125 - data: ModelData, 125 + context: Context, 126 126 self: user.User, 127 127 subscriptions: List(rss.Location), 128 128 users: List(user.User), ··· 138 138 woof.field("form-email", form.field_value(form, "email")), 139 139 ] 140 140 ConfirmOneTimePassword( 141 - data: _, 141 + context: _, 142 142 user:, 143 143 form: _, 144 144 password_to_confirm: _, ··· 148 148 woof.field("form-user-email", user.email), 149 149 woof.int_field("attempts_left", attempts_left), 150 150 ] 151 - LoginForm(data: _, form:) -> [ 151 + LoginForm(context: _, form:) -> [ 152 152 woof.field("model", "LoginForm"), 153 153 woof.field("form-email", form.field_value(form, "email")), 154 154 ] 155 - User(data: _, self:, subscriptions:) -> [ 155 + User(context: _, self:, subscriptions:) -> [ 156 156 woof.field("model", "User"), 157 157 woof.field("user-email", self.email), 158 158 woof.int_field("subscription-count", subscriptions |> list.length()), 159 159 ] 160 - Admin(data: _, self:, subscriptions:, users: _) -> [ 160 + Admin(context: _, self:, subscriptions:, users: _) -> [ 161 161 woof.field("model", "Admin"), 162 162 woof.field("user-email", self.email), 163 163 woof.int_field("subscription-count", subscriptions |> list.length()), ··· 319 319 case message, model { 320 320 // signup ------------------------------------------------------------------- 321 321 UserClickedGotoSignUp, _ -> #( 322 - SignUpForm(model.data, signup_form()), 322 + SignUpForm(model.context, signup_form()), 323 323 effect.none(), 324 324 ) 325 325 UserSubmittedSignUpForm(Error(form)), _ -> #( 326 - SignUpForm(model.data, form), 326 + SignUpForm(model.context, form), 327 327 effect.none(), 328 328 ) 329 329 UserSubmittedSignUpForm(Ok(user)), _ -> #( ··· 337 337 send_one_time_password( 338 338 password_to_confirm, 339 339 user, 340 - model.data.smtp_environment, 340 + model.context.smtp_environment, 341 341 ), 342 342 ) 343 343 } ··· 353 353 354 354 #( 355 355 ConfirmOneTimePassword( 356 - data: ModelData(..model.data, toasts: new_model.data.toasts), 356 + context: Context(..model.context, toasts: new_model.context.toasts), 357 357 user:, 358 358 password_to_confirm:, 359 359 form: one_time_password_form(), ··· 381 381 382 382 // one time password matches, add a new user 383 383 UserSubmittedOneTimePassword(Ok(password)), 384 - ConfirmOneTimePassword(password_to_confirm:, data: _, user:, ..) 384 + ConfirmOneTimePassword(password_to_confirm:, context: _, user:, ..) 385 385 if password == password_to_confirm 386 386 -> #(model, create_new_user(user)) 387 387 388 388 ServerCreatedNewUser(user), _ -> #( 389 389 model, 390 - persist_new_user(user, model.data.database), 390 + persist_new_user(user, model.context.database), 391 391 ) 392 392 DatabasePersistedNewUser(Ok(user)), _ -> #( 393 - User(model.data, user, []), 394 - fetch_logged_in_data(model.data.database, user), 393 + User(model.context, user, []), 394 + fetch_logged_in_data(model.context.database, user), 395 395 ) 396 396 DatabasePersistedNewUser(Error(_)), _ -> { 397 397 log_model_n_message( ··· 429 429 #( 430 430 ConfirmOneTimePassword( 431 431 ..model, 432 - data: ModelData(..model.data, toasts: new_model.data.toasts), 432 + context: Context(..model.context, toasts: new_model.context.toasts), 433 433 attempts_left:, 434 434 ), 435 435 effect, ··· 448 448 449 449 #( 450 450 SignUpForm( 451 - ModelData(..model.data, toasts: new_model.data.toasts), 451 + Context(..model.context, toasts: new_model.context.toasts), 452 452 signup_form(), 453 453 ), 454 454 effect, ··· 465 465 466 466 // login -------------------------------------------------------------------- 467 467 UserClickedGotoLogIn, _ -> #( 468 - LoginForm(model.data, login_form()), 468 + LoginForm(model.context, login_form()), 469 469 effect.none(), 470 470 ) 471 471 UserSubmittedLoginForm(Error(form)), _ -> #( 472 - LoginForm(model.data, form), 472 + LoginForm(model.context, form), 473 473 effect.none(), 474 474 ) 475 475 UserSubmittedLoginForm(Ok(login)), _ -> #( 476 476 model, 477 - fetch_user_from_database(model.data, login), 477 + fetch_user_from_database(model.context, login), 478 478 ) 479 479 DatabaseReturnedUser(Ok(Ok(user)), from_form), _ -> #( 480 480 model, 481 481 verify_login(user, from_form), 482 482 ) 483 483 DatabaseReturnedUser(Ok(Error(_)), _), _ -> { 484 - case model.data.configuration.allow_signups { 484 + case model.context.configuration.allow_signups { 485 485 True -> { 486 486 let toast = 487 487 toaster.Toast( ··· 496 496 toaster.Toast( 497 497 title: Some("Invalid login"), 498 498 message: "Try again or contact " 499 - <> smtp.sender_email(model.data.smtp_environment) 499 + <> smtp.sender_email(model.context.smtp_environment) 500 500 <> " about getting / recovering an account.", 501 501 options: toast.default_options(toast.Info), 502 502 ) ··· 521 521 do_toast(toast, model) 522 522 } 523 523 ServerVerifiedLogin(valid: True, user:), _ -> #( 524 - User(model.data, user, []), 525 - fetch_logged_in_data(model.data.database, user), 524 + User(model.context, user, []), 525 + fetch_logged_in_data(model.context.database, user), 526 526 ) 527 527 ServerVerifiedLogin(valid: False, user: _), _ -> { 528 528 let toast = ··· 538 538 TimerDismissedToast, _ -> { 539 539 // the amount of toasts should stay small enough that this isnt an issue 540 540 let toasts = 541 - model.data.toasts 541 + model.context.toasts 542 542 |> list.reverse 543 543 |> list.drop(1) 544 544 |> list.reverse 545 - let model = ModelData(..model.data, toasts:) |> update_data(model) 545 + let model = Context(..model.context, toasts:) |> update_context(model) 546 546 547 547 #(model, effect.none()) 548 548 } ··· 607 607 } 608 608 609 609 /// fetch data required when logged in 610 - /// user stuff and admin stuff if applicaple 610 + /// user stuff 611 + /// admin stuff if applicaple 611 612 /// 612 613 fn fetch_logged_in_data( 613 614 database: sqlight.Connection, ··· 699 700 /// 700 701 /// `DatabaseReturnedUser` 701 702 /// 702 - fn fetch_user_from_database(data: ModelData, user: FormUser) -> Effect(Message) { 703 + fn fetch_user_from_database(data: Context, user: FormUser) -> Effect(Message) { 703 704 use dispatch <- effect.from 704 705 705 706 database.user_by_email(data.database, user.email) ··· 718 719 let description = 719 720 list.append(describe_model(model), describe_message(message)) 720 721 721 - model.data.logger 722 + model.context.logger 722 723 |> woof.log(level, text, description) 723 724 } 724 725 ··· 757 758 fn view(model: Model) -> Element(Message) { 758 759 html.main([], [ 759 760 case model { 760 - SignUpForm(data: _, form:) -> view_signup_form(form:) 761 + SignUpForm(context: _, form:) -> view_signup_form(form:) 761 762 ConfirmOneTimePassword(form:, ..) -> 762 763 view_one_time_password_form(form:, busy: False) 763 - LoginForm(data:, form:) -> 764 + LoginForm(context:, form:) -> 764 765 view_login_form( 765 766 form:, 766 767 busy: False, 767 - allow_signups: data.configuration.allow_signups, 768 + allow_signups: context.configuration.allow_signups, 768 769 ) 769 - User(data:, user:) -> view_logged_in(data, user) 770 + User(context:, self:, subscriptions: _) -> view_logged_in(context, self) 771 + Admin(context: _, self: _, subscriptions: _, users: _) -> todo 770 772 }, 771 773 // button.button([event.on_click(SpawnToast)], [element.text("spawn toast")]), 772 774 portal.to("body", [], [ 773 775 keyed.fragment({ 774 - use #(key, toasts) <- list.map(toaster.view_toasts(model.data.toasts)) 776 + use #(key, toasts) <- list.map(toaster.view_toasts(model.context.toasts)) 775 777 776 778 #(key, toasts) 777 779 }), ··· 834 836 ) 835 837 } 836 838 837 - fn view_logged_in(_data: ModelData, _user: user.User) -> Element(Message) { 839 + fn view_logged_in(_data: Context, _user: user.User) -> Element(Message) { 838 840 html.div([], [ 839 841 html.h1([], [element.text("*hacker voice* im in!")]), 840 842 ]) ··· 1051 1053 /// update the model and schedule dismissal of a new toast 1052 1054 /// 1053 1055 fn do_toast(toast: toaster.Toast, model: Model) { 1054 - let data = ModelData(..model.data, toasts: [toast, ..model.data.toasts]) 1056 + let context = 1057 + Context(..model.context, toasts: [toast, ..model.context.toasts]) 1055 1058 1056 1059 let effect = 1057 1060 schedule_message( ··· 1059 1062 after: toast.options.duration_ms, 1060 1063 ) 1061 1064 1062 - #(update_data(data, model), effect) 1065 + #(update_context(context, model), effect) 1063 1066 }
+1 -1
src/eater/webserver.gleam
··· 223 223 let assert Ok(component) = 224 224 lustre.start_server_component( 225 225 login, 226 - with: main_ui.new_model_data( 226 + with: main_ui.new_context( 227 227 csrf_token: token, 228 228 database:, 229 229 smtp_environment:,