mail based rss feed aggregator
2
fork

Configure Feed

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

update deps to support stdlib v1!!

ollie b3d85bbd ed905671

+48 -51
+1 -1
gleam.toml
··· 13 13 # https://gleam.run/writing-gleam/gleam-toml/. 14 14 15 15 [dependencies] 16 - gleam_stdlib = ">= 0.44.0 and < 2.0.0" 16 + gleam_stdlib = ">= 1.0.0 and < 2.0.0" 17 17 parsed_it = ">= 0.1.1 and < 1.0.0" 18 18 gcourier = { git = "git@github.com:nnuuvv/gcourier.git", ref="main" } 19 19 # gcourier = { path = "../gcourier/" }
+11 -11
manifest.toml
··· 4 4 packages = [ 5 5 { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" }, 6 6 { name = "compresso", version = "0.1.0", build_tools = ["gleam"], requirements = ["exception", "gleam_erlang", "gleam_stdlib", "gleam_yielder", "logging"], otp_app = "compresso", source = "hex", outer_checksum = "8BE29A1EDA42F70826ED148EAE40C46BB3FC18E78FE472663DB01DD4A38172D4" }, 7 - { name = "envoy", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "850DA9D29D2E5987735872A2B5C81035146D7FE19EFC486129E44440D03FD832" }, 7 + { name = "envoy", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "9C6FBB6BFA02A52798BEEC5977A738CAD6E4A057F4B67FD0C8061AD2502C191A" }, 8 8 { name = "esqlite", version = "0.9.0", build_tools = ["rebar3"], requirements = [], otp_app = "esqlite", source = "hex", outer_checksum = "CCF72258A4EE152EC7AD92AA9A03552EB6CA1B06B65C93AD5B6E55C302E05855" }, 9 9 { name = "ewe", version = "3.0.7", build_tools = ["gleam"], requirements = ["compresso", "exception", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "logging", "websocks"], otp_app = "ewe", source = "hex", outer_checksum = "5679A3763B79376C0846B23E42C60091441524FF6A6B5DD022ACB2BCB3F35BEC" }, 10 10 { name = "exception", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "329D269D5C2A314F7364BD2711372B6F2C58FA6F39981572E5CA68624D291F8C" }, 11 11 { name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" }, 12 12 { name = "formal", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_time"], otp_app = "formal", source = "hex", outer_checksum = "8FBEB42758F90ACAA82A8B6B8FE11B4A3B2A2B290E97B4DDD4B7DCE98DEB885C" }, 13 - { name = "gcourier", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib", "gleam_time", "youid"], source = "git", repo = "git@github.com:nnuuvv/gcourier.git", commit = "504d59f21553afbc63c3d4505ad70dac09aa25f2" }, 13 + { name = "gcourier", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib", "gleam_time", "youid"], source = "git", repo = "git@github.com:nnuuvv/gcourier.git", commit = "945277542533752d15ddb8f2795eb615581058ff" }, 14 14 { name = "glaze_oat", version = "3.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib", "lustre"], otp_app = "glaze_oat", source = "hex", outer_checksum = "B1373CA720EBB9D7FBDA4D2E28CAAD2B1928F6845313570AE72CA1D93B069706" }, 15 - { name = "gleam_crypto", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "50774BAFFF1144E7872814C566C5D653D83A3EBF23ACC3156B757A1B6819086E" }, 15 + { name = "gleam_crypto", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "2DE9E4EF53CF6FEE049D4F765731F7178F7A11AEFAE00EEE63BF7536B354AD3F" }, 16 16 { name = "gleam_erlang", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "1124AD3AA21143E5AF0FC5CF3D9529F6DB8CA03E43A55711B60B6B7B3874375C" }, 17 17 { name = "gleam_http", version = "4.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "82EA6A717C842456188C190AFB372665EA56CE13D8559BF3B1DD9E40F619EE0C" }, 18 18 { name = "gleam_httpc", version = "5.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "C545172618D07811494E97AAA4A0FB34DA6F6D0061FDC8041C2F8E3BE2B2E48F" }, 19 19 { name = "gleam_json", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "44FDAA8847BE8FC48CA7A1C089706BD54BADCC4C45B237A992EDDF9F2CDB2836" }, 20 20 { name = "gleam_otp", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "BA6A294E295E428EC1562DC1C11EA7530DCB981E8359134BEABC8493B7B2258E" }, 21 - { name = "gleam_stdlib", version = "0.71.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "702F3BC2A14793906880B1078B19A6165F87323AEE8D0C4A34085846336FCAAE" }, 21 + { name = "gleam_stdlib", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "960090C2FB391784BB34267B099DC9315CC1B1F6013E7415BC763CEF1905D7D3" }, 22 22 { name = "gleam_time", version = "1.8.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "533D8723774D61AD4998324F5DD1DABDCDBFABAFB9E87CB5D03C6955448FC97D" }, 23 23 { name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" }, 24 - { name = "glearray", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "5E272F7CB278CC05A929C58DEB58F5D5AC6DB5B879A681E71138658D0061C38A" }, 25 - { name = "gleeunit", version = "1.9.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "DA9553CE58B67924B3C631F96FE3370C49EB6D6DC6B384EC4862CC4AAA718F3C" }, 26 - { name = "glisten", version = "9.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "logging"], otp_app = "glisten", source = "hex", outer_checksum = "D92808C66F7D3F22F2289CD04CBA8151757AAE9CB3D86992F0C6DE32A41205E1" }, 24 + { name = "glearray", version = "2.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "C013E0F153E73F5D35609AA6F2570D41D2E35C0DD404E91E847859EE41CBC139" }, 25 + { name = "gleeunit", version = "1.10.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "254B697FE72EEAD7BF82E941723918E421317813AC49923EE76A18C788C61E72" }, 26 + { name = "glisten", version = "9.0.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "logging"], otp_app = "glisten", source = "hex", outer_checksum = "7795AA50830656F3A0316A6B26595F893C83272DA901B3405E31339CAA31A10B" }, 27 27 { name = "group_registry", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "group_registry", source = "hex", outer_checksum = "BC798A53D6F2406DB94E27CB45C57052CB56B32ACF7CC16EA20F6BAEC7E36B90" }, 28 - { name = "houdini", version = "1.2.0", build_tools = ["gleam"], requirements = [], otp_app = "houdini", source = "hex", outer_checksum = "5DB1053F1AF828049C2B206D4403C18970ABEF5C18671CA3C2D2ED0DD64F6385" }, 28 + { name = "houdini", version = "1.2.1", build_tools = ["gleam"], requirements = [], otp_app = "houdini", source = "hex", outer_checksum = "6F8AC2F12974567FB744BEA66AC93CEB76AAEA19AD28564623F76CDA9BC26A85" }, 29 29 { name = "logging", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "BC5F18CE5DD9686100229FE5409BDC3DD5C46D5A7DF2F804AD2D8F0DD6C5060E" }, 30 30 { name = "lustre", version = "5.6.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib", "houdini"], otp_app = "lustre", source = "hex", outer_checksum = "EE558CD4DB9F09FCC16417ADF0183A3C2DAC3E4B21ED3AC0CAE859792AB810CA" }, 31 31 { name = "lustre_portal", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "lustre"], otp_app = "lustre_portal", source = "hex", outer_checksum = "7531667B9321B644E139F5BE42077932829431BE74BC7239471CEFC68943A661" }, ··· 33 33 { name = "parsed_it", version = "0.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "parsed_it", source = "hex", outer_checksum = "9F8BA3C634FEA847AD195E3322FD1DA51980F57C4171B02DCF069C6FC807944A" }, 34 34 { name = "repeatedly", version = "2.1.2", build_tools = ["gleam"], requirements = [], otp_app = "repeatedly", source = "hex", outer_checksum = "93AE1938DDE0DC0F7034F32C1BF0D4E89ACEBA82198A1FE21F604E849DA5F589" }, 35 35 { name = "simplifile", version = "2.4.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "7C18AFA4FED0B4CE1FA5B0B4BAC1FA1744427054EA993565F6F3F82E5453170D" }, 36 - { name = "sqlight", version = "1.0.3", build_tools = ["gleam"], requirements = ["esqlite", "gleam_stdlib"], otp_app = "sqlight", source = "hex", outer_checksum = "CADD79663C9B61D4BAC960A47CC2D42CA8F48EAF5804DBEB79977287750F4B16" }, 36 + { name = "sqlight", version = "1.1.0", build_tools = ["gleam"], requirements = ["esqlite", "gleam_stdlib"], otp_app = "sqlight", source = "hex", outer_checksum = "ECA1A4B45C35EB9EFCEEB7FAAC7BF5D8B2C777A7C1FC8A9C12CB67D54CED42E7" }, 37 37 { name = "tom", version = "2.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_time"], otp_app = "tom", source = "hex", outer_checksum = "234A842F3D087D35737483F5DFB6DE9839E3366EF0CAF8726D2D094210227670" }, 38 38 { name = "websocks", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_stdlib"], otp_app = "websocks", source = "hex", outer_checksum = "C70340E5B6C3390383ADA17029DCA6F8903863A7AD8CD8E1520EDCC4FE70D6FD" }, 39 - { name = "woof", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "woof", source = "hex", outer_checksum = "A5DC2FCB04F23B0F440978885A167A91450B88F7760B969127187C57E05D489C" }, 39 + { name = "woof", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "woof", source = "hex", outer_checksum = "6E5647638E57DE1C7E6643C8F44D950C1B5FC7F6AD4EBD3B1494B0E38531D7F2" }, 40 40 { name = "youid", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_stdlib", "gleam_time"], otp_app = "youid", source = "hex", outer_checksum = "7A3ABA44B1B38BC2BDCB5474C5317AA372BE58DFBC649815EE08B03526DDA18D" }, 41 41 ] 42 42 ··· 52 52 gleam_httpc = { version = ">= 5.0.0 and < 6.0.0" } 53 53 gleam_json = { version = ">= 3.1.0 and < 4.0.0" } 54 54 gleam_otp = { version = ">= 1.2.0 and < 2.0.0" } 55 - gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } 55 + gleam_stdlib = { version = ">= 1.0.0 and < 2.0.0" } 56 56 gleam_time = { version = ">= 1.8.0 and < 2.0.0" } 57 57 gleeunit = { version = ">= 1.0.0 and < 2.0.0" } 58 58 group_registry = { version = ">= 1.0.0 and < 2.0.0" }
+3 -7
src/eater/backend.gleam
··· 33 33 34 34 /// log with module related structured data 35 35 /// 36 - fn log( 37 - level: woof.Level, 38 - message: String, 39 - fields: List(#(String, String)), 40 - ) -> Nil { 36 + fn log(level: woof.Level, message: String, fields: List(#(String, _))) -> Nil { 41 37 woof.new("BACKEND") 42 38 |> woof.log(level, message, fields) 43 39 } ··· 363 359 RestartUser(user.User) 364 360 } 365 361 366 - fn describe_message(message: Message) -> List(#(String, String)) { 362 + fn describe_message(message: Message) -> List(#(String, _)) { 367 363 case message { 368 364 NewSubscription(user, feed) -> [ 369 365 woof.field("message", "NewSubscription"), ··· 552 548 fn log_and_stop( 553 549 logger logger: woof.Logger, 554 550 message message: String, 555 - fields fields: List(#(String, String)), 551 + fields fields: List(#(String, _)), 556 552 ) -> fn(a) -> actor.Next(b, c) { 557 553 fn(error) { 558 554 woof.log(logger, woof.Error, message, [
+1 -5
src/eater/fetcher.gleam
··· 53 53 54 54 /// log with module related structured data 55 55 /// 56 - fn log( 57 - level: woof.Level, 58 - message: String, 59 - fields: List(#(String, String)), 60 - ) -> Nil { 56 + fn log(level: woof.Level, message: String, fields: List(#(String, _))) -> Nil { 61 57 woof.new("FETCHER") 62 58 |> woof.log(level, message, fields) 63 59 }
+1 -5
src/eater/pubsub.gleam
··· 29 29 30 30 /// log with module related structured data 31 31 /// 32 - fn log( 33 - level: woof.Level, 34 - message: String, 35 - fields: List(#(String, String)), 36 - ) -> Nil { 32 + fn log(level: woof.Level, message: String, fields: List(#(String, _))) -> Nil { 37 33 woof.new("PUBSUB") 38 34 |> woof.log(level, message, fields) 39 35 }
+4 -8
src/eater/sender.gleam
··· 40 40 41 41 /// log with module related structured data 42 42 /// 43 - fn log( 44 - level: woof.Level, 45 - message: String, 46 - fields: List(#(String, String)), 47 - ) -> Nil { 43 + fn log(level: woof.Level, message: String, fields: List(#(String, _))) -> Nil { 48 44 woof.new("SENDER") 49 45 |> woof.log(level, message, fields) 50 46 } ··· 371 367 ]) 372 368 373 369 // tell self to get this users feeds from the database 374 - process.send_after(self, 150, GetFeeds) 370 + process.send_after(self, 150, FetchFeeds) 375 371 376 372 let state = 377 373 State( ··· 405 401 pub opaque type Message { 406 402 /// sent once at the start to fetch all feeds 407 403 /// 408 - GetFeeds 404 + FetchFeeds 409 405 PubSubMessage(pubsub.Message) 410 406 Retry(message: pubsub.Message, attempt: Int) 411 407 ··· 428 424 ) 429 425 430 426 case message { 431 - GetFeeds -> { 427 + FetchFeeds -> { 432 428 case database.feeds_for_user(for: state.user, in: state.database) { 433 429 Ok(feeds) -> { 434 430 let state =
+25 -12
src/eater/smtp.gleam
··· 28 28 import lustre/element 29 29 import lustre/element/html 30 30 31 + // TODO: long lived mailer 31 32 /// takes a `message` and sends it using the configured sender from the supplied `environment` 32 33 /// 33 34 pub fn send_message( 34 35 message: gcourier.Message, 35 36 environment: SmtpEnvironment, 36 37 ) -> Result(Nil, gcourier.Error) { 37 - gcourier.send( 38 + use mailer <- result.try(gcourier.start_smtp( 38 39 environment.host, 39 40 environment.port, 40 - option.Some(#(environment.username, environment.password)), 41 - message, 42 - ) 41 + option.Some(gcourier.Auth(environment.username, environment.password)), 42 + gcourier.RejectNonTls, 43 + )) 44 + 45 + let sent = gcourier.send(mailer, message) 46 + 47 + let _ = gcourier.stop(mailer) 48 + 49 + sent 43 50 } 44 51 45 52 /// turn a feed item into an email ready to be sent using `smtp.send_message` ··· 49 56 update: rss.FeedUpdate, 50 57 user: user.User, 51 58 ) -> gcourier.Message { 52 - gcourier.new_message(sender(environment)) 59 + gcourier.new_message( 60 + sender(environment), 61 + gcourier.Address(option.None, user.email), 62 + ) 53 63 |> gcourier.set_subject(update.channel.title <> ": " <> update.new.title) 54 - |> gcourier.add_recipient(gcourier.To(user.email)) 55 64 |> gcourier.set_content(gcourier.Html( 56 65 html.html([], [ 57 66 html.body([], [ ··· 75 84 email email: String, 76 85 one_time_password one_time_password: String, 77 86 ) -> gcourier.Message { 78 - gcourier.new_message(sender(environment)) 87 + gcourier.new_message( 88 + sender(environment), 89 + gcourier.Address(option.None, email), 90 + ) 79 91 |> gcourier.set_subject("Your one time password") 80 - |> gcourier.add_recipient(gcourier.To(email)) 81 92 |> gcourier.set_content(gcourier.Html( 82 93 html.html([], [ 83 94 html.body([], [ ··· 97 108 deleted_feed: rss.Location, 98 109 user: user.User, 99 110 ) -> gcourier.Message { 100 - gcourier.new_message(sender(environment)) 111 + gcourier.new_message( 112 + sender(environment), 113 + gcourier.Address(option.None, user.email), 114 + ) 101 115 |> gcourier.set_subject("One of your feeds has been paused") 102 - |> gcourier.add_recipient(gcourier.To(user.email)) 103 116 |> gcourier.set_content(gcourier.Html( 104 117 html.html([], [ 105 118 html.body([], [ ··· 138 151 environment.sender_email |> option.unwrap(environment.username) 139 152 } 140 153 141 - fn sender(environment: SmtpEnvironment) -> gcourier.Sender { 154 + fn sender(environment: SmtpEnvironment) -> gcourier.Address { 142 155 let address = sender_email(environment) 143 156 let name = environment.sender_name 144 157 145 - gcourier.Sender(address:, name:) 158 + gcourier.Address(address:, name:) 146 159 } 147 160 148 161 /// get the smtp_environment from the environment variables
+2 -2
src/eater/ui/main_ui.gleam
··· 141 141 142 142 /// describe a model using structured data 143 143 /// 144 - fn describe_model(model: Model) -> List(#(String, String)) { 144 + fn describe_model(model: Model) -> List(#(String, _)) { 145 145 case model { 146 146 SignUpForm(_data, form) -> [ 147 147 woof.field("model", "SignUpForm"), ··· 213 213 214 214 /// describe a message using structured data 215 215 /// 216 - fn describe_message(message: Message) -> List(#(String, String)) { 216 + fn describe_message(message: Message) -> List(#(String, _)) { 217 217 case message { 218 218 UserSubmittedLoginForm(Ok(login)) -> [ 219 219 woof.field("message", "UserSubmittedEmail"),