417 lines
16 KiB
JavaScript
417 lines
16 KiB
JavaScript
import { Controller } from '@hotwired/stimulus';
|
|
|
|
export default class extends Controller {
|
|
static targets = [
|
|
'step', 'progressFill', 'status', 'loading', 'buttonText',
|
|
'panelType', 'host', 'username', 'password', 'domain',
|
|
'databaseName', 'databaseUser', 'databasePassword', 'adminUrl'
|
|
];
|
|
|
|
static values = {
|
|
currentStep: { type: Number, default: 1 },
|
|
installationData: { type: Object, default: {} }
|
|
};
|
|
|
|
connect() {
|
|
console.log('Installation controller connected');
|
|
this.updateProgress();
|
|
}
|
|
|
|
updateProgress() {
|
|
const progress = (this.currentStepValue / 6) * 100;
|
|
if (this.hasProgressFillTarget) {
|
|
this.progressFillTarget.style.width = progress + '%';
|
|
}
|
|
}
|
|
|
|
showStep(stepNumber) {
|
|
// مخفی کردن همه مراحل
|
|
this.stepTargets.forEach(step => {
|
|
step.classList.add('step-hidden');
|
|
});
|
|
|
|
// نمایش مرحله فعلی
|
|
if (this.stepTargets[stepNumber - 1]) {
|
|
this.stepTargets[stepNumber - 1].classList.remove('step-hidden');
|
|
}
|
|
this.currentStepValue = stepNumber;
|
|
this.updateProgress();
|
|
}
|
|
|
|
showStatus(stepIndex, message, type = 'info') {
|
|
if (this.statusTargets[stepIndex]) {
|
|
const statusElement = this.statusTargets[stepIndex];
|
|
statusElement.textContent = message;
|
|
statusElement.className = `status-message status-${type}`;
|
|
statusElement.style.display = 'block';
|
|
}
|
|
}
|
|
|
|
showLoading(buttonIndex, loadingIndex, buttonTextIndex, originalText) {
|
|
if (this.buttonTextTargets[buttonIndex] && this.loadingTargets[loadingIndex]) {
|
|
this.buttonTextTargets[buttonIndex].style.display = 'none';
|
|
this.loadingTargets[loadingIndex].style.display = 'inline-block';
|
|
this.buttonTextTargets[buttonTextIndex].textContent = 'در حال پردازش...';
|
|
}
|
|
}
|
|
|
|
hideLoading(buttonIndex, loadingIndex, buttonTextIndex, originalText) {
|
|
if (this.buttonTextTargets[buttonIndex] && this.loadingTargets[loadingIndex]) {
|
|
this.buttonTextTargets[buttonIndex].style.display = 'inline-block';
|
|
this.loadingTargets[loadingIndex].style.display = 'none';
|
|
this.buttonTextTargets[buttonTextIndex].textContent = originalText;
|
|
}
|
|
}
|
|
|
|
async testConnection() {
|
|
console.log('testConnection called');
|
|
|
|
// بررسی وجود targets
|
|
if (!this.hasPanelTypeTarget || !this.hasHostTarget || !this.hasUsernameTarget || !this.hasPasswordTarget) {
|
|
console.error('Required targets not found');
|
|
this.showStatus(0, 'خطا در بارگذاری فرم', 'error');
|
|
return;
|
|
}
|
|
|
|
const panelType = this.panelTypeTarget.value;
|
|
const host = this.hostTarget.value;
|
|
const username = this.usernameTarget.value;
|
|
const password = this.passwordTarget.value;
|
|
|
|
console.log('Form data:', { panelType, host, username, password: '***' });
|
|
|
|
if (!host || !username || !password) {
|
|
this.showStatus(0, 'لطفاً تمام فیلدها را پر کنید', 'error');
|
|
return;
|
|
}
|
|
|
|
this.showLoading(0, 0, 0, 'تست اتصال');
|
|
|
|
try {
|
|
const requestData = {
|
|
panel_type: panelType,
|
|
host: host,
|
|
username: username,
|
|
password: password
|
|
};
|
|
|
|
console.log('Sending request:', requestData);
|
|
|
|
const response = await fetch('/api/installation/test-connection', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json',
|
|
},
|
|
body: JSON.stringify(requestData)
|
|
});
|
|
|
|
console.log('Response status:', response.status);
|
|
|
|
let result = null;
|
|
try {
|
|
result = await response.json();
|
|
} catch (e) {
|
|
result = { success: false, error: 'پاسخ نامعتبر از سرور' };
|
|
}
|
|
|
|
if (!result.success) {
|
|
// اگر خطا مربوط به دسترسی یا API یا timeout بود، فرم FTP را نمایش بده
|
|
const errorText = result.error || '';
|
|
if (
|
|
errorText.includes('403') ||
|
|
errorText.includes('401') ||
|
|
errorText.includes('API') ||
|
|
errorText.includes('دسترسی') ||
|
|
errorText.includes('timeout')
|
|
) {
|
|
document.getElementById('ftpOption').classList.remove('step-hidden');
|
|
}
|
|
this.showStatus(0, result.error || 'خطای نامشخص', 'error');
|
|
return;
|
|
}
|
|
|
|
console.log('Response result:', result);
|
|
|
|
this.installationDataValue = {
|
|
panel_type: panelType,
|
|
host: host,
|
|
username: username,
|
|
password: password
|
|
};
|
|
|
|
this.showStatus(0, result.data.message, 'success');
|
|
setTimeout(() => this.showStep(2), 1000);
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
this.showStatus(0, 'خطا در اتصال به سرور: ' + error.message, 'error');
|
|
} finally {
|
|
this.hideLoading(0, 0, 0, 'تست اتصال');
|
|
}
|
|
}
|
|
|
|
async getDomainInfo() {
|
|
this.showLoading(1, 1, 1, 'دریافت دامنهها');
|
|
|
|
try {
|
|
const response = await fetch('/api/installation/get-domain-info', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(this.installationDataValue)
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
this.domainTarget.innerHTML = '<option value="">انتخاب کنید...</option>';
|
|
|
|
result.data.domains.forEach(domain => {
|
|
const option = document.createElement('option');
|
|
option.value = domain;
|
|
option.textContent = domain;
|
|
this.domainTarget.appendChild(option);
|
|
});
|
|
|
|
this.showStatus(1, result.data.message, 'success');
|
|
setTimeout(() => this.showStep(3), 1000);
|
|
} else {
|
|
this.showStatus(1, result.error, 'error');
|
|
}
|
|
} catch (error) {
|
|
this.showStatus(1, 'خطا در دریافت اطلاعات دامنه', 'error');
|
|
} finally {
|
|
this.hideLoading(1, 1, 1, 'دریافت دامنهها');
|
|
}
|
|
}
|
|
|
|
async createDatabase() {
|
|
const databaseName = this.databaseNameTarget.value;
|
|
const databaseUser = this.databaseUserTarget.value;
|
|
const databasePassword = this.databasePasswordTarget.value;
|
|
|
|
if (!databaseName || !databaseUser || !databasePassword) {
|
|
this.showStatus(2, 'لطفاً تمام فیلدها را پر کنید', 'error');
|
|
return;
|
|
}
|
|
|
|
this.showLoading(2, 2, 2, 'ایجاد دیتابیس');
|
|
|
|
try {
|
|
const response = await fetch('/api/installation/create-database', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
...this.installationDataValue,
|
|
database_name: databaseName,
|
|
database_user: databaseUser,
|
|
database_password: databasePassword
|
|
})
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
this.installationDataValue = {
|
|
...this.installationDataValue,
|
|
database_name: databaseName,
|
|
database_user: databaseUser,
|
|
database_password: databasePassword
|
|
};
|
|
|
|
this.showStatus(2, result.data.message, 'success');
|
|
setTimeout(() => this.showStep(4), 1000);
|
|
} else {
|
|
this.showStatus(2, result.error, 'error');
|
|
}
|
|
} catch (error) {
|
|
this.showStatus(2, 'خطا در ایجاد دیتابیس', 'error');
|
|
} finally {
|
|
this.hideLoading(2, 2, 2, 'ایجاد دیتابیس');
|
|
}
|
|
}
|
|
|
|
async uploadFiles() {
|
|
const domain = this.domainTarget.value;
|
|
|
|
if (!domain) {
|
|
this.showStatus(3, 'لطفاً دامنه را انتخاب کنید', 'error');
|
|
return;
|
|
}
|
|
|
|
this.showLoading(3, 3, 3, 'شروع آپلود');
|
|
|
|
try {
|
|
const response = await fetch('/api/installation/upload-files', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
...this.installationDataValue,
|
|
domain: domain
|
|
})
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
this.installationDataValue.domain = domain;
|
|
this.showStatus(3, result.data.message, 'success');
|
|
setTimeout(() => this.showStep(5), 1000);
|
|
} else {
|
|
this.showStatus(3, result.error, 'error');
|
|
}
|
|
} catch (error) {
|
|
this.showStatus(3, 'خطا در آپلود فایلها', 'error');
|
|
} finally {
|
|
this.hideLoading(3, 3, 3, 'شروع آپلود');
|
|
}
|
|
}
|
|
|
|
async finalizeInstallation() {
|
|
this.showLoading(4, 4, 4, 'نهاییسازی نصب');
|
|
|
|
try {
|
|
const response = await fetch('/api/installation/finalize', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(this.installationDataValue)
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
this.showStatus(4, result.data.message, 'success');
|
|
setTimeout(() => {
|
|
this.showStep(6);
|
|
this.adminUrlTarget.href = result.data.admin_url;
|
|
}, 1000);
|
|
} else {
|
|
this.showStatus(4, result.error, 'error');
|
|
}
|
|
} catch (error) {
|
|
this.showStatus(4, 'خطا در نهاییسازی نصب', 'error');
|
|
} finally {
|
|
this.hideLoading(4, 4, 4, 'نهاییسازی نصب');
|
|
}
|
|
}
|
|
|
|
onDomainChange() {
|
|
const domain = this.domainTarget.value;
|
|
if (domain) {
|
|
const dbName = 'hesabix_' + domain.replace(/[^a-zA-Z0-9]/g, '_');
|
|
const dbUser = 'hesabix_' + domain.replace(/[^a-zA-Z0-9]/g, '_');
|
|
|
|
this.databaseNameTarget.value = dbName;
|
|
this.databaseUserTarget.value = dbUser;
|
|
}
|
|
}
|
|
}
|
|
|
|
window.showApiInstall = function() {
|
|
document.getElementById('apiInstallSection').style.display = '';
|
|
document.getElementById('ftpOption').style.display = 'none';
|
|
// ریست مراحل FTP
|
|
document.getElementById('ftpStep1').classList.remove('step-hidden');
|
|
document.getElementById('ftpStep2').classList.add('step-hidden');
|
|
document.getElementById('ftpStep3').classList.add('step-hidden');
|
|
}
|
|
window.showFtpInstall = function() {
|
|
document.getElementById('apiInstallSection').style.display = 'none';
|
|
const ftpOption = document.getElementById('ftpOption');
|
|
ftpOption.style.display = '';
|
|
ftpOption.classList.remove('step-hidden');
|
|
// ریست مراحل FTP
|
|
document.getElementById('ftpStep1').classList.remove('step-hidden');
|
|
document.getElementById('ftpStep2').classList.add('step-hidden');
|
|
document.getElementById('ftpStep3').classList.add('step-hidden');
|
|
}
|
|
function showBootstrapAlert(message, type = 'danger', parentId = 'ftpStep1') {
|
|
// type: 'danger', 'success', 'info', ...
|
|
let parent = document.getElementById(parentId);
|
|
let oldAlert = parent.querySelector('.bootstrap-alert');
|
|
if (oldAlert) oldAlert.remove();
|
|
let div = document.createElement('div');
|
|
div.className = `alert alert-${type} bootstrap-alert`;
|
|
div.style.marginTop = '10px';
|
|
div.innerHTML = message;
|
|
parent.querySelector('.step-content').prepend(div);
|
|
}
|
|
|
|
window.showFtpDbStep = function() {
|
|
const ftpHost = document.getElementById('ftpHost').value;
|
|
const ftpUsername = document.getElementById('ftpUsername').value;
|
|
const ftpPassword = document.getElementById('ftpPassword').value;
|
|
if (!ftpHost || !ftpUsername || !ftpPassword) {
|
|
showBootstrapAlert('تمام فیلدهای FTP الزامی است', 'danger', 'ftpStep1');
|
|
return;
|
|
}
|
|
// حذف هشدار قبلی
|
|
showBootstrapAlert('', 'danger', 'ftpStep1');
|
|
document.getElementById('ftpStep1').classList.add('step-hidden');
|
|
document.getElementById('ftpStep2').classList.remove('step-hidden');
|
|
}
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
showApiInstall();
|
|
});
|
|
|
|
window.startFtpInstall = async function() {
|
|
// مرحله دوم: اطلاعات دیتابیس
|
|
const ftpHost = document.getElementById('ftpHost').value;
|
|
const ftpUsername = document.getElementById('ftpUsername').value;
|
|
const ftpPassword = document.getElementById('ftpPassword').value;
|
|
const ftpPort = document.getElementById('ftpPort').value;
|
|
const domain = document.querySelector('[data-installation-target="host"]').value;
|
|
const databaseName = document.getElementById('ftpDatabaseName').value;
|
|
const databaseUser = document.getElementById('ftpDatabaseUser').value;
|
|
const databasePassword = document.getElementById('ftpDatabasePassword').value;
|
|
if (!databaseName || !databaseUser || !databasePassword) {
|
|
showBootstrapAlert('تمام فیلدهای دیتابیس الزامی است', 'danger', 'ftpStep2');
|
|
return;
|
|
}
|
|
// حذف هشدار قبلی
|
|
showBootstrapAlert('', 'danger', 'ftpStep2');
|
|
const payload = {
|
|
ftp_host: ftpHost,
|
|
ftp_username: ftpUsername,
|
|
ftp_password: ftpPassword,
|
|
ftp_port: ftpPort,
|
|
domain: domain,
|
|
database_name: databaseName,
|
|
database_user: databaseUser,
|
|
database_password: databasePassword
|
|
};
|
|
try {
|
|
const response = await fetch('/api/installation/ftp-install', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json',
|
|
},
|
|
body: JSON.stringify(payload)
|
|
});
|
|
const result = await response.json();
|
|
document.getElementById('ftpStep2').classList.add('step-hidden');
|
|
document.getElementById('ftpStep3').classList.remove('step-hidden');
|
|
const msg = document.getElementById('ftpResultMsg');
|
|
if (result.success) {
|
|
msg.className = 'status-message status-success';
|
|
msg.innerHTML = 'نصب با موفقیت از طریق FTP انجام شد!';
|
|
} else {
|
|
msg.className = 'status-message status-error';
|
|
msg.innerHTML = 'خطا: ' + (result.error || 'خطای نامشخص');
|
|
}
|
|
} catch (error) {
|
|
document.getElementById('ftpStep2').classList.add('step-hidden');
|
|
document.getElementById('ftpStep3').classList.remove('step-hidden');
|
|
const msg = document.getElementById('ftpResultMsg');
|
|
msg.className = 'status-message status-error';
|
|
msg.innerHTML = 'خطا در ارتباط با سرور: ' + error.message;
|
|
}
|
|
}
|