fixy i usprwnienia
This commit is contained in:
		
							
								
								
									
										8
									
								
								alters.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								alters.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					ALTER TABLE user_settings ADD COLUMN deploy_cron VARCHAR(100) DEFAULT '12 12 * * *';
 | 
				
			||||||
 | 
					ALTER TABLE user_settings ADD COLUMN backup_cron VARCHAR(100) DEFAULT '12 12 * * *';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE host ADD COLUMN auto_deploy_enabled BOOLEAN DEFAULT 1;
 | 
				
			||||||
 | 
					ALTER TABLE host ADD COLUMN auto_backup_enabled BOOLEAN DEFAULT 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE user_settings DROP COLUMN deploy_interval;
 | 
				
			||||||
 | 
					ALTER TABLE user_settings DROP COLUMN backup_interval;
 | 
				
			||||||
							
								
								
									
										144
									
								
								app.py
									
									
									
									
									
								
							
							
						
						
									
										144
									
								
								app.py
									
									
									
									
									
								
							@@ -7,7 +7,9 @@ from datetime import datetime, timezone, timedelta
 | 
				
			|||||||
from io import StringIO
 | 
					from io import StringIO
 | 
				
			||||||
import socket
 | 
					import socket
 | 
				
			||||||
import ipaddress
 | 
					import ipaddress
 | 
				
			||||||
import pytz
 | 
					from croniter import croniter
 | 
				
			||||||
 | 
					from tzlocal import get_localzone
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from werkzeug.serving import WSGIRequestHandler
 | 
					from werkzeug.serving import WSGIRequestHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WSGIRequestHandler.server_version = ""
 | 
					WSGIRequestHandler.server_version = ""
 | 
				
			||||||
@@ -38,7 +40,8 @@ class Host(db.Model):
 | 
				
			|||||||
    key_passphrase = db.Column(db.String(200), nullable=True)
 | 
					    key_passphrase = db.Column(db.String(200), nullable=True)
 | 
				
			||||||
    port = db.Column(db.Integer, default=22)
 | 
					    port = db.Column(db.Integer, default=22)
 | 
				
			||||||
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
 | 
					    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
 | 
				
			||||||
    
 | 
					    auto_deploy_enabled = db.Column(db.Boolean, default=True) 
 | 
				
			||||||
 | 
					    auto_backup_enabled = db.Column(db.Boolean, default=True)   
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def resolved_hostname(self):
 | 
					    def resolved_hostname(self):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
@@ -63,8 +66,10 @@ class UserSettings(db.Model):
 | 
				
			|||||||
    id = db.Column(db.Integer, primary_key=True)
 | 
					    id = db.Column(db.Integer, primary_key=True)
 | 
				
			||||||
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), unique=True, nullable=False)
 | 
					    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), unique=True, nullable=False)
 | 
				
			||||||
    auto_deploy_enabled = db.Column(db.Boolean, default=False)
 | 
					    auto_deploy_enabled = db.Column(db.Boolean, default=False)
 | 
				
			||||||
    deploy_interval = db.Column(db.Integer, default=60)  # interwał wdrożeń (minuty)
 | 
					    #deploy_interval = db.Column(db.Integer, default=60)  # interwał wdrożeń (minuty)
 | 
				
			||||||
    backup_interval = db.Column(db.Integer, default=60)  # interwał backupów (minuty)
 | 
					    #backup_interval = db.Column(db.Integer, default=60)  # interwał backupów (minuty)
 | 
				
			||||||
 | 
					    deploy_cron = db.Column(db.String(100), default="12 12 * * *")
 | 
				
			||||||
 | 
					    backup_cron = db.Column(db.String(100), default="12 12 * * *")
 | 
				
			||||||
    auto_backup_enabled = db.Column(db.Boolean, default=False)
 | 
					    auto_backup_enabled = db.Column(db.Boolean, default=False)
 | 
				
			||||||
    last_deploy_time = db.Column(db.DateTime, nullable=True)
 | 
					    last_deploy_time = db.Column(db.DateTime, nullable=True)
 | 
				
			||||||
    regex_deploy_enabled = db.Column(db.Boolean, default=True)
 | 
					    regex_deploy_enabled = db.Column(db.Boolean, default=True)
 | 
				
			||||||
