updated structure
This commit is contained in:
@@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import pymysql
|
||||
|
||||
try:
|
||||
# Connect to the database
|
||||
conn = pymysql.connect(
|
||||
host='localhost',
|
||||
database='trasabilitate',
|
||||
user='trasabilitate',
|
||||
password='Initial01!',
|
||||
cursorclass=pymysql.cursors.DictCursor
|
||||
)
|
||||
|
||||
with conn.cursor() as cursor:
|
||||
cursor.execute("SELECT id, username, role, modules FROM users")
|
||||
users = cursor.fetchall()
|
||||
|
||||
print("Current users in database:")
|
||||
print("-" * 50)
|
||||
for user in users:
|
||||
print(f"ID: {user['id']}")
|
||||
print(f"Username: {user['username']}")
|
||||
print(f"Role: {user['role']}")
|
||||
print(f"Modules: {user['modules']}")
|
||||
print("-" * 30)
|
||||
|
||||
finally:
|
||||
conn.close()
|
||||
@@ -1,263 +0,0 @@
|
||||
// Background service worker for Chrome extension
|
||||
console.log('Quality Recticel Print Helper - Background script loaded');
|
||||
|
||||
// Listen for messages from content script
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
console.log('Background received message:', request);
|
||||
|
||||
if (request.action === 'print_label') {
|
||||
handlePrintLabel(request.data, sendResponse);
|
||||
return true; // Keep message channel open for async response
|
||||
}
|
||||
|
||||
if (request.action === 'fallback_print') {
|
||||
handleFallbackPrint(request.data, sendResponse);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (request.action === 'get_printers') {
|
||||
getPrinters(sendResponse);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (request.action === 'check_extension') {
|
||||
sendResponse({status: 'installed', version: chrome.runtime.getManifest().version});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// Function to handle label printing
|
||||
async function handlePrintLabel(printData, sendResponse) {
|
||||
try {
|
||||
console.log('Attempting to print label with data:', printData);
|
||||
|
||||
// Check if printing API is available
|
||||
if (!chrome.printing || !chrome.printing.getPrinters) {
|
||||
console.error('Chrome printing API not available - browser may be Brave, Edge, or older Chrome');
|
||||
sendResponse({
|
||||
success: false,
|
||||
error: 'Direct printing API not available in this browser. The extension works best in Google Chrome 85+. Using fallback method instead.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Get available printers
|
||||
const printers = await chrome.printing.getPrinters();
|
||||
console.log('Available printers:', printers);
|
||||
|
||||
if (printers.length === 0) {
|
||||
sendResponse({success: false, error: 'No printers found. Please ensure a printer is installed and set as default.'});
|
||||
return;
|
||||
}
|
||||
|
||||
// Find selected printer or use default/first available
|
||||
let selectedPrinter;
|
||||
if (printData.printerId && printData.printerId !== 'default') {
|
||||
selectedPrinter = printers.find(p => p.id === printData.printerId);
|
||||
}
|
||||
|
||||
if (!selectedPrinter) {
|
||||
selectedPrinter = printers.find(p => p.isDefault) || printers[0];
|
||||
}
|
||||
|
||||
console.log('Using printer:', selectedPrinter);
|
||||
|
||||
// Create print job
|
||||
const printJob = {
|
||||
printerId: selectedPrinter.id,
|
||||
ticket: {
|
||||
version: '1.0',
|
||||
print: {
|
||||
color: {
|
||||
type: 'STANDARD_MONOCHROME'
|
||||
},
|
||||
duplex: {
|
||||
type: 'NO_DUPLEX'
|
||||
},
|
||||
page_orientation: {
|
||||
type: 'PORTRAIT'
|
||||
},
|
||||
copies: {
|
||||
copies: 1
|
||||
},
|
||||
dpi: {
|
||||
horizontal_dpi: 300,
|
||||
vertical_dpi: 300
|
||||
},
|
||||
media_size: {
|
||||
width_microns: 210000, // A4 width
|
||||
height_microns: 297000 // A4 height
|
||||
},
|
||||
collate: {
|
||||
collate: false
|
||||
}
|
||||
}
|
||||
},
|
||||
documentBlob: new Blob([printData.html], {type: 'text/html'})
|
||||
};
|
||||
|
||||
// Submit print job
|
||||
const result = await chrome.printing.submitJob(printJob);
|
||||
console.log('Print job result:', result);
|
||||
|
||||
if (result.status === 'OK') {
|
||||
sendResponse({success: true, jobId: result.jobId});
|
||||
|
||||
// Store successful print in extension storage
|
||||
chrome.storage.local.set({
|
||||
lastPrint: {
|
||||
timestamp: Date.now(),
|
||||
jobId: result.jobId,
|
||||
printer: selectedPrinter.displayName
|
||||
}
|
||||
});
|
||||
} else {
|
||||
sendResponse({success: false, error: result.status});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Print error:', error);
|
||||
sendResponse({success: false, error: error.message});
|
||||
}
|
||||
}
|
||||
|
||||
// Function to get available printers
|
||||
async function getPrinters(sendResponse) {
|
||||
try {
|
||||
// Check if printing API is available
|
||||
if (!chrome.printing || !chrome.printing.getPrinters) {
|
||||
sendResponse({
|
||||
success: false,
|
||||
error: 'Direct printing API not available in this browser (works in Chrome only)'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const printers = await chrome.printing.getPrinters();
|
||||
sendResponse({success: true, printers: printers});
|
||||
} catch (error) {
|
||||
console.error('Error getting printers:', error);
|
||||
sendResponse({success: false, error: error.message});
|
||||
}
|
||||
}
|
||||
|
||||
// Extension installation/startup
|
||||
chrome.runtime.onInstalled.addListener((details) => {
|
||||
console.log('Quality Recticel Print Helper installed:', details);
|
||||
|
||||
// Set initial storage values
|
||||
chrome.storage.local.set({
|
||||
extensionVersion: chrome.runtime.getManifest().version,
|
||||
installDate: Date.now()
|
||||
});
|
||||
});
|
||||
|
||||
// Fallback print method using tabs API (works in Brave, Edge, Chrome)
|
||||
async function handleFallbackPrint(printData, sendResponse) {
|
||||
try {
|
||||
console.log('Using fallback print method for Brave/Edge/Chrome');
|
||||
|
||||
// Create enhanced HTML with better print styles
|
||||
const enhancedHTML = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Quality Recticel Label</title>
|
||||
<style>
|
||||
@page {
|
||||
margin: 10mm;
|
||||
size: A4;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
background: white;
|
||||
}
|
||||
.print-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.label-wrapper {
|
||||
transform: scale(1.5);
|
||||
transform-origin: center;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
@media print {
|
||||
body { padding: 0; margin: 0; }
|
||||
.print-container { min-height: auto; padding: 20px 0; }
|
||||
.no-print { display: none !important; }
|
||||
}
|
||||
.print-instructions {
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
z-index: 1000;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
// Auto-print after 1 second
|
||||
setTimeout(() => {
|
||||
window.print();
|
||||
// Auto-close after printing (or after 10 seconds)
|
||||
setTimeout(() => {
|
||||
window.close();
|
||||
}, 2000);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
// Handle print events
|
||||
window.onbeforeprint = function() {
|
||||
console.log('Print dialog opened');
|
||||
};
|
||||
|
||||
window.onafterprint = function() {
|
||||
console.log('Print dialog closed');
|
||||
setTimeout(() => {
|
||||
window.close();
|
||||
}, 500);
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="print-instructions no-print">
|
||||
🖨️ Printing will start automatically...<br>
|
||||
<small>If dialog doesn't appear, press Ctrl+P</small>
|
||||
</div>
|
||||
<div class="print-container">
|
||||
<div class="label-wrapper">
|
||||
${printData.html.replace(/<!DOCTYPE html>|<html>|<\/html>|<head>.*?<\/head>|<body>|<\/body>/gi, '')}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
// Create a new tab with the enhanced print content
|
||||
const tab = await chrome.tabs.create({
|
||||
url: 'data:text/html;charset=utf-8,' + encodeURIComponent(enhancedHTML),
|
||||
active: true // Make active so user can see the print dialog
|
||||
});
|
||||
|
||||
console.log('Created print tab:', tab.id);
|
||||
sendResponse({success: true, method: 'fallback_tab', tabId: tab.id});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Fallback print error:', error);
|
||||
sendResponse({success: false, error: 'Browser print fallback failed: ' + error.message});
|
||||
}
|
||||
}
|
||||
|
||||
// Keep service worker alive
|
||||
chrome.runtime.onConnect.addListener((port) => {
|
||||
console.log('Port connected:', port.name);
|
||||
});
|
||||
@@ -1,301 +0,0 @@
|
||||
// Content script for Quality Recticel Print Helper
|
||||
console.log('Quality Recticel Print Helper - Content script loaded');
|
||||
|
||||
// Check if we're on the print module page
|
||||
if (window.location.pathname.includes('print_module')) {
|
||||
console.log('Print module page detected, initializing extension features');
|
||||
|
||||
// Wait for DOM to be ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initializePrintExtension);
|
||||
} else {
|
||||
initializePrintExtension();
|
||||
}
|
||||
}
|
||||
|
||||
function initializePrintExtension() {
|
||||
console.log('Initializing print extension features');
|
||||
|
||||
// Add extension status indicator
|
||||
addExtensionStatusIndicator();
|
||||
|
||||
// Override the print button functionality
|
||||
overridePrintButton();
|
||||
|
||||
// Add printer selection dropdown
|
||||
addPrinterSelection();
|
||||
|
||||
// Check extension status
|
||||
checkExtensionStatus();
|
||||
}
|
||||
|
||||
function addExtensionStatusIndicator() {
|
||||
// Detect browser type
|
||||
const browserType = getBrowserType();
|
||||
|
||||
// Create status indicator element
|
||||
const statusIndicator = document.createElement('div');
|
||||
statusIndicator.id = 'extension-status';
|
||||
statusIndicator.style.cssText = `
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: ${browserType === 'chrome' ? '#28a745' : '#ffc107'};
|
||||
color: ${browserType === 'chrome' ? 'white' : 'black'};
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
z-index: 9999;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||
max-width: 250px;
|
||||
`;
|
||||
|
||||
if (browserType === 'chrome') {
|
||||
statusIndicator.textContent = '🖨️ Print Extension Active (Direct Print Available)';
|
||||
} else {
|
||||
statusIndicator.innerHTML = `🖨️ Print Extension Active<br><small>${browserType.toUpperCase()} - Browser Print Mode</small>`;
|
||||
}
|
||||
|
||||
document.body.appendChild(statusIndicator);
|
||||
|
||||
// Hide after 4 seconds (longer for non-Chrome browsers)
|
||||
setTimeout(() => {
|
||||
statusIndicator.style.opacity = '0';
|
||||
statusIndicator.style.transition = 'opacity 0.5s';
|
||||
setTimeout(() => statusIndicator.remove(), 500);
|
||||
}, browserType === 'chrome' ? 3000 : 5000);
|
||||
}
|
||||
|
||||
// Detect browser type
|
||||
function getBrowserType() {
|
||||
const userAgent = navigator.userAgent.toLowerCase();
|
||||
if (userAgent.includes('edg/')) return 'edge';
|
||||
if (userAgent.includes('brave')) return 'brave';
|
||||
if (userAgent.includes('chrome') && !userAgent.includes('edg/')) return 'chrome';
|
||||
return 'chromium';
|
||||
}
|
||||
|
||||
function overridePrintButton() {
|
||||
// Find the print button
|
||||
const printButton = document.getElementById('print-label-btn');
|
||||
|
||||
if (printButton) {
|
||||
console.log('Found print button, overriding functionality');
|
||||
|
||||
// Remove existing event listeners by cloning the element
|
||||
const newPrintButton = printButton.cloneNode(true);
|
||||
printButton.parentNode.replaceChild(newPrintButton, printButton);
|
||||
|
||||
// Add new event listener for extension printing
|
||||
newPrintButton.addEventListener('click', handleExtensionPrint);
|
||||
|
||||
// Update button text based on browser capabilities
|
||||
const browserType = getBrowserType();
|
||||
if (browserType === 'chrome') {
|
||||
newPrintButton.innerHTML = '🖨️ Print Direct';
|
||||
newPrintButton.title = 'Print directly to default printer (Chrome Extension)';
|
||||
} else {
|
||||
newPrintButton.innerHTML = '🖨️ Print Enhanced';
|
||||
newPrintButton.title = `Enhanced printing for ${browserType.toUpperCase()} browser - Opens optimized print dialog`;
|
||||
}
|
||||
|
||||
console.log('Print button override complete');
|
||||
} else {
|
||||
console.log('Print button not found, will retry...');
|
||||
// Retry after 1 second if button not found yet
|
||||
setTimeout(overridePrintButton, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
function handleExtensionPrint(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
console.log('Extension print button clicked');
|
||||
|
||||
// Get the label preview element
|
||||
const labelPreview = document.getElementById('label-preview');
|
||||
|
||||
if (!labelPreview) {
|
||||
alert('Label preview not found. Please select an order first.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Show printing status
|
||||
showPrintStatus('Preparing to print...', 'info');
|
||||
|
||||
// Create complete HTML for printing
|
||||
const printHTML = createPrintableHTML(labelPreview);
|
||||
|
||||
// Get selected printer from dropdown
|
||||
const selectedPrinterId = window.getSelectedPrinter ? window.getSelectedPrinter() : 'default';
|
||||
|
||||
// Try direct printing first, then fallback
|
||||
chrome.runtime.sendMessage({
|
||||
action: 'print_label',
|
||||
data: {
|
||||
html: printHTML,
|
||||
timestamp: Date.now(),
|
||||
printerId: selectedPrinterId
|
||||
}
|
||||
}, (response) => {
|
||||
if (response && response.success) {
|
||||
handlePrintResponse(response);
|
||||
} else {
|
||||
console.log('Direct printing failed, trying fallback method');
|
||||
showPrintStatus('Direct printing unavailable, using browser print...', 'info');
|
||||
|
||||
// Try fallback method
|
||||
chrome.runtime.sendMessage({
|
||||
action: 'fallback_print',
|
||||
data: {
|
||||
html: printHTML,
|
||||
timestamp: Date.now(),
|
||||
printerId: selectedPrinterId
|
||||
}
|
||||
}, handlePrintResponse);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createPrintableHTML(labelElement) {
|
||||
// Get the computed styles and create a complete HTML document
|
||||
const styles = `
|
||||
<style>
|
||||
body { margin: 0; padding: 20px; font-family: Arial, sans-serif; }
|
||||
.print-container { width: 210mm; height: 297mm; margin: 0 auto; }
|
||||
.label-wrapper { transform: scale(1); transform-origin: top left; }
|
||||
</style>
|
||||
`;
|
||||
|
||||
const bodyContent = `
|
||||
<div class="print-container">
|
||||
<div class="label-wrapper">
|
||||
${labelElement.outerHTML}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Quality Recticel Label</title>
|
||||
${styles}
|
||||
</head>
|
||||
<body>
|
||||
${bodyContent}
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
}
|
||||
|
||||
function handlePrintResponse(response) {
|
||||
console.log('Print response:', response);
|
||||
|
||||
if (response && response.success) {
|
||||
showPrintStatus('✅ Label sent to printer successfully!', 'success');
|
||||
|
||||
// Update the order status in the table if possible
|
||||
updateOrderPrintStatus();
|
||||
|
||||
} else {
|
||||
const errorMsg = response?.error || 'Unknown error occurred';
|
||||
showPrintStatus(`❌ Print failed: ${errorMsg}`, 'error');
|
||||
|
||||
// Fallback to browser print dialog
|
||||
setTimeout(() => {
|
||||
if (confirm('Direct printing failed. Open browser print dialog?')) {
|
||||
window.print();
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
function showPrintStatus(message, type) {
|
||||
// Remove existing status messages
|
||||
const existingStatus = document.getElementById('print-status-message');
|
||||
if (existingStatus) {
|
||||
existingStatus.remove();
|
||||
}
|
||||
|
||||
// Create status message
|
||||
const statusDiv = document.createElement('div');
|
||||
statusDiv.id = 'print-status-message';
|
||||
statusDiv.style.cssText = `
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: ${type === 'success' ? '#28a745' : type === 'error' ? '#dc3545' : '#17a2b8'};
|
||||
color: white;
|
||||
padding: 15px 25px;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
z-index: 10000;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
|
||||
text-align: center;
|
||||
min-width: 300px;
|
||||
`;
|
||||
statusDiv.textContent = message;
|
||||
|
||||
document.body.appendChild(statusDiv);
|
||||
|
||||
// Auto-remove after 3 seconds for success/info, 5 seconds for errors
|
||||
const timeout = type === 'error' ? 5000 : 3000;
|
||||
setTimeout(() => {
|
||||
statusDiv.style.opacity = '0';
|
||||
statusDiv.style.transition = 'opacity 0.5s';
|
||||
setTimeout(() => statusDiv.remove(), 500);
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
function addPrinterSelection() {
|
||||
// Get available printers and add selection dropdown
|
||||
chrome.runtime.sendMessage({action: 'get_printers'}, (response) => {
|
||||
if (response && response.success && response.printers.length > 0) {
|
||||
console.log('Available printers:', response.printers);
|
||||
// Could add printer selection UI here if needed
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateOrderPrintStatus() {
|
||||
// Find selected row in table and update print status
|
||||
const selectedRow = document.querySelector('.print-module-table tbody tr.selected');
|
||||
if (selectedRow) {
|
||||
const printStatusCell = selectedRow.querySelector('td:nth-last-child(2)'); // Second to last column
|
||||
if (printStatusCell) {
|
||||
printStatusCell.innerHTML = '<span style="color: #28a745; font-weight: bold;">✓ Yes</span>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkExtensionStatus() {
|
||||
// Verify extension is working
|
||||
chrome.runtime.sendMessage({action: 'check_extension'}, (response) => {
|
||||
if (response) {
|
||||
console.log('Extension status:', response);
|
||||
} else {
|
||||
console.error('Extension communication failed');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add CSS for extension-specific styling
|
||||
const extensionStyles = document.createElement('style');
|
||||
extensionStyles.textContent = `
|
||||
#print-label-btn {
|
||||
background: linear-gradient(45deg, #28a745, #20c997) !important;
|
||||
border: none !important;
|
||||
transition: all 0.3s ease !important;
|
||||
}
|
||||
|
||||
#print-label-btn:hover {
|
||||
background: linear-gradient(45deg, #218838, #1ea97c) !important;
|
||||
transform: translateY(-1px) !important;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.2) !important;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(extensionStyles);
|
||||
@@ -1,7 +0,0 @@
|
||||
# Placeholder for icon files - in production, add actual PNG icons:
|
||||
# - icon16.png (16x16 pixels)
|
||||
# - icon48.png (48x48 pixels)
|
||||
# - icon128.png (128x128 pixels)
|
||||
|
||||
# For now, create simple text-based icons using SVG converted to PNG
|
||||
# These should be replaced with proper icons later
|
||||
@@ -1,27 +0,0 @@
|
||||
# Simple text-based icons for the Chrome extension
|
||||
# These are placeholder files - replace with actual PNG icons for production
|
||||
|
||||
# Create simple SVG icons that can be converted to PNG
|
||||
ICON_16_SVG = '''
|
||||
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="16" height="16" fill="#007bff"/>
|
||||
<text x="8" y="12" font-family="Arial" font-size="10" fill="white" text-anchor="middle">🖨</text>
|
||||
</svg>
|
||||
'''
|
||||
|
||||
ICON_48_SVG = '''
|
||||
<svg width="48" height="48" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="48" height="48" fill="#007bff" rx="8"/>
|
||||
<text x="24" y="32" font-family="Arial" font-size="24" fill="white" text-anchor="middle">🖨️</text>
|
||||
</svg>
|
||||
'''
|
||||
|
||||
ICON_128_SVG = '''
|
||||
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="128" height="128" fill="#007bff" rx="16"/>
|
||||
<text x="64" y="84" font-family="Arial" font-size="48" fill="white" text-anchor="middle">🖨️</text>
|
||||
</svg>
|
||||
'''
|
||||
|
||||
# For now, create simple text placeholders
|
||||
# In production, convert these SVGs to PNG files
|
||||
@@ -1,4 +0,0 @@
|
||||
# Placeholder for 128x128 icon
|
||||
# This is a text file placeholder
|
||||
# Replace with actual icon128.png file
|
||||
🖨️
|
||||
@@ -1,4 +0,0 @@
|
||||
# Placeholder for 16x16 icon
|
||||
# This is a text file placeholder
|
||||
# Replace with actual icon16.png file
|
||||
🖨️
|
||||
@@ -1,4 +0,0 @@
|
||||
# Placeholder for 48x48 icon
|
||||
# This is a text file placeholder
|
||||
# Replace with actual icon48.png file
|
||||
🖨️
|
||||
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Quality Recticel Print Helper",
|
||||
"version": "1.0",
|
||||
"description": "Direct printing extension for Quality Recticel label printing system",
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
"storage",
|
||||
"tabs"
|
||||
],
|
||||
"optional_permissions": [
|
||||
"printing"
|
||||
],
|
||||
"host_permissions": [
|
||||
"http://localhost:*/*",
|
||||
"http://127.0.0.1:*/*",
|
||||
"*://*/print_module*"
|
||||
],
|
||||
"background": {
|
||||
"service_worker": "background.js"
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": [
|
||||
"http://localhost:*/print_module*",
|
||||
"http://127.0.0.1:*/print_module*",
|
||||
"*://*/print_module*"
|
||||
],
|
||||
"js": ["content.js"],
|
||||
"run_at": "document_end"
|
||||
}
|
||||
],
|
||||
"action": {
|
||||
"default_popup": "popup.html",
|
||||
"default_title": "Quality Recticel Print Helper"
|
||||
},
|
||||
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"resources": ["content.js"],
|
||||
"matches": ["<all_urls>"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Quality Recticel Print Helper</title>
|
||||
<style>
|
||||
body {
|
||||
width: 300px;
|
||||
padding: 15px;
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-size: 24px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.version {
|
||||
font-size: 11px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.status {
|
||||
background: #e8f5e8;
|
||||
border: 1px solid #28a745;
|
||||
color: #28a745;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.info {
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
color: #555;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.button {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin: 5px 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
|
||||
.button.secondary {
|
||||
background: #6c757d;
|
||||
}
|
||||
|
||||
.button.secondary:hover {
|
||||
background: #545b62;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<div class="logo">🖨️</div>
|
||||
<div class="title">Quality Recticel Print Helper</div>
|
||||
<div class="version">Version 1.0</div>
|
||||
</div>
|
||||
|
||||
<div class="status">
|
||||
✅ Extension Active
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
This extension enables direct printing from the Quality Recticel label system to your default printer without browser dialogs.
|
||||
</div>
|
||||
|
||||
<button class="button" id="test-print">Test Print Connection</button>
|
||||
<button class="button secondary" id="open-settings">Printer Settings</button>
|
||||
|
||||
<div class="info">
|
||||
<strong>Usage:</strong> Navigate to the Print Module page and use the enhanced print button for direct printing.
|
||||
</div>
|
||||
|
||||
<script src="popup.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,29 +0,0 @@
|
||||
// Popup script for Quality Recticel Print Helper
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('Popup loaded');
|
||||
|
||||
// Test print button
|
||||
document.getElementById('test-print').addEventListener('click', function() {
|
||||
chrome.runtime.sendMessage({action: 'get_printers'}, function(response) {
|
||||
if (response && response.success) {
|
||||
if (response.printers.length > 0) {
|
||||
alert(`✅ Found ${response.printers.length} printer(s):\n${response.printers.map(p => p.displayName).join('\n')}`);
|
||||
} else {
|
||||
alert('⚠️ No printers found. Please ensure a printer is installed and set as default.');
|
||||
}
|
||||
} else {
|
||||
const error = response?.error || 'Unknown error';
|
||||
if (error.includes('Chrome printing API not available')) {
|
||||
alert('⚠️ Chrome Printing API not available.\n\nThis may be due to:\n• Chrome version too old (need 85+)\n• Extension permissions not granted\n• Corporate/managed Chrome installation\n\nThe extension will use browser print dialog as fallback.');
|
||||
} else {
|
||||
alert('❌ Error getting printers: ' + error);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Settings button
|
||||
document.getElementById('open-settings').addEventListener('click', function() {
|
||||
chrome.tabs.create({url: 'chrome://settings/printing'});
|
||||
});
|
||||
});
|
||||
@@ -1,43 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import pymysql
|
||||
import json
|
||||
|
||||
try:
|
||||
# Connect to the database
|
||||
conn = pymysql.connect(
|
||||
host='localhost',
|
||||
database='trasabilitate',
|
||||
user='trasabilitate',
|
||||
password='Initial01!',
|
||||
cursorclass=pymysql.cursors.DictCursor
|
||||
)
|
||||
|
||||
with conn.cursor() as cursor:
|
||||
cursor.execute("SELECT id, username, role, modules FROM users")
|
||||
users = cursor.fetchall()
|
||||
|
||||
print("Debug: User data and get_modules() output:")
|
||||
print("=" * 60)
|
||||
|
||||
for user_data in users:
|
||||
print(f"Username: {user_data['username']}")
|
||||
print(f"Role: {user_data['role']}")
|
||||
print(f"Raw modules: {user_data['modules']} (type: {type(user_data['modules'])})")
|
||||
|
||||
# Simulate the get_modules() method
|
||||
modules = user_data['modules']
|
||||
if not modules:
|
||||
parsed_modules = []
|
||||
else:
|
||||
try:
|
||||
parsed_modules = json.loads(modules)
|
||||
except:
|
||||
parsed_modules = []
|
||||
|
||||
print(f"Parsed modules: {parsed_modules} (type: {type(parsed_modules)})")
|
||||
print(f"JSON output: {json.dumps(parsed_modules)}")
|
||||
print("-" * 40)
|
||||
|
||||
finally:
|
||||
conn.close()
|
||||
@@ -1,44 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import pymysql
|
||||
import json
|
||||
|
||||
try:
|
||||
# Connect to the database
|
||||
conn = pymysql.connect(
|
||||
host='localhost',
|
||||
database='trasabilitate',
|
||||
user='trasabilitate',
|
||||
password='Initial01!',
|
||||
cursorclass=pymysql.cursors.DictCursor
|
||||
)
|
||||
|
||||
with conn.cursor() as cursor:
|
||||
# Update Ciprian's role from quality_manager to manager
|
||||
print("Updating Ciprian's role from 'quality_manager' to 'manager'...")
|
||||
cursor.execute("UPDATE users SET role = 'manager' WHERE username = 'Ciprian'")
|
||||
|
||||
# Assign quality module to Ciprian since he was a quality manager
|
||||
quality_modules = json.dumps(['quality'])
|
||||
print(f"Assigning quality module to Ciprian: {quality_modules}")
|
||||
cursor.execute("UPDATE users SET modules = %s WHERE username = 'Ciprian'", (quality_modules,))
|
||||
|
||||
# Commit the changes
|
||||
conn.commit()
|
||||
print("Database updated successfully!")
|
||||
|
||||
# Show updated users
|
||||
print("\nUpdated users:")
|
||||
print("-" * 50)
|
||||
cursor.execute("SELECT id, username, role, modules FROM users")
|
||||
users = cursor.fetchall()
|
||||
|
||||
for user in users:
|
||||
print(f"ID: {user['id']}")
|
||||
print(f"Username: {user['username']}")
|
||||
print(f"Role: {user['role']}")
|
||||
print(f"Modules: {user['modules']}")
|
||||
print("-" * 30)
|
||||
|
||||
finally:
|
||||
conn.close()
|
||||
@@ -1,114 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Production Management Script for Trasabilitate Application
|
||||
# Usage: ./manage_production.sh {start|stop|restart|status|logs|install-service}
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}❌ $1${NC}"
|
||||
}
|
||||
|
||||
print_info() {
|
||||
echo -e "${BLUE}ℹ️ $1${NC}"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 {start|stop|restart|status|logs|install-service|help}"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " start Start the production server"
|
||||
echo " stop Stop the production server"
|
||||
echo " restart Restart the production server"
|
||||
echo " status Show server status"
|
||||
echo " logs Show recent logs"
|
||||
echo " install-service Install systemd service"
|
||||
echo " help Show this help message"
|
||||
echo ""
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
./start_production.sh
|
||||
;;
|
||||
stop)
|
||||
./stop_production.sh
|
||||
;;
|
||||
restart)
|
||||
echo -e "${BLUE}🔄 Restarting Trasabilitate Application${NC}"
|
||||
echo "=============================================="
|
||||
./stop_production.sh
|
||||
sleep 2
|
||||
./start_production.sh
|
||||
;;
|
||||
status)
|
||||
./status_production.sh
|
||||
;;
|
||||
logs)
|
||||
echo -e "${BLUE}📋 Recent Error Logs${NC}"
|
||||
echo "=============================================="
|
||||
if [[ -f "/srv/quality_recticel/logs/error.log" ]]; then
|
||||
tail -20 /srv/quality_recticel/logs/error.log
|
||||
else
|
||||
print_error "Error log file not found"
|
||||
fi
|
||||
echo ""
|
||||
echo -e "${BLUE}📋 Recent Access Logs${NC}"
|
||||
echo "=============================================="
|
||||
if [[ -f "/srv/quality_recticel/logs/access.log" ]]; then
|
||||
tail -10 /srv/quality_recticel/logs/access.log
|
||||
else
|
||||
print_error "Access log file not found"
|
||||
fi
|
||||
;;
|
||||
install-service)
|
||||
echo -e "${BLUE}📦 Installing Systemd Service${NC}"
|
||||
echo "=============================================="
|
||||
|
||||
if [[ ! -f "trasabilitate.service" ]]; then
|
||||
print_error "Service file not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_info "Installing service file..."
|
||||
sudo cp trasabilitate.service /etc/systemd/system/
|
||||
|
||||
print_info "Reloading systemd daemon..."
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
print_info "Enabling service..."
|
||||
sudo systemctl enable trasabilitate.service
|
||||
|
||||
print_success "Service installed successfully!"
|
||||
echo ""
|
||||
echo "Systemd commands:"
|
||||
echo " sudo systemctl start trasabilitate # Start service"
|
||||
echo " sudo systemctl stop trasabilitate # Stop service"
|
||||
echo " sudo systemctl restart trasabilitate # Restart service"
|
||||
echo " sudo systemctl status trasabilitate # Check status"
|
||||
echo " sudo systemctl enable trasabilitate # Enable auto-start"
|
||||
echo " sudo systemctl disable trasabilitate # Disable auto-start"
|
||||
;;
|
||||
help|--help|-h)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
print_error "Invalid command: $1"
|
||||
echo ""
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -1,173 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Production Startup Script for Trasabilitate Application
|
||||
# This script starts the application using Gunicorn WSGI server
|
||||
|
||||
set -e # Exit on any error
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
print_step() {
|
||||
echo -e "\n${BLUE}📋 $1${NC}"
|
||||
echo "----------------------------------------"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}❌ $1${NC}"
|
||||
}
|
||||
|
||||
echo -e "${BLUE}🚀 Trasabilitate Application - Production Startup${NC}"
|
||||
echo "=============================================="
|
||||
|
||||
# Check if we're in the right directory
|
||||
if [[ ! -f "wsgi.py" ]]; then
|
||||
print_error "Please run this script from the py_app directory"
|
||||
print_error "Expected location: /srv/quality_app/py_app or /srv/quality_recticel/py_app"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Detect which installation we're running from
|
||||
if [[ "$PWD" == *"/quality_app/"* ]]; then
|
||||
LOG_DIR="/srv/quality_app/logs"
|
||||
PROJECT_NAME="quality_app"
|
||||
else
|
||||
LOG_DIR="/srv/quality_recticel/logs"
|
||||
PROJECT_NAME="quality_recticel"
|
||||
fi
|
||||
|
||||
print_step "Checking Prerequisites"
|
||||
|
||||
# Check if virtual environment exists
|
||||
if [[ ! -d "../recticel" ]]; then
|
||||
print_error "Virtual environment 'recticel' not found"
|
||||
print_error "Please create it first or run './quick_deploy.sh'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_success "Virtual environment found"
|
||||
|
||||
# Activate virtual environment
|
||||
print_step "Activating Virtual Environment"
|
||||
source ../recticel/bin/activate
|
||||
print_success "Virtual environment activated"
|
||||
|
||||
# Check if Gunicorn is installed
|
||||
if ! command -v gunicorn &> /dev/null; then
|
||||
print_error "Gunicorn not found. Installing..."
|
||||
pip install gunicorn
|
||||
fi
|
||||
|
||||
print_success "Gunicorn is available"
|
||||
|
||||
# Check database connection
|
||||
print_step "Testing Database Connection"
|
||||
if python3 -c "
|
||||
import mariadb
|
||||
try:
|
||||
conn = mariadb.connect(user='trasabilitate', password='Initial01!', host='localhost', database='trasabilitate')
|
||||
conn.close()
|
||||
print('Database connection successful')
|
||||
except Exception as e:
|
||||
print(f'Database connection failed: {e}')
|
||||
exit(1)
|
||||
" > /dev/null 2>&1; then
|
||||
print_success "Database connection verified"
|
||||
else
|
||||
print_error "Database connection failed. Please run database setup first:"
|
||||
print_error "python3 app/db_create_scripts/setup_complete_database.py"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create PID file directory
|
||||
print_step "Setting up Runtime Environment"
|
||||
mkdir -p ../run
|
||||
print_success "Runtime directory created"
|
||||
|
||||
# Check if already running
|
||||
PID_FILE="../run/trasabilitate.pid"
|
||||
if [[ -f "$PID_FILE" ]]; then
|
||||
PID=$(cat "$PID_FILE")
|
||||
if ps -p "$PID" > /dev/null 2>&1; then
|
||||
print_warning "Application is already running (PID: $PID)"
|
||||
echo "To stop the application, run:"
|
||||
echo "kill $PID"
|
||||
echo "rm $PID_FILE"
|
||||
exit 1
|
||||
else
|
||||
print_warning "Stale PID file found, removing..."
|
||||
rm -f "$PID_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Start Gunicorn
|
||||
print_step "Starting Production Server"
|
||||
|
||||
echo "Starting Gunicorn WSGI server..."
|
||||
echo "Configuration: gunicorn.conf.py"
|
||||
echo "Workers: $(python3 -c 'import multiprocessing; print(multiprocessing.cpu_count() * 2 + 1)')"
|
||||
echo "Binding to: 0.0.0.0:8781"
|
||||
echo ""
|
||||
|
||||
# Start Gunicorn with configuration file
|
||||
gunicorn --config gunicorn.conf.py \
|
||||
--pid "$PID_FILE" \
|
||||
--daemon \
|
||||
wsgi:application
|
||||
|
||||
# Wait a moment for startup
|
||||
sleep 2
|
||||
|
||||
# Check if the process started successfully
|
||||
if [[ -f "$PID_FILE" ]]; then
|
||||
PID=$(cat "$PID_FILE")
|
||||
if ps -p "$PID" > /dev/null 2>&1; then
|
||||
print_success "Application started successfully!"
|
||||
echo ""
|
||||
echo "=============================================="
|
||||
echo -e "${GREEN}🎉 PRODUCTION SERVER RUNNING${NC}"
|
||||
echo "=============================================="
|
||||
echo ""
|
||||
echo "📋 Server Information:"
|
||||
echo " • Process ID: $PID"
|
||||
echo " • Configuration: gunicorn.conf.py"
|
||||
echo " • Project: $PROJECT_NAME"
|
||||
echo " • Access Log: $LOG_DIR/access.log"
|
||||
echo " • Error Log: $LOG_DIR/error.log"
|
||||
echo ""
|
||||
echo "🌐 Application URLs:"
|
||||
echo " • Local: http://127.0.0.1:8781"
|
||||
echo " • Network: http://$(hostname -I | awk '{print $1}'):8781"
|
||||
echo ""
|
||||
echo "👤 Default Login:"
|
||||
echo " • Username: superadmin"
|
||||
echo " • Password: superadmin123"
|
||||
echo ""
|
||||
echo "🔧 Management Commands:"
|
||||
echo " • Stop server: kill $PID && rm $PID_FILE"
|
||||
echo " • View logs: tail -f $LOG_DIR/error.log"
|
||||
echo " • Monitor access: tail -f $LOG_DIR/access.log"
|
||||
echo " • Server status: ps -p $PID"
|
||||
echo ""
|
||||
print_warning "Server is running in daemon mode (background)"
|
||||
else
|
||||
print_error "Failed to start application. Check logs:"
|
||||
print_error "tail $LOG_DIR/error.log"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
print_error "Failed to create PID file. Check permissions and logs."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,88 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Production Status Script for Trasabilitate Application
|
||||
# This script shows the current status of the Gunicorn WSGI server
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}❌ $1${NC}"
|
||||
}
|
||||
|
||||
echo -e "${BLUE}📊 Trasabilitate Application - Status Check${NC}"
|
||||
echo "=============================================="
|
||||
|
||||
PID_FILE="../run/trasabilitate.pid"
|
||||
|
||||
# Detect which installation we're running from
|
||||
if [[ "$PWD" == *"/quality_app/"* ]]; then
|
||||
LOG_DIR="/srv/quality_app/logs"
|
||||
PROJECT_NAME="quality_app"
|
||||
else
|
||||
LOG_DIR="/srv/quality_recticel/logs"
|
||||
PROJECT_NAME="quality_recticel"
|
||||
fi
|
||||
|
||||
if [[ ! -f "$PID_FILE" ]]; then
|
||||
print_error "Application is not running (no PID file found)"
|
||||
echo "To start the application, run: ./start_production.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PID=$(cat "$PID_FILE")
|
||||
|
||||
if ps -p "$PID" > /dev/null 2>&1; then
|
||||
print_success "Application is running (PID: $PID)"
|
||||
echo ""
|
||||
echo "📋 Process Information:"
|
||||
ps -p "$PID" -o pid,ppid,pcpu,pmem,etime,cmd --no-headers | while read line; do
|
||||
echo " $line"
|
||||
done
|
||||
echo ""
|
||||
echo "🌐 Server Information:"
|
||||
echo " • Project: $PROJECT_NAME"
|
||||
echo " • Listening on: 0.0.0.0:8781"
|
||||
echo " • Local URL: http://127.0.0.1:8781"
|
||||
echo " • Network URL: http://$(hostname -I | awk '{print $1}'):8781"
|
||||
echo ""
|
||||
echo "📁 Log Files:"
|
||||
echo " • Access Log: $LOG_DIR/access.log"
|
||||
echo " • Error Log: $LOG_DIR/error.log"
|
||||
echo ""
|
||||
echo "🔧 Quick Commands:"
|
||||
echo " • Stop server: ./stop_production.sh"
|
||||
echo " • Restart server: ./stop_production.sh && ./start_production.sh"
|
||||
echo " • View error log: tail -f $LOG_DIR/error.log"
|
||||
echo " • View access log: tail -f $LOG_DIR/access.log"
|
||||
echo ""
|
||||
|
||||
# Check if the web server is responding
|
||||
if command -v curl > /dev/null 2>&1; then
|
||||
echo "🌐 Connection Test:"
|
||||
if curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8781 | grep -q "200\|302\|401"; then
|
||||
print_success "Web server is responding"
|
||||
else
|
||||
print_warning "Web server may not be responding properly"
|
||||
fi
|
||||
fi
|
||||
|
||||
else
|
||||
print_error "Process $PID not found (stale PID file)"
|
||||
print_warning "Cleaning up stale PID file..."
|
||||
rm -f "$PID_FILE"
|
||||
echo "To start the application, run: ./start_production.sh"
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,69 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Production Stop Script for Trasabilitate Application
|
||||
# This script stops the Gunicorn WSGI server
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}❌ $1${NC}"
|
||||
}
|
||||
|
||||
echo -e "${BLUE}🛑 Trasabilitate Application - Production Stop${NC}"
|
||||
echo "=============================================="
|
||||
|
||||
PID_FILE="../run/trasabilitate.pid"
|
||||
|
||||
if [[ ! -f "$PID_FILE" ]]; then
|
||||
print_warning "No PID file found. Server may not be running."
|
||||
echo "PID file location: $PID_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PID=$(cat "$PID_FILE")
|
||||
|
||||
if ps -p "$PID" > /dev/null 2>&1; then
|
||||
echo "Stopping Trasabilitate application (PID: $PID)..."
|
||||
|
||||
# Send SIGTERM first (graceful shutdown)
|
||||
kill "$PID"
|
||||
|
||||
# Wait for graceful shutdown
|
||||
sleep 3
|
||||
|
||||
# Check if still running
|
||||
if ps -p "$PID" > /dev/null 2>&1; then
|
||||
print_warning "Process still running, sending SIGKILL..."
|
||||
kill -9 "$PID"
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# Check if process is finally stopped
|
||||
if ! ps -p "$PID" > /dev/null 2>&1; then
|
||||
print_success "Application stopped successfully"
|
||||
rm -f "$PID_FILE"
|
||||
else
|
||||
print_error "Failed to stop application (PID: $PID)"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
print_warning "Process $PID not found. Cleaning up PID file..."
|
||||
rm -f "$PID_FILE"
|
||||
print_success "PID file cleaned up"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_success "Trasabilitate application has been stopped"
|
||||
@@ -1,73 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import pymysql
|
||||
import json
|
||||
|
||||
def test_login_data():
|
||||
try:
|
||||
# Connect to the database
|
||||
conn = pymysql.connect(
|
||||
host='localhost',
|
||||
database='trasabilitate',
|
||||
user='trasabilitate',
|
||||
password='Initial01!',
|
||||
cursorclass=pymysql.cursors.DictCursor
|
||||
)
|
||||
|
||||
with conn.cursor() as cursor:
|
||||
# Simulate login for Ciprian
|
||||
cursor.execute("SELECT username, password, role, modules FROM users WHERE username = 'Ciprian'")
|
||||
user = cursor.fetchone()
|
||||
|
||||
if user:
|
||||
print("Ciprian's database record:")
|
||||
print(f"Username: {user['username']}")
|
||||
print(f"Role: {user['role']}")
|
||||
print(f"Raw modules: {user['modules']}")
|
||||
|
||||
# Simulate what happens in login
|
||||
user_modules = []
|
||||
if user['modules']:
|
||||
try:
|
||||
user_modules = json.loads(user['modules'])
|
||||
print(f"Parsed modules: {user_modules}")
|
||||
except Exception as e:
|
||||
print(f"Error parsing modules: {e}")
|
||||
user_modules = []
|
||||
|
||||
# Check if user should have quality access
|
||||
has_quality = 'quality' in user_modules
|
||||
print(f"Has quality module access: {has_quality}")
|
||||
|
||||
# Check role level
|
||||
ROLES = {
|
||||
'superadmin': {'level': 100},
|
||||
'admin': {'level': 90},
|
||||
'manager': {'level': 70},
|
||||
'worker': {'level': 50}
|
||||
}
|
||||
|
||||
user_level = ROLES.get(user['role'], {}).get('level', 0)
|
||||
print(f"Role level: {user_level}")
|
||||
|
||||
# Test access control logic
|
||||
print("\nAccess Control Test:")
|
||||
print(f"Required modules: ['quality']")
|
||||
print(f"User role: {user['role']}")
|
||||
print(f"User modules: {user_modules}")
|
||||
|
||||
if user['role'] in ['superadmin', 'admin']:
|
||||
print("✅ Access granted: Superadmin/Admin has access to all modules")
|
||||
elif any(module in user_modules for module in ['quality']):
|
||||
print("✅ Access granted: User has required quality module")
|
||||
else:
|
||||
print("❌ Access denied: User does not have quality module")
|
||||
|
||||
else:
|
||||
print("User 'Ciprian' not found!")
|
||||
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_login_data()
|
||||
@@ -1,49 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Quick test for updated worker permissions
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'app'))
|
||||
|
||||
from permissions_simple import validate_user_modules
|
||||
|
||||
def test_worker_multiple_modules():
|
||||
"""Test that workers can now have multiple modules"""
|
||||
print("Testing Updated Worker Module Permissions")
|
||||
print("=" * 45)
|
||||
|
||||
test_cases = [
|
||||
# (role, modules, expected_result, description)
|
||||
('worker', ['quality'], True, "Worker with quality module"),
|
||||
('worker', ['warehouse'], True, "Worker with warehouse module"),
|
||||
('worker', ['quality', 'warehouse'], True, "Worker with multiple modules (NEW)"),
|
||||
('worker', ['quality', 'warehouse', 'labels'], True, "Worker with all modules (NEW)"),
|
||||
('worker', [], False, "Worker with no modules"),
|
||||
('manager', ['quality', 'warehouse'], True, "Manager with multiple modules"),
|
||||
]
|
||||
|
||||
passed = 0
|
||||
failed = 0
|
||||
|
||||
for role, modules, expected, description in test_cases:
|
||||
is_valid, error_msg = validate_user_modules(role, modules)
|
||||
status = "PASS" if is_valid == expected else "FAIL"
|
||||
|
||||
print(f"{status}: {description}")
|
||||
print(f" Role: {role}, Modules: {modules} -> {is_valid} (expected {expected})")
|
||||
if error_msg:
|
||||
print(f" Error: {error_msg}")
|
||||
print()
|
||||
|
||||
if is_valid == expected:
|
||||
passed += 1
|
||||
else:
|
||||
failed += 1
|
||||
|
||||
print(f"Results: {passed} passed, {failed} failed")
|
||||
print("\n✅ Workers can now have multiple modules!" if failed == 0 else "❌ Some tests failed")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_worker_multiple_modules()
|
||||
@@ -1,27 +0,0 @@
|
||||
[Unit]
|
||||
Description=Trasabilitate Quality Management Application
|
||||
After=network.target mariadb.service
|
||||
Wants=mariadb.service
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
User=ske087
|
||||
Group=ske087
|
||||
WorkingDirectory=/srv/quality_recticel/py_app
|
||||
Environment="PATH=/srv/quality_recticel/recticel/bin"
|
||||
ExecStart=/srv/quality_recticel/recticel/bin/gunicorn --config gunicorn.conf.py --pid /srv/quality_recticel/run/trasabilitate.pid --daemon wsgi:application
|
||||
ExecReload=/bin/kill -s HUP $MAINPID
|
||||
ExecStop=/bin/kill -s TERM $MAINPID
|
||||
PIDFile=/srv/quality_recticel/run/trasabilitate.pid
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
# Security settings
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/srv/quality_recticel
|
||||
ProtectHome=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user