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

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

added on local at 2026-07-01 13:47:19

Added
+143
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to c90d94614b9a
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# WebSTLs -- GDPR / CCPA self-service data export.
4#
5# GET /export_request.cgi -> queue page + history
6# POST /export_request.cgi action=queue -> enqueue a new export job
7#
8# A background worker (_data_export_worker.pl, to be wired later) will
9# pick up rows with status='queued', dump the user's data to a zip
10# under /uploads/data_exports/, and flip the row to 'ready' with a
11# download URL. Until that worker exists, the request still records
12# the seller's intent so support can fulfil it manually. The dashboard
13# shows queue / ready / failed rows with download links when ready.
14#======================================================================
15use strict;
16use warnings;
17
18use lib '/var/www/vhosts/3dshawn.com/affiliate.3dshawn.com';
19use CGI;
20use MODS::Template;
21use MODS::DBConnect;
22use MODS::Login;
23use MODS::AffSoft::Config;
24use MODS::AffSoft::Wrapper;
25
26$|=1;
27
28my $q = CGI->new;
29my $form = $q->Vars;
30my $auth = MODS::Login->new;
31my $tfile = MODS::Template->new;
32my $db = MODS::DBConnect->new;
33my $cfg = MODS::AffSoft::Config->new;
34my $wrap = MODS::AffSoft::Wrapper->new;
35my $DB = $cfg->settings('database_name');
36
37my $userinfo = $auth->login_verify();
38unless ($userinfo) {
39 print "Status: 302 Found\nLocation: /login.cgi\n\n";
40 exit;
41}
42my $uid = $userinfo->{user_id};
43$uid =~ s/[^0-9]//g;
44
45my $dbh = $db->db_connect();
46
47# Schema-presence guard. data_export_requests is created lazily so
48# pre-migration installs still render the page (with an info banner).
49my $have_tbl = $db->db_readwrite($dbh, qq~
50 SELECT COUNT(*) AS n FROM information_schema.tables
51 WHERE table_schema='$DB' AND table_name='data_export_requests'
52~, $ENV{SCRIPT_NAME}, __LINE__);
53my $table_ready = ($have_tbl && $have_tbl->{n}) ? 1 : 0;
54
55# ---------- POST: enqueue a new export -------------------------------
56if (($ENV{REQUEST_METHOD} || '') eq 'POST'
57 && ($form->{action} || '') eq 'queue'
58 && $table_ready) {
59
60 # Rate-limit: at most one queued/processing request per user at a
61 # time. If they already have one in flight, just bounce to the
62 # status page.
63 my $pending = $db->db_readwrite($dbh, qq~
64 SELECT id FROM `${DB}`.data_export_requests
65 WHERE user_id='$uid'
66 AND status IN ('queued','processing')
67 LIMIT 1
68 ~, $ENV{SCRIPT_NAME}, __LINE__);
69
70 unless ($pending && $pending->{id}) {
71 $db->db_readwrite($dbh, qq~
72 INSERT INTO `${DB}`.data_export_requests SET
73 user_id='$uid',
74 status='queued',
75 requested_at=NOW()
76 ~, $ENV{SCRIPT_NAME}, __LINE__);
77 }
78 $db->db_disconnect($dbh);
79 print "Status: 302 Found\nLocation: /export_request.cgi?queued=1\n\n";
80 exit;
81}
82
83# ---------- GET: render the page + history ---------------------------
84my @rows;
85if ($table_ready) {
86 @rows = $db->db_readwrite_multiple($dbh, qq~
87 SELECT id, status,
88 DATE_FORMAT(requested_at, '%Y-%m-%d %H:%i') AS requested_at,
89 DATE_FORMAT(ready_at, '%Y-%m-%d %H:%i') AS ready_at,
90 download_url, error_message
91 FROM `${DB}`.data_export_requests
92 WHERE user_id='$uid'
93 ORDER BY id DESC
94 LIMIT 20
95 ~, $ENV{SCRIPT_NAME}, __LINE__);
96}
97$db->db_disconnect($dbh);
98
99my @export_rows;
100foreach my $r (@rows) {
101 push @export_rows, {
102 id => $r->{id},
103 status => $r->{status} || 'queued',
104 status_label => ucfirst($r->{status} || 'queued'),
105 is_queued => ($r->{status} || '') eq 'queued' ? 1 : 0,
106 is_processing=> ($r->{status} || '') eq 'processing' ? 1 : 0,
107 is_ready => ($r->{status} || '') eq 'ready' ? 1 : 0,
108 is_failed => ($r->{status} || '') eq 'failed' ? 1 : 0,
109 requested_at => _h($r->{requested_at} || ''),
110 ready_at => _h($r->{ready_at} || ''),
111 download_url => _h($r->{download_url} || ''),
112 error_message=> _h($r->{error_message}|| ''),
113 };
114}
115
116my $has_pending = scalar(grep { $_->{is_queued} || $_->{is_processing} } @export_rows) ? 1 : 0;
117
118my $tvars = {
119 table_ready => $table_ready,
120 table_missing=> $table_ready ? 0 : 1,
121 has_pending => $has_pending,
122 exports => \@export_rows,
123 has_exports => scalar(@export_rows) ? 1 : 0,
124 queued_flash => ($form->{queued} && $form->{queued} eq '1') ? 1 : 0,
125 email => _h($userinfo->{email} || ''),
126};
127
128print "Content-Type: text/html; charset=utf-8\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\nPragma: no-cache\nExpires: 0\n\n";
129my $body = join('', $tfile->template('webstls_export_request.html', $tvars, $userinfo));
130$wrap->render({
131 userinfo => $userinfo,
132 page_key => 'my_profile',
133 title => 'Request data export',
134 body => $body,
135});
136exit;
137
138sub _h {
139 my $s = shift // '';
140 $s =~ s/&/&amp;/g; $s =~ s/</&lt;/g; $s =~ s/>/&gt;/g;
141 $s =~ s/"/&quot;/g; $s =~ s/'/&#39;/g;
142 return $s;
143}
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help