╭ changed ────╮ │src/event.zig│ ╰─────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2123 return id_bytes; │ │2124 } │ │2125 │ │2126 +// change a user's email, and their password when the password fields are │ │2127 +// filled in │ │2128 +pub fn updateUser( │ │2129 + io: std.Io, │ │2130 + allocator: std.mem.Allocator, │ │2131 + users_dir: []const u8, │ │2132 + admin_repo: *rp.Repo(.xit, admin_repo_opts), │ │2133 + user_id: *const [event_id_size]u8, │ │2134 + email: []const u8, │ │2135 + current_password: []const u8, │ │2136 + new_password: []const u8, │ │2137 + new_password_again: []const u8, │ │2138 +) !void { │ │2139 + if (email.len == 0) return error.EmailEmpty; │ │2140 + var arena = std.heap.ArenaAllocator.init(allocator); │ │2141 + defer arena.deinit(); │ │2142 + const moment = try currentMoment(admin_repo_opts, admin_repo); │ │2143 + const user = (try User.readById(AdminDB, admin_repo_opts.hash, moment, &arena, user_id)) orelse return error.NotFound; │ │2144 + if (user.removed) return error.NotFound; │ │2145 + if (!std.mem.eql(u8, email, user.event.email) and try User.readByEmail(AdminDB, admin_repo_opts.hash, moment, &arena, email) != null) return error.EmailTaken;│ │2146 + │ │2147 + var event = user.event; │ │2148 + event.email = email; │ │2149 + var password_hash_buf: [User.password_hash_max_len]u8 = undefined; │ │2150 + if (current_password.len + new_password.len + new_password_again.len > 0) { │ │2151 + if (!User.verifyPassword(user.event.password_hash, current_password)) return error.WrongPassword; │ │2152 + if (new_password.len == 0) return error.PasswordEmpty; │ │2153 + if (!std.mem.eql(u8, new_password, new_password_again)) return error.PasswordMismatch; │ │2154 + event.password_hash = try User.hashPassword(new_password, &password_hash_buf, io); │ │2155 + } │ │2156 + │ │2157 + try consume(.{ .server = .{ .users_dir = users_dir } }, .admin, .xit, admin_repo_opts, io, allocator, admin_repo, events_ref, &[_]EventWithId{.{ │ │2158 + .id = std.fmt.bytesToHex(user_id.*, .lower), │ │2159 + .timestamp = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()), │ │2160 + .author = .{ .name = event.name, .email = email }, │ │2161 + .event = .{ .user = event }, │ │2162 + }}); │ │2163 +} │ │2164 + │ │2165 // consume a new repo's event into its owner's user repo and mark it active │ │2166 fn writeRepoEvent( │ │2167 io: std.Io, │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