hecks 3.7.0 → 3.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/hecks/bluebook/meta_validator/modes.rb +14 -0
- data/lib/hecks/bluebook/meta_validator.rb +4 -2
- data/lib/hecks/corpus/routes.rb +1 -1
- data/lib/hecks/gate/stages.yml +11 -1
- data/lib/hecks/hecks/adapters/site_toolchain/prober.rb +64 -0
- data/lib/hecks/hecks/adapters/site_toolchain.rb +41 -5
- data/lib/hecks/language/bluebook/vocabulary.bluebook +1 -1
- data/lib/hecks/projections/deploy/shared_database_instance/templates/rds.yaml.tmpl +1 -1
- data/lib/hecks/projections/deploy/templates/lambda/template.yaml.tmpl +1 -1
- data/lib/hecks/projections/site/probe.rb +131 -0
- data/lib/hecks/projections/site/site_host/dockerfile.rb +1 -1
- data/lib/hecks/runtime/value/validation.rb +34 -3
- data/lib/hecks/site/bluebook/site.bluebook +31 -0
- data/lib/hecks/site/bluebook/site.ports.hecksagon +6 -0
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +1 -1
- data/prebuilt/{verdicts-be73f0df9eee0abe2f4aadc968321c4b919d19d424a3ccfe1777a71dabf7d9e7.json → verdicts-91aaf93ce8981bd9a754948f075d95650dc2ec6435015376f5c60992b36a24b1.json} +1 -1
- data/rust/codegen/src/fielded.rs +3 -3
- data/rust/codegen/src/json_codec.rs +2 -2
- data/rust/codegen/src/naming.rs +20 -0
- data/rust/host/Cargo.toml +4 -0
- data/rust/host/HECKS_RELEASE +1 -1
- data/rust/host/src/boot.rs +443 -0
- data/rust/host/src/boundary_fuzz/ir.rs +1 -0
- data/rust/host/src/commerce_ir.rs +459 -0
- data/rust/host/src/extension.rs +100 -0
- data/rust/host/src/ir.rs +0 -448
- data/rust/host/src/journal.rs +1 -1
- data/rust/host/src/lib.rs +40 -0
- data/rust/host/src/main.rs +4 -477
- data/rust/host/src/mint.rs +1 -1
- data/rust/host/src/payments/tests.rs +8 -8
- data/rust/host/src/payments.rs +10 -10
- data/rust/host/src/rate_limit.rs +27 -41
- data/rust/host/src/secrets.rs +15 -0
- data/rust/host/src/web/commerce.rs +121 -0
- data/rust/host/src/web/newsletter.rs +2 -1
- data/rust/host/src/web/newsletter_send.rs +1 -1
- data/rust/host/src/web/registration_receipt.rs +2 -2
- data/rust/host/src/web/registrations.rs +49 -49
- data/rust/host/src/web/resend_webhook.rs +300 -0
- data/rust/host/src/web.rs +43 -47
- metadata +13 -5
- /data/prebuilt/{a0818e2de67364dc1ab22868b6cbf869c62da6f8d9b924c778fa5cce2e76ee94.marshal → 0ee7f83cba59ce7d1c45c65ba166b071779f70143449f584f33ff7989f64eccb.marshal} +0 -0
- /data/prebuilt/{945481eefbdb584649d45f256307053558966a868b9c38dee7ee88f8169610f8.marshal → 6e4a6bcf0aa880e2e6b056e1846b70e5a768090b9dc998bbadeaf5d6bcfd3db8.marshal} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
use super::{instances_for, last_refusal, respond, with_id};
|
|
2
2
|
use crate::checkout;
|
|
3
3
|
use crate::dispatch;
|
|
4
|
-
use crate::
|
|
4
|
+
use crate::commerce_ir::{payments_provider, PaymentsProvider};
|
|
5
5
|
use crate::journal::LineageConfig;
|
|
6
6
|
use crate::lambda_client::LambdaInvoker;
|
|
7
7
|
use crate::payments;
|
|
@@ -15,7 +15,7 @@ use tokio_postgres::Client;
|
|
|
15
15
|
|
|
16
16
|
/// Whether checkout is on: `configured` must be set and equal `domain`
|
|
17
17
|
/// exactly — a mismatch would dispatch the wrong domain's Registration.Request.
|
|
18
|
-
pub
|
|
18
|
+
pub fn checkout_enabled(configured: Option<&str>, domain: &str) -> bool {
|
|
19
19
|
configured.is_some_and(|c| !c.is_empty() && c == domain)
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -63,7 +63,7 @@ fn seat_counts(read: &Value, domain: &str, payments: &PaymentsProvider) -> std::
|
|
|
63
63
|
.filter_map(|(id, payment)| payment.get("status").and_then(|s| s.as_str()).map(|s| (id, s.to_string())))
|
|
64
64
|
.collect();
|
|
65
65
|
let mut counts = std::collections::HashMap::new();
|
|
66
|
-
for (id, registration) in instances_for(read, &crate::
|
|
66
|
+
for (id, registration) in instances_for(read, &crate::commerce_ir::registrations_binding(domain).registration_prefix()) {
|
|
67
67
|
let holds = statuses.get(&id).is_some_and(|status| SEAT_HOLDING_PAYMENT_STATUSES.contains(&status.as_str()));
|
|
68
68
|
if let (true, false, Some(event_slug)) = (holds, registration_archived(®istration), plain_id(registration.get("event_slug"))) {
|
|
69
69
|
*counts.entry(event_slug).or_insert(0) += 1;
|
|
@@ -90,7 +90,7 @@ fn open_seats(capacity: i64, taken: usize) -> i64 {
|
|
|
90
90
|
/// Seats still open on one event, never below zero; `None` when there is no
|
|
91
91
|
/// such event or it carries no readable capacity.
|
|
92
92
|
pub(crate) fn seats_left(read: &Value, domain: &str, payments: &PaymentsProvider, event_slug: &str) -> Option<i64> {
|
|
93
|
-
let events = instances_for(read, &crate::
|
|
93
|
+
let events = instances_for(read, &crate::commerce_ir::registrations_binding(domain).event_prefix());
|
|
94
94
|
let (_, event) = events.iter().find(|(id, _)| id == event_slug)?;
|
|
95
95
|
Some(open_seats(event_capacity(event)?, seats_taken(read, domain, payments, event_slug)))
|
|
96
96
|
}
|
|
@@ -105,7 +105,7 @@ fn seat_figures(event: &Value, taken: usize) -> Value {
|
|
|
105
105
|
/// The seat figures of every event, keyed by event slug.
|
|
106
106
|
fn all_seat_figures(read: &Value, domain: &str, payments: &PaymentsProvider) -> Value {
|
|
107
107
|
let counts = seat_counts(read, domain, payments);
|
|
108
|
-
let events = instances_for(read, &crate::
|
|
108
|
+
let events = instances_for(read, &crate::commerce_ir::registrations_binding(domain).event_prefix());
|
|
109
109
|
let figures: serde_json::Map<String, Value> =
|
|
110
110
|
events.iter().map(|(slug, event)| (slug.clone(), seat_figures(event, counts.get(slug).copied().unwrap_or(0)))).collect();
|
|
111
111
|
json!({"events": figures})
|
|
@@ -113,7 +113,7 @@ fn all_seat_figures(read: &Value, domain: &str, payments: &PaymentsProvider) ->
|
|
|
113
113
|
|
|
114
114
|
/// The seat figures of one event, with its `slug`; `None` when there is no such event.
|
|
115
115
|
fn one_seat_figures(read: &Value, domain: &str, payments: &PaymentsProvider, event_slug: &str) -> Option<Value> {
|
|
116
|
-
let events = instances_for(read, &crate::
|
|
116
|
+
let events = instances_for(read, &crate::commerce_ir::registrations_binding(domain).event_prefix());
|
|
117
117
|
let (_, event) = events.iter().find(|(id, _)| id == event_slug)?;
|
|
118
118
|
let mut figures = seat_figures(event, seats_taken(read, domain, payments, event_slug));
|
|
119
119
|
figures["slug"] = json!(event_slug);
|
|
@@ -224,7 +224,7 @@ async fn events_route(raw_body: &str, client: &Mutex<Client>, wasm_path: &Path,
|
|
|
224
224
|
Ok(r) => r,
|
|
225
225
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
226
226
|
};
|
|
227
|
-
let events = instances_for(&read, &crate::
|
|
227
|
+
let events = instances_for(&read, &crate::commerce_ir::registrations_binding(&config.domain).event_prefix());
|
|
228
228
|
if let Some((_, existing)) = events.iter().find(|(id, _)| id == slug) {
|
|
229
229
|
return respond(200, "application/json", &serde_json::to_string_pretty(&with_id(slug, existing)).unwrap_or_default());
|
|
230
230
|
}
|
|
@@ -245,7 +245,7 @@ async fn events_route(raw_body: &str, client: &Mutex<Client>, wasm_path: &Path,
|
|
|
245
245
|
"price": {"cents": price_cents},
|
|
246
246
|
"capacity": {"value": capacity},
|
|
247
247
|
});
|
|
248
|
-
let verb = crate::
|
|
248
|
+
let verb = crate::commerce_ir::registrations_binding(&config.domain).schedule;
|
|
249
249
|
let outcome = match dispatch::handle(client, wasm_path, &verb, args, None, config, invoker).await {
|
|
250
250
|
Ok(o) => o,
|
|
251
251
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
@@ -258,7 +258,7 @@ async fn events_route(raw_body: &str, client: &Mutex<Client>, wasm_path: &Path,
|
|
|
258
258
|
Ok(r) => r,
|
|
259
259
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
260
260
|
};
|
|
261
|
-
let events = instances_for(&read, &crate::
|
|
261
|
+
let events = instances_for(&read, &crate::commerce_ir::registrations_binding(&config.domain).event_prefix());
|
|
262
262
|
let Some((_, event)) = events.iter().find(|(id, _)| id == slug) else {
|
|
263
263
|
return respond(500, "text/plain", "event vanished immediately after being scheduled");
|
|
264
264
|
};
|
|
@@ -272,12 +272,12 @@ async fn registration_show_route(registration_id: &str, client: &Mutex<Client>,
|
|
|
272
272
|
Ok(r) => r,
|
|
273
273
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
274
274
|
};
|
|
275
|
-
let registrations = instances_for(&read, &crate::
|
|
275
|
+
let registrations = instances_for(&read, &crate::commerce_ir::registrations_binding(&config.domain).registration_prefix());
|
|
276
276
|
let Some((_, registration)) = registrations.iter().find(|(id, _)| id == registration_id) else {
|
|
277
277
|
return respond(404, "application/json", &json!({"error": "no such registration"}).to_string());
|
|
278
278
|
};
|
|
279
279
|
let event_slug = registration.get("event_slug").and_then(|v| v.as_str());
|
|
280
|
-
let events = instances_for(&read, &crate::
|
|
280
|
+
let events = instances_for(&read, &crate::commerce_ir::registrations_binding(&config.domain).event_prefix());
|
|
281
281
|
let event = event_slug.and_then(|slug| events.iter().find(|(id, _)| id == slug)).map(|(_, e)| e);
|
|
282
282
|
|
|
283
283
|
let payment_instances = instances_for(&read, &payments.instance_prefix());
|
|
@@ -327,7 +327,7 @@ pub(crate) async fn registration_complete_route(
|
|
|
327
327
|
Ok(r) => r,
|
|
328
328
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
329
329
|
};
|
|
330
|
-
let registrations = instances_for(&read, &crate::
|
|
330
|
+
let registrations = instances_for(&read, &crate::commerce_ir::registrations_binding(&config.domain).registration_prefix());
|
|
331
331
|
if !registrations.iter().any(|(id, _)| id == registration_id) {
|
|
332
332
|
return respond(404, "application/json", &json!({"error": "no such registration"}).to_string());
|
|
333
333
|
}
|
|
@@ -441,7 +441,7 @@ pub(crate) async fn registrations_route(
|
|
|
441
441
|
Ok(r) => r,
|
|
442
442
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
443
443
|
};
|
|
444
|
-
let events = instances_for(&read, &crate::
|
|
444
|
+
let events = instances_for(&read, &crate::commerce_ir::registrations_binding(&config.domain).event_prefix());
|
|
445
445
|
let Some((_, event)) = events.iter().find(|(id, _)| id == event_slug) else {
|
|
446
446
|
return respond(404, "application/json", &json!({"error": "no such event"}).to_string());
|
|
447
447
|
};
|
|
@@ -518,9 +518,9 @@ pub(crate) async fn registrations_route(
|
|
|
518
518
|
// inside `attendee`, so newsletter fields are declared flat on
|
|
519
519
|
// Registration.Request; a command refuses args it doesn't declare.
|
|
520
520
|
let news_signup = body.get("news_signup").and_then(|v| v.as_bool()).unwrap_or(false);
|
|
521
|
-
let binding = crate::
|
|
521
|
+
let binding = crate::commerce_ir::registrations_binding(&config.domain);
|
|
522
522
|
let forwards_newsletter = crate::ir::ir().is_some_and(|ir| {
|
|
523
|
-
binding.request_target().is_some_and(|(aggregate, command)| crate::
|
|
523
|
+
binding.request_target().is_some_and(|(aggregate, command)| crate::commerce_ir::command_declares(ir, aggregate, command, "news_signup"))
|
|
524
524
|
});
|
|
525
525
|
if forwards_newsletter {
|
|
526
526
|
request_args["news_signup"] = json!(news_signup);
|
|
@@ -531,7 +531,7 @@ pub(crate) async fn registrations_route(
|
|
|
531
531
|
}
|
|
532
532
|
}
|
|
533
533
|
}
|
|
534
|
-
let request_verb = crate::
|
|
534
|
+
let request_verb = crate::commerce_ir::registrations_binding(&config.domain).request;
|
|
535
535
|
let outcome = match dispatch::handle(client, wasm_path, &request_verb, request_args, None, config, invoker).await {
|
|
536
536
|
Ok(o) => o,
|
|
537
537
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
@@ -749,7 +749,7 @@ mod tests {
|
|
|
749
749
|
|
|
750
750
|
#[test]
|
|
751
751
|
fn a_registration_holds_a_seat_while_its_payment_is_open_paid_or_being_settled() {
|
|
752
|
-
let payments = crate::
|
|
752
|
+
let payments = crate::commerce_ir::fixture_payments();
|
|
753
753
|
let read = read_with(
|
|
754
754
|
10,
|
|
755
755
|
&[("a", "yoga", "pending"), ("b", "yoga", "succeeded"), ("c", "yoga", "refunding"), ("d", "yoga", "disputed")],
|
|
@@ -760,7 +760,7 @@ mod tests {
|
|
|
760
760
|
|
|
761
761
|
#[test]
|
|
762
762
|
fn a_failed_refunded_or_charged_back_payment_gives_its_seat_back() {
|
|
763
|
-
let payments = crate::
|
|
763
|
+
let payments = crate::commerce_ir::fixture_payments();
|
|
764
764
|
let read = read_with(
|
|
765
765
|
3,
|
|
766
766
|
&[("a", "yoga", "failed"), ("b", "yoga", "refunded"), ("c", "yoga", "charged_back"), ("d", "yoga", "succeeded")],
|
|
@@ -771,7 +771,7 @@ mod tests {
|
|
|
771
771
|
|
|
772
772
|
#[test]
|
|
773
773
|
fn seats_are_counted_per_event_and_a_registration_without_a_payment_holds_none() {
|
|
774
|
-
let payments = crate::
|
|
774
|
+
let payments = crate::commerce_ir::fixture_payments();
|
|
775
775
|
let mut read = read_with(4, &[("a", "yoga", "succeeded"), ("b", "other", "succeeded")]);
|
|
776
776
|
read["instances"]["CheckoutFixture::Registration#orphan"] = json!({"event_slug": "yoga"});
|
|
777
777
|
assert_eq!(seats_taken(&read, "CheckoutFixture", &payments, "yoga"), 1, "only this event's registrations, and only those with a payment");
|
|
@@ -780,7 +780,7 @@ mod tests {
|
|
|
780
780
|
|
|
781
781
|
#[test]
|
|
782
782
|
fn an_archived_registration_gives_its_seat_back_whatever_its_payment_says() {
|
|
783
|
-
let payments = crate::
|
|
783
|
+
let payments = crate::commerce_ir::fixture_payments();
|
|
784
784
|
let mut read = read_with(3, &[("a", "yoga", "succeeded"), ("b", "yoga", "pending"), ("c", "yoga", "succeeded")]);
|
|
785
785
|
assert_eq!(seats_taken(&read, "CheckoutFixture", &payments, "yoga"), 3);
|
|
786
786
|
read["instances"]["CheckoutFixture::Registration#a"]["status"] = json!("archived");
|
|
@@ -790,7 +790,7 @@ mod tests {
|
|
|
790
790
|
|
|
791
791
|
#[test]
|
|
792
792
|
fn a_registration_with_no_status_counts_as_active() {
|
|
793
|
-
let payments = crate::
|
|
793
|
+
let payments = crate::commerce_ir::fixture_payments();
|
|
794
794
|
let mut read = read_with(5, &[("a", "yoga", "succeeded"), ("b", "yoga", "succeeded")]);
|
|
795
795
|
// `a` carries no status at all (a domain without the lifecycle, or data
|
|
796
796
|
// from before it existed); `b` says it is active.
|
|
@@ -802,7 +802,7 @@ mod tests {
|
|
|
802
802
|
|
|
803
803
|
#[test]
|
|
804
804
|
fn a_restored_registration_takes_its_seat_back() {
|
|
805
|
-
let payments = crate::
|
|
805
|
+
let payments = crate::commerce_ir::fixture_payments();
|
|
806
806
|
let mut read = read_with(2, &[("a", "yoga", "succeeded")]);
|
|
807
807
|
read["instances"]["CheckoutFixture::Registration#a"]["status"] = json!("archived");
|
|
808
808
|
assert_eq!(seats_left(&read, "CheckoutFixture", &payments, "yoga"), Some(2));
|
|
@@ -812,7 +812,7 @@ mod tests {
|
|
|
812
812
|
|
|
813
813
|
#[test]
|
|
814
814
|
fn seats_left_with_mixed_statuses_counts_only_the_active_holders() {
|
|
815
|
-
let payments = crate::
|
|
815
|
+
let payments = crate::commerce_ir::fixture_payments();
|
|
816
816
|
let mut read = read_with(
|
|
817
817
|
6,
|
|
818
818
|
&[("a", "yoga", "succeeded"), ("b", "yoga", "succeeded"), ("c", "yoga", "pending"), ("d", "yoga", "failed"), ("e", "other", "succeeded")],
|
|
@@ -830,7 +830,7 @@ mod tests {
|
|
|
830
830
|
|
|
831
831
|
#[test]
|
|
832
832
|
fn seats_left_never_goes_below_zero_and_is_none_without_an_event_or_capacity() {
|
|
833
|
-
let payments = crate::
|
|
833
|
+
let payments = crate::commerce_ir::fixture_payments();
|
|
834
834
|
let oversold = read_with(1, &[("a", "yoga", "succeeded"), ("b", "yoga", "succeeded")]);
|
|
835
835
|
assert_eq!(seats_left(&oversold, "CheckoutFixture", &payments, "yoga"), Some(0));
|
|
836
836
|
assert_eq!(seats_left(&oversold, "CheckoutFixture", &payments, "nowhere"), None);
|
|
@@ -858,7 +858,7 @@ mod tests {
|
|
|
858
858
|
|
|
859
859
|
#[test]
|
|
860
860
|
fn every_holding_status_holds_one_seat_and_every_freeing_status_holds_none() {
|
|
861
|
-
let payments = crate::
|
|
861
|
+
let payments = crate::commerce_ir::fixture_payments();
|
|
862
862
|
for status in HOLDING {
|
|
863
863
|
let read = read_with(10, &[("r", "yoga", status)]);
|
|
864
864
|
assert_eq!(seats_taken(&read, "CheckoutFixture", &payments, "yoga"), 1, "{status} should hold a seat");
|
|
@@ -871,7 +871,7 @@ mod tests {
|
|
|
871
871
|
|
|
872
872
|
#[test]
|
|
873
873
|
fn a_reference_reads_as_a_plain_id_or_a_wrapped_value_and_counts_per_event() {
|
|
874
|
-
let payments = crate::
|
|
874
|
+
let payments = crate::commerce_ir::fixture_payments();
|
|
875
875
|
let mut read = read_with(
|
|
876
876
|
10,
|
|
877
877
|
&[("a", "yoga", "succeeded"), ("b", "yoga", "pending"), ("c", "other", "pending"), ("d", "yoga", "failed")],
|
|
@@ -885,7 +885,7 @@ mod tests {
|
|
|
885
885
|
|
|
886
886
|
#[test]
|
|
887
887
|
fn a_payment_with_no_registration_is_ignored_and_a_missing_or_empty_read_counts_nothing() {
|
|
888
|
-
let payments = crate::
|
|
888
|
+
let payments = crate::commerce_ir::fixture_payments();
|
|
889
889
|
let mut read = read_with(5, &[]);
|
|
890
890
|
read["instances"]["CheckoutFixture::Registration#lonely"] = json!({"event_slug": "yoga"});
|
|
891
891
|
read["instances"]["Payments::Payment#orphan"] = json!({"status": "succeeded"});
|
|
@@ -898,7 +898,7 @@ mod tests {
|
|
|
898
898
|
|
|
899
899
|
#[test]
|
|
900
900
|
fn an_archived_registration_frees_its_seat_whichever_holding_status_its_payment_has() {
|
|
901
|
-
let payments = crate::
|
|
901
|
+
let payments = crate::commerce_ir::fixture_payments();
|
|
902
902
|
for status in HOLDING {
|
|
903
903
|
let mut read = read_with(10, &[("r", "yoga", status)]);
|
|
904
904
|
set_registration_status(&mut read, "r", "archived");
|
|
@@ -908,7 +908,7 @@ mod tests {
|
|
|
908
908
|
|
|
909
909
|
#[test]
|
|
910
910
|
fn archiving_one_of_several_guests_frees_exactly_one_seat() {
|
|
911
|
-
let payments = crate::
|
|
911
|
+
let payments = crate::commerce_ir::fixture_payments();
|
|
912
912
|
let mut read = read_with(10, &[("a", "yoga", "succeeded"), ("b", "yoga", "succeeded"), ("c", "yoga", "pending")]);
|
|
913
913
|
set_registration_status(&mut read, "a", "active");
|
|
914
914
|
set_registration_status(&mut read, "b", "archived");
|
|
@@ -918,7 +918,7 @@ mod tests {
|
|
|
918
918
|
|
|
919
919
|
#[test]
|
|
920
920
|
fn seat_figures_carry_capacity_taken_and_left_and_null_without_a_capacity() {
|
|
921
|
-
let payments = crate::
|
|
921
|
+
let payments = crate::commerce_ir::fixture_payments();
|
|
922
922
|
let read = read_with(3, &[("a", "yoga", "succeeded"), ("b", "yoga", "pending"), ("c", "yoga", "succeeded"), ("d", "yoga", "succeeded")]);
|
|
923
923
|
assert_eq!(one_seat_figures(&read, "CheckoutFixture", &payments, "yoga"), Some(json!({"slug": "yoga", "capacity": 3, "seats_taken": 4, "seats_left": 0})));
|
|
924
924
|
assert_eq!(one_seat_figures(&read, "CheckoutFixture", &payments, "nowhere"), None);
|
|
@@ -938,7 +938,7 @@ mod tests {
|
|
|
938
938
|
|
|
939
939
|
#[test]
|
|
940
940
|
fn the_seat_figures_agree_with_seats_left_for_every_event() {
|
|
941
|
-
let payments = crate::
|
|
941
|
+
let payments = crate::commerce_ir::fixture_payments();
|
|
942
942
|
let mut read = read_with(6, &[("a", "yoga", "succeeded"), ("b", "yoga", "refunding"), ("c", "other", "pending"), ("d", "yoga", "failed")]);
|
|
943
943
|
set_registration_status(&mut read, "b", "archived");
|
|
944
944
|
let all = all_seat_figures(&read, "CheckoutFixture", &payments);
|
|
@@ -963,7 +963,7 @@ mod tests {
|
|
|
963
963
|
let config = checkout_config(1);
|
|
964
964
|
let wasm_path = checkout_wasm_path();
|
|
965
965
|
schedule_event(&client, &wasm_path, &config, "yoga", 4200).await;
|
|
966
|
-
let ir = crate::
|
|
966
|
+
let ir = crate::commerce_ir::fixture_ir();
|
|
967
967
|
let get = |path: &'static str| {
|
|
968
968
|
let (client, wasm_path, config, ir) = (&client, &wasm_path, &config, &ir);
|
|
969
969
|
async move {
|
|
@@ -1045,7 +1045,7 @@ mod tests {
|
|
|
1045
1045
|
let client = scratch_db("hecks_host_web_test_registrations_missing_fields").await;
|
|
1046
1046
|
provision_lineage(&*client.lock().await, "CheckoutFixture", 1, &["Event", "Registration", "Payment"]).await;
|
|
1047
1047
|
|
|
1048
|
-
let response = registrations_route(r#"{"event_slug":"yoga-aug"}"#, &payments::test_platform(), &client, &checkout_wasm_path(), &checkout_config(1), &lambda_client::NeverInvoker, &crate::
|
|
1048
|
+
let response = registrations_route(r#"{"event_slug":"yoga-aug"}"#, &payments::test_platform(), &client, &checkout_wasm_path(), &checkout_config(1), &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1049
1049
|
assert_eq!(response["statusCode"], 400);
|
|
1050
1050
|
assert!(response["body"].as_str().unwrap().contains("missing name"));
|
|
1051
1051
|
}
|
|
@@ -1069,7 +1069,7 @@ mod tests {
|
|
|
1069
1069
|
"email": "ada@example.com",
|
|
1070
1070
|
})
|
|
1071
1071
|
.to_string();
|
|
1072
|
-
let response = registrations_route(&body, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::
|
|
1072
|
+
let response = registrations_route(&body, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1073
1073
|
|
|
1074
1074
|
// Registration.Request refuses (no first_name/last_name in this
|
|
1075
1075
|
// Attendee) but only after Payment.Initiate already ran, proving
|
|
@@ -1117,7 +1117,7 @@ mod tests {
|
|
|
1117
1117
|
}
|
|
1118
1118
|
}
|
|
1119
1119
|
|
|
1120
|
-
let fixture_ir = crate::
|
|
1120
|
+
let fixture_ir = crate::commerce_ir::fixture_ir();
|
|
1121
1121
|
let response = payments_routes(Some(&fixture_ir), "POST", "/registrations", "not json", "", &client, &wasm_path, &config, &lambda_client::NeverInvoker).await;
|
|
1122
1122
|
assert_eq!(response.expect("the fixture IR declares payments, so the route answers")["statusCode"], 400);
|
|
1123
1123
|
}
|
|
@@ -1127,7 +1127,7 @@ mod tests {
|
|
|
1127
1127
|
let client = scratch_db("hecks_host_web_test_registrations_bad_json").await;
|
|
1128
1128
|
provision_lineage(&*client.lock().await, "CheckoutFixture", 1, &["Event", "Registration", "Payment"]).await;
|
|
1129
1129
|
|
|
1130
|
-
let response = registrations_route("not json", &payments::test_platform(), &client, &checkout_wasm_path(), &checkout_config(1), &lambda_client::NeverInvoker, &crate::
|
|
1130
|
+
let response = registrations_route("not json", &payments::test_platform(), &client, &checkout_wasm_path(), &checkout_config(1), &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1131
1131
|
assert_eq!(response["statusCode"], 400);
|
|
1132
1132
|
}
|
|
1133
1133
|
|
|
@@ -1212,7 +1212,7 @@ mod tests {
|
|
|
1212
1212
|
provision_lineage(&*client.lock().await, "CheckoutFixture", 1, &["Event", "Registration", "Payment"]).await;
|
|
1213
1213
|
|
|
1214
1214
|
let body = json!({"event_slug": "nope", "name": "Ada", "email": "ada@example.com"}).to_string();
|
|
1215
|
-
let response = registrations_route(&body, &payments::test_platform(), &client, &checkout_wasm_path(), &checkout_config(1), &lambda_client::NeverInvoker, &crate::
|
|
1215
|
+
let response = registrations_route(&body, &payments::test_platform(), &client, &checkout_wasm_path(), &checkout_config(1), &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1216
1216
|
assert_eq!(response["statusCode"], 404);
|
|
1217
1217
|
}
|
|
1218
1218
|
|
|
@@ -1230,7 +1230,7 @@ mod tests {
|
|
|
1230
1230
|
assert!(close.accepted, "closing the fixture event should succeed: {:?}", close.result);
|
|
1231
1231
|
|
|
1232
1232
|
let body = json!({"event_slug": "closed-event", "name": "Ada", "email": "ada@example.com"}).to_string();
|
|
1233
|
-
let response = registrations_route(&body, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::
|
|
1233
|
+
let response = registrations_route(&body, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1234
1234
|
assert_eq!(response["statusCode"], 422);
|
|
1235
1235
|
assert!(response["body"].as_str().unwrap().contains("closed"));
|
|
1236
1236
|
}
|
|
@@ -1248,7 +1248,7 @@ mod tests {
|
|
|
1248
1248
|
schedule_event(&client, &wasm_path, &config, "free-event", 0).await;
|
|
1249
1249
|
|
|
1250
1250
|
let body = json!({"event_slug": "free-event", "name": "Ada", "email": "ada@example.com"}).to_string();
|
|
1251
|
-
let response = registrations_route(&body, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::
|
|
1251
|
+
let response = registrations_route(&body, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1252
1252
|
assert_eq!(response["statusCode"], 422);
|
|
1253
1253
|
assert!(
|
|
1254
1254
|
response["body"].as_str().unwrap().contains("positive"),
|
|
@@ -1275,7 +1275,7 @@ mod tests {
|
|
|
1275
1275
|
// a misconfiguration — the whole chain runs and returns a real
|
|
1276
1276
|
// checkout URL, never a 500.
|
|
1277
1277
|
let body = json!({"event_slug": "happy-event", "name": "Ada Lovelace", "email": "ada@example.com"}).to_string();
|
|
1278
|
-
let response = registrations_route(&body, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::
|
|
1278
|
+
let response = registrations_route(&body, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1279
1279
|
assert_eq!(response["statusCode"], 200, "{response:?}");
|
|
1280
1280
|
let body: Value = serde_json::from_str(response["body"].as_str().unwrap()).unwrap();
|
|
1281
1281
|
let reference = body["registration_id"].as_str().unwrap().to_string();
|
|
@@ -1330,7 +1330,7 @@ mod tests {
|
|
|
1330
1330
|
"return_to": "/sample-studio.html",
|
|
1331
1331
|
})
|
|
1332
1332
|
.to_string();
|
|
1333
|
-
let response = registrations_route(&body, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::
|
|
1333
|
+
let response = registrations_route(&body, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1334
1334
|
assert_eq!(response["statusCode"], 200, "{response:?}");
|
|
1335
1335
|
let body: Value = serde_json::from_str(response["body"].as_str().unwrap()).unwrap();
|
|
1336
1336
|
let reference = body["registration_id"].as_str().unwrap().to_string();
|
|
@@ -1361,7 +1361,7 @@ mod tests {
|
|
|
1361
1361
|
"return_to": unsafe_return_to,
|
|
1362
1362
|
})
|
|
1363
1363
|
.to_string();
|
|
1364
|
-
let response = registrations_route(&body, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::
|
|
1364
|
+
let response = registrations_route(&body, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1365
1365
|
assert_eq!(response["statusCode"], 200, "{response:?}");
|
|
1366
1366
|
let body: Value = serde_json::from_str(response["body"].as_str().unwrap()).unwrap();
|
|
1367
1367
|
// checkout_url is the /pay/<id>.html walkthrough page; return_to
|
|
@@ -1390,7 +1390,7 @@ mod tests {
|
|
|
1390
1390
|
schedule_event(&client, &wasm_path, &config, "mock-loop-event", 4200).await;
|
|
1391
1391
|
|
|
1392
1392
|
let body = json!({"event_slug": "mock-loop-event", "name": "Ada Lovelace", "email": "ada@example.com"}).to_string();
|
|
1393
|
-
let response = registrations_route(&body, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::
|
|
1393
|
+
let response = registrations_route(&body, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1394
1394
|
assert_eq!(response["statusCode"], 200, "{response:?}");
|
|
1395
1395
|
let response_body: Value = serde_json::from_str(response["body"].as_str().unwrap()).unwrap();
|
|
1396
1396
|
let reference = response_body["registration_id"].as_str().unwrap().to_string();
|
|
@@ -1403,7 +1403,7 @@ mod tests {
|
|
|
1403
1403
|
let now = now_secs();
|
|
1404
1404
|
let header = sign_stripe_header(secret, now, &payload);
|
|
1405
1405
|
|
|
1406
|
-
let response = webhook_route(&payload, &header, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::
|
|
1406
|
+
let response = webhook_route(&payload, &header, &payments::test_platform(), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1407
1407
|
assert_eq!(response["statusCode"], 200, "{response:?}");
|
|
1408
1408
|
|
|
1409
1409
|
let read = dispatch::read(&client, &wasm_path).await.unwrap();
|
|
@@ -1420,7 +1420,7 @@ mod tests {
|
|
|
1420
1420
|
let payload = json!({"type": "checkout.session.completed", "data": {"object": {}}}).to_string();
|
|
1421
1421
|
let bad_header = "t=1700000000,v1=deadbeef";
|
|
1422
1422
|
|
|
1423
|
-
let response = webhook_route(&payload, bad_header, &payments::test_platform_with_secret("whsec_test_bad_sig"), &client, &checkout_wasm_path(), &checkout_config(1), &lambda_client::NeverInvoker, &crate::
|
|
1423
|
+
let response = webhook_route(&payload, bad_header, &payments::test_platform_with_secret("whsec_test_bad_sig"), &client, &checkout_wasm_path(), &checkout_config(1), &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1424
1424
|
assert_eq!(response["statusCode"], 400);
|
|
1425
1425
|
}
|
|
1426
1426
|
|
|
@@ -1451,7 +1451,7 @@ mod tests {
|
|
|
1451
1451
|
let now = now_secs();
|
|
1452
1452
|
let header = sign_stripe_header(secret, now, &payload);
|
|
1453
1453
|
|
|
1454
|
-
let response = webhook_route(&payload, &header, &payments::test_platform_with_secret(secret), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::
|
|
1454
|
+
let response = webhook_route(&payload, &header, &payments::test_platform_with_secret(secret), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1455
1455
|
assert_eq!(response["statusCode"], 200, "{response:?}");
|
|
1456
1456
|
|
|
1457
1457
|
let read = dispatch::read(&client, &wasm_path).await.unwrap();
|
|
@@ -1462,7 +1462,7 @@ mod tests {
|
|
|
1462
1462
|
// A redelivered webhook (Stripe's delivery is at-least-once) for an
|
|
1463
1463
|
// already-succeeded payment must still answer 200 — the refusal
|
|
1464
1464
|
// underneath is a benign no-op, not surfaced as an error.
|
|
1465
|
-
let redelivered = webhook_route(&payload, &header, &payments::test_platform_with_secret(secret), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::
|
|
1465
|
+
let redelivered = webhook_route(&payload, &header, &payments::test_platform_with_secret(secret), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1466
1466
|
assert_eq!(redelivered["statusCode"], 200, "a redelivered webhook must not surface the resulting refusal as an error: {redelivered:?}");
|
|
1467
1467
|
}
|
|
1468
1468
|
|
|
@@ -1492,7 +1492,7 @@ mod tests {
|
|
|
1492
1492
|
let now = now_secs();
|
|
1493
1493
|
let header = sign_stripe_header(secret, now, &payload);
|
|
1494
1494
|
|
|
1495
|
-
let response = webhook_route(&payload, &header, &payments::test_platform_with_secret(secret), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::
|
|
1495
|
+
let response = webhook_route(&payload, &header, &payments::test_platform_with_secret(secret), &client, &wasm_path, &config, &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1496
1496
|
assert_eq!(response["statusCode"], 200, "{response:?}");
|
|
1497
1497
|
|
|
1498
1498
|
let read = dispatch::read(&client, &wasm_path).await.unwrap();
|
|
@@ -1511,7 +1511,7 @@ mod tests {
|
|
|
1511
1511
|
let now = now_secs();
|
|
1512
1512
|
let header = sign_stripe_header(secret, now, &payload);
|
|
1513
1513
|
|
|
1514
|
-
let response = webhook_route(&payload, &header, &payments::test_platform_with_secret(secret), &client, &checkout_wasm_path(), &checkout_config(1), &lambda_client::NeverInvoker, &crate::
|
|
1514
|
+
let response = webhook_route(&payload, &header, &payments::test_platform_with_secret(secret), &client, &checkout_wasm_path(), &checkout_config(1), &lambda_client::NeverInvoker, &crate::commerce_ir::fixture_payments()).await;
|
|
1515
1515
|
assert_eq!(response["statusCode"], 200);
|
|
1516
1516
|
}
|
|
1517
1517
|
}
|