added on WebSTLs (webstls.com) at 2026-07-01 22:26:39
| 1 | package MODS::WebSTLs::Onboarding; | |
| 2 | #====================================================================== | |
| 3 | # WebSTLs -- new-user sample data seeder | |
| 4 | # | |
| 5 | # Called from signup.cgi. Creates a sample storefront + 4 sample 3D | |
| 6 | # printables so the dashboard isn't empty on first login. Idempotent. | |
| 7 | #====================================================================== | |
| 8 | use strict; use warnings; | |
| 9 | ||
| 10 | sub new { return bless {}, shift } | |
| 11 | ||
| 12 | sub seed_sample_data { | |
| 13 | my ($self, $db, $dbh, $DB, $user_id) = @_; | |
| 14 | return unless $user_id; | |
| 15 | ||
| 16 | # Skip if user already has a storefront | |
| 17 | my $r = $db->db_readwrite($dbh, qq~ | |
| 18 | SELECT COUNT(*) AS n FROM `${DB}`.storefronts WHERE user_id='$user_id' | |
| 19 | ~, $ENV{SCRIPT_NAME}, __LINE__); | |
| 20 | return if $r && $r->{n}; | |
| 21 | ||
| 22 | # Unique subdomain per user (storefronts.subdomain is UNIQUE) | |
| 23 | my $sub = "demo-u$user_id"; | |
| 24 | ||
| 25 | my $sf = $db->db_readwrite($dbh, qq~ | |
| 26 | INSERT INTO `${DB}`.storefronts | |
| 27 | SET user_id='$user_id', | |
| 28 | subdomain='$sub', | |
| 29 | name='My 3D Printables (example)', | |
| 30 | tagline='Example storefront -- edit or replace with your brand.', | |
| 31 | about_text='This is your sample storefront. Replace the name, tagline, and about text with your brand story, switch the theme, point your custom domain. Auto-SSL on every store.' | |
| 32 | ~, $ENV{SCRIPT_NAME}, __LINE__); | |
| 33 | ||
| 34 | # Four sample STL/printable products across categories so the | |
| 35 | # /models.cgi list and Kanban-ish overview don't look empty. | |
| 36 | my @samples = ( | |
| 37 | { title => 'Articulated Dragon (sample STL)', | |
| 38 | slug => 'sample-articulated-dragon', | |
| 39 | price => 599, | |
| 40 | category => 'Toys & Figures', | |
| 41 | license => 'Personal use', | |
| 42 | desc => 'Example product. Print-in-place articulated dragon, supports-free, 4-hour print on 0.2mm. Replace this with your own model + photos + description.' }, | |
| 43 | { title => 'Modular Drawer System (sample STL)', | |
| 44 | slug => 'sample-modular-drawers', | |
| 45 | price => 799, | |
| 46 | category => 'Home & Office', | |
| 47 | license => 'Personal + commercial', | |
| 48 | desc => 'Example product. Snap-fit drawer modules in 3 sizes. Tile to fill any drawer. Replace with your own design.' }, | |
| 49 | { title => 'Tabletop Mini Bundle of 6 (sample STL)', | |
| 50 | slug => 'sample-mini-bundle', | |
| 51 | price => 1499, | |
| 52 | category => 'Tabletop & Wargaming', | |
| 53 | license => 'Personal use', | |
| 54 | desc => 'Example bundle. Six 28mm-scale heroes pre-supported. Replace with your own minis.' }, | |
| 55 | { title => 'Phone Stand - Hexagonal (free sample)', | |
| 56 | slug => 'sample-phone-stand-hex', | |
| 57 | price => 0, | |
| 58 | category => 'Gadgets', | |
| 59 | license => 'Personal use', | |
| 60 | desc => 'Free example to demo your free-tier offering. Universal-fit hex-pattern phone stand. Replace with your own freebie.' }, | |
| 61 | ); | |
| 62 | ||
| 63 | foreach my $p (@samples) { | |
| 64 | my $t_q = $p->{title}; $t_q =~ s/'/''/g; | |
| 65 | my $s_q = $p->{slug} . '-u' . $user_id; # unique per user | |
| 66 | my $d_q = $p->{desc}; $d_q =~ s/'/''/g; | |
| 67 | my $c_q = $p->{category}; $c_q =~ s/'/''/g; | |
| 68 | my $l_q = $p->{license}; $l_q =~ s/'/''/g; | |
| 69 | $db->db_readwrite($dbh, qq~ | |
| 70 | INSERT INTO `${DB}`.models | |
| 71 | SET user_id='$user_id', | |
| 72 | title='$t_q', | |
| 73 | slug='$s_q', | |
| 74 | description='$d_q', | |
| 75 | base_price_cents='$p->{price}', | |
| 76 | currency='USD', | |
| 77 | category='$c_q', | |
| 78 | license_type='$l_q' | |
| 79 | ~, $ENV{SCRIPT_NAME}, __LINE__); | |
| 80 | } | |
| 81 | ||
| 82 | return 1; | |
| 83 | } | |
| 84 | ||
| 85 | 1; |