From 9ea7c18d85bb90ff514d9000214412e73c457090 Mon Sep 17 00:00:00 2001 From: Alex Manning Date: Sun, 7 Jul 2024 17:15:28 -0400 Subject: [PATCH] bump decode; clean up / fix user module --- manifest.toml | 4 ++-- src/spades/date.gleam | 45 ++++++++++++++++++++++------------ src/spades/router.gleam | 3 +++ src/spades/user.gleam | 53 ++++++++++++++--------------------------- 4 files changed, 53 insertions(+), 52 deletions(-) diff --git a/manifest.toml b/manifest.toml index 7a27f56..846d3e9 100644 --- a/manifest.toml +++ b/manifest.toml @@ -6,7 +6,7 @@ packages = [ { name = "backoff", version = "1.1.6", build_tools = ["rebar3"], requirements = [], otp_app = "backoff", source = "hex", outer_checksum = "CF0CFFF8995FB20562F822E5CC47D8CCF664C5ECDC26A684CBE85C225F9D7C39" }, { name = "bigben", version = "1.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "bigben", source = "hex", outer_checksum = "8E5A98FA6E981EEEF016C40F1CDFADA095927CAF6CAAA0C7E295EED02FC95947" }, { name = "birl", version = "1.7.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "5C66647D62BCB11FE327E7A6024907C4A17954EF22865FE0940B54A852446D01" }, - { name = "decode", version = "0.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "decode", source = "hex", outer_checksum = "D31AAB8C8B9DDEFC62A41FA5FB1B1851A0C04E882ACF22A96462E8761844D145" }, + { name = "decode", version = "0.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "decode", source = "hex", outer_checksum = "965F517F67B8C172CA27A5C8E34C73733139E8C9E64736181B8C3179281F9793" }, { name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" }, { name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" }, { name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, @@ -17,7 +17,7 @@ packages = [ { name = "gleam_javascript", version = "0.11.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_javascript", source = "hex", outer_checksum = "483631D3001FCE8EB12ADEAD5E1B808440038E96F93DA7A32D326C82F480C0B2" }, { name = "gleam_json", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "CB10B0E7BF44282FB25162F1A24C1A025F6B93E777CCF238C4017E4EEF2CDE97" }, { name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" }, - { name = "gleam_pgo", version = "0.11.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "pgo"], otp_app = "gleam_pgo", source = "hex", outer_checksum = "1897C299A05AE3DE6BF6CC92CD1D67FDF8504B15E8826CBEBFD0E4471A698DD3" }, + { name = "gleam_pgo", version = "0.12.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "pgo"], otp_app = "gleam_pgo", source = "hex", outer_checksum = "D66DDF151FF1EBF65F30FB54C8CA938EA52A563811BC67DB53866D1861CE1528" }, { name = "gleam_stdlib", version = "0.38.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "663CF11861179AF415A625307447775C09404E752FF99A24E2057C835319F1BE" }, { name = "glint", version = "1.0.0-rc2", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "FD5C47CE237CA67121F3946ADE7C630750BB67F5E8A4717D2DF5B5EE758CCFDB" }, { name = "glisten", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "glisten", source = "hex", outer_checksum = "CF3A9383E9BA4A8CBAF2F7B799716290D02F2AC34E7A77556B49376B662B9314" }, diff --git a/src/spades/date.gleam b/src/spades/date.gleam index 11adcba..b0186aa 100644 --- a/src/spades/date.gleam +++ b/src/spades/date.gleam @@ -1,4 +1,5 @@ -import decode +import decode.{type Decoder} +import gleam/float import gleam/int import gleam/json.{type Json} import gleam/list.{Continue, Stop} @@ -9,22 +10,36 @@ pub type Date { Date(year: Int, month: Int, day: Int, hour: Int, minute: Int, second: Int) } -pub fn decoder() -> decode.Decoder(Date) { +pub fn decoder() -> Decoder(Date) { + let ymd_decoder = + decode.into({ + use year <- decode.parameter + use month <- decode.parameter + use day <- decode.parameter + #(year, month, day) + }) + |> decode.field(0, decode.int) + |> decode.field(1, decode.int) + |> decode.field(2, decode.int) + + let hms_decoder = + decode.into({ + use hour <- decode.parameter + use minute <- decode.parameter + use second <- decode.parameter + #(hour, minute, second) + }) + |> decode.field(0, decode.int) + |> decode.field(1, decode.int) + |> decode.field(2, decode.float) + decode.into({ - use year <- decode.parameter - use month <- decode.parameter - use day <- decode.parameter - use hour <- decode.parameter - use minute <- decode.parameter - use second <- decode.parameter - Date(year, month, day, hour, minute, second) + use #(year, month, day) <- decode.parameter + use #(hour, minute, second) <- decode.parameter + Date(year, month, day, hour, minute, float.round(second)) }) - |> decode.field(0, decode.int) - |> decode.field(1, decode.int) - |> decode.field(2, decode.int) - |> decode.field(3, decode.int) - |> decode.field(4, decode.int) - |> decode.field(5, decode.int) + |> decode.field(0, ymd_decoder) + |> decode.field(1, hms_decoder) } pub fn from_string(date_string: String) -> Result(Date, Nil) { diff --git a/src/spades/router.gleam b/src/spades/router.gleam index e37168f..f19ae3e 100644 --- a/src/spades/router.gleam +++ b/src/spades/router.gleam @@ -89,6 +89,8 @@ pub fn session_middleware( } } +import gleam/io + pub fn router(app_req: AppRequest) -> AppResult { case app_req.req.method, request.path_segments(app_req.req) { Get, ["assets" as start, ..path] | Get, ["images" as start, ..path] -> @@ -113,6 +115,7 @@ pub fn router(app_req: AppRequest) -> AppResult { json_response(200, session.to_json(value)) |> session.add_cookie_header(value) }) + |> io.debug |> result.replace_error(empty_response(403)) |> result.unwrap_both } diff --git a/src/spades/user.gleam b/src/spades/user.gleam index aaf9992..845b67f 100644 --- a/src/spades/user.gleam +++ b/src/spades/user.gleam @@ -1,4 +1,4 @@ -import decode +import decode.{type Decoder} import gleam/bit_array import gleam/crypto.{Sha256} import gleam/list @@ -7,11 +7,19 @@ import gleam/result import spades/date.{type Date} pub type User { - User(id: Int, username: String, password_hash: String, inserted_at: Date) + User(id: Int, username: String, inserted_at: Date) } -pub type PublicUser { - PublicUser(id: Int, username: String, inserted_at: Date) +fn decoder() -> Decoder(User) { + decode.into({ + use id <- decode.parameter + use username <- decode.parameter + use inserted_at <- decode.parameter + User(id, username, inserted_at) + }) + |> decode.field(0, decode.int) + |> decode.field(1, decode.string) + |> decode.field(2, date.decoder()) } pub fn create( @@ -19,14 +27,14 @@ pub fn create( salt: String, username: String, password: String, -) -> Result(PublicUser, Nil) { +) -> Result(User, Nil) { let encoded = password |> bit_array.from_string |> crypto.sign_message(bit_array.from_string(salt), Sha256) use returned <- result.then( - "insert into users (username, password_hash, created_at) values ($1, $2, now()) returning *" + "insert into users (username, password_hash, created_at) values ($1, $2, now()) returning id, username, created_at" |> pgo.execute(db, [pgo.text(username), pgo.text(encoded)], decode.from( decoder(), _, @@ -36,16 +44,13 @@ pub fn create( let assert [user] = returned.rows - user - |> to_public - |> Ok + Ok(user) } -pub fn list(db: Connection) -> Result(List(PublicUser), Nil) { - "select id, username, password_hash, created_at from users" +pub fn list(db: Connection) -> Result(List(User), Nil) { + "select id, username, created_at from users" |> pgo.execute(db, [], decode.from(decoder(), _)) |> result.map(fn(returned) { returned.rows }) - |> result.map(fn(rows) { list.map(rows, to_public) }) |> result.replace_error(Nil) } @@ -60,7 +65,7 @@ pub fn login( |> bit_array.from_string |> crypto.sign_message(bit_array.from_string(salt), Sha256) - "select id, username, password_hash, created_at from users where username = $1 and password_hash = $2" + "select id, username, created_at from users where username = $1 and password_hash = $2" |> pgo.execute(db, [pgo.text(username), pgo.text(hashed)], decode.from( decoder(), _, @@ -69,25 +74,3 @@ pub fn login( |> result.map(fn(resp) { resp.rows }) |> result.then(list.first(_)) } - -pub fn decoder() -> decode.Decoder(User) { - decode.into({ - use id <- decode.parameter - use username <- decode.parameter - use password_hash <- decode.parameter - use inserted_at <- decode.parameter - User(id, username, password_hash, inserted_at) - }) - |> decode.field(0, decode.int) - |> decode.field(1, decode.string) - |> decode.field(2, decode.string) - |> decode.field(3, date.decoder()) -} - -fn to_public(user: User) -> PublicUser { - PublicUser( - id: user.id, - username: user.username, - inserted_at: user.inserted_at, - ) -}