Diff -- /var/www/vhosts/3dshawn.com/repricer.3dshawn.com/my_account_close.cgi
Diff

/var/www/vhosts/3dshawn.com/repricer.3dshawn.com/my_account_close.cgi

added on local at 2026-07-02 16:53:30

Added
+144
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to acc9efb927e1
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# RePricer - My Account: close (self-cancel)
4#
5# Self-service: authenticated user can cancel their own account.
6# Sets account_state='cancelled', cancelled_at=NOW(), kills sessions.
7# Data is preserved. Login is blocked until an admin reinstates.
8#
9# For sites with paid subscriptions, this is the "cancel-at-period-end"
10# equivalent: the row stays in Stripe (subscription lifecycle is
11# managed elsewhere via stripe_webhook.cgi). This CGI only flips the
12# app-side account_state so login is denied cleanly.
13#
14# Auto-generated 2026-07-02 from phase89_my_account_close.pl.tmpl
15#======================================================================
16use strict; use warnings;
17use lib '/var/www/vhosts/3dshawn.com/repricer.3dshawn.com';
18use CGI;
19use MODS::Template;
20use MODS::DBConnect;
21use MODS::Login;
22use MODS::RePricer::Config;
23use MODS::RePricer::Wrapper;
24
25my $q = CGI->new;
26my $form = $q->Vars;
27my $auth = MODS::Login->new;
28my $wrap = MODS::RePricer::Wrapper->new;
29my $db = MODS::DBConnect->new;
30my $cfg = MODS::RePricer::Config->new;
31my $DB = $cfg->settings('database_name');
32
33my $userinfo = $auth->login_verify();
34if (!$userinfo) { print "Status: 302 Found\nLocation: /login.cgi\n\n"; exit; }
35
36# ---- Handle POST: confirm self-cancel ----------------------------------
37if (($ENV{REQUEST_METHOD} || '') eq 'POST' && ($form->{action} || '') eq 'self_cancel') {
38 # Require explicit typed confirmation to prevent accidental cancels.
39 my $typed = $form->{confirm_text} || '';
40 $typed =~ s/^\s+|\s+$//g;
41 if (lc($typed) ne 'cancel my account') {
42 _render_page("Please type <strong>cancel my account</strong> exactly to confirm.");
43 exit;
44 }
45 my $uid = $userinfo->{_admin_user_id} || $userinfo->{user_id};
46 $uid =~ s/[^0-9]//g;
47 if ($uid) {
48 my $dbh = $db->db_connect();
49 if ($dbh) {
50 # Flip account_state and stamp cancelled_at.
51 $db->db_readwrite($dbh, qq~
52 UPDATE ${DB}.users
53 SET account_state = 'cancelled',
54 cancelled_at = NOW()
55 WHERE id = '$uid'
56 ~, $ENV{SCRIPT_NAME}, __LINE__);
57 # Kill all active sessions for this user.
58 $db->db_readwrite($dbh, qq~
59 DELETE FROM ${DB}.user_sessions WHERE user_id = '$uid'
60 ~, $ENV{SCRIPT_NAME}, __LINE__);
61 $db->db_disconnect($dbh);
62 }
63 }
64 # Redirect to login with a marker so we can show a "your account was cancelled" message.
65 print "Status: 302 Found\nLocation: /login.cgi?cancelled=1\n\n";
66 exit;
67}
68
69# ---- GET: show the confirm form ---------------------------------------
70_render_page('');
71exit;
72
73
74sub _render_page {
75 my ($error) = @_;
76 my $email = _esc($userinfo->{email} // '');
77 my $err_html = $error ? qq~<div class="myc-err">$error</div>~ : '';
78 my $accent = '#059669';
79 my $body = qq~
80<style>
81.myc-shell { padding: 40px 40px 80px; max-width: 720px; margin: 0 auto; }
82.myc-title { color: #fff; font-size: 28px; font-weight: 800; letter-spacing: -0.01em; margin-bottom: 6px; }
83.myc-sub { color: #9aa4b7; font-size: 15px; margin-bottom: 26px; }
84.myc-card { background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.06); border-radius: 14px; padding: 26px; }
85.myc-warn { padding: 14px 16px; margin-bottom: 20px; background: rgba(245,158,11,0.10); border: 1px solid rgba(245,158,11,0.35); border-radius: 10px; color: #fbbf24; font-size: 14px; }
86.myc-what { margin: 0 0 22px; padding-left: 20px; color: #cfd6e0; font-size: 14px; line-height: 1.7; }
87.myc-what li{ margin: 6px 0; }
88.myc-what li.keep::marker { color: #6ee7b7; }
89.myc-what li.stop::marker { color: #fca5a5; }
90.myc-input { width: 100%; box-sizing: border-box; background: #161c25; border: 1px solid rgba(255,255,255,0.08); color: #e8edf2; padding: 12px 14px; border-radius: 10px; font-size: 14px; margin-bottom: 14px; }
91.myc-actions{ display: flex; gap: 10px; align-items: center; }
92.myc-btn { display: inline-flex; align-items: center; gap: 6px; padding: 12px 22px; border-radius: 10px; font-size: 14px; font-weight: 600; text-decoration: none; border: none; cursor: pointer; }
93.myc-btn.cancel { background: rgba(239,68,68,0.14); color: #fca5a5; border: 1px solid rgba(239,68,68,0.42); }
94.myc-btn.cancel:hover { background: rgba(239,68,68,0.20); }
95.myc-btn.ghost { background: rgba(255,255,255,0.05); color: #cfd6e0; border: 1px solid rgba(255,255,255,0.08); }
96.myc-err { padding: 12px 14px; margin-bottom: 16px; background: rgba(239,68,68,0.12); border: 1px solid rgba(239,68,68,0.35); border-radius: 10px; color: #fca5a5; font-size: 14px; }
97</style>
98<div class="myc-shell">
99 <div class="myc-title">Close my account</div>
100 <div class="myc-sub">Signed in as <strong>$email</strong></div>
101
102 <div class="myc-card">
103 <div class="myc-warn">
104 Your data is preserved. If you change your mind, contact support and an admin
105 can reinstate the account.
106 </div>
107
108 <ul class="myc-what">
109 <li class="stop">Your login will be disabled immediately.</li>
110 <li class="stop">Any active sessions will be signed out.</li>
111 <li class="keep">Your account data (settings, history) stays on file.</li>
112 <li class="keep">Reinstatement is one click for an admin.</li>
113 </ul>
114
115 $err_html
116
117 <form method="POST" onsubmit="return confirm('Really close this account?')">
118 <input type="hidden" name="action" value="self_cancel"/>
119 <label for="confirm_text" style="display:block;color:#cfd6e0;font-size:13px;margin-bottom:8px">
120 Type <strong>cancel my account</strong> to confirm:
121 </label>
122 <input class="myc-input" id="confirm_text" name="confirm_text" autocomplete="off" placeholder="cancel my account"/>
123 <div class="myc-actions">
124 <button class="myc-btn cancel" type="submit">Close my account</button>
125 <a class="myc-btn ghost" href="/dashboard.cgi">Never mind</a>
126 </div>
127 </form>
128 </div>
129</div>
130~;
131 print "Content-Type: text/html; charset=utf-8\nCache-Control: no-cache\n\n";
132 $wrap->render({
133 userinfo => $userinfo,
134 title => 'Close my account',
135 body => $body,
136 });
137}
138
139sub _esc {
140 my $s = defined $_[0] ? $_[0] : '';
141 $s =~ s/&/&amp;/g; $s =~ s/</&lt;/g; $s =~ s/>/&gt;/g;
142 $s =~ s/"/&quot;/g; $s =~ s/'/&#39;/g;
143 return $s;
144}
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help