Diff -- /var/www/vhosts/3dshawn.com/affiliate.3dshawn.com/admin_email_controls.cgi
Diff

/var/www/vhosts/3dshawn.com/affiliate.3dshawn.com/admin_email_controls.cgi

added on local at 2026-07-01 13:46:58

Added
+165
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to d18037b01015
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
1#!/usr/bin/perl
2#======================================================================
3# AffSoft -- /admin_email_controls.cgi
4#
5# Controls tab of the Email Setup screen. Tunes the rate / age / bounce /
6# abuse thresholds. Super-admin only.
7#
8# GET show current values
9# POST act=save_controls update platform_settings
10#======================================================================
11use strict;
12use warnings;
13
14use lib '/var/www/vhosts/3dshawn.com/affiliate.3dshawn.com';
15use CGI;
16use MODS::DBConnect;
17use MODS::AffSoft::Wrapper;
18use MODS::AffSoft::Config;
19use MODS::Login;
20
21my $q = CGI->new;
22my $form = $q->Vars;
23my $wrap = MODS::AffSoft::Wrapper->new;
24my $db = MODS::DBConnect->new;
25my $cfg = MODS::AffSoft::Config->new;
26my $DB = $cfg->settings('database_name');
27
28my $auth = MODS::Login->new;
29my $u = $auth->login_verify;
30unless ($u) { print "Status: 302 Found\nLocation: /login.cgi\n\n"; exit; }
31require MODS::AffSoft::Permissions;
32MODS::AffSoft::Permissions->new->require_super_admin($u);
33my $uid = $u->{user_id} + 0;
34
35my $dbh = $db->db_connect;
36my $act = $form->{act} || '';
37my $flash = '';
38
39if (($ENV{REQUEST_METHOD} || '') eq 'POST' && $act eq 'save_controls') {
40 my %controls = (
41 email_rate_hourly_cap => { min=>1, max=>10000, default=>20 },
42 email_rate_daily_cap => { min=>1, max=>100000, default=>100 },
43 email_dedupe_window_hours => { min=>0, max=>720, default=>24 },
44 email_account_age_min_hours => { min=>0, max=>720, default=>1 },
45 email_bounce_suspend_pct => { min=>0, max=>100, default=>10 },
46 email_bounce_min_volume => { min=>1, max=>100000, default=>20 },
47 email_abuse_suspend_threshold => { min=>1, max=>100, default=>1 },
48 email_suspend_days => { min=>1, max=>365, default=>7 },
49 );
50 foreach my $k (keys %controls) {
51 my $raw = $form->{$k}; next unless defined $raw;
52 my $n = $raw + 0;
53 my $spec = $controls{$k};
54 $n = $spec->{default} if ($n < $spec->{min} || $n > $spec->{max});
55 my $kq = $k; $kq =~ s/'/''/g;
56 my $vq = $n; $vq =~ s/'/''/g;
57 $db->db_readwrite($dbh, qq~
58 INSERT INTO ${DB}.platform_settings (setting_key, setting_value)
59 VALUES ('$kq', '$vq')
60 ON DUPLICATE KEY UPDATE setting_value='$vq'
61 ~, $0, __LINE__);
62 }
63 $flash = 'Email controls saved.';
64}
65
66my @control_rows = $db->db_readwrite_multiple($dbh, qq~
67 SELECT setting_key, setting_value FROM ${DB}.platform_settings
68 WHERE setting_key IN (
69 'email_rate_hourly_cap','email_rate_daily_cap','email_dedupe_window_hours',
70 'email_account_age_min_hours','email_bounce_suspend_pct','email_bounce_min_volume',
71 'email_abuse_suspend_threshold','email_suspend_days')
72~, $0, __LINE__);
73my %controls;
74foreach my $r (@control_rows) { $controls{$r->{setting_key}} = $r->{setting_value}; }
75my %control_defaults = (
76 email_rate_hourly_cap => 20, email_rate_daily_cap => 100,
77 email_dedupe_window_hours => 24, email_account_age_min_hours => 1,
78 email_bounce_suspend_pct => 10, email_bounce_min_volume => 20,
79 email_abuse_suspend_threshold => 1, email_suspend_days => 7,
80);
81foreach my $k (keys %control_defaults) { $controls{$k} //= $control_defaults{$k}; }
82
83$db->db_disconnect($dbh);
84
85print "Content-Type: text/html; charset=utf-8\r\nCache-Control: no-store\r\n\r\n";
86
87my $flash_html = $flash ? qq~<div style="padding:10px 14px;background:rgba(34,197,94,.12);border:1px solid rgba(34,197,94,.3);border-radius:8px;color:#86efac;font-size:13px;margin-bottom:18px">$flash</div>~ : '';
88
89my $tabs = _email_setup_tabs('controls');
90
91my $body = qq~
92<div class="page-pad">
93 <h1 style="margin:0 0 6px;font-size:28px;color:#fff">Email Setup</h1>
94 <p style="color:#94a3b8;margin:0 0 18px;font-size:14px">Templates, schedules, and spam-protection controls.</p>
95 $tabs
96 $flash_html
97 <h2 style="font-size:18px;color:#fff;margin:0 0 6px">Controls <span style="font-size:11px;color:#94a3b8;font-weight:400;letter-spacing:.05em">&middot; SPAM PROTECTION</span></h2>
98 <p style="color:#94a3b8;margin:0 0 14px;font-size:13px">Tune the per-account caps, account-age gate, bounce auto-suspend, and abuse-report threshold. Defaults are conservative &mdash; raise carefully.</p>
99 <form method="POST" action="/admin_email_controls.cgi" style="border:1px solid rgba(255,255,255,.08);border-radius:12px;background:rgba(20,20,30,.4);padding:18px">
100 <input type="hidden" name="act" value="save_controls">
101 <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px">
102 <label style="font-size:12px;color:#cbd5e1">
103 <div style="text-transform:uppercase;letter-spacing:.05em;color:#94a3b8;font-size:10px;margin-bottom:4px">Hourly burst cap</div>
104 <input class="input" type="number" name="email_rate_hourly_cap" value="$controls{email_rate_hourly_cap}" min="1" max="10000" style="width:100%">
105 <div style="color:#94a3b8;font-size:11px;margin-top:4px">Sends/account/hour. Hard cap.</div>
106 </label>
107 <label style="font-size:12px;color:#cbd5e1">
108 <div style="text-transform:uppercase;letter-spacing:.05em;color:#94a3b8;font-size:10px;margin-bottom:4px">Daily cap</div>
109 <input class="input" type="number" name="email_rate_daily_cap" value="$controls{email_rate_daily_cap}" min="1" max="100000" style="width:100%">
110 <div style="color:#94a3b8;font-size:11px;margin-top:4px">Sends/account/24h. Hard cap.</div>
111 </label>
112 <label style="font-size:12px;color:#cbd5e1">
113 <div style="text-transform:uppercase;letter-spacing:.05em;color:#94a3b8;font-size:10px;margin-bottom:4px">Dedupe window (hours)</div>
114 <input class="input" type="number" name="email_dedupe_window_hours" value="$controls{email_dedupe_window_hours}" min="0" max="720" style="width:100%">
115 <div style="color:#94a3b8;font-size:11px;margin-top:4px">Same recipient + same template within N hours = drop.</div>
116 </label>
117 <label style="font-size:12px;color:#cbd5e1">
118 <div style="text-transform:uppercase;letter-spacing:.05em;color:#94a3b8;font-size:10px;margin-bottom:4px">Account-age gate (hours)</div>
119 <input class="input" type="number" name="email_account_age_min_hours" value="$controls{email_account_age_min_hours}" min="0" max="720" style="width:100%">
120 <div style="color:#94a3b8;font-size:11px;margin-top:4px">Min account age before inviter can send (password reset / verify bypass).</div>
121 </label>
122 <label style="font-size:12px;color:#cbd5e1">
123 <div style="text-transform:uppercase;letter-spacing:.05em;color:#94a3b8;font-size:10px;margin-bottom:4px">Bounce suspend %</div>
124 <input class="input" type="number" name="email_bounce_suspend_pct" value="$controls{email_bounce_suspend_pct}" min="0" max="100" style="width:100%">
125 <div style="color:#94a3b8;font-size:11px;margin-top:4px">Auto-suspend inviter at &gt;= this % bounces.</div>
126 </label>
127 <label style="font-size:12px;color:#cbd5e1">
128 <div style="text-transform:uppercase;letter-spacing:.05em;color:#94a3b8;font-size:10px;margin-bottom:4px">Bounce min volume</div>
129 <input class="input" type="number" name="email_bounce_min_volume" value="$controls{email_bounce_min_volume}" min="1" max="100000" style="width:100%">
130 <div style="color:#94a3b8;font-size:11px;margin-top:4px">% only triggers above this send volume (avoids 1/1 = 100%).</div>
131 </label>
132 <label style="font-size:12px;color:#cbd5e1">
133 <div style="text-transform:uppercase;letter-spacing:.05em;color:#94a3b8;font-size:10px;margin-bottom:4px">Abuse-report threshold</div>
134 <input class="input" type="number" name="email_abuse_suspend_threshold" value="$controls{email_abuse_suspend_threshold}" min="1" max="100" style="width:100%">
135 <div style="color:#94a3b8;font-size:11px;margin-top:4px">N reports in 30d = auto-suspend.</div>
136 </label>
137 <label style="font-size:12px;color:#cbd5e1">
138 <div style="text-transform:uppercase;letter-spacing:.05em;color:#94a3b8;font-size:10px;margin-bottom:4px">Suspend duration (days)</div>
139 <input class="input" type="number" name="email_suspend_days" value="$controls{email_suspend_days}" min="1" max="365" style="width:100%">
140 <div style="color:#94a3b8;font-size:11px;margin-top:4px">How long the auto-suspend lasts.</div>
141 </label>
142 </div>
143 <div style="margin-top:18px">
144 <button type="submit" class="btn" style="background:#5aa9ff;color:#0b1220;border:0;border-radius:8px;padding:10px 18px;font-weight:600">Save email controls</button>
145 </div>
146 </form>
147</div>~;
148
149$wrap->render({ userinfo => $u, page_key => 'email_setup', title => 'Email Setup', body => $body });
150
151sub _email_setup_tabs {
152 my ($active) = @_;
153 my %t = (templates => 'Templates', schedules => 'Schedules', controls => 'Controls');
154 my %h = (templates => '/admin_emails.cgi', schedules => '/admin_email_schedules.cgi', controls => '/admin_email_controls.cgi');
155 my $html = '<div style="display:flex;gap:0;border-bottom:1px solid rgba(255,255,255,.08);margin:0 0 22px">';
156 foreach my $k (qw(templates schedules controls)) {
157 my $is_active = ($k eq $active);
158 my $color = $is_active ? '#5aa9ff' : '#94a3b8';
159 my $border = $is_active ? '#5aa9ff' : 'transparent';
160 my $weight = $is_active ? '600' : '500';
161 $html .= qq~<a href="$h{$k}" style="padding:10px 20px;color:$color;text-decoration:none;font-size:13px;border-bottom:2px solid $border;font-weight:$weight;letter-spacing:.02em">$t{$k}</a>~;
162 }
163 $html .= '</div>';
164 return $html;
165}
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help