@@ -170,41 +175,43 @@ def automated_backup_for_host(host):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        db.session.add(backup)
 | 
					        db.session.add(backup)
 | 
				
			||||||
        db.session.commit()
 | 
					        db.session.commit()
 | 
				
			||||||
 | 
					        log_entry = DeployLog(
 | 
				
			||||||
 | 
					            details=f'[BACKUP] Automatic backup created for host {host.hostname}',
 | 
				
			||||||
 | 
					            user_id=host.user_id
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        db.session.add(log_entry)
 | 
				
			||||||
 | 
					        db.session.commit()
 | 
				
			||||||
        print(f'Automated backup for host {host.hostname} created successfully.')
 | 
					        print(f'Automated backup for host {host.hostname} created successfully.')
 | 
				
			||||||
    except Exception as e:
 | 
					    except Exception as e:
 | 
				
			||||||
        print(f'Error creating automated backup for host {host.hostname}: {str(e)}')
 | 
					        print(f'Error creating automated backup for host {host.hostname}: {str(e)}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def automated_backups():
 | 
					def automated_backups():
 | 
				
			||||||
    with app.app_context():
 | 
					    with app.app_context():
 | 
				
			||||||
        logger.debug("Rozpoczynam funkcję automated_backups")
 | 
					 | 
				
			||||||
        hosts = Host.query.all()
 | 
					 | 
				
			||||||
        now = datetime.now(timezone.utc)
 | 
					        now = datetime.now(timezone.utc)
 | 
				
			||||||
 | 
					        hosts = Host.query.all()
 | 
				
			||||||
        for host in hosts:
 | 
					        for host in hosts:
 | 
				
			||||||
            settings = UserSettings.query.filter_by(user_id=host.user_id).first()
 | 
					            # Dodaj warunek: backup dla danego hosta ma być wykonywany tylko, jeśli jest włączony
 | 
				
			||||||
            if not settings or not settings.auto_backup_enabled:
 | 
					            if not host.auto_backup_enabled:
 | 
				
			||||||
                logger.debug(f"Pomijam host {host.hostname} - auto_backup nie włączone")
 | 
					 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
            backup_interval = settings.backup_interval if settings.backup_interval else 60
 | 
					
 | 
				
			||||||
            logger.debug(f"Backup interval dla hosta {host.hostname}: {backup_interval} minut")
 | 
					            settings = UserSettings.query.filter_by(user_id=host.user_id).first()
 | 
				
			||||||
 | 
					            if not settings or not settings.auto_backup_enabled or not settings.backup_cron:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            # Pobieramy ostatni backup dla hosta
 | 
				
			||||||
            last_backup = Backup.query.filter_by(user_id=host.user_id, host_id=host.id)\
 | 
					            last_backup = Backup.query.filter_by(user_id=host.user_id, host_id=host.id)\
 | 
				
			||||||
                                      .order_by(Backup.created_at.desc()).first()
 | 
					                                      .order_by(Backup.created_at.desc()).first()
 | 
				
			||||||
            if last_backup:
 | 
					            if last_backup:
 | 
				
			||||||
                last_backup_time = last_backup.created_at
 | 
					                base_time = last_backup.created_at
 | 
				
			||||||
                if last_backup_time.tzinfo is None:
 | 
					                if base_time.tzinfo is None:
 | 
				
			||||||
                    # Zakładamy, że zapisany czas jest już w UTC
 | 
					                    base_time = base_time.replace(tzinfo=timezone.utc)
 | 
				
			||||||
                    last_backup_time = last_backup_time.replace(tzinfo=timezone.utc)
 | 
					 | 
				
			||||||
                diff = (now - last_backup_time).total_seconds()
 | 
					 | 
				
			||||||
                logger.debug(f"Różnica czasu dla hosta {host.hostname}: {diff} sekund")
 | 
					 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                last_backup_time = None
 | 
					                base_time = datetime.now(timezone.utc) - timedelta(minutes=1)
 | 
				
			||||||
                logger.debug(f"Brak poprzedniego backupu dla hosta {host.hostname}")
 | 
					            cron = croniter(settings.backup_cron, base_time)
 | 
				
			||||||
            if (last_backup_time is None) or ((now - last_backup_time).total_seconds() >= backup_interval * 60):
 | 
					            next_backup_time = cron.get_next(datetime)
 | 
				
			||||||
                logger.debug(f"Wykonuję backup dla hosta {host.hostname}")
 | 
					            if now >= next_backup_time:
 | 
				
			||||||
                automated_backup_for_host(host)
 | 
					                automated_backup_for_host(host)
 | 
				
			||||||
                db.session.commit()
 | 
					                db.session.commit()
 | 
				
			||||||
                db.session.expire_all()
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                logger.debug(f"Backup dla hosta {host.hostname} nie jest jeszcze potrzebny")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def wrap_content_with_comments(content):
 | 
					def wrap_content_with_comments(content):
 | 
				
			||||||
@@ -838,22 +845,28 @@ def settings():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if request.method == 'POST':
 | 
					    if request.method == 'POST':
 | 
				
			||||||
        auto_deploy = request.form.get('auto_deploy')
 | 
					        auto_deploy = request.form.get('auto_deploy')
 | 
				
			||||||
        deploy_interval = request.form.get('deploy_interval')
 | 
					        deploy_cron = request.form.get('deploy_cron')
 | 
				
			||||||
        backup_interval = request.form.get('backup_interval')
 | 
					 | 
				
			||||||
        auto_backup = request.form.get('auto_backup')
 | 
					        auto_backup = request.form.get('auto_backup')
 | 
				
			||||||
 | 
					        backup_cron = request.form.get('backup_cron')
 | 
				
			||||||
        enable_regex_entries = request.form.get('enable_regex_entries')
 | 
					        enable_regex_entries = request.form.get('enable_regex_entries')
 | 
				
			||||||
        retention_val = request.form.get('backup_retention_days', '0')
 | 
					        retention_val = request.form.get('backup_retention_days', '0')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Walidacja wyrażeń cron przy pomocy croniter
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            croniter(deploy_cron)
 | 
				
			||||||
 | 
					        except Exception as e:
 | 
				
			||||||
 | 
					            flash("Błędne wyrażenie cron dla deploy: " + str(e), "danger")
 | 
				
			||||||
 | 
					            return redirect(url_for('settings'))
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            croniter(backup_cron)
 | 
				
			||||||
 | 
					        except Exception as e:
 | 
				
			||||||
 | 
					            flash("Błędne wyrażenie cron dla backup: " + str(e), "danger")
 | 
				
			||||||
 | 
					            return redirect(url_for('settings'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        user_settings.auto_deploy_enabled = bool(auto_deploy)
 | 
					        user_settings.auto_deploy_enabled = bool(auto_deploy)
 | 
				
			||||||
        user_settings.auto_backup_enabled = bool(auto_backup)
 | 
					        user_settings.auto_backup_enabled = bool(auto_backup)
 | 
				
			||||||
        try:
 | 
					        user_settings.deploy_cron = deploy_cron if deploy_cron else "12 12 * * *"
 | 
				
			||||||
            user_settings.deploy_interval = int(deploy_interval)
 | 
					        user_settings.backup_cron = backup_cron if backup_cron else "12 12 * * *"
 | 
				
			||||||
        except ValueError:
 | 
					 | 
				
			||||||
            user_settings.deploy_interval = 60
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            user_settings.backup_interval = int(backup_interval)
 | 
					 | 
				
			||||||
        except ValueError:
 | 
					 | 
				
			||||||
            user_settings.backup_interval = 60
 | 
					 | 
				
			||||||
        user_settings.regex_deploy_enabled = bool(enable_regex_entries)
 | 
					        user_settings.regex_deploy_enabled = bool(enable_regex_entries)
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            user_settings.backup_retention_days = int(retention_val)
 | 
					            user_settings.backup_retention_days = int(retention_val)
 | 
				
			||||||
@@ -921,6 +934,9 @@ def deploy_user(user_id):
 | 
				
			|||||||
    hosts = Host.query.filter_by(user_id=user_id).all()
 | 
					    hosts = Host.query.filter_by(user_id=user_id).all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for h in hosts:
 | 
					    for h in hosts:
 | 
				
			||||||
 | 
					        # Tylko dla serwerów z włączonym auto_deploy
 | 
				
			||||||
 | 
					        if not h.auto_deploy_enabled:
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            if h.type == 'linux':
 | 
					            if h.type == 'linux':
 | 
				
			||||||
                ssh = open_ssh_connection(h)
 | 
					                ssh = open_ssh_connection(h)
 | 
				
			||||||
@@ -934,12 +950,11 @@ def deploy_user(user_id):
 | 
				
			|||||||
                sftp.close()
 | 
					                sftp.close()
 | 
				
			||||||
                ssh.close()
 | 
					                ssh.close()
 | 
				
			||||||
                os.remove(tmp_file_path)
 | 
					                os.remove(tmp_file_path)
 | 
				
			||||||
                db.session.add(DeployLog(details=f'[LINUX] Updated {h.hostname} for user {user_id}',user_id=user_id))
 | 
					                db.session.add(DeployLog(details=f'[LINUX] Updated {h.hostname} for user {user_id}', user_id=user_id))
 | 
				
			||||||
            elif h.type == 'mikrotik':
 | 
					            elif h.type == 'mikrotik':
 | 
				
			||||||
                wrapped_content = wrap_mikrotik_content(final_content)
 | 
					                wrapped_content = wrap_mikrotik_content(final_content)
 | 
				
			||||||
                deploy_mikrotik(h, wrapped_content)
 | 
					                deploy_mikrotik(h, wrapped_content)
 | 
				
			||||||
                db.session.add(DeployLog(details=f'[MIKROTIK] Updated {h.hostname} for user {user_id}',user_id=user_id))
 | 
					                db.session.add(DeployLog(details=f'[MIKROTIK] Updated {h.hostname} for user {user_id}', user_id=user_id))
 | 
				
			||||||
 | 
					 | 
				
			||||||
            db.session.commit()
 | 
					            db.session.commit()
 | 
				
			||||||
        except Exception as e:
 | 
					        except Exception as e:
 | 
				
			||||||
            db.session.add(DeployLog(details=f'Failed to update {h.hostname}: {str(e)} for user {user_id}'))
 | 
					            db.session.add(DeployLog(details=f'Failed to update {h.hostname}: {str(e)} for user {user_id}'))
 | 
				
			||||||
@@ -1131,20 +1146,61 @@ def delete_regex_host(entry_id):
 | 
				
			|||||||
    flash('Row deleted', 'info')
 | 
					    flash('Row deleted', 'info')
 | 
				
			||||||
    return redirect(url_for('list_regex_hosts'))
 | 
					    return redirect(url_for('list_regex_hosts'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.route('/delete-selected-backups', methods=['POST'])
 | 
				
			||||||
 | 
					def delete_selected_backups():
 | 
				
			||||||
 | 
					    if 'user_id' not in session:
 | 
				
			||||||
 | 
					        return redirect(url_for('login'))
 | 
				
			||||||
 | 
					    selected_ids = request.form.getlist('selected_backups')
 | 
				
			||||||
 | 
					    for backup_id in selected_ids:
 | 
				
			||||||
 | 
					        backup = db.session.get(Backup, backup_id)
 | 
				
			||||||
 | 
					        if backup and backup.user_id == session['user_id']:
 | 
				
			||||||
 | 
					            db.session.delete(backup)
 | 
				
			||||||
 | 
					    db.session.commit()
 | 
				
			||||||
 | 
					    flash('Zaznaczone backupy zostały usunięte.', 'info')
 | 
				
			||||||
 | 
					    return redirect(url_for('backups'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.route('/update-host-automation/<int:id>', methods=['POST'])
 | 
				
			||||||
 | 
					def update_host_automation(id):
 | 
				
			||||||
 | 
					    if 'user_id' not in session:
 | 
				
			||||||
 | 
					        return redirect(url_for('login'))
 | 
				
			||||||
 | 
					    host = db.session.get(Host, id)
 | 
				
			||||||
 | 
					    if not host or host.user_id != session['user_id']:
 | 
				
			||||||
 | 
					        flash('Serwer nie istnieje lub nie masz uprawnień', 'danger')
 | 
				
			||||||
 | 
					        return redirect(url_for('server_list'))
 | 
				
			||||||
 | 
					    setting = request.form.get('setting')
 | 
				
			||||||
 | 
					    enabled = request.form.get('enabled') == '1'
 | 
				
			||||||
 | 
					    if setting == 'auto_deploy':
 | 
				
			||||||
 | 
					        host.auto_deploy_enabled = enabled
 | 
				
			||||||
 | 
					    elif setting == 'auto_backup':
 | 
				
			||||||
 | 
					        host.auto_backup_enabled = enabled
 | 
				
			||||||
 | 
					    db.session.commit()
 | 
				
			||||||
 | 
					    flash('Ustawienia automatyzacji zostały zaktualizowane.', 'success')
 | 
				
			||||||
 | 
					    return redirect(url_for('server_list'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def scheduled_deployments():
 | 
					def scheduled_deployments():
 | 
				
			||||||
    with app.app_context():
 | 
					    with app.app_context():
 | 
				
			||||||
        now = datetime.now(timezone.utc)
 | 
					        now = datetime.now(timezone.utc)
 | 
				
			||||||
        all_settings = UserSettings.query.filter_by(auto_deploy_enabled=True).all()
 | 
					        settings_list = UserSettings.query.filter_by(auto_deploy_enabled=True).all()
 | 
				
			||||||
        for setting in all_settings:
 | 
					        for setting in settings_list:
 | 
				
			||||||
            last_deploy_time = setting.last_deploy_time
 | 
					            if not setting.deploy_cron:
 | 
				
			||||||
            if last_deploy_time:
 | 
					                continue
 | 
				
			||||||
                last_deploy_time = last_deploy_time.replace(tzinfo=timezone.utc)
 | 
					            if setting.last_deploy_time:
 | 
				
			||||||
            if not last_deploy_time or now - last_deploy_time >= timedelta(minutes=setting.deploy_interval):
 | 
					                base_time = setting.last_deploy_time
 | 
				
			||||||
 | 
					                if base_time.tzinfo is None:
 | 
				
			||||||
 | 
					                    base_time = base_time.replace(tzinfo=timezone.utc)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                base_time = datetime(1970,1,1, tzinfo=timezone.utc)
 | 
				
			||||||
 | 
					            cron = croniter(setting.deploy_cron, base_time)
 | 
				
			||||||
 | 
					            next_deploy = cron.get_next(datetime)
 | 
				
			||||||
 | 
					            if now >= next_deploy:
 | 
				
			||||||
                deploy_user(setting.user_id)
 | 
					                deploy_user(setting.user_id)
 | 
				
			||||||
                setting.last_deploy_time = now
 | 
					                setting.last_deploy_time = now
 | 
				
			||||||
                db.session.commit()
 | 
					                db.session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
scheduler = BackgroundScheduler(timezone="UTC")
 | 
					
 | 
				
			||||||
 | 
					scheduler = BackgroundScheduler(timezone=get_localzone())
 | 
				
			||||||
scheduler.add_job(func=scheduled_deployments, trigger="interval", minutes=1, next_run_time=datetime.now())
 | 
					scheduler.add_job(func=scheduled_deployments, trigger="interval", minutes=1, next_run_time=datetime.now())
 | 
				
			||||||
scheduler.add_job(func=automated_backups, trigger="interval", minutes=1, next_run_time=datetime.now())
 | 
					scheduler.add_job(func=automated_backups, trigger="interval", minutes=1, next_run_time=datetime.now())
 | 
				
			||||||
scheduler.add_job(func=cleanup_old_backups, trigger="interval", hours=24, next_run_time=datetime.now())
 | 
					scheduler.add_job(func=cleanup_old_backups, trigger="interval", hours=24, next_run_time=datetime.now())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,9 +5,8 @@ from datetime import datetime
 | 
				
			|||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
    with app.app_context():
 | 
					    with app.app_context():
 | 
				
			||||||
        db.create_all()
 | 
					        db.create_all()
 | 
				
			||||||
    for job in scheduler.get_jobs():
 | 
					
 | 
				
			||||||
        job.modify(next_run_time=datetime.now())
 | 
					 | 
				
			||||||
        print(job)
 | 
					 | 
				
			||||||
    if not scheduler.running:
 | 
					    if not scheduler.running:
 | 
				
			||||||
        scheduler.start()
 | 
					        scheduler.start()
 | 
				
			||||||
    serve(app, listen="*:5580", threads=4, ident="")
 | 
					
 | 
				
			||||||
 | 
					    serve(app, listen="*:5580", threads=4, ident="")
 | 
				
			||||||
@@ -19,6 +19,7 @@
 | 
				
			|||||||
    <table class="table table-striped">
 | 
					    <table class="table table-striped">
 | 
				
			||||||
      <thead>
 | 
					      <thead>
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
 | 
					          <th><input type="checkbox" id="select-all"></th>
 | 
				
			||||||
          <th>Data utworzenia</th>
 | 
					          <th>Data utworzenia</th>
 | 
				
			||||||
          <th>Opis</th>
 | 
					          <th>Opis</th>
 | 
				
			||||||
          <th>Akcje</th>
 | 
					          <th>Akcje</th>
 | 
				
			||||||
@@ -27,11 +28,16 @@
 | 
				
			|||||||
      <tbody>
 | 
					      <tbody>
 | 
				
			||||||
        {% for backup in backups %}
 | 
					        {% for backup in backups %}
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
 | 
					          <td>
 | 
				
			||||||
 | 
					            <!-- Każdy checkbox jest przypisany do formularza bulkDeleteForm -->
 | 
				
			||||||
 | 
					            <input type="checkbox" name="selected_backups" value="{{ backup.id }}" form="bulkDeleteForm">
 | 
				
			||||||
 | 
					          </td>
 | 
				
			||||||
          <td>{{ backup.created_at.strftime("%Y-%m-%d %H:%M:%S") }}</td>
 | 
					          <td>{{ backup.created_at.strftime("%Y-%m-%d %H:%M:%S") }}</td>
 | 
				
			||||||
          <td>{{ backup.description }}</td>
 | 
					          <td>{{ backup.description }}</td>
 | 
				
			||||||
          <td>
 | 
					          <td>
 | 
				
			||||||
            <a href="{{ url_for('view_backup', backup_id=backup.id) }}" class="btn btn-sm btn-info">Podgląd</a>
 | 
					            <a href="{{ url_for('view_backup', backup_id=backup.id) }}" class="btn btn-sm btn-info">Podgląd</a>
 | 
				
			||||||
            <a href="{{ url_for('restore_backup', backup_id=backup.id) }}" class="btn btn-sm btn-success">Przywróć</a>
 | 
					            <a href="{{ url_for('restore_backup', backup_id=backup.id) }}" class="btn btn-sm btn-success">Przywróć</a>
 | 
				
			||||||
 | 
					            <!-- Usuwanie pojedynczego backupu -->
 | 
				
			||||||
            <form action="{{ url_for('delete_backup', backup_id=backup.id) }}" method="post" style="display:inline;">
 | 
					            <form action="{{ url_for('delete_backup', backup_id=backup.id) }}" method="post" style="display:inline;">
 | 
				
			||||||
              <button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Czy na pewno usunąć backup?');">Usuń</button>
 | 
					              <button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Czy na pewno usunąć backup?');">Usuń</button>
 | 
				
			||||||
            </form>
 | 
					            </form>
 | 
				
			||||||
@@ -40,6 +46,22 @@
 | 
				
			|||||||
        {% endfor %}
 | 
					        {% endfor %}
 | 
				
			||||||
      </tbody>
 | 
					      </tbody>
 | 
				
			||||||
    </table>
 | 
					    </table>
 | 
				
			||||||
 | 
					    <!-- Formularz do bulk usuwania – checkboxy znajdują się poza tym formularzem, ale dzięki atrybutowi form są z nim powiązane -->
 | 
				
			||||||
 | 
					    <form id="bulkDeleteForm" action="{{ url_for('delete_selected_backups') }}" method="post">
 | 
				
			||||||
 | 
					      <button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Czy na pewno usunąć zaznaczone backupy?');">Usuń zaznaczone</button>
 | 
				
			||||||
 | 
					    </form>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					{% block extra_js %}
 | 
				
			||||||
 | 
					  {{ super() }}
 | 
				
			||||||
 | 
					  <script>
 | 
				
			||||||
 | 
					    // Skrypt do zaznaczania/odznaczania wszystkich checkboxów
 | 
				
			||||||
 | 
					    document.getElementById('select-all').addEventListener('change', function(){
 | 
				
			||||||
 | 
					      var checkboxes = document.querySelectorAll('input[name="selected_backups"]');
 | 
				
			||||||
 | 
					      checkboxes.forEach(function(checkbox) {
 | 
				
			||||||
 | 
					        checkbox.checked = document.getElementById('select-all').checked;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  </script>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,8 @@
 | 
				
			|||||||
          <th>Port</th>
 | 
					          <th>Port</th>
 | 
				
			||||||
          <th>Typ</th>
 | 
					          <th>Typ</th>
 | 
				
			||||||
          <th>Metoda uwierzytelniania</th>
 | 
					          <th>Metoda uwierzytelniania</th>
 | 
				
			||||||
 | 
					          <th>Auto Deploy</th>
 | 
				
			||||||
 | 
					          <th>Auto Backup</th>
 | 
				
			||||||
          <th>Akcje</th>
 | 
					          <th>Akcje</th>
 | 
				
			||||||
        </tr>
 | 
					        </tr>
 | 
				
			||||||
      </thead>
 | 
					      </thead>
 | 
				
			||||||
@@ -38,10 +40,24 @@
 | 
				
			|||||||
          <td>{{ h.port }}</td>
 | 
					          <td>{{ h.port }}</td>
 | 
				
			||||||
          <td>{{ h.type }}</td>
 | 
					          <td>{{ h.type }}</td>
 | 
				
			||||||
          <td>{{ h.auth_method }}</td>
 | 
					          <td>{{ h.auth_method }}</td>
 | 
				
			||||||
 | 
					          <!-- Formularz aktualizujący automatyczny deploy dla serwera -->
 | 
				
			||||||
 | 
					          <td>
 | 
				
			||||||
 | 
					            <form method="POST" action="{{ url_for('update_host_automation', id=h.id) }}" style="display:inline;">
 | 
				
			||||||
 | 
					              <input type="hidden" name="setting" value="auto_deploy">
 | 
				
			||||||
 | 
					              <input type="checkbox" name="enabled" value="1" onchange="this.form.submit()" {% if h.auto_deploy_enabled %}checked{% endif %}>
 | 
				
			||||||
 | 
					            </form>
 | 
				
			||||||
 | 
					          </td>
 | 
				
			||||||
 | 
					          <!-- Formularz aktualizujący automatyczny backup dla serwera -->
 | 
				
			||||||
 | 
					          <td>
 | 
				
			||||||
 | 
					            <form method="POST" action="{{ url_for('update_host_automation', id=h.id) }}" style="display:inline;">
 | 
				
			||||||
 | 
					              <input type="hidden" name="setting" value="auto_backup">
 | 
				
			||||||
 | 
					              <input type="checkbox" name="enabled" value="1" onchange="this.form.submit()" {% if h.auto_backup_enabled %}checked{% endif %}>
 | 
				
			||||||
 | 
					            </form>
 | 
				
			||||||
 | 
					          </td>
 | 
				
			||||||
          <td>
 | 
					          <td>
 | 
				
			||||||
            <a href="{{ url_for('edit_server', id=h.id) }}" class="btn btn-primary btn-sm">Edytuj</a>
 | 
					            <a href="{{ url_for('edit_server', id=h.id) }}" class="btn btn-primary btn-sm">Edytuj</a>
 | 
				
			||||||
            <a href="{{ url_for('test_server_connection', id=h.id) }}" class="btn btn-info btn-sm">Testuj</a>
 | 
					            <a href="{{ url_for('test_server_connection', id=h.id) }}" class="btn btn-info btn-sm">Testuj</a>
 | 
				
			||||||
            <a href="{{ url_for('server_backup', host_id=h.id) }}" class="btn btn-success btn-sm">Backup</a>            
 | 
					            <a href="{{ url_for('server_backup', host_id=h.id) }}" class="btn btn-success btn-sm">Backup</a>
 | 
				
			||||||
            <form method="GET" action="{{ url_for('delete_server', id=h.id) }}" style="display:inline;">
 | 
					            <form method="GET" action="{{ url_for('delete_server', id=h.id) }}" style="display:inline;">
 | 
				
			||||||
              <button type="submit" class="btn btn-danger btn-sm">Usuń</button>
 | 
					              <button type="submit" class="btn btn-danger btn-sm">Usuń</button>
 | 
				
			||||||
            </form>
 | 
					            </form>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,17 +21,25 @@
 | 
				
			|||||||
        <label class="form-check-label" for="auto_deploy">Automatyczny deploy</label>
 | 
					        <label class="form-check-label" for="auto_deploy">Automatyczny deploy</label>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="mb-3">
 | 
					      <div class="mb-3">
 | 
				
			||||||
        <label for="deploy_interval" class="form-label">Interwał deploy (minuty)</label>
 | 
					        <label for="deploy_cron" class="form-label">Harmonogram deploy (cron)</label>
 | 
				
			||||||
        <input type="number" class="form-control" id="deploy_interval" name="deploy_interval" value="{{ settings.deploy_interval }}">
 | 
					        <div class="input-group">
 | 
				
			||||||
      </div>
 | 
					          <input type="text" class="form-control" id="deploy_cron" name="deploy_cron" value="{{ settings.deploy_cron }}">
 | 
				
			||||||
      <div class="mb-3">
 | 
					          <button type="button" class="btn btn-outline-secondary" onclick="openCronModal('deploy_cron')">Generuj cron</button>
 | 
				
			||||||
        <label for="backup_interval" class="form-label">Interwał backupów (minuty)</label>
 | 
					        </div>
 | 
				
			||||||
        <input type="number" class="form-control" id="backup_interval" name="backup_interval" value="{{ settings.backup_interval }}">
 | 
					        <small class="text-muted">Np. <code>0 0 * * *</code> – codziennie o północy</small>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="mb-3 form-check">
 | 
					      <div class="mb-3 form-check">
 | 
				
			||||||
        <input type="checkbox" class="form-check-input" id="auto_backup" name="auto_backup" {% if settings.auto_backup_enabled %}checked{% endif %}>
 | 
					        <input type="checkbox" class="form-check-input" id="auto_backup" name="auto_backup" {% if settings.auto_backup_enabled %}checked{% endif %}>
 | 
				
			||||||
        <label class="form-check-label" for="auto_backup">Automatyczne kopie zapasowe</label>
 | 
					        <label class="form-check-label" for="auto_backup">Automatyczne kopie zapasowe</label>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="mb-3">
 | 
				
			||||||
 | 
					        <label for="backup_cron" class="form-label">Harmonogram backup (cron)</label>
 | 
				
			||||||
 | 
					        <div class="input-group">
 | 
				
			||||||
 | 
					          <input type="text" class="form-control" id="backup_cron" name="backup_cron" value="{{ settings.backup_cron }}">
 | 
				
			||||||
 | 
					          <button type="button" class="btn btn-outline-secondary" onclick="openCronModal('backup_cron')">Generuj cron</button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <small class="text-muted">Np. <code>0 */6 * * *</code> – co 6 godzin</small>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
      <div class="mb-3 form-check">
 | 
					      <div class="mb-3 form-check">
 | 
				
			||||||
        <input type="checkbox" class="form-check-input" id="enable_regex_entries" name="enable_regex_entries" {% if settings.regex_deploy_enabled %}checked{% endif %}>
 | 
					        <input type="checkbox" class="form-check-input" id="enable_regex_entries" name="enable_regex_entries" {% if settings.regex_deploy_enabled %}checked{% endif %}>
 | 
				
			||||||
        <label class="form-check-label" for="enable_regex_entries">Włącz regex/CIDR deploy</label>
 | 
					        <label class="form-check-label" for="enable_regex_entries">Włącz regex/CIDR deploy</label>
 | 
				
			||||||
@@ -44,4 +52,81 @@
 | 
				
			|||||||
    </form>
 | 
					    </form>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!-- Modal do generowania wyrażenia CRON -->
 | 
				
			||||||
 | 
					<div class="modal fade" id="cronModal" tabindex="-1" aria-labelledby="cronModalLabel" aria-hidden="true">
 | 
				
			||||||
 | 
					  <div class="modal-dialog">
 | 
				
			||||||
 | 
					    <div class="modal-content">
 | 
				
			||||||
 | 
					      <div class="modal-header">
 | 
				
			||||||
 | 
					        <h5 class="modal-title" id="cronModalLabel">Generuj wyrażenie CRON</h5>
 | 
				
			||||||
 | 
					        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Zamknij"></button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="modal-body">
 | 
				
			||||||
 | 
					        <div class="mb-3">
 | 
				
			||||||
 | 
					          <label for="cron_minute" class="form-label">Minuta</label>
 | 
				
			||||||
 | 
					          <input type="text" class="form-control" id="cron_minute" placeholder="0-59">
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="mb-3">
 | 
				
			||||||
 | 
					          <label for="cron_hour_modal" class="form-label">Godzina</label>
 | 
				
			||||||
 | 
					          <input type="text" class="form-control" id="cron_hour_modal" placeholder="0-23">
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="mb-3">
 | 
				
			||||||
 | 
					          <label for="cron_day" class="form-label">Dzień miesiąca</label>
 | 
				
			||||||
 | 
					          <input type="text" class="form-control" id="cron_day" placeholder="1-31 lub *">
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="mb-3">
 | 
				
			||||||
 | 
					          <label for="cron_month" class="form-label">Miesiąc</label>
 | 
				
			||||||
 | 
					          <input type="text" class="form-control" id="cron_month" placeholder="1-12 lub *">
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="mb-3">
 | 
				
			||||||
 | 
					          <label for="cron_dow" class="form-label">Dzień tygodnia</label>
 | 
				
			||||||
 | 
					          <input type="text" class="form-control" id="cron_dow" placeholder="0-6 (0 = niedziela) lub *">
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="modal-footer">
 | 
				
			||||||
 | 
					        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Anuluj</button>
 | 
				
			||||||
 | 
					        <button type="button" class="btn btn-primary" onclick="generateCronExpression()">Generuj</button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block extra_js %}
 | 
				
			||||||
 | 
					  {{ super() }}
 | 
				
			||||||
 | 
					  <script>
 | 
				
			||||||
 | 
					    // Globalna zmienna, która będzie przechowywać ID pola formularza do aktualizacji
 | 
				
			||||||
 | 
					    var currentCronField = null;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    function openCronModal(fieldId) {
 | 
				
			||||||
 | 
					      currentCronField = fieldId;
 | 
				
			||||||
 | 
					      // Resetuj wartości w modal
 | 
				
			||||||
 | 
					      document.getElementById('cron_minute').value = "";
 | 
				
			||||||
 | 
					      document.getElementById('cron_hour_modal').value = "";
 | 
				
			||||||
 | 
					      document.getElementById('cron_day').value = "";
 | 
				
			||||||
 | 
					      document.getElementById('cron_month').value = "";
 | 
				
			||||||
 | 
					      document.getElementById('cron_dow').value = "";
 | 
				
			||||||
 | 
					      // Wyświetl modal przy użyciu Bootstrap
 | 
				
			||||||
 | 
					      var cronModal = new bootstrap.Modal(document.getElementById('cronModal'));
 | 
				
			||||||
 | 
					      cronModal.show();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    function generateCronExpression() {
 | 
				
			||||||
 | 
					      var minute = document.getElementById('cron_minute').value || "*";
 | 
				
			||||||
 | 
					      var hour = document.getElementById('cron_hour_modal').value || "*";
 | 
				
			||||||
 | 
					      var day = document.getElementById('cron_day').value || "*";
 | 
				
			||||||
 | 
					      var month = document.getElementById('cron_month').value || "*";
 | 
				
			||||||
 | 
					      var dow = document.getElementById('cron_dow').value || "*";
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      var cronExpression = minute + " " + hour + " " + day + " " + month + " " + dow;
 | 
				
			||||||
 | 
					      if (currentCronField) {
 | 
				
			||||||
 | 
					        document.getElementById(currentCronField).value = cronExpression;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // Zamknij modal
 | 
				
			||||||
 | 
					      var modalEl = document.getElementById('cronModal');
 | 
				
			||||||
 | 
					      var modal = bootstrap.Modal.getInstance(modalEl);
 | 
				
			||||||
 | 
					      modal.hide();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  </script>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user