added on local at 2026-07-01 13:48:21
| 1 | #!/usr/bin/perl | |
| 2 | #====================================================================== | |
| 3 | # WebSTLs -- _set_timezone.cgi | |
| 4 | # | |
| 5 | # Background pingback fired once per session by the JS at the bottom | |
| 6 | # of webstls_wrapper.html. Reads the browser's IANA timezone (via | |
| 7 | # Intl.DateTimeFormat().resolvedOptions().timeZone) and updates the | |
| 8 | # logged-in user's `users.timezone` so every subsequent page load | |
| 9 | # applies SET time_zone = '<tz>' via MODS::DBConnect, making every | |
| 10 | # reporting graph/KPI render in the viewer's local time. | |
| 11 | # | |
| 12 | # POST tz=America/Denver -> updates users.timezone if different. | |
| 13 | # No-op if not authenticated, no tz provided, or tz unchanged. | |
| 14 | #====================================================================== | |
| 15 | use strict; | |
| 16 | use warnings; | |
| 17 | ||
| 18 | use lib '/var/www/vhosts/3dshawn.com/affiliate.3dshawn.com'; | |
| 19 | use CGI; | |
| 20 | use MODS::Login; | |
| 21 | use MODS::DBConnect; | |
| 22 | use MODS::AffSoft::Config; | |
| 23 | ||
| 24 | my $q = CGI->new; | |
| 25 | my $auth = MODS::Login->new; | |
| 26 | my $db = MODS::DBConnect->new; | |
| 27 | my $cfg = MODS::AffSoft::Config->new; | |
| 28 | my $DB = $cfg->settings('database_name'); | |
| 29 | ||
| 30 | print "Content-Type: text/plain; charset=utf-8\nCache-Control: no-store\n\n"; | |
| 31 | ||
| 32 | my $userinfo = $auth->login_verify(); | |
| 33 | unless ($userinfo && $userinfo->{user_id}) { | |
| 34 | print "noauth"; | |
| 35 | exit; | |
| 36 | } | |
| 37 | ||
| 38 | # Refuse to overwrite the target user's stored timezone while an admin | |
| 39 | # is impersonating them. The admin's browser zone would otherwise leak | |
| 40 | # into the seller's row and stick around after the admin exits. | |
| 41 | if ($userinfo->{_impersonating}) { | |
| 42 | print "impersonating-skip"; | |
| 43 | exit; | |
| 44 | } | |
| 45 | ||
| 46 | my $tz = $q->param('tz') || ''; | |
| 47 | # IANA names: letters/digits, underscore, hyphen, plus, colon, slash. | |
| 48 | # Also accept +HH:MM offset form. | |
| 49 | $tz =~ s/[^A-Za-z0-9_+\-:\/]//g; | |
| 50 | $tz = substr($tz, 0, 63); | |
| 51 | unless (length $tz) { | |
| 52 | print "no-tz"; | |
| 53 | exit; | |
| 54 | } | |
| 55 | ||
| 56 | # Skip the write if the stored value already matches. | |
| 57 | if (($userinfo->{timezone} || '') eq $tz) { | |
| 58 | print "ok-nochange"; | |
| 59 | exit; | |
| 60 | } | |
| 61 | ||
| 62 | my $dbh = $db->db_connect(); | |
| 63 | unless ($dbh) { | |
| 64 | print "no-db"; | |
| 65 | exit; | |
| 66 | } | |
| 67 | ||
| 68 | my $uid = $userinfo->{user_id}; | |
| 69 | $uid =~ s/[^0-9]//g; | |
| 70 | ||
| 71 | my $safe_tz = $tz; | |
| 72 | $safe_tz =~ s/'/\\'/g; | |
| 73 | ||
| 74 | $db->db_readwrite($dbh, qq~ | |
| 75 | UPDATE `${DB}`.users SET timezone='$safe_tz' WHERE id='$uid' | |
| 76 | ~, $ENV{SCRIPT_NAME}, __LINE__); | |
| 77 | ||
| 78 | $db->db_disconnect($dbh); | |
| 79 | print "ok-updated"; | |
| 80 | exit; |