- Timestamp:
- 02/22/26 17:24:14 (7 months ago)
- Branches:
- finki-main, main
- Children:
- 4dff800
- Parents:
- 69f2a41
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
server.js
r69f2a41 r591278c 10 10 11 11 const port = process.env.PORT || 3000; 12 12 13 const sessions = new Map(); 13 14 const verificationCodes = new Map(); … … 31 32 } 32 33 }; 34 33 35 emailTransporter = nodemailer.createTransport(emailConfig); 34 36 … … 73 75 subject: 'Your Verification Code - Handcraft Marketplace', 74 76 html: ` 75 <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; background: linear-gradient(135deg, #4169E1 0%, #FF69B4 100%); color: white; padding: 20px; border-radius: 10px;">76 <h2 style="text-align: center;">🎨 Handcraft Marketplace</h2>77 <div style="background-color: white; color: #333; padding: 20px; border-radius: 8px; margin: 20px 0;">78 <h3 style="color: #4169E1;">Account Verification</h3>79 <p>Your verification code is:</p>80 <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; text-align: center; font-size: 24px; font-weight: bold; letter-spacing: 5px; margin: 20px 0; color: #4169E1;">81 ${code}82 </div>83 <p style="color: #e74c3c; font-weight: bold;">⚠️ This code will expire in 30 seconds</p>84 <p style="color: #666; font-size: 12px;">If you didn't request this verification, please ignore this email.</p>85 </div>86 </div>`77 <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; background: linear-gradient(135deg, #4169E1 0%, #FF69B4 100%); color: white; padding: 20px; border-radius: 10px;"> 78 <h2 style="text-align: center;">🎨 Handcraft Marketplace</h2> 79 <div style="background-color: white; color: #333; padding: 20px; border-radius: 8px; margin: 20px 0;"> 80 <h3 style="color: #4169E1;">Account Verification</h3> 81 <p>Your verification code is:</p> 82 <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; text-align: center; font-size: 24px; font-weight: bold; letter-spacing: 5px; margin: 20px 0; color: #4169E1;"> 83 ${code} 84 </div> 85 <p style="color: #e74c3c; font-weight: bold;">⚠️ This code will expire in 30 seconds</p> 86 <p style="color: #666; font-size: 12px;">If you didn't request this verification, please ignore this email.</p> 87 </div> 88 </div>` 87 89 }; 88 90 … … 104 106 subject: 'Your 2FA Code - Handcraft Marketplace', 105 107 html: ` 106 <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; background: linear-gradient(135deg, #4169E1 0%, #FF69B4 100%); color: white; padding: 20px; border-radius: 10px;">107 <h2 style="text-align: center;">🎨 Handcraft Marketplace</h2>108 <div style="background-color: white; color: #333; padding: 20px; border-radius: 8px; margin: 20px 0;">109 <h3 style="color: #4169E1;">Two-Factor Authentication</h3>110 <p>Your login verification code is:</p>111 <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; text-align: center; font-size: 24px; font-weight: bold; letter-spacing: 5px; margin: 20px 0; color: #4169E1;">112 ${code}113 </div>114 <p style="color: #e74c3c; font-weight: bold;">⚠️ This code will expire in 30 seconds</p>115 <p style="color: #666; font-size: 12px;">If you're not trying to login, please secure your account immediately.</p>116 </div>117 </div>`108 <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; background: linear-gradient(135deg, #4169E1 0%, #FF69B4 100%); color: white; padding: 20px; border-radius: 10px;"> 109 <h2 style="text-align: center;">🎨 Handcraft Marketplace</h2> 110 <div style="background-color: white; color: #333; padding: 20px; border-radius: 8px; margin: 20px 0;"> 111 <h3 style="color: #4169E1;">Two-Factor Authentication</h3> 112 <p>Your login verification code is:</p> 113 <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; text-align: center; font-size: 24px; font-weight: bold; letter-spacing: 5px; margin: 20px 0; color: #4169E1;"> 114 ${code} 115 </div> 116 <p style="color: #e74c3c; font-weight: bold;">⚠️ This code will expire in 30 seconds</p> 117 <p style="color: #666; font-size: 12px;">If you're not trying to login, please secure your account immediately.</p> 118 </div> 119 </div>` 118 120 }; 119 121 … … 135 137 subject: 'Store Registration Verification - Handcraft Marketplace', 136 138 html: ` 137 <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; background: linear-gradient(135deg, #4169E1 0%, #FF69B4 100%); color: white; padding: 20px; border-radius: 10px;">138 <h2 style="text-align: center;">🎨 Handcraft Marketplace</h2>139 <div style="background-color: white; color: #333; padding: 20px; border-radius: 8px; margin: 20px 0;">140 <h3 style="color: #4169E1;">Store Registration Verification</h3>141 <p>Thank you for registering your store "<strong>${storeName}</strong>" on Handcraft Marketplace!</p>142 <p>Your verification code is:</p>143 <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; text-align: center; font-size: 24px; font-weight: bold; letter-spacing: 5px; margin: 20px 0; color: #4169E1;">144 ${code}145 </div>146 <p style="color: #e74c3c; font-weight: bold;">⚠️ This code will expire in 30 seconds</p>147 <p style="color: #666; font-size: 12px;">If you didn't request this verification, please ignore this email.</p>148 </div>149 </div>`139 <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; background: linear-gradient(135deg, #4169E1 0%, #FF69B4 100%); color: white; padding: 20px; border-radius: 10px;"> 140 <h2 style="text-align: center;">🎨 Handcraft Marketplace</h2> 141 <div style="background-color: white; color: #333; padding: 20px; border-radius: 8px; margin: 20px 0;"> 142 <h3 style="color: #4169E1;">Store Registration Verification</h3> 143 <p>Thank you for registering your store "<strong>${storeName}</strong>" on Handcraft Marketplace!</p> 144 <p>Your verification code is:</p> 145 <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; text-align: center; font-size: 24px; font-weight: bold; letter-spacing: 5px; margin: 20px 0; color: #4169E1;"> 146 ${code} 147 </div> 148 <p style="color: #e74c3c; font-weight: bold;">⚠️ This code will expire in 30 seconds</p> 149 <p style="color: #666; font-size: 12px;">If you didn't request this verification, please ignore this email.</p> 150 </div> 151 </div>` 150 152 }; 151 153 … … 350 352 351 353 try { 352 // Check if all tables exist 353 const checkTablesQuery = ` 354 SELECT table_name 355 FROM information_schema.tables 356 WHERE table_schema = 'public' 357 `; 358 354 // For SQLite, we need to use a different approach to check tables 359 355 const result = await new Promise((resolve, reject) => { 360 database.database.all(checkTablesQuery, [], (err, rows) => { 361 if (err) reject(err); 362 else resolve(rows || []); 363 }); 364 }); 365 366 const existingTables = result.map(row => row.table_name); 356 database.database.all( 357 "SELECT name FROM sqlite_master WHERE type='table'", 358 [], 359 (err, rows) => { 360 if (err) reject(err); 361 else resolve(rows || []); 362 } 363 ); 364 }); 365 366 const existingTables = result.map(row => row.name); 367 367 const missingTables = requiredTables.filter(table => !existingTables.includes(table)); 368 368 … … 409 409 // Drop in reverse order of creation (respect foreign keys) 410 410 const dropQueries = [ 411 'DROP TABLE IF EXISTS user_roles CASCADE',412 'DROP TABLE IF EXISTS roles CASCADE',413 'DROP TABLE IF EXISTS delivery_address CASCADE',414 'DROP TABLE IF EXISTS image CASCADE',415 'DROP TABLE IF EXISTS color CASCADE',416 'DROP TABLE IF EXISTS audit_log CASCADE',417 'DROP TABLE IF EXISTS report CASCADE',418 'DROP TABLE IF EXISTS refund CASCADE',419 'DROP TABLE IF EXISTS request CASCADE',420 'DROP TABLE IF EXISTS review CASCADE',421 'DROP TABLE IF EXISTS order_items CASCADE',422 'DROP TABLE IF EXISTS "order" CASCADE',423 'DROP TABLE IF EXISTS permissions CASCADE',424 'DROP TABLE IF EXISTS works_in_store CASCADE',425 'DROP TABLE IF EXISTS employees CASCADE',426 'DROP TABLE IF EXISTS boss CASCADE',427 'DROP TABLE IF EXISTS product CASCADE',428 'DROP TABLE IF EXISTS personal CASCADE',429 'DROP TABLE IF EXISTS users CASCADE',430 'DROP TABLE IF EXISTS category CASCADE',431 'DROP TABLE IF EXISTS store CASCADE',432 'DROP TABLE IF EXISTS client CASCADE'411 'DROP TABLE IF EXISTS user_roles', 412 'DROP TABLE IF EXISTS roles', 413 'DROP TABLE IF EXISTS delivery_address', 414 'DROP TABLE IF EXISTS image', 415 'DROP TABLE IF EXISTS color', 416 'DROP TABLE IF EXISTS audit_log', 417 'DROP TABLE IF EXISTS report', 418 'DROP TABLE IF EXISTS refund', 419 'DROP TABLE IF EXISTS request', 420 'DROP TABLE IF EXISTS review', 421 'DROP TABLE IF EXISTS order_items', 422 'DROP TABLE IF EXISTS "order"', 423 'DROP TABLE IF EXISTS permissions', 424 'DROP TABLE IF EXISTS works_in_store', 425 'DROP TABLE IF EXISTS employees', 426 'DROP TABLE IF EXISTS boss', 427 'DROP TABLE IF EXISTS product', 428 'DROP TABLE IF EXISTS personal', 429 'DROP TABLE IF EXISTS users', 430 'DROP TABLE IF EXISTS category', 431 'DROP TABLE IF EXISTS store', 432 'DROP TABLE IF EXISTS client' 433 433 ]; 434 434 … … 463 463 // Client table (SERIAL ID starting from 1000) 464 464 `CREATE TABLE IF NOT EXISTS client ( 465 client_id SERIAL PRIMARY KEY,466 first_name VARCHAR(100) NOT NULL,467 last_name VARCHAR(100) NOT NULL,468 email VARCHAR(255) UNIQUE NOT NULL,469 password VARCHAR(255) NOT NULL,470 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP471 )`,465 client_id INTEGER PRIMARY KEY AUTOINCREMENT, 466 first_name VARCHAR(100) NOT NULL, 467 last_name VARCHAR(100) NOT NULL, 468 email VARCHAR(255) UNIQUE NOT NULL, 469 password VARCHAR(255) NOT NULL, 470 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 471 )`, 472 472 473 473 // Store table (VARCHAR ID) 474 474 `CREATE TABLE IF NOT EXISTS store ( 475 store_id VARCHAR(10) PRIMARY KEY,476 name VARCHAR(255) NOT NULL,477 date_of_founding DATE NOT NULL,478 physical_address TEXT NOT NULL,479 store_email VARCHAR(255) UNIQUE NOT NULL,480 rating DECIMAL(3,2) DEFAULT 0.0481 )`,475 store_id VARCHAR(10) PRIMARY KEY, 476 name VARCHAR(255) NOT NULL, 477 date_of_founding DATE NOT NULL, 478 physical_address TEXT NOT NULL, 479 store_email VARCHAR(255) UNIQUE NOT NULL, 480 rating DECIMAL(3,2) DEFAULT 0.0 481 )`, 482 482 483 483 // Category table (SERIAL ID starting from 1) 484 484 `CREATE TABLE IF NOT EXISTS category ( 485 category_id SERIAL PRIMARY KEY,486 name VARCHAR(100) NOT NULL,487 description TEXT,488 parent_category_id INTEGER REFERENCES category(category_id) ON DELETE SET NULL489 )`,485 category_id INTEGER PRIMARY KEY AUTOINCREMENT, 486 name VARCHAR(100) NOT NULL, 487 description TEXT, 488 parent_category_id INTEGER REFERENCES category(category_id) ON DELETE SET NULL 489 )`, 490 490 491 491 // Users table (VARCHAR ID) 492 492 `CREATE TABLE IF NOT EXISTS users ( 493 id VARCHAR(50) PRIMARY KEY,494 username VARCHAR(100) UNIQUE NOT NULL,495 email VARCHAR(255) UNIQUE NOT NULL,496 password VARCHAR(255) NOT NULL,497 user_type VARCHAR(50) NOT NULL,498 force_password_change INTEGER DEFAULT 0,499 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP500 )`,493 id VARCHAR(50) PRIMARY KEY, 494 username VARCHAR(100) UNIQUE NOT NULL, 495 email VARCHAR(255) UNIQUE NOT NULL, 496 password VARCHAR(255) NOT NULL, 497 user_type VARCHAR(50) NOT NULL, 498 force_password_change INTEGER DEFAULT 0, 499 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 500 )`, 501 501 502 502 // Personal table (VARCHAR ID - format: storeId(3) + '001' for owner, storeId(3) + employeeNum(3) for employees) 503 503 `CREATE TABLE IF NOT EXISTS personal ( 504 id VARCHAR(10) PRIMARY KEY,505 first_name VARCHAR(100) NOT NULL,506 last_name VARCHAR(100) NOT NULL,507 ssn VARCHAR(13) UNIQUE NOT NULL,508 email VARCHAR(255) UNIQUE NOT NULL,509 password VARCHAR(255) NOT NULL,510 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP511 )`,504 id VARCHAR(10) PRIMARY KEY, 505 first_name VARCHAR(100) NOT NULL, 506 last_name VARCHAR(100) NOT NULL, 507 ssn VARCHAR(13) UNIQUE NOT NULL, 508 email VARCHAR(255) UNIQUE NOT NULL, 509 password VARCHAR(255) NOT NULL, 510 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 511 )`, 512 512 513 513 // Product table (VARCHAR ID) 514 514 `CREATE TABLE IF NOT EXISTS product ( 515 id VARCHAR(50) PRIMARY KEY,516 code VARCHAR(20) UNIQUE NOT NULL,517 description TEXT NOT NULL,518 price DECIMAL(10,2) NOT NULL,519 availability INTEGER NOT NULL DEFAULT 0,520 weight DECIMAL(10,2),521 dimensions VARCHAR(50),522 production_time INTEGER,523 category_id INTEGER REFERENCES category(category_id) ON DELETE SET NULL,524 store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE,525 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP526 )`,515 id VARCHAR(50) PRIMARY KEY, 516 code VARCHAR(20) UNIQUE NOT NULL, 517 description TEXT NOT NULL, 518 price DECIMAL(10,2) NOT NULL, 519 availability INTEGER NOT NULL DEFAULT 0, 520 weight DECIMAL(10,2), 521 dimensions VARCHAR(50), 522 production_time INTEGER, 523 category_id INTEGER REFERENCES category(category_id) ON DELETE SET NULL, 524 store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE, 525 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 526 )`, 527 527 528 528 // Boss table (VARCHAR ID - references personal.id) 529 529 `CREATE TABLE IF NOT EXISTS boss ( 530 boss_id VARCHAR(10) PRIMARY KEY REFERENCES personal(id) ON DELETE CASCADE,531 signature TEXT NOT NULL,532 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP533 )`,530 boss_id VARCHAR(10) PRIMARY KEY REFERENCES personal(id) ON DELETE CASCADE, 531 signature TEXT NOT NULL, 532 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 533 )`, 534 534 535 535 // Employees table (VARCHAR ID - references personal.id) 536 536 `CREATE TABLE IF NOT EXISTS employees ( 537 employee_id VARCHAR(10) PRIMARY KEY REFERENCES personal(id) ON DELETE CASCADE,538 date_of_hire DATE NOT NULL,539 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP540 )`,537 employee_id VARCHAR(10) PRIMARY KEY REFERENCES personal(id) ON DELETE CASCADE, 538 date_of_hire DATE NOT NULL, 539 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 540 )`, 541 541 542 542 // Works_in_store table (junction) 543 543 `CREATE TABLE IF NOT EXISTS works_in_store ( 544 personal_id VARCHAR(10) REFERENCES personal(id) ON DELETE CASCADE,545 store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE,546 PRIMARY KEY (personal_id, store_id)547 )`,544 personal_id VARCHAR(10) REFERENCES personal(id) ON DELETE CASCADE, 545 store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE, 546 PRIMARY KEY (personal_id, store_id) 547 )`, 548 548 549 549 // Permissions table 550 550 `CREATE TABLE IF NOT EXISTS permissions ( 551 permission_id SERIAL PRIMARY KEY,552 personal_id VARCHAR(10) REFERENCES personal(id) ON DELETE CASCADE,553 type VARCHAR(50) NOT NULL,554 authorisation TEXT,555 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP556 )`,551 permission_id INTEGER PRIMARY KEY AUTOINCREMENT, 552 personal_id VARCHAR(10) REFERENCES personal(id) ON DELETE CASCADE, 553 type VARCHAR(50) NOT NULL, 554 authorisation TEXT, 555 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 556 )`, 557 557 558 558 // Order table (VARCHAR ID) 559 559 `CREATE TABLE IF NOT EXISTS "order" ( 560 order_num VARCHAR(20) PRIMARY KEY,561 client_id INTEGER REFERENCES client(client_id) ON DELETE SET NULL,562 order_date TIMESTAMP NOT NULL,563 quantity INTEGER NOT NULL,564 payment_method VARCHAR(50) NOT NULL,565 discount DECIMAL(10,2) DEFAULT 0,566 delivery_address TEXT NOT NULL,567 store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE SET NULL,568 status VARCHAR(50) DEFAULT 'pending',569 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP570 )`,560 order_num VARCHAR(20) PRIMARY KEY, 561 client_id INTEGER REFERENCES client(client_id) ON DELETE SET NULL, 562 order_date TIMESTAMP NOT NULL, 563 quantity INTEGER NOT NULL, 564 payment_method VARCHAR(50) NOT NULL, 565 discount DECIMAL(10,2) DEFAULT 0, 566 delivery_address TEXT NOT NULL, 567 store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE SET NULL, 568 status VARCHAR(50) DEFAULT 'pending', 569 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 570 )`, 571 571 572 572 // Order_items table 573 573 `CREATE TABLE IF NOT EXISTS order_items ( 574 item_id SERIAL PRIMARY KEY,575 order_num VARCHAR(20) REFERENCES "order"(order_num) ON DELETE CASCADE,576 product_code VARCHAR(20) REFERENCES product(code) ON DELETE SET NULL,577 quantity INTEGER NOT NULL,578 price DECIMAL(10,2) NOT NULL,579 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP580 )`,574 item_id INTEGER PRIMARY KEY AUTOINCREMENT, 575 order_num VARCHAR(20) REFERENCES "order"(order_num) ON DELETE CASCADE, 576 product_code VARCHAR(20) REFERENCES product(code) ON DELETE SET NULL, 577 quantity INTEGER NOT NULL, 578 price DECIMAL(10,2) NOT NULL, 579 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 580 )`, 581 581 582 582 // Review table (VARCHAR ID) 583 583 `CREATE TABLE IF NOT EXISTS review ( 584 review_id VARCHAR(20) PRIMARY KEY,585 client_id INTEGER REFERENCES client(client_id) ON DELETE SET NULL,586 product_code VARCHAR(20) REFERENCES product(code) ON DELETE CASCADE,587 rating INTEGER NOT NULL CHECK (rating >= 1 AND rating <= 5),588 comment TEXT,589 review_date TIMESTAMP NOT NULL,590 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP591 )`,584 review_id VARCHAR(20) PRIMARY KEY, 585 client_id INTEGER REFERENCES client(client_id) ON DELETE SET NULL, 586 product_code VARCHAR(20) REFERENCES product(code) ON DELETE CASCADE, 587 rating INTEGER NOT NULL CHECK (rating >= 1 AND rating <= 5), 588 comment TEXT, 589 review_date TIMESTAMP NOT NULL, 590 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 591 )`, 592 592 593 593 // Request table (VARCHAR ID) 594 594 `CREATE TABLE IF NOT EXISTS request ( 595 request_num VARCHAR(50) PRIMARY KEY,596 date_and_time TIMESTAMP NOT NULL,597 problem TEXT NOT NULL,598 client_id INTEGER REFERENCES client(client_id) ON DELETE SET NULL,599 store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE,600 status VARCHAR(50) DEFAULT 'pending',601 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP602 )`,595 request_num VARCHAR(50) PRIMARY KEY, 596 date_and_time TIMESTAMP NOT NULL, 597 problem TEXT NOT NULL, 598 client_id INTEGER REFERENCES client(client_id) ON DELETE SET NULL, 599 store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE, 600 status VARCHAR(50) DEFAULT 'pending', 601 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 602 )`, 603 603 604 604 // Refund table (VARCHAR ID) 605 605 `CREATE TABLE IF NOT EXISTS refund ( 606 refund_id VARCHAR(50) PRIMARY KEY,607 order_num VARCHAR(20) REFERENCES "order"(order_num) ON DELETE CASCADE,608 amount DECIMAL(10,2) NOT NULL,609 reason TEXT NOT NULL,610 status VARCHAR(50) DEFAULT 'pending',611 request_date TIMESTAMP NOT NULL,612 processed_date TIMESTAMP,613 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP614 )`,606 refund_id VARCHAR(50) PRIMARY KEY, 607 order_num VARCHAR(20) REFERENCES "order"(order_num) ON DELETE CASCADE, 608 amount DECIMAL(10,2) NOT NULL, 609 reason TEXT NOT NULL, 610 status VARCHAR(50) DEFAULT 'pending', 611 request_date TIMESTAMP NOT NULL, 612 processed_date TIMESTAMP, 613 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 614 )`, 615 615 616 616 // Report table (VARCHAR ID) 617 617 `CREATE TABLE IF NOT EXISTS report ( 618 id VARCHAR(50) PRIMARY KEY,619 store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE,620 period VARCHAR(50) NOT NULL,621 start_date DATE NOT NULL,622 end_date DATE NOT NULL,623 type VARCHAR(50) NOT NULL,624 generated_by VARCHAR(10) REFERENCES personal(id) ON DELETE SET NULL,625 generated_at TIMESTAMP NOT NULL,626 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP627 )`,618 id VARCHAR(50) PRIMARY KEY, 619 store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE, 620 period VARCHAR(50) NOT NULL, 621 start_date DATE NOT NULL, 622 end_date DATE NOT NULL, 623 type VARCHAR(50) NOT NULL, 624 generated_by VARCHAR(10) REFERENCES personal(id) ON DELETE SET NULL, 625 generated_at TIMESTAMP NOT NULL, 626 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 627 )`, 628 628 629 629 // Audit_log table (SERIAL ID) 630 630 `CREATE TABLE IF NOT EXISTS audit_log ( 631 log_id SERIAL PRIMARY KEY,632 user_id VARCHAR(50),633 action VARCHAR(100) NOT NULL,634 resource_type VARCHAR(50),635 resource_id VARCHAR(50),636 details TEXT,637 ip_address VARCHAR(45),638 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP639 )`,631 log_id INTEGER PRIMARY KEY AUTOINCREMENT, 632 user_id VARCHAR(50), 633 action VARCHAR(100) NOT NULL, 634 resource_type VARCHAR(50), 635 resource_id VARCHAR(50), 636 details TEXT, 637 ip_address VARCHAR(45), 638 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 639 )`, 640 640 641 641 // Color table (SERIAL ID) 642 642 `CREATE TABLE IF NOT EXISTS color ( 643 color_id SERIAL PRIMARY KEY,644 name VARCHAR(50) NOT NULL,645 hex_code VARCHAR(7) NOT NULL,646 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP647 )`,643 color_id INTEGER PRIMARY KEY AUTOINCREMENT, 644 name VARCHAR(50) NOT NULL, 645 hex_code VARCHAR(7) NOT NULL, 646 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 647 )`, 648 648 649 649 // Image table (SERIAL ID) 650 650 `CREATE TABLE IF NOT EXISTS image ( 651 image_id SERIAL PRIMARY KEY,652 product_code VARCHAR(20) REFERENCES product(code) ON DELETE CASCADE,653 image_url TEXT NOT NULL,654 is_primary BOOLEAN DEFAULT FALSE,655 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP656 )`,651 image_id INTEGER PRIMARY KEY AUTOINCREMENT, 652 product_code VARCHAR(20) REFERENCES product(code) ON DELETE CASCADE, 653 image_url TEXT NOT NULL, 654 is_primary BOOLEAN DEFAULT FALSE, 655 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 656 )`, 657 657 658 658 // Delivery_address table (SERIAL ID) 659 659 `CREATE TABLE IF NOT EXISTS delivery_address ( 660 address_id SERIAL PRIMARY KEY,661 client_id INTEGER REFERENCES client(client_id) ON DELETE CASCADE,662 address TEXT NOT NULL,663 city VARCHAR(100) NOT NULL,664 postcode VARCHAR(20) NOT NULL,665 country VARCHAR(100) NOT NULL,666 is_default BOOLEAN DEFAULT FALSE,667 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP668 )`,660 address_id INTEGER PRIMARY KEY AUTOINCREMENT, 661 client_id INTEGER REFERENCES client(client_id) ON DELETE CASCADE, 662 address TEXT NOT NULL, 663 city VARCHAR(100) NOT NULL, 664 postcode VARCHAR(20) NOT NULL, 665 country VARCHAR(100) NOT NULL, 666 is_default BOOLEAN DEFAULT FALSE, 667 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 668 )`, 669 669 670 670 // Roles table (SERIAL ID) 671 671 `CREATE TABLE IF NOT EXISTS roles ( 672 role_id SERIAL PRIMARY KEY,673 name VARCHAR(50) UNIQUE NOT NULL,674 description TEXT,675 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP676 )`,672 role_id INTEGER PRIMARY KEY AUTOINCREMENT, 673 name VARCHAR(50) UNIQUE NOT NULL, 674 description TEXT, 675 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 676 )`, 677 677 678 678 // User_roles table (junction) 679 679 `CREATE TABLE IF NOT EXISTS user_roles ( 680 user_id VARCHAR(50) REFERENCES users(id) ON DELETE CASCADE,681 role_id INTEGER REFERENCES roles(role_id) ON DELETE CASCADE,682 PRIMARY KEY (user_id, role_id)683 )`680 user_id VARCHAR(50) REFERENCES users(id) ON DELETE CASCADE, 681 role_id INTEGER REFERENCES roles(role_id) ON DELETE CASCADE, 682 PRIMARY KEY (user_id, role_id) 683 )` 684 684 ]; 685 685 … … 766 766 console.log('📝 Inserting initial data...'); 767 767 768 // Insert General category (ID will be 1 due to SERIAL) 769 database.database.run( 770 `INSERT INTO category (name, description) 771 VALUES ('General', 'General products category') 772 ON CONFLICT DO NOTHING`, 773 [], 774 (err) => { 775 if (err) { 776 console.error('Error inserting General category:', err.message); 777 } 778 } 779 ); 768 // REMOVED: Category insertion - now handled by database.ensureGeneralCategory() 780 769 781 770 // Insert admin user … … 785 774 database.database.run( 786 775 `INSERT INTO users (id, username, email, password, user_type, force_password_change) 787 VALUES ($1, $2, $3, $4, $5, $6)788 ON CONFLICT DO NOTHING`,776 VALUES ($1, $2, $3, $4, $5, $6) 777 ON CONFLICT DO NOTHING`, 789 778 [adminId, 'admin', 'admin@handcraft.com', adminPassword, 'admin', 1], 790 779 (err) => { … … 811 800 database.database.run( 812 801 `INSERT INTO roles (name, description) 813 VALUES ($1, $2)814 ON CONFLICT DO NOTHING`,802 VALUES ($1, $2) 803 ON CONFLICT DO NOTHING`, 815 804 [role.name, role.description], 816 805 (err) => { … … 822 811 console.log('✅ Roles inserted'); 823 812 824 // Check ifGeneral category exists813 // Ensure General category exists 825 814 database.ensureGeneralCategory((err) => { 826 815 if (err) { 827 816 console.error('Error ensuring General category:', err.message); 828 817 } else { 829 console.log('✅ General category exists');818 console.log('✅ General category checked/created'); 830 819 } 831 820 resolve(); … … 925 914 body += chunk.toString(); 926 915 }); 916 927 917 req.on('end', () => { 928 918 const { username, email, password, userType, firstName, lastName } = JSON.parse(body); … … 989 979 console.log('✅ Verification email sent to:', email); 990 980 database.logAudit(null, 'REGISTER_ATTEMPT', 'user', null, `Registration attempt for ${email} as ${userType}`, ipAddress); 981 991 982 res.writeHead(200, { 'Content-Type': 'application/json' }); 992 983 res.end(JSON.stringify({ … … 1016 1007 body += chunk.toString(); 1017 1008 }); 1009 1018 1010 req.on('end', () => { 1019 1011 const formData = JSON.parse(body); … … 1182 1174 console.log('✅ Store registration email sent to:', formData.ownerEmail); 1183 1175 database.logAudit(null, 'STORE_REGISTER_ATTEMPT', 'store', null, `Store registration attempt: ${formData.storeName}`, ipAddress); 1176 1184 1177 res.writeHead(200, { 'Content-Type': 'application/json' }); 1185 1178 res.end(JSON.stringify({ … … 1214 1207 body += chunk.toString(); 1215 1208 }); 1209 1216 1210 req.on('end', () => { 1217 1211 const { firstName, lastName, email, password, address, city, postcode, country, isDefaultAddress } = JSON.parse(body); … … 1278 1272 console.log('✅ Verification email sent to:', email); 1279 1273 database.logAudit(null, 'CLIENT_REGISTER_ATTEMPT', 'client', null, `Client registration attempt for ${email}`, ipAddress); 1274 1280 1275 res.writeHead(200, { 'Content-Type': 'application/json' }); 1281 1276 res.end(JSON.stringify({ … … 1304 1299 body += chunk.toString(); 1305 1300 }); 1301 1306 1302 req.on('end', () => { 1307 1303 const { email } = JSON.parse(body); … … 1438 1434 body += chunk.toString(); 1439 1435 }); 1436 1440 1437 req.on('end', () => { 1441 1438 const { email, code } = JSON.parse(body); … … 1668 1665 } else { 1669 1666 const userId = 'user_' + Date.now().toString().slice(-8); 1667 1670 1668 database.createUser(userId, tempUserData.username, tempUserData.email, tempUserData.password, tempUserData.userType, (err, userId) => { 1671 1669 if (err) { … … 1698 1696 body += chunk.toString(); 1699 1697 }); 1698 1700 1699 req.on('end', () => { 1701 1700 const { email, password } = JSON.parse(body); 1701 1702 1702 console.log(`🔍 Login attempt for email: ${email}`); 1703 1703 … … 1710 1710 if (client) { 1711 1711 console.log(`🔍 Found client: ${client.email}`); 1712 1712 1713 if (!client.password) { 1713 1714 console.log('❌ Client has no password set'); … … 1732 1733 const sessionId = generateSessionId(); 1733 1734 const clientId = client.client_ID; 1735 1734 1736 sessions.set(sessionId, `client_${clientId}`); 1735 1737 1736 1738 console.log(`✅ Client login successful. Session: ${sessionId}, User: client_${clientId}`); 1739 1737 1740 database.logAudit(clientId, 'LOGIN_SUCCESS', 'auth', 1738 1741 typeof clientId === 'string' ? clientId : String(clientId), … … 1743 1746 'Set-Cookie': `sessionId=${sessionId}; HttpOnly; Path=/; Max-Age=3600; SameSite=Strict` 1744 1747 }); 1745 1746 1748 res.end(JSON.stringify({ 1747 1749 success: true, … … 1768 1770 if (personal) { 1769 1771 console.log(`🔍 Found personal user: ${personal.email}`); 1772 1770 1773 if (!personal.password) { 1771 1774 console.log('❌ Personal has no password set'); … … 1803 1806 1804 1807 const twoFACode = generateVerificationCode(); 1808 1805 1809 verificationCodes.set(personal.email, { 1806 1810 code: twoFACode, … … 1862 1866 1863 1867 const twoFACode = generateVerificationCode(); 1868 1864 1869 verificationCodes.set(personal.email, { 1865 1870 code: twoFACode, … … 1923 1928 1924 1929 const twoFACode = generateVerificationCode(); 1930 1925 1931 verificationCodes.set(userByUsername.email, { 1926 1932 code: twoFACode, … … 1973 1979 1974 1980 const twoFACode = generateVerificationCode(); 1981 1975 1982 verificationCodes.set(user.email, { 1976 1983 code: twoFACode, … … 2038 2045 body += chunk.toString(); 2039 2046 }); 2047 2040 2048 req.on('end', () => { 2041 2049 const { email } = JSON.parse(body); … … 2060 2068 2061 2069 const newTwoFACode = generateVerificationCode(); 2070 2062 2071 verificationCodes.set(userByUsername.email, { 2063 2072 code: newTwoFACode, … … 2095 2104 2096 2105 const newTwoFACode = generateVerificationCode(); 2106 2097 2107 verificationCodes.set(user.email, { 2098 2108 code: newTwoFACode, … … 2135 2145 body += chunk.toString(); 2136 2146 }); 2147 2137 2148 req.on('end', () => { 2138 2149 const { email, code } = JSON.parse(body); … … 2173 2184 'Set-Cookie': `sessionId=${tempSessionId}; HttpOnly; Path=/; Max-Age=3600; SameSite=Strict` 2174 2185 }); 2175 2176 2186 res.end(JSON.stringify({ 2177 2187 success: true, … … 2203 2213 // Determine redirect based on user type 2204 2214 let redirectTo = ''; 2215 2205 2216 switch(verificationData.userType) { 2206 2217 case 'client': … … 2226 2237 'Set-Cookie': `sessionId=${sessionId}; HttpOnly; Path=/; Max-Age=3600; SameSite=Strict` 2227 2238 }); 2228 2229 2239 res.end(JSON.stringify({ 2230 2240 success: true, … … 2279 2289 if (userIdStr.startsWith('client_')) { 2280 2290 const clientId = parseInt(userIdStr.replace('client_', '')); 2291 2281 2292 database.getClientById(clientId, (err, client) => { 2282 2293 if (err || !client) { … … 2298 2309 }); 2299 2310 } 2311 2300 2312 else if (userIdStr.startsWith('personal_')) { 2301 2313 const personalId = userIdStr.replace('personal_', ''); 2314 2302 2315 database.getPersonalById(personalId, (err, personal) => { 2303 2316 if (err || !personal) { … … 2318 2331 database.database.all( 2319 2332 `SELECT s.* FROM store s 2320 JOIN works_in_store w ON s.store_id = w.store_id2321 WHERE w.personal_id = $1`,2333 JOIN works_in_store w ON s.store_id = w.store_id 2334 WHERE w.personal_id = $1`, 2322 2335 [personalId], 2323 2336 (err, stores) => { … … 2353 2366 database.database.all( 2354 2367 `SELECT s.* FROM store s 2355 JOIN works_in_store w ON s.store_id = w.store_id2356 WHERE w.personal_id = $1`,2368 JOIN works_in_store w ON s.store_id = w.store_id 2369 WHERE w.personal_id = $1`, 2357 2370 [personalId], 2358 2371 (err, stores) => { … … 2445 2458 body += chunk.toString(); 2446 2459 }); 2460 2447 2461 req.on('end', () => { 2448 2462 const categoryData = JSON.parse(body); … … 2470 2484 } else { 2471 2485 database.logAudit(personalId, 'CATEGORY_CREATED', 'category', category.id.toString(), `New category created: ${category.name}`, ipAddress); 2486 2472 2487 res.writeHead(200, { 'Content-Type': 'application/json' }); 2473 2488 res.end(JSON.stringify({ … … 2526 2541 body += chunk.toString(); 2527 2542 }); 2543 2528 2544 req.on('end', () => { 2529 2545 const orderData = JSON.parse(body); 2530 2531 2546 const userIdStr = String(userId); 2532 2547 … … 2601 2616 if (userIdStr.startsWith('client_')) { 2602 2617 const clientId = parseInt(userIdStr.replace('client_', '')); 2618 2603 2619 database.getOrdersByClient(clientId, (err, orders) => { 2604 2620 if (err) { … … 2623 2639 body += chunk.toString(); 2624 2640 }); 2641 2625 2642 req.on('end', () => { 2626 2643 const reviewData = JSON.parse(body); 2627 2628 2644 const userIdStr = String(userId); 2629 2645 2630 2646 if (userIdStr.startsWith('client_')) { 2631 2647 const clientId = parseInt(userIdStr.replace('client_', '')); 2648 2632 2649 reviewData.client_id = clientId; 2633 2650 … … 2656 2673 body += chunk.toString(); 2657 2674 }); 2675 2658 2676 req.on('end', () => { 2659 2677 const requestData = JSON.parse(body); 2660 2661 2678 const userIdStr = String(userId); 2662 2679 … … 2726 2743 body += chunk.toString(); 2727 2744 }); 2745 2728 2746 req.on('end', () => { 2729 2747 const refundData = JSON.parse(body); 2730 2731 2748 const userIdStr = String(userId); 2732 2749 … … 2745 2762 2746 2763 const storeId = result[0].store_id; 2747 2748 2764 const now = new Date(); 2749 2765 const month = (now.getMonth() + 1).toString().padStart(2, '0'); … … 2797 2813 body += chunk.toString(); 2798 2814 }); 2815 2799 2816 req.on('end', () => { 2800 2817 const productData = JSON.parse(body); … … 2828 2845 } 2829 2846 2847 // FIXED: Changed SQL syntax from SUBSTRING(code FROM 4) to SUBSTR(code, 4) for SQLite compatibility 2830 2848 database.database.get( 2831 'SELECT MAX(CAST(SUBSTR ING(code FROM4) AS INTEGER)) as max_product_num FROM product WHERE store_id = $1',2849 'SELECT MAX(CAST(SUBSTR(code, 4) AS INTEGER)) as max_product_num FROM product WHERE store_id = $1', 2832 2850 [storeId], 2833 2851 (err, result) => { … … 2863 2881 } else { 2864 2882 database.logAudit(personalId, 'PRODUCT_ADDED', 'product', productId.toString(), 'New product added', ipAddress); 2883 2865 2884 res.writeHead(200, { 'Content-Type': 'application/json' }); 2866 2885 res.end(JSON.stringify({ … … 2888 2907 body += chunk.toString(); 2889 2908 }); 2909 2890 2910 req.on('end', () => { 2891 2911 const productData = JSON.parse(body); … … 2996 3016 body += chunk.toString(); 2997 3017 }); 3018 2998 3019 req.on('end', () => { 2999 3020 const { currentPassword, newPassword, confirmPassword } = JSON.parse(body); … … 3089 3110 body += chunk.toString(); 3090 3111 }); 3112 3091 3113 req.on('end', () => { 3092 3114 const { firstName, lastName, ssn, email, password, storeId, dateOfHire } = JSON.parse(body); … … 3300 3322 body += chunk.toString(); 3301 3323 }); 3324 3302 3325 req.on('end', () => { 3303 3326 const { employeeId, storeId } = JSON.parse(body); … … 3451 3474 body += chunk.toString(); 3452 3475 }); 3476 3453 3477 req.on('end', () => { 3454 3478 const { employeeId, storeId, status } = JSON.parse(body); … … 3550 3574 body += chunk.toString(); 3551 3575 }); 3576 3552 3577 req.on('end', () => { 3553 3578 const { employeeId, storeId, firstName, lastName, email } = JSON.parse(body); … … 3966 3991 body += chunk.toString(); 3967 3992 }); 3993 3968 3994 req.on('end', () => { 3969 3995 const { productCode, storeId } = JSON.parse(body); … … 4035 4061 body += chunk.toString(); 4036 4062 }); 4063 4037 4064 req.on('end', () => { 4038 4065 const { storeId, period, startDate, endDate, type } = JSON.parse(body);
Note:
See TracChangeset
for help on using the changeset viewer.
