╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ UserLogin.zig ────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
150 } 151 } 152 153 if (box.children.getIndex(child_id)) |idx| { 154 try box.children.values()[idx].widget.input(allocator, key, root_focus); 155 } 156 } 157 158 pub fn clearGrid(self: *View) void { 159 self.center.clearGrid(); 160 } 161 162 pub fn getGrid(self: View) ?Grid { 163 return self.center.getGrid(); 164 } 165 166 pub fn getFocus(self: *View) *Focus { 167 return self.center.getFocus(); 168 } 169 170 pub fn atTop(self: View) bool { 171 return self.center.child.box.focus.child_id == self.nav_ids[username_index]; 172 } 173 174 fn indexOf(self: View, child_id: usize) ?usize { 175 for (self.nav_ids, 0..) |id, i| { 176 if (id == child_id) return i; 177 } 178 return null; 179 } 180 181 fn submit(self: *View, allocator: std.mem.Allocator) !void { 182 const box = &self.center.child.box; 183 const username_input = &box.children.values()[username_index].widget.text_input; 184 const password_input = &box.children.values()[password_index].widget.text_input; 185 186 const username = try username_input.text(allocator); 187 defer allocator.free(username); 188 189 const password = try password_input.text(allocator); 190 defer allocator.free(password); 191 192 if (comptime wasm) { 193 // no DB cursor available on the wasm render path 194 try self.rememberFailure(.unknown_user, username); 195 return; 196 } 197 198 const haxy_moment = self.session.haxy_moment orelse { 199 // no DB context (e.g. wasm/web rendering path); treat as unknown. 200 try self.rememberFailure(.unknown_user, username); 201 return; 202 }; 203 204 const result = try evt.User.verifyCredentials(evt.AdminDB, evt.admin_repo_opts.hash, haxy_moment, self.session.arena, username, password); 205 switch (result) { 206 .unknown_user => { 207 try self.rememberFailure(.unknown_user, username); 208 return; 209 }, 210 .wrong_password => { 211 try self.rememberFailure(.wrong_password, username); 212 return; 213 }, 214 .success => |user_id| { 215 // dupe user_id into the arena so the session can hold a stable slice 216 const user_id_stable = try self.session.arena.allocator().dupe(u8, &user_id); 217 self.session.data.user_id = user_id_stable; 218 219 // adopt the user's name and persisted prefs 220 try self.session.loadUser(); 221 222 // wipe the entered credentials so they don't linger if the 223 // user returns to this page after logging out 224 username_input.clear(allocator); 225 password_input.clear(allocator); 226 227 // leave the user tab for the page it belongs to, where the 228 // web's /login redirect also lands 229 try self.session.navigate(self.session.data.current_page.pageRoot()); 230 }, 231 } 232 } 233 234 fn rememberFailure(self: *View, failure: ui.Session.FormFeedback.LoginFailure, username: []const u8) !void { 235 self.session.data.form_feedback = .{ .login = .{ 236 .failure = failure, 237 .username = try self.session.arena.allocator().dupe(u8, username), 238 } }; 239 } 240 }; 241