mirror of
https://github.com/jetzig-framework/jetzig.git
synced 2025-05-14 22:16:08 +00:00
Closes #105: Configure SMTP from environment variables
Fall back to hardcoded values if each `JETZIG_SMTP_*` variable is not present.
This commit is contained in:
parent
bf6c595d64
commit
9e4a81aa19
@ -95,6 +95,7 @@ pub fn build(b: *std.Build) !void {
|
||||
main_tests.root_module.addImport("zmpl", zmpl_dep.module("zmpl"));
|
||||
main_tests.root_module.addImport("jetkv", jetkv_dep.module("jetkv"));
|
||||
main_tests.root_module.addImport("httpz", httpz_dep.module("httpz"));
|
||||
main_tests.root_module.addImport("smtp", smtp_client_dep.module("smtp_client"));
|
||||
const run_main_tests = b.addRunArtifact(main_tests);
|
||||
|
||||
const test_step = b.step("test", "Run library tests");
|
||||
|
@ -9,6 +9,7 @@ pub fn run(allocator: std.mem.Allocator, params: *jetzig.data.Value, env: jetzig
|
||||
|
||||
const mail = jetzig.mail.Mail.init(
|
||||
allocator,
|
||||
env,
|
||||
.{
|
||||
.subject = "Hello!!!",
|
||||
.from = "bob@jetzig.dev",
|
||||
|
@ -116,6 +116,13 @@ pub const jetzig_options = struct {
|
||||
|
||||
/// SMTP configuration for Jetzig Mail. It is recommended to use a local SMTP relay,
|
||||
/// e.g.: https://github.com/juanluisbaptiste/docker-postfix
|
||||
///
|
||||
/// Each configuration option can be overridden with environment variables:
|
||||
/// `JETZIG_SMTP_PORT`
|
||||
/// `JETZIG_SMTP_ENCRYPTION`
|
||||
/// `JETZIG_SMTP_HOST`
|
||||
/// `JETZIG_SMTP_USERNAME`
|
||||
/// `JETZIG_SMTP_PASSWORD`
|
||||
// pub const smtp: jetzig.mail.SMTPConfig = .{
|
||||
// .port = 25,
|
||||
// .encryption = .none, // .insecure, .none, .tls, .start_tls
|
||||
|
@ -217,13 +217,10 @@ pub const initHook: ?*const fn (*App) anyerror!void = if (@hasDecl(root, "init")
|
||||
/// Initialize a new Jetzig app. Call this from `src/main.zig` and then call
|
||||
/// `start(@import("routes").routes)` on the returned value.
|
||||
pub fn init(allocator: std.mem.Allocator) !App {
|
||||
const args = try std.process.argsAlloc(allocator);
|
||||
defer std.process.argsFree(allocator, args);
|
||||
|
||||
const environment = Environment.init(allocator);
|
||||
const env = try Environment.init(allocator);
|
||||
|
||||
return .{
|
||||
.environment = environment,
|
||||
.env = env,
|
||||
.allocator = allocator,
|
||||
.custom_routes = std.ArrayList(views.Route).init(allocator),
|
||||
.initHook = initHook,
|
||||
|
@ -7,7 +7,7 @@ const mime_types = @import("mime_types").mime_types; // Generated at build time.
|
||||
|
||||
const App = @This();
|
||||
|
||||
environment: jetzig.Environment,
|
||||
env: jetzig.Environment,
|
||||
allocator: std.mem.Allocator,
|
||||
custom_routes: std.ArrayList(jetzig.views.Route),
|
||||
initHook: ?*const fn (*App) anyerror!void,
|
||||
@ -26,6 +26,8 @@ const AppOptions = struct {};
|
||||
pub fn start(self: *const App, routes_module: type, options: AppOptions) !void {
|
||||
_ = options; // See `AppOptions`
|
||||
|
||||
defer self.env.deinit();
|
||||
|
||||
if (self.initHook) |hook| try hook(@constCast(self));
|
||||
|
||||
var mime_map = jetzig.http.mime.MimeMap.init(self.allocator);
|
||||
@ -61,18 +63,14 @@ pub fn start(self: *const App, routes_module: type, options: AppOptions) !void {
|
||||
);
|
||||
defer cache.deinit();
|
||||
|
||||
const server_options = try self.environment.getServerOptions();
|
||||
defer self.allocator.free(server_options.bind);
|
||||
defer self.allocator.free(server_options.secret);
|
||||
|
||||
var log_thread = try std.Thread.spawn(
|
||||
.{ .allocator = self.allocator },
|
||||
jetzig.loggers.LogQueue.Reader.publish,
|
||||
.{ &server_options.log_queue.reader, .{} },
|
||||
.{ &self.env.log_queue.reader, .{} },
|
||||
);
|
||||
defer log_thread.join();
|
||||
|
||||
if (server_options.detach) {
|
||||
if (self.env.detach) {
|
||||
const argv = try std.process.argsAlloc(self.allocator);
|
||||
defer std.process.argsFree(self.allocator, argv);
|
||||
var child_argv = std.ArrayList([]const u8).init(self.allocator);
|
||||
@ -89,7 +87,7 @@ pub fn start(self: *const App, routes_module: type, options: AppOptions) !void {
|
||||
|
||||
var server = jetzig.http.Server.init(
|
||||
self.allocator,
|
||||
server_options,
|
||||
self.env,
|
||||
routes,
|
||||
self.custom_routes.items,
|
||||
&routes_module.jobs,
|
||||
@ -106,7 +104,8 @@ pub fn start(self: *const App, routes_module: type, options: AppOptions) !void {
|
||||
&job_queue,
|
||||
.{
|
||||
.logger = server.logger,
|
||||
.environment = server.options.environment,
|
||||
.vars = self.env.vars,
|
||||
.environment = self.env.environment,
|
||||
.routes = routes,
|
||||
.jobs = &routes_module.jobs,
|
||||
.mailers = &routes_module.mailers,
|
||||
@ -127,7 +126,7 @@ pub fn start(self: *const App, routes_module: type, options: AppOptions) !void {
|
||||
error.AddressInUse => {
|
||||
try server.logger.ERROR(
|
||||
"Socket unavailable: {s}:{} - unable to start server.\n",
|
||||
.{ server_options.bind, server_options.port },
|
||||
.{ self.env.bind, self.env.port },
|
||||
);
|
||||
return;
|
||||
},
|
||||
|
@ -7,8 +7,54 @@ const jetzig = @import("../jetzig.zig");
|
||||
const Environment = @This();
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
logger: jetzig.loggers.Logger,
|
||||
bind: []const u8,
|
||||
port: u16,
|
||||
secret: []const u8,
|
||||
detach: bool,
|
||||
environment: jetzig.Environment.EnvironmentName,
|
||||
vars: jetzig.Environment.Vars,
|
||||
log_queue: *jetzig.loggers.LogQueue,
|
||||
|
||||
pub const EnvironmentName = enum { development, production, testing };
|
||||
pub const Vars = struct {
|
||||
env_map: std.process.EnvMap,
|
||||
|
||||
pub fn get(self: Vars, key: []const u8) ?[]const u8 {
|
||||
return self.env_map.get(key);
|
||||
}
|
||||
|
||||
pub fn getT(self: Vars, T: type, key: []const u8) !switch (@typeInfo(T)) {
|
||||
.bool => T,
|
||||
else => ?T,
|
||||
} {
|
||||
const value = self.env_map.get(key) orelse return if (@typeInfo(T) == .bool)
|
||||
false
|
||||
else
|
||||
null;
|
||||
|
||||
return switch (@typeInfo(T)) {
|
||||
.int => try std.fmt.parseInt(T, value, 10),
|
||||
.bool => if (std.mem.eql(u8, value, "1"))
|
||||
true
|
||||
else if (std.mem.eql(u8, value, "0"))
|
||||
false
|
||||
else
|
||||
error.JetzigInvalidEnvironmentVariableBooleanValue,
|
||||
.@"enum" => parseEnum(T, value),
|
||||
else => @compileError("Unsupported environment value type: `" ++ @typeName(T) ++ "`"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Vars) void {
|
||||
var env_map = self.env_map;
|
||||
env_map.deinit();
|
||||
}
|
||||
|
||||
fn parseEnum(E: type, value: []const u8) ?E {
|
||||
return std.meta.stringToEnum(E, value);
|
||||
}
|
||||
};
|
||||
|
||||
const Options = struct {
|
||||
help: bool = false,
|
||||
@ -54,17 +100,12 @@ const Options = struct {
|
||||
};
|
||||
};
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator) Environment {
|
||||
return .{ .allocator = allocator };
|
||||
}
|
||||
|
||||
/// Generate server initialization options using command line args with defaults.
|
||||
pub fn getServerOptions(self: Environment) !jetzig.http.Server.ServerOptions {
|
||||
const options = try args.parseForCurrentProcess(Options, self.allocator, .print);
|
||||
pub fn init(allocator: std.mem.Allocator) !Environment {
|
||||
const options = try args.parseForCurrentProcess(Options, allocator, .print);
|
||||
defer options.deinit();
|
||||
|
||||
const log_queue = try self.allocator.create(jetzig.loggers.LogQueue);
|
||||
log_queue.* = jetzig.loggers.LogQueue.init(self.allocator);
|
||||
const log_queue = try allocator.create(jetzig.loggers.LogQueue);
|
||||
log_queue.* = jetzig.loggers.LogQueue.init(allocator);
|
||||
try log_queue.setFiles(
|
||||
try getLogFile(.stdout, options.options),
|
||||
try getLogFile(.stderr, options.options),
|
||||
@ -77,18 +118,19 @@ pub fn getServerOptions(self: Environment) !jetzig.http.Server.ServerOptions {
|
||||
}
|
||||
|
||||
const environment = options.options.environment;
|
||||
const vars = Vars{ .env_map = try std.process.getEnvMap(allocator) };
|
||||
|
||||
var logger = switch (options.options.@"log-format") {
|
||||
.development => jetzig.loggers.Logger{
|
||||
.development_logger = jetzig.loggers.DevelopmentLogger.init(
|
||||
self.allocator,
|
||||
allocator,
|
||||
resolveLogLevel(options.options.@"log-level", environment),
|
||||
log_queue,
|
||||
),
|
||||
},
|
||||
.json => jetzig.loggers.Logger{
|
||||
.json_logger = jetzig.loggers.JsonLogger.init(
|
||||
self.allocator,
|
||||
allocator,
|
||||
resolveLogLevel(options.options.@"log-level", environment),
|
||||
log_queue,
|
||||
),
|
||||
@ -101,7 +143,7 @@ pub fn getServerOptions(self: Environment) !jetzig.http.Server.ServerOptions {
|
||||
}
|
||||
|
||||
const secret_len = jetzig.http.Session.Cipher.key_length;
|
||||
const secret = (try self.getSecret(&logger, secret_len, environment))[0..secret_len];
|
||||
const secret = (try getSecret(allocator, &logger, secret_len, environment))[0..secret_len];
|
||||
|
||||
if (secret.len != secret_len) {
|
||||
try logger.ERROR("Expected secret length: {}, found: {}.", .{ secret_len, secret.len });
|
||||
@ -110,16 +152,24 @@ pub fn getServerOptions(self: Environment) !jetzig.http.Server.ServerOptions {
|
||||
}
|
||||
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.logger = logger,
|
||||
.secret = secret,
|
||||
.bind = try self.allocator.dupe(u8, options.options.bind),
|
||||
.bind = try allocator.dupe(u8, options.options.bind),
|
||||
.port = options.options.port,
|
||||
.detach = options.options.detach,
|
||||
.environment = environment,
|
||||
.vars = vars,
|
||||
.log_queue = log_queue,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Environment) void {
|
||||
self.vars.deinit();
|
||||
self.allocator.free(self.bind);
|
||||
self.allocator.free(self.secret);
|
||||
}
|
||||
|
||||
fn getLogFile(stream: enum { stdout, stderr }, options: Options) !std.fs.File {
|
||||
const path = switch (stream) {
|
||||
.stdout => options.log,
|
||||
@ -139,10 +189,15 @@ fn getLogFile(stream: enum { stdout, stderr }, options: Options) !std.fs.File {
|
||||
return file;
|
||||
}
|
||||
|
||||
fn getSecret(self: Environment, logger: *jetzig.loggers.Logger, comptime len: u10, environment: EnvironmentName) ![]const u8 {
|
||||
fn getSecret(
|
||||
allocator: std.mem.Allocator,
|
||||
logger: *jetzig.loggers.Logger,
|
||||
comptime len: u10,
|
||||
environment: EnvironmentName,
|
||||
) ![]const u8 {
|
||||
const env_var = "JETZIG_SECRET";
|
||||
|
||||
return std.process.getEnvVarOwned(self.allocator, env_var) catch |err| {
|
||||
return std.process.getEnvVarOwned(allocator, env_var) catch |err| {
|
||||
switch (err) {
|
||||
error.EnvironmentVariableNotFound => {
|
||||
if (environment != .development) {
|
||||
@ -151,7 +206,7 @@ fn getSecret(self: Environment, logger: *jetzig.loggers.Logger, comptime len: u1
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
const secret = try jetzig.util.generateSecret(self.allocator, len);
|
||||
const secret = try jetzig.util.generateSecret(allocator, len);
|
||||
try logger.WARN(
|
||||
"Running in development mode, using auto-generated cookie encryption key: {s}",
|
||||
.{secret},
|
||||
|
@ -393,7 +393,11 @@ pub fn session(self: *Request) !*jetzig.http.Session {
|
||||
if (self._session) |capture| return capture;
|
||||
|
||||
const local_session = try self.allocator.create(jetzig.http.Session);
|
||||
local_session.* = jetzig.http.Session.init(self.allocator, try self.cookies(), self.server.options.secret);
|
||||
local_session.* = jetzig.http.Session.init(
|
||||
self.allocator,
|
||||
try self.cookies(),
|
||||
self.server.env.secret,
|
||||
);
|
||||
local_session.parse() catch |err| {
|
||||
switch (err) {
|
||||
error.JetzigInvalidSessionCookie => {
|
||||
@ -477,7 +481,8 @@ const RequestMail = struct {
|
||||
self.request.allocator,
|
||||
mail_job.params,
|
||||
jetzig.jobs.JobEnv{
|
||||
.environment = self.request.server.options.environment,
|
||||
.vars = self.request.server.env.vars,
|
||||
.environment = self.request.server.env.environment,
|
||||
.logger = self.request.server.logger,
|
||||
.routes = self.request.server.routes,
|
||||
.mailers = self.request.server.mailer_definitions,
|
||||
|
@ -6,19 +6,9 @@ const zmpl = @import("zmpl");
|
||||
const zmd = @import("zmd");
|
||||
const httpz = @import("httpz");
|
||||
|
||||
pub const ServerOptions = struct {
|
||||
logger: jetzig.loggers.Logger,
|
||||
bind: []const u8,
|
||||
port: u16,
|
||||
secret: []const u8,
|
||||
detach: bool,
|
||||
environment: jetzig.Environment.EnvironmentName,
|
||||
log_queue: *jetzig.loggers.LogQueue,
|
||||
};
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
logger: jetzig.loggers.Logger,
|
||||
options: ServerOptions,
|
||||
env: jetzig.Environment,
|
||||
routes: []*jetzig.views.Route,
|
||||
custom_routes: []jetzig.views.Route,
|
||||
job_definitions: []const jetzig.JobDefinition,
|
||||
@ -35,7 +25,7 @@ const Server = @This();
|
||||
|
||||
pub fn init(
|
||||
allocator: std.mem.Allocator,
|
||||
options: ServerOptions,
|
||||
env: jetzig.Environment,
|
||||
routes: []*jetzig.views.Route,
|
||||
custom_routes: []jetzig.views.Route,
|
||||
job_definitions: []const jetzig.JobDefinition,
|
||||
@ -47,8 +37,8 @@ pub fn init(
|
||||
) Server {
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.logger = options.logger,
|
||||
.options = options,
|
||||
.logger = env.logger,
|
||||
.env = env,
|
||||
.routes = routes,
|
||||
.custom_routes = custom_routes,
|
||||
.job_definitions = job_definitions,
|
||||
@ -62,8 +52,8 @@ pub fn init(
|
||||
|
||||
pub fn deinit(self: *Server) void {
|
||||
if (self.initialized) self.std_net_server.deinit();
|
||||
self.allocator.free(self.options.secret);
|
||||
self.allocator.free(self.options.bind);
|
||||
self.allocator.free(self.env.secret);
|
||||
self.allocator.free(self.env.bind);
|
||||
}
|
||||
|
||||
const Dispatcher = struct {
|
||||
@ -82,8 +72,8 @@ pub fn listen(self: *Server) !void {
|
||||
var httpz_server = try httpz.Server(Dispatcher).init(
|
||||
self.allocator,
|
||||
.{
|
||||
.port = self.options.port,
|
||||
.address = self.options.bind,
|
||||
.port = self.env.port,
|
||||
.address = self.env.bind,
|
||||
.thread_pool = .{
|
||||
.count = jetzig.config.get(?u16, "thread_count") orelse @intCast(try std.Thread.getCpuCount()),
|
||||
.buffer_size = jetzig.config.get(usize, "buffer_size"),
|
||||
@ -102,9 +92,9 @@ pub fn listen(self: *Server) !void {
|
||||
defer httpz_server.deinit();
|
||||
|
||||
try self.logger.INFO("Listening on http://{s}:{} [{s}]", .{
|
||||
self.options.bind,
|
||||
self.options.port,
|
||||
@tagName(self.options.environment),
|
||||
self.env.bind,
|
||||
self.env.port,
|
||||
@tagName(self.env.environment),
|
||||
});
|
||||
|
||||
self.initialized = true;
|
||||
@ -262,7 +252,7 @@ fn renderJSON(
|
||||
|
||||
if (data.value) |_| {} else _ = try data.object();
|
||||
|
||||
rendered.content = if (self.options.environment == .development)
|
||||
rendered.content = if (self.env.environment == .development)
|
||||
try data.toJsonOptions(.{ .pretty = true, .color = false })
|
||||
else
|
||||
try data.toJson();
|
||||
|
@ -13,6 +13,8 @@ pub const JobEnv = struct {
|
||||
logger: jetzig.loggers.Logger,
|
||||
/// The current server environment, `enum { development, production }`
|
||||
environment: jetzig.Environment.EnvironmentName,
|
||||
/// Environment configured at server launch
|
||||
vars: jetzig.Environment.Vars,
|
||||
/// All routes detected by Jetzig on startup
|
||||
routes: []*const jetzig.Route,
|
||||
/// All mailers detected by Jetzig on startup
|
||||
|
@ -38,7 +38,7 @@ pub fn run(allocator: std.mem.Allocator, params: *jetzig.data.Value, env: jetzig
|
||||
|
||||
try mailer.deliverFn(allocator, &mail_params, &data, params.get("params").?, env);
|
||||
|
||||
const mail = jetzig.mail.Mail.init(allocator, .{
|
||||
const mail = jetzig.mail.Mail.init(allocator, env, .{
|
||||
.subject = mail_params.get(.subject) orelse "(No subject)",
|
||||
.from = mail_params.get(.from) orelse return error.JetzigMailerMissingFromAddress,
|
||||
.to = mail_params.get(.to) orelse return error.JetzigMailerMissingToAddress,
|
||||
|
@ -8,16 +8,19 @@ allocator: std.mem.Allocator,
|
||||
config: jetzig.mail.SMTPConfig,
|
||||
params: jetzig.mail.MailParams,
|
||||
boundary: u32,
|
||||
env: jetzig.jobs.JobEnv,
|
||||
|
||||
const Mail = @This();
|
||||
|
||||
pub fn init(
|
||||
allocator: std.mem.Allocator,
|
||||
env: jetzig.jobs.JobEnv,
|
||||
params: jetzig.mail.MailParams,
|
||||
) Mail {
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.config = jetzig.config.get(jetzig.mail.SMTPConfig, "smtp"),
|
||||
.env = env,
|
||||
.params = params,
|
||||
.boundary = std.crypto.random.int(u32),
|
||||
};
|
||||
@ -31,7 +34,7 @@ pub fn deliver(self: Mail) !void {
|
||||
.from = self.params.from.?,
|
||||
.to = self.params.to.?,
|
||||
.data = data,
|
||||
}, self.config.toSMTP(self.allocator));
|
||||
}, try self.config.toSMTP(self.allocator, self.env));
|
||||
}
|
||||
|
||||
pub fn generateData(self: Mail) ![]const u8 {
|
||||
@ -140,6 +143,7 @@ inline fn isEncoded(char: u8) bool {
|
||||
test "HTML part only" {
|
||||
const mail = Mail{
|
||||
.allocator = std.testing.allocator,
|
||||
.env = undefined,
|
||||
.config = .{},
|
||||
.boundary = 123456789,
|
||||
.params = .{
|
||||
@ -175,6 +179,7 @@ test "HTML part only" {
|
||||
test "text part only" {
|
||||
const mail = Mail{
|
||||
.allocator = std.testing.allocator,
|
||||
.env = undefined,
|
||||
.config = .{},
|
||||
.boundary = 123456789,
|
||||
.params = .{
|
||||
@ -210,6 +215,7 @@ test "text part only" {
|
||||
test "HTML and text parts" {
|
||||
const mail = Mail{
|
||||
.allocator = std.testing.allocator,
|
||||
.env = undefined,
|
||||
.config = .{},
|
||||
.boundary = 123456789,
|
||||
.params = .{
|
||||
@ -252,6 +258,7 @@ test "HTML and text parts" {
|
||||
test "long content encoding" {
|
||||
const mail = Mail{
|
||||
.allocator = std.testing.allocator,
|
||||
.env = undefined,
|
||||
.config = .{},
|
||||
.boundary = 123456789,
|
||||
.params = .{
|
||||
@ -301,6 +308,7 @@ test "long content encoding" {
|
||||
test "non-latin alphabet encoding" {
|
||||
const mail = Mail{
|
||||
.allocator = std.testing.allocator,
|
||||
.env = undefined,
|
||||
.config = .{},
|
||||
.boundary = 123456789,
|
||||
.params = .{
|
||||
@ -341,3 +349,32 @@ test "non-latin alphabet encoding" {
|
||||
|
||||
try std.testing.expectEqualStrings(expected, actual);
|
||||
}
|
||||
|
||||
test "environment SMTP config" {
|
||||
var env: jetzig.jobs.JobEnv = undefined;
|
||||
var env_map = std.process.EnvMap.init(std.testing.allocator);
|
||||
defer env_map.deinit();
|
||||
|
||||
try env_map.put("JETZIG_SMTP_PORT", "999");
|
||||
try env_map.put("JETZIG_SMTP_ENCRYPTION", "start_tls");
|
||||
try env_map.put("JETZIG_SMTP_HOST", "smtp.example.com");
|
||||
try env_map.put("JETZIG_SMTP_USERNAME", "example-username");
|
||||
try env_map.put("JETZIG_SMTP_PASSWORD", "example-password");
|
||||
|
||||
env.vars = jetzig.Environment.Vars{ .env_map = env_map };
|
||||
|
||||
const mail = Mail{
|
||||
.allocator = undefined,
|
||||
.env = undefined,
|
||||
.config = .{},
|
||||
.boundary = undefined,
|
||||
.params = undefined,
|
||||
};
|
||||
|
||||
const config = try mail.config.toSMTP(std.testing.allocator, env);
|
||||
try std.testing.expect(config.port == 999);
|
||||
try std.testing.expect(config.encryption == .start_tls);
|
||||
try std.testing.expectEqualStrings("smtp.example.com", config.host);
|
||||
try std.testing.expectEqualStrings("example-username", config.username.?);
|
||||
try std.testing.expectEqualStrings("example-password", config.password.?);
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ const std = @import("std");
|
||||
|
||||
const smtp = @import("smtp");
|
||||
|
||||
const jetzig = @import("../../jetzig.zig");
|
||||
|
||||
port: u16 = 25,
|
||||
encryption: enum { none, insecure, tls, start_tls } = .none,
|
||||
host: []const u8 = "localhost",
|
||||
@ -10,14 +12,19 @@ password: ?[]const u8 = null,
|
||||
|
||||
const SMTPConfig = @This();
|
||||
|
||||
pub fn toSMTP(self: SMTPConfig, allocator: std.mem.Allocator) smtp.Config {
|
||||
pub fn toSMTP(
|
||||
self: SMTPConfig,
|
||||
allocator: std.mem.Allocator,
|
||||
env: jetzig.jobs.JobEnv,
|
||||
) !smtp.Config {
|
||||
return smtp.Config{
|
||||
.allocator = allocator,
|
||||
.port = self.port,
|
||||
.encryption = self.getEncryption(),
|
||||
.host = self.host,
|
||||
.username = self.username,
|
||||
.password = self.password,
|
||||
.port = try env.vars.getT(u16, "JETZIG_SMTP_PORT") orelse self.port,
|
||||
.encryption = try env.vars.getT(smtp.Encryption, "JETZIG_SMTP_ENCRYPTION") orelse
|
||||
self.getEncryption(),
|
||||
.host = env.vars.get("JETZIG_SMTP_HOST") orelse self.host,
|
||||
.username = env.vars.get("JETZIG_SMTP_USERNAME") orelse self.username,
|
||||
.password = env.vars.get("JETZIG_SMTP_PASSWORD") orelse self.password,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -87,10 +87,16 @@ pub fn request(
|
||||
|
||||
const logger = jetzig.loggers.Logger{ .test_logger = jetzig.loggers.TestLogger{} };
|
||||
var log_queue = jetzig.loggers.LogQueue.init(allocator);
|
||||
// We init the `std.process.EnvMap` directly here (instead of calling `std.process.getEnvMap`
|
||||
// to ensure that tests run in a clean environment. Users can manually add items to the
|
||||
// environment within a test if required.
|
||||
const vars = jetzig.Environment.Vars{ .env_map = std.process.EnvMap.init(allocator) };
|
||||
var server = jetzig.http.Server{
|
||||
.allocator = allocator,
|
||||
.logger = logger,
|
||||
.options = .{
|
||||
.env = .{
|
||||
.allocator = allocator,
|
||||
.vars = vars,
|
||||
.logger = logger,
|
||||
.bind = undefined,
|
||||
.port = undefined,
|
||||
|
Loading…
x
Reference in New Issue
Block a user