codoseo_web/
crawl_policy.rs1use codoseo_core::plan::{ManualAllowance, Plan};
5use time::Duration;
6
7pub const PAID_MANUAL_PRIORITY: i16 = 2;
9pub const FREE_MANUAL_PRIORITY: i16 = 4;
11
12pub fn manual_priority(plan: Plan) -> i16 {
14 match plan {
15 Plan::Free => FREE_MANUAL_PRIORITY,
16 Plan::Pro | Plan::Agency | Plan::SelfHosted => PAID_MANUAL_PRIORITY,
17 }
18}
19
20pub fn plan_name(plan: Plan) -> &'static str {
21 match plan {
22 Plan::Free => "Free",
23 Plan::Pro => "Pro",
24 Plan::Agency => "Agency",
25 Plan::SelfHosted => "self-hosted",
26 }
27}
28
29pub fn allowance_phrase(allowance: ManualAllowance) -> Option<String> {
31 let (n, per) = match allowance {
32 ManualAllowance::PerWeek(n) => (n, "week"),
33 ManualAllowance::PerDay(n) => (n, "day"),
34 ManualAllowance::Unlimited => return None,
35 };
36 let s = if n == 1 { "" } else { "s" };
37 Some(format!("{n} manual crawl{s} a {per}"))
38}
39
40pub fn limit_message(plan: Plan, allowance: ManualAllowance, wait: Duration) -> String {
43 let phrase = allowance_phrase(allowance).unwrap_or_else(|| "manual crawls".to_owned());
44 format!(
45 "Your {} plan includes {phrase}. The next one is available {}.",
46 plan_name(plan),
47 until(wait)
48 )
49}
50
51pub fn until(wait: Duration) -> String {
54 let minutes = (wait.whole_seconds().max(0) + 59) / 60;
55 if minutes <= 1 {
56 return "in a minute".to_owned();
57 }
58 if minutes < 60 {
59 return format!("in {minutes} minutes");
60 }
61 let hours = (minutes + 59) / 60;
62 if hours < 24 {
63 let s = if hours == 1 { "" } else { "s" };
64 return format!("in {hours} hour{s}");
65 }
66 let days = (hours + 12) / 24;
67 let s = if days == 1 { "" } else { "s" };
68 format!("in {days} day{s}")
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn manual_lanes() {
77 assert_eq!(manual_priority(Plan::Free), 4);
78 assert_eq!(manual_priority(Plan::Pro), 2);
79 assert_eq!(manual_priority(Plan::Agency), 2);
80 assert_eq!(manual_priority(Plan::SelfHosted), 2);
81 }
82
83 #[test]
84 fn waits() {
85 assert_eq!(until(Duration::seconds(-5)), "in a minute");
86 assert_eq!(until(Duration::seconds(50)), "in a minute");
87 assert_eq!(until(Duration::minutes(12)), "in 12 minutes");
88 assert_eq!(
89 until(Duration::minutes(59) + Duration::seconds(59)),
90 "in 1 hour"
91 );
92 assert_eq!(
93 until(Duration::hours(4) + Duration::minutes(10)),
94 "in 5 hours"
95 );
96 assert_eq!(until(Duration::hours(25)), "in 1 day");
97 assert_eq!(until(Duration::days(3) - Duration::seconds(1)), "in 3 days");
98 assert_eq!(until(Duration::days(6) + Duration::hours(23)), "in 7 days");
99 }
100
101 #[test]
102 fn limit_messages() {
103 assert_eq!(
104 limit_message(
105 Plan::Free,
106 ManualAllowance::PerWeek(1),
107 Duration::days(3) - Duration::seconds(1)
108 ),
109 "Your Free plan includes 1 manual crawl a week. The next one is available in 3 days."
110 );
111 assert_eq!(
112 limit_message(Plan::Pro, ManualAllowance::PerDay(2), Duration::minutes(30)),
113 "Your Pro plan includes 2 manual crawls a day. The next one is available in 30 minutes."
114 );
115 }
116}