mirror of
https://github.com/myronblair/tomsjavajive
synced 2026-07-27 16:52:36 -05:00
security: remove stray !install!! deploy folder, block .py files, move secrets out of webroot
- Delete !install!!/ (schema.sql, migrations, fix_tjj.py) - unreferenced leftover deploy artifacts, fix_tjj.py was publicly downloadable (200) since the folder name did not match the existing /install/ block pattern - .htaccess: add .py to blocked extensions, explicitly block the !install!!/ path - config/config.php: replace with a require shim pointing to config-secrets.php outside the web root (Stripe/CyberMail keys no longer sit in a web-servable file)
This commit is contained in:
@@ -1,105 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import subprocess, os
|
||||
|
||||
BASE = '/home/tomsjavajive.com/public_html'
|
||||
|
||||
# ── Fix 1: Remove wholesale and careers from footer ──────────
|
||||
print("[1] Fixing footer...")
|
||||
f = BASE + '/includes/footer.php'
|
||||
with open(f) as fh:
|
||||
c = fh.read()
|
||||
|
||||
before = len(c)
|
||||
c = c.replace(' <li><a href="/wholesale.php">Wholesale</a></li>\n', '')
|
||||
c = c.replace(' <li><a href="/careers.php">Careers</a></li>\n', '')
|
||||
# Also try without leading spaces
|
||||
c = c.replace('<li><a href="/wholesale.php">Wholesale</a></li>\n', '')
|
||||
c = c.replace('<li><a href="/careers.php">Careers</a></li>\n', '')
|
||||
|
||||
with open(f, 'w') as fh:
|
||||
fh.write(c)
|
||||
removed = before - len(c)
|
||||
print(f" Footer: removed {removed} chars (wholesale + careers)")
|
||||
|
||||
# ── Fix 2: Check account pages for errors ───────────────────
|
||||
print("\n[2] Checking account pages...")
|
||||
for page in ['rewards', 'wishlist', 'reviews']:
|
||||
path = f'{BASE}/account/{page}.php'
|
||||
r = subprocess.run(
|
||||
['/usr/local/lsws/lsphp85/bin/php', '-d', 'display_errors=1',
|
||||
'-d', 'error_reporting=32767', path],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
output = r.stdout + r.stderr
|
||||
errors = [l for l in output.split('\n')
|
||||
if any(x in l for x in ['Fatal','Error','Undefined','undefined','Call to'])]
|
||||
if errors:
|
||||
print(f" {page}.php ERRORS:")
|
||||
for e in errors[:3]:
|
||||
print(f" {e[:120]}")
|
||||
else:
|
||||
# Check if page has actual HTML content
|
||||
has_html = '<' in r.stdout and len(r.stdout) > 100
|
||||
print(f" {page}.php: {'OK - has content' if has_html else 'WARNING - minimal output'}")
|
||||
|
||||
# ── Fix 3: Check admin customers Modal ──────────────────────
|
||||
print("\n[3] Checking admin customers...")
|
||||
f2 = BASE + '/admin/customers.php'
|
||||
with open(f2) as fh:
|
||||
c2 = fh.read()
|
||||
|
||||
print(f" Modal.open present: {'Modal.open' in c2}")
|
||||
print(f" openCustomerModal present: {'openCustomerModal' in c2}")
|
||||
print(f" admin.js exists: {os.path.exists(BASE+'/admin/assets/admin.js')}")
|
||||
|
||||
# Check if admin.js has Modal object
|
||||
if os.path.exists(BASE+'/admin/assets/admin.js'):
|
||||
with open(BASE+'/admin/assets/admin.js') as fh:
|
||||
js = fh.read()
|
||||
print(f" Modal object in admin.js: {'Modal' in js}")
|
||||
print(f" admin.js size: {len(js)} chars")
|
||||
else:
|
||||
print(" admin.js MISSING - this is why customer modal doesn't work!")
|
||||
# Create a basic Modal object
|
||||
modal_js = """
|
||||
// Modal helper
|
||||
const Modal = {
|
||||
open: function(id) {
|
||||
const el = document.getElementById(id);
|
||||
if (el) { el.style.display = 'flex'; el.classList.add('active'); }
|
||||
},
|
||||
close: function(id) {
|
||||
const el = document.getElementById(id);
|
||||
if (el) { el.style.display = 'none'; el.classList.remove('active'); }
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape') {
|
||||
document.querySelectorAll('.modal-overlay.active').forEach(m => {
|
||||
m.style.display = 'none'; m.classList.remove('active');
|
||||
});
|
||||
}
|
||||
});
|
||||
document.addEventListener('click', function(e) {
|
||||
if (e.target.classList.contains('modal-overlay')) {
|
||||
e.target.style.display = 'none'; e.target.classList.remove('active');
|
||||
}
|
||||
});
|
||||
"""
|
||||
os.makedirs(BASE+'/admin/assets', exist_ok=True)
|
||||
with open(BASE+'/admin/assets/admin.js', 'w') as fh:
|
||||
fh.write(modal_js)
|
||||
print(" Created admin.js with Modal object")
|
||||
|
||||
# ── Fix 4: Check account page includes ─────────────────────
|
||||
print("\n[4] Checking account page structure...")
|
||||
for page in ['rewards', 'wishlist', 'reviews']:
|
||||
path = f'{BASE}/account/{page}.php'
|
||||
with open(path) as fh:
|
||||
content = fh.read()
|
||||
has_auth = 'CustomerAuth::require' in content
|
||||
has_header = "require_once" in content and 'header' in content
|
||||
has_footer = 'footer' in content
|
||||
print(f" {page}.php: auth={has_auth}, header={has_header}, footer={has_footer}, size={len(content)}")
|
||||
|
||||
print("\nDone!")
|
||||
@@ -1,37 +0,0 @@
|
||||
-- Migration: Add wishlist table and addresses column to customers
|
||||
-- Run this in phpMyAdmin to add the new features
|
||||
|
||||
-- Add addresses column to customers table
|
||||
ALTER TABLE `customers` ADD COLUMN `addresses` JSON DEFAULT NULL AFTER `billing_address`;
|
||||
|
||||
-- Add preferences column to customers table
|
||||
ALTER TABLE `customers` ADD COLUMN `preferences` JSON DEFAULT NULL AFTER `addresses`;
|
||||
|
||||
-- Add is_active column to customers table if not exists
|
||||
ALTER TABLE `customers` ADD COLUMN `is_active` TINYINT(1) DEFAULT 1 AFTER `preferences`;
|
||||
|
||||
-- Create wishlist table
|
||||
CREATE TABLE IF NOT EXISTS `wishlist` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`customer_id` VARCHAR(50) NOT NULL,
|
||||
`product_id` VARCHAR(50) NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY `unique_wishlist` (`customer_id`, `product_id`),
|
||||
INDEX `idx_customer` (`customer_id`),
|
||||
INDEX `idx_product` (`product_id`),
|
||||
FOREIGN KEY (`customer_id`) REFERENCES `customers`(`customer_id`) ON DELETE CASCADE,
|
||||
FOREIGN KEY (`product_id`) REFERENCES `products`(`product_id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Add reorder_level column to products if not exists
|
||||
ALTER TABLE `products` ADD COLUMN `reorder_level` INT DEFAULT 10 AFTER `low_stock_threshold`;
|
||||
|
||||
-- Add slug column to products if not exists
|
||||
ALTER TABLE `products` ADD COLUMN `slug` VARCHAR(255) DEFAULT NULL AFTER `name`;
|
||||
ALTER TABLE `products` ADD INDEX `idx_slug` (`slug`);
|
||||
|
||||
-- Update existing products to have slugs based on name
|
||||
UPDATE `products` SET `slug` = LOWER(REPLACE(REPLACE(REPLACE(`name`, ' ', '-'), "'", ''), '"', '')) WHERE `slug` IS NULL;
|
||||
|
||||
-- Add is_pos_order to orders table
|
||||
ALTER TABLE `orders` ADD COLUMN `is_pos_order` TINYINT(1) DEFAULT 0 AFTER `notes`;
|
||||
@@ -1,96 +0,0 @@
|
||||
-- Migration: Add tables for push notifications, loyalty program, and integration settings
|
||||
-- Run this in phpMyAdmin
|
||||
|
||||
-- Push notification subscriptions
|
||||
CREATE TABLE IF NOT EXISTS `push_subscriptions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`customer_id` VARCHAR(50) DEFAULT NULL,
|
||||
`endpoint` TEXT NOT NULL,
|
||||
`p256dh_key` VARCHAR(255) NOT NULL,
|
||||
`auth_key` VARCHAR(255) NOT NULL,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_customer` (`customer_id`),
|
||||
INDEX `idx_active` (`is_active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Push notifications queue
|
||||
CREATE TABLE IF NOT EXISTS `push_notifications` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`notification_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`subscription_endpoint` TEXT NOT NULL,
|
||||
`payload` TEXT NOT NULL,
|
||||
`status` ENUM('pending', 'sent', 'failed') DEFAULT 'pending',
|
||||
`error_message` TEXT DEFAULT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`sent_at` TIMESTAMP NULL DEFAULT NULL,
|
||||
INDEX `idx_status` (`status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Loyalty transactions history
|
||||
CREATE TABLE IF NOT EXISTS `loyalty_transactions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`transaction_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`customer_id` VARCHAR(50) NOT NULL,
|
||||
`points` INT NOT NULL,
|
||||
`type` ENUM('earn', 'redeem', 'tier_upgrade', 'birthday_bonus', 'referral_bonus', 'referral_welcome', 'adjustment', 'expiry') NOT NULL,
|
||||
`description` VARCHAR(255) DEFAULT NULL,
|
||||
`reference_amount` DECIMAL(10,2) DEFAULT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_customer` (`customer_id`),
|
||||
INDEX `idx_type` (`type`),
|
||||
INDEX `idx_created` (`created_at`),
|
||||
FOREIGN KEY (`customer_id`) REFERENCES `customers`(`customer_id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Add lifetime_points and loyalty_tier to customers
|
||||
ALTER TABLE `customers`
|
||||
ADD COLUMN IF NOT EXISTS `lifetime_points` INT DEFAULT 0 AFTER `reward_points`,
|
||||
ADD COLUMN IF NOT EXISTS `loyalty_tier` ENUM('bronze', 'silver', 'gold', 'platinum') DEFAULT 'bronze' AFTER `lifetime_points`,
|
||||
ADD COLUMN IF NOT EXISTS `birthday` DATE DEFAULT NULL AFTER `loyalty_tier`,
|
||||
ADD COLUMN IF NOT EXISTS `referral_code` VARCHAR(20) DEFAULT NULL AFTER `birthday`,
|
||||
ADD COLUMN IF NOT EXISTS `referred_by` VARCHAR(50) DEFAULT NULL AFTER `referral_code`;
|
||||
|
||||
-- Add unique index on referral_code
|
||||
ALTER TABLE `customers` ADD UNIQUE INDEX IF NOT EXISTS `idx_referral_code` (`referral_code`);
|
||||
|
||||
-- Update settings table with integration keys (INSERT IGNORE to not overwrite existing)
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`, `updated_at`) VALUES
|
||||
('sendgrid_api_key', '', NOW()),
|
||||
('sendgrid_from_email', 'noreply@tomsjavajive.com', NOW()),
|
||||
('sendgrid_from_name', 'Tom''s Java Jive', NOW()),
|
||||
('twilio_account_sid', '', NOW()),
|
||||
('twilio_auth_token', '', NOW()),
|
||||
('twilio_phone_number', '', NOW()),
|
||||
('vapid_public_key', '', NOW()),
|
||||
('vapid_private_key', '', NOW()),
|
||||
('loyalty_enabled', '1', NOW()),
|
||||
('email_notifications_enabled', '1', NOW()),
|
||||
('sms_notifications_enabled', '0', NOW()),
|
||||
('push_notifications_enabled', '1', NOW());
|
||||
|
||||
-- Add Stripe checkout session column to orders
|
||||
ALTER TABLE `orders` ADD COLUMN IF NOT EXISTS `stripe_checkout_session` VARCHAR(255) DEFAULT NULL AFTER `stripe_payment_intent`;
|
||||
|
||||
-- Payment transactions table for tracking payment attempts
|
||||
CREATE TABLE IF NOT EXISTS `payment_transactions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`transaction_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`order_id` VARCHAR(50) NOT NULL,
|
||||
`customer_id` VARCHAR(50) DEFAULT NULL,
|
||||
`amount` DECIMAL(10,2) NOT NULL,
|
||||
`currency` VARCHAR(3) DEFAULT 'USD',
|
||||
`payment_method` VARCHAR(50) DEFAULT 'stripe',
|
||||
`stripe_session_id` VARCHAR(255) DEFAULT NULL,
|
||||
`stripe_payment_intent` VARCHAR(255) DEFAULT NULL,
|
||||
`status` ENUM('initiated', 'pending', 'processing', 'succeeded', 'failed', 'cancelled', 'refunded') DEFAULT 'initiated',
|
||||
`metadata` JSON DEFAULT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_order` (`order_id`),
|
||||
INDEX `idx_customer` (`customer_id`),
|
||||
INDEX `idx_status` (`status`),
|
||||
INDEX `idx_stripe_session` (`stripe_session_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
@@ -1,402 +0,0 @@
|
||||
-- Tom's Java Jive - MySQL Database Schema
|
||||
-- Version: 1.0
|
||||
-- Compatible with MySQL 8.0+
|
||||
|
||||
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||
SET AUTOCOMMIT = 0;
|
||||
START TRANSACTION;
|
||||
SET time_zone = "+00:00";
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Database Schema for Tom's Java Jive
|
||||
-- NOTE: Database must already exist in cPanel
|
||||
-- Select your database in phpMyAdmin before importing
|
||||
-- --------------------------------------------------------
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: settings
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `settings` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`setting_key` VARCHAR(100) NOT NULL UNIQUE,
|
||||
`setting_value` JSON,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: admin_users
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `admin_users` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`user_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`email` VARCHAR(255) NOT NULL UNIQUE,
|
||||
`password_hash` VARCHAR(255) DEFAULT NULL,
|
||||
`name` VARCHAR(255) DEFAULT NULL,
|
||||
`picture` VARCHAR(500) DEFAULT NULL,
|
||||
`is_admin` TINYINT(1) DEFAULT 1,
|
||||
`is_master` TINYINT(1) DEFAULT 0,
|
||||
`permissions` JSON DEFAULT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`last_login` TIMESTAMP NULL,
|
||||
INDEX `idx_email` (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: customers
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `customers` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`customer_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`email` VARCHAR(255) NOT NULL UNIQUE,
|
||||
`password_hash` VARCHAR(255) DEFAULT NULL,
|
||||
`name` VARCHAR(255) DEFAULT NULL,
|
||||
`phone` VARCHAR(50) DEFAULT NULL,
|
||||
`shipping_address` JSON DEFAULT NULL,
|
||||
`billing_address` JSON DEFAULT NULL,
|
||||
`wallet_balance` DECIMAL(10,2) DEFAULT 0.00,
|
||||
`reward_points` INT DEFAULT 0,
|
||||
`is_guest` TINYINT(1) DEFAULT 0,
|
||||
`created_via` VARCHAR(50) DEFAULT 'web',
|
||||
`email_verified` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_email` (`email`),
|
||||
INDEX `idx_customer_id` (`customer_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: products
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `products` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`product_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`description` TEXT,
|
||||
`price` DECIMAL(10,2) NOT NULL,
|
||||
`sale_price` DECIMAL(10,2) DEFAULT NULL,
|
||||
`cost_price` DECIMAL(10,2) DEFAULT NULL,
|
||||
`sku` VARCHAR(100) DEFAULT NULL,
|
||||
`barcode` VARCHAR(100) DEFAULT NULL,
|
||||
`category` VARCHAR(100) DEFAULT NULL,
|
||||
`tags` JSON DEFAULT NULL,
|
||||
`images` JSON DEFAULT NULL,
|
||||
`stock` INT DEFAULT 0,
|
||||
`low_stock_threshold` INT DEFAULT 10,
|
||||
`weight` DECIMAL(10,2) DEFAULT NULL,
|
||||
`dimensions` JSON DEFAULT NULL,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`is_featured` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_product_id` (`product_id`),
|
||||
INDEX `idx_category` (`category`),
|
||||
INDEX `idx_is_active` (`is_active`),
|
||||
FULLTEXT INDEX `idx_search` (`name`, `description`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: orders
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `orders` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`order_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`order_number` VARCHAR(20) NOT NULL UNIQUE,
|
||||
`customer_id` VARCHAR(50) DEFAULT NULL,
|
||||
`customer_email` VARCHAR(255) NOT NULL,
|
||||
`customer_name` VARCHAR(255) DEFAULT NULL,
|
||||
`customer_phone` VARCHAR(50) DEFAULT NULL,
|
||||
`items` JSON NOT NULL,
|
||||
`subtotal` DECIMAL(10,2) NOT NULL,
|
||||
`shipping_cost` DECIMAL(10,2) DEFAULT 0.00,
|
||||
`tax` DECIMAL(10,2) DEFAULT 0.00,
|
||||
`discount` DECIMAL(10,2) DEFAULT 0.00,
|
||||
`gift_card_discount` DECIMAL(10,2) DEFAULT 0.00,
|
||||
`wallet_amount_used` DECIMAL(10,2) DEFAULT 0.00,
|
||||
`total` DECIMAL(10,2) NOT NULL,
|
||||
`shipping_address` JSON DEFAULT NULL,
|
||||
`billing_address` JSON DEFAULT NULL,
|
||||
`shipping_method` VARCHAR(50) DEFAULT NULL,
|
||||
`payment_method` VARCHAR(50) DEFAULT NULL,
|
||||
`payment_status` ENUM('pending', 'paid', 'failed', 'refunded', 'partially_refunded') DEFAULT 'pending',
|
||||
`order_status` ENUM('pending', 'confirmed', 'processing', 'shipped', 'delivered', 'cancelled', 'refunded') DEFAULT 'pending',
|
||||
`stripe_session_id` VARCHAR(255) DEFAULT NULL,
|
||||
`stripe_payment_intent` VARCHAR(255) DEFAULT NULL,
|
||||
`tracking_number` VARCHAR(100) DEFAULT NULL,
|
||||
`tracking_url` VARCHAR(500) DEFAULT NULL,
|
||||
`notes` TEXT DEFAULT NULL,
|
||||
`is_pos_order` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_order_id` (`order_id`),
|
||||
INDEX `idx_customer_id` (`customer_id`),
|
||||
INDEX `idx_customer_email` (`customer_email`),
|
||||
INDEX `idx_order_status` (`order_status`),
|
||||
INDEX `idx_payment_status` (`payment_status`),
|
||||
INDEX `idx_created_at` (`created_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: order_items (normalized for reporting)
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `order_items` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`order_id` VARCHAR(50) NOT NULL,
|
||||
`product_id` VARCHAR(50) NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`price` DECIMAL(10,2) NOT NULL,
|
||||
`quantity` INT NOT NULL,
|
||||
`total` DECIMAL(10,2) NOT NULL,
|
||||
INDEX `idx_order_id` (`order_id`),
|
||||
INDEX `idx_product_id` (`product_id`),
|
||||
FOREIGN KEY (`order_id`) REFERENCES `orders`(`order_id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: gift_cards
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `gift_cards` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`gift_card_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`code` VARCHAR(20) NOT NULL UNIQUE,
|
||||
`initial_balance` DECIMAL(10,2) NOT NULL,
|
||||
`current_balance` DECIMAL(10,2) NOT NULL,
|
||||
`purchaser_email` VARCHAR(255) DEFAULT NULL,
|
||||
`recipient_email` VARCHAR(255) DEFAULT NULL,
|
||||
`recipient_name` VARCHAR(255) DEFAULT NULL,
|
||||
`message` TEXT DEFAULT NULL,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`expires_at` TIMESTAMP NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_code` (`code`),
|
||||
INDEX `idx_is_active` (`is_active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: gift_card_transactions
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `gift_card_transactions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`gift_card_id` VARCHAR(50) NOT NULL,
|
||||
`order_id` VARCHAR(50) DEFAULT NULL,
|
||||
`amount` DECIMAL(10,2) NOT NULL,
|
||||
`balance_after` DECIMAL(10,2) NOT NULL,
|
||||
`type` ENUM('purchase', 'redemption', 'refund') NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_gift_card_id` (`gift_card_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: wallet_transactions
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `wallet_transactions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`transaction_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`customer_id` VARCHAR(50) NOT NULL,
|
||||
`amount` DECIMAL(10,2) NOT NULL,
|
||||
`balance_after` DECIMAL(10,2) NOT NULL,
|
||||
`type` ENUM('deposit', 'withdrawal', 'purchase', 'refund', 'reward') NOT NULL,
|
||||
`description` VARCHAR(255) DEFAULT NULL,
|
||||
`order_id` VARCHAR(50) DEFAULT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_customer_id` (`customer_id`),
|
||||
INDEX `idx_type` (`type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: reviews
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `reviews` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`review_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`product_id` VARCHAR(50) NOT NULL,
|
||||
`customer_id` VARCHAR(50) DEFAULT NULL,
|
||||
`customer_name` VARCHAR(255) NOT NULL,
|
||||
`customer_email` VARCHAR(255) NOT NULL,
|
||||
`rating` INT NOT NULL CHECK (rating >= 1 AND rating <= 5),
|
||||
`title` VARCHAR(255) DEFAULT NULL,
|
||||
`comment` TEXT,
|
||||
`is_verified_purchase` TINYINT(1) DEFAULT 0,
|
||||
`is_approved` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_product_id` (`product_id`),
|
||||
INDEX `idx_is_approved` (`is_approved`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: email_campaigns
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `email_campaigns` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`campaign_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`subject` VARCHAR(255) NOT NULL,
|
||||
`content` TEXT NOT NULL,
|
||||
`recipient_type` ENUM('all', 'customers_only', 'subscribers_only') DEFAULT 'all',
|
||||
`status` ENUM('draft', 'scheduled', 'sent', 'cancelled') DEFAULT 'draft',
|
||||
`scheduled_at` TIMESTAMP NULL,
|
||||
`sent_at` TIMESTAMP NULL,
|
||||
`recipients_count` INT DEFAULT 0,
|
||||
`opened_count` INT DEFAULT 0,
|
||||
`clicked_count` INT DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_status` (`status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: email_subscribers
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `email_subscribers` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`email` VARCHAR(255) NOT NULL UNIQUE,
|
||||
`name` VARCHAR(255) DEFAULT NULL,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`source` VARCHAR(50) DEFAULT 'website',
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_is_active` (`is_active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: abandoned_carts
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `abandoned_carts` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`cart_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`customer_id` VARCHAR(50) DEFAULT NULL,
|
||||
`customer_email` VARCHAR(255) DEFAULT NULL,
|
||||
`items` JSON NOT NULL,
|
||||
`subtotal` DECIMAL(10,2) NOT NULL,
|
||||
`recovery_email_sent` TINYINT(1) DEFAULT 0,
|
||||
`recovered` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_customer_email` (`customer_email`),
|
||||
INDEX `idx_recovered` (`recovered`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: referrals
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `referrals` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`referral_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`referrer_customer_id` VARCHAR(50) NOT NULL,
|
||||
`referral_code` VARCHAR(20) NOT NULL UNIQUE,
|
||||
`referred_customer_id` VARCHAR(50) DEFAULT NULL,
|
||||
`referred_email` VARCHAR(255) DEFAULT NULL,
|
||||
`status` ENUM('pending', 'completed', 'expired') DEFAULT 'pending',
|
||||
`reward_amount` DECIMAL(10,2) DEFAULT 5.00,
|
||||
`reward_given` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_referral_code` (`referral_code`),
|
||||
INDEX `idx_referrer` (`referrer_customer_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: visitor_sessions
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `visitor_sessions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`session_id` VARCHAR(100) NOT NULL UNIQUE,
|
||||
`visitor_id` VARCHAR(50) NOT NULL,
|
||||
`ip_address` VARCHAR(45) DEFAULT NULL,
|
||||
`user_agent` TEXT DEFAULT NULL,
|
||||
`current_page` VARCHAR(500) DEFAULT NULL,
|
||||
`referrer` VARCHAR(500) DEFAULT NULL,
|
||||
`country` VARCHAR(100) DEFAULT NULL,
|
||||
`city` VARCHAR(100) DEFAULT NULL,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`page_views` INT DEFAULT 1,
|
||||
`started_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`last_activity` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_is_active` (`is_active`),
|
||||
INDEX `idx_last_activity` (`last_activity`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: categories
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `categories` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`category_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`slug` VARCHAR(255) NOT NULL UNIQUE,
|
||||
`description` TEXT DEFAULT NULL,
|
||||
`image` VARCHAR(500) DEFAULT NULL,
|
||||
`parent_id` VARCHAR(50) DEFAULT NULL,
|
||||
`sort_order` INT DEFAULT 0,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_slug` (`slug`),
|
||||
INDEX `idx_is_active` (`is_active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: coupons
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `coupons` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`coupon_id` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`code` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`discount_type` ENUM('percentage', 'fixed') NOT NULL DEFAULT 'percentage',
|
||||
`discount_value` DECIMAL(10,2) NOT NULL,
|
||||
`min_order_amount` DECIMAL(10,2) DEFAULT NULL,
|
||||
`max_uses` INT DEFAULT NULL,
|
||||
`times_used` INT DEFAULT 0,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`starts_at` TIMESTAMP NULL,
|
||||
`expires_at` TIMESTAMP NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_code` (`code`),
|
||||
INDEX `idx_is_active` (`is_active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: password_reset_tokens
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `password_reset_tokens` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`email` VARCHAR(255) NOT NULL,
|
||||
`token` VARCHAR(255) NOT NULL,
|
||||
`user_type` ENUM('admin', 'customer') NOT NULL,
|
||||
`expires_at` TIMESTAMP NOT NULL,
|
||||
`used` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_token` (`token`),
|
||||
INDEX `idx_email` (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Table: sessions
|
||||
-- --------------------------------------------------------
|
||||
CREATE TABLE `sessions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`session_id` VARCHAR(128) NOT NULL UNIQUE,
|
||||
`user_id` VARCHAR(50) DEFAULT NULL,
|
||||
`user_type` ENUM('admin', 'customer') DEFAULT NULL,
|
||||
`data` TEXT,
|
||||
`ip_address` VARCHAR(45) DEFAULT NULL,
|
||||
`user_agent` VARCHAR(255) DEFAULT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`expires_at` TIMESTAMP NOT NULL,
|
||||
INDEX `idx_session_id` (`session_id`),
|
||||
INDEX `idx_expires_at` (`expires_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
-- Insert default settings
|
||||
-- --------------------------------------------------------
|
||||
INSERT INTO `settings` (`setting_key`, `setting_value`) VALUES
|
||||
('store_name', '"Tom\'s Java Jive"'),
|
||||
('store_email', '"support@tomsjavajive.com"'),
|
||||
('store_phone', '""'),
|
||||
('store_address', '""'),
|
||||
('currency', '"USD"'),
|
||||
('currency_symbol', '"$"'),
|
||||
('tax_rate', '0'),
|
||||
('shipping', '{"flat_rate_enabled": true, "flat_rate_amount": 5.99, "free_shipping_threshold": 50, "weight_based_enabled": false}'),
|
||||
('payment', '{"stripe_enabled": true, "paypal_enabled": false, "cod_enabled": false}'),
|
||||
('email', '{"sendgrid_api_key": "", "sender_email": "noreply@tomsjavajive.com", "sender_name": "Tom\'s Java Jive"}');
|
||||
|
||||
COMMIT;
|
||||
@@ -8,9 +8,10 @@ RewriteEngine On
|
||||
# includes/*.php, and .git/ were all still reachable live despite the
|
||||
# RedirectMatch rules further down) — only mod_rewrite matching on REQUEST_URI
|
||||
# is confirmed to actually work here. This must come before other rewrites.
|
||||
RewriteCond %{REQUEST_URI} ^/(\.git|config/|includes/.*\.php|install/|db/)
|
||||
RewriteCond %{REQUEST_URI} ^/(\.git|config/|includes/.*\.php|install/|!install!!/|db/)
|
||||
RewriteRule .* - [F,L]
|
||||
RewriteCond %{REQUEST_URI} \.sql$
|
||||
RewriteCond %{REQUEST_URI} \.sql$ [OR]
|
||||
RewriteCond %{REQUEST_URI} \.py$
|
||||
RewriteRule .* - [F,L]
|
||||
|
||||
# Force HTTPS (uncomment in production)
|
||||
|
||||
+1
-65
@@ -1,66 +1,2 @@
|
||||
<?php
|
||||
/**
|
||||
* Tom's Java Jive - Main Configuration
|
||||
*/
|
||||
|
||||
// Site Configuration
|
||||
if (!defined('SITE_NAME')) { define('SITE_NAME', "Tom's Java Jive"); }
|
||||
if (!defined('SITE_URL')) { define('SITE_URL', 'https://tomsjavajive.com'); }
|
||||
if (!defined('SITE_EMAIL')) { define('SITE_EMAIL', 'support@tomsjavajive.com'); }
|
||||
|
||||
// Environment
|
||||
if (!defined('ENVIRONMENT')) { define('ENVIRONMENT', 'production'); }
|
||||
if (!defined('DEBUG_MODE')) { define('DEBUG_MODE', false); }
|
||||
|
||||
// Session Configuration
|
||||
if (!defined('SESSION_NAME')) { define('SESSION_NAME', 'tjj_session'); }
|
||||
if (!defined('SESSION_LIFETIME')) { define('SESSION_LIFETIME', 86400 * 7); }
|
||||
|
||||
// Security
|
||||
if (!defined('HASH_COST')) { define('HASH_COST', 12); }
|
||||
if (!defined('CSRF_TOKEN_NAME')) { define('CSRF_TOKEN_NAME', 'csrf_token'); }
|
||||
|
||||
// Stripe
|
||||
if (!defined('STRIPE_SECRET_KEY')) { define('STRIPE_SECRET_KEY', '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'); }
|
||||
if (!defined('STRIPE_PUBLISHABLE_KEY')) { define('STRIPE_PUBLISHABLE_KEY', 'pk_live_51TcSte42hN9FJ8ht6QMzoTJwji8q1me1cFvEX5Y3mES1cJnA6LQ0ROvqkoiiPBMGf73jszIHZPv6Q37qUgLYdCeG00W4uehVba'); }
|
||||
if (!defined('STRIPE_WEBHOOK_SECRET')) { define('STRIPE_WEBHOOK_SECRET', 'whsec_esEudSGg3zch1zoHaYD3b9Bj2CfZerO9'); }
|
||||
|
||||
// CyberMail SMTP
|
||||
if (!defined('SMTP_HOST')) { define('SMTP_HOST', 'mail.cyberpersons.com'); }
|
||||
if (!defined('SMTP_PORT')) { define('SMTP_PORT', 587); }
|
||||
if (!defined('SMTP_USER')) { define('SMTP_USER', 'smtp_49a1fa9c0f15d2d7'); }
|
||||
if (!defined('SMTP_PASS')) { define('SMTP_PASS', 'T3mOFSMK1SG1l4D1d7N8NefRd8xypwMy'); }
|
||||
if (!defined('SMTP_SECURE')) { define('SMTP_SECURE', 'tls'); } // STARTTLS
|
||||
if (!defined('SENDER_EMAIL')) { define('SENDER_EMAIL', 'noreply@tomsjavajive.com'); }
|
||||
if (!defined('SENDER_NAME')) { define('SENDER_NAME', "Tom's Java Jive"); }
|
||||
if (!defined('CYBERMAIL_API_KEY')) { define('CYBERMAIL_API_KEY', 'sk_live_d52bf062797105aeaafac9954c21ff988e9b41b77315807d'); }
|
||||
|
||||
// Twilio (optional)
|
||||
if (!defined('TWILIO_SID')) { define('TWILIO_SID', ''); }
|
||||
if (!defined('TWILIO_AUTH_TOKEN')) { define('TWILIO_AUTH_TOKEN', ''); }
|
||||
if (!defined('TWILIO_PHONE')) { define('TWILIO_PHONE', ''); }
|
||||
|
||||
// File Uploads
|
||||
if (!defined('UPLOAD_DIR')) { define('UPLOAD_DIR', __DIR__ . '/../uploads/'); }
|
||||
if (!defined('MAX_UPLOAD_SIZE')) { define('MAX_UPLOAD_SIZE', 5 * 1024 * 1024); }
|
||||
if (!defined('ALLOWED_IMAGE_TYPES')) { define('ALLOWED_IMAGE_TYPES', ['image/jpeg', 'image/png', 'image/gif', 'image/webp']); }
|
||||
|
||||
// Pagination
|
||||
if (!defined('ITEMS_PER_PAGE')) { define('ITEMS_PER_PAGE', 12); }
|
||||
if (!defined('ADMIN_ITEMS_PER_PAGE')) { define('ADMIN_ITEMS_PER_PAGE', 20); }
|
||||
|
||||
// Currency
|
||||
if (!defined('CURRENCY_CODE')) { define('CURRENCY_CODE', 'USD'); }
|
||||
if (!defined('TJJ_CURRENCY_SYMBOL')) { define('TJJ_CURRENCY_SYMBOL', '$'); }
|
||||
|
||||
// Timezone
|
||||
date_default_timezone_set('America/New_York');
|
||||
|
||||
// Error Reporting
|
||||
if (ENVIRONMENT === 'development' || DEBUG_MODE) {
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
} else {
|
||||
error_reporting(0);
|
||||
ini_set('display_errors', 0);
|
||||
}
|
||||
require_once dirname(__DIR__, 2) . "/config-secrets.php";
|
||||
|
||||
Reference in New Issue
Block a user