forge_server/surface/
connectors.rs1use std::collections::BTreeMap;
4
5use forge_primitives::GotifySubscription;
6use forge_primitives::slack::SlackSubscription;
7
8use super::ViewSurface;
9
10pub struct ConnectorsView {
12 pub gotify: GotifyView,
13 pub slack: SlackView,
14}
15
16pub struct GotifyView {
18 pub connected: bool,
19 pub subscriptions: Vec<GotifySubscription>,
20}
21
22pub struct SlackView {
24 pub connected_workspaces: BTreeMap<String, bool>,
26 pub load_failed: bool,
28 pub subscriptions: Vec<SlackSubscription>,
29}
30
31impl ViewSurface {
32 pub fn connectors(&self, project: Option<&str>) -> ConnectorsView {
36 let workspace = &self.workspace;
37 ConnectorsView {
38 gotify: GotifyView {
39 connected: workspace.gotify_connected(),
40 subscriptions: project
41 .map(|name| workspace.gotify_subscriptions_for_project(name))
42 .unwrap_or_default(),
43 },
44 slack: SlackView {
45 connected_workspaces: workspace.slack_connected_workspaces(),
46 load_failed: workspace.slack_subscription_load_failed(),
47 subscriptions: project
48 .map(|name| workspace.slack_subscriptions_for_project(name))
49 .unwrap_or_default(),
50 },
51 }
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use std::sync::Arc;
58
59 use super::*;
60
61 #[test]
69 fn connectors_agrees_with_the_calls_it_replaces() {
70 let (workspace, _dir) = crate::surface::testing::workspace_with_connector_subs();
71 workspace.seed_test_gotify_connected(true);
72
73 let view = ViewSurface::new(Arc::clone(&workspace)).connectors(Some("forge"));
74
75 assert_ne!(
76 workspace.gotify_connected(),
77 workspace.slack_subscription_load_failed(),
78 "the fixture gives the two connectors' flags different values, or the comparisons below agree on a false",
79 );
80 assert_ne!(
81 view.gotify.connected, view.slack.load_failed,
82 "gotify's liveness and slack's load failure are read from different flags, not one value under both headings",
83 );
84 assert_eq!(
85 view.gotify.connected,
86 workspace.gotify_connected(),
87 "gotify's liveness is the same flag",
88 );
89 assert_eq!(
90 view.gotify.subscriptions,
91 workspace.gotify_subscriptions_for_project("forge"),
92 "gotify's rows are the project's own",
93 );
94 assert_eq!(
95 view.slack.connected_workspaces,
96 workspace.slack_connected_workspaces(),
97 "slack's per-workspace liveness is the same map",
98 );
99 assert_eq!(
100 view.slack.load_failed,
101 workspace.slack_subscription_load_failed(),
102 "slack's load failure is the same flag",
103 );
104 assert_eq!(
105 view.slack.subscriptions,
106 workspace.slack_subscriptions_for_project("forge"),
107 "slack's rows are the project's own",
108 );
109 assert_eq!(
110 (view.gotify.subscriptions.len(), view.slack.subscriptions.len()),
111 (1, 1),
112 "the seeded subscriptions are what the read returns, so the rows above are not empty on both sides",
113 );
114
115 let other = ViewSurface::new(Arc::clone(&workspace)).connectors(Some("elsewhere"));
116 assert!(
117 other.gotify.subscriptions.is_empty() && other.slack.subscriptions.is_empty(),
118 "another project's scope returns none of forge's rows",
119 );
120 let unscoped = ViewSurface::new(Arc::clone(&workspace)).connectors(None);
121 assert!(
122 unscoped.gotify.subscriptions.is_empty() && unscoped.slack.subscriptions.is_empty(),
123 "an unstamped session is scoped to no project rather than every project",
124 );
125 }
126}