diff --git a/horilla/locale/pt-br/LC_MESSAGES/django.po b/horilla/locale/pt-br/LC_MESSAGES/django.po
index dfe958866..76c760932 100644
--- a/horilla/locale/pt-br/LC_MESSAGES/django.po
+++ b/horilla/locale/pt-br/LC_MESSAGES/django.po
@@ -25608,4 +25608,3 @@ msgstr "Progresso"
#~ msgid "individual"
#~ msgstr "Creation"
-
diff --git a/horilla_backup/__init__.py b/horilla_backup/__init__.py
index ce8e07933..9e36fe06c 100644
--- a/horilla_backup/__init__.py
+++ b/horilla_backup/__init__.py
@@ -1 +1 @@
-default_app_config = 'horilla_backup.apps.backupConfig'
\ No newline at end of file
+default_app_config = "horilla_backup.apps.backupConfig"
diff --git a/horilla_backup/admin.py b/horilla_backup/admin.py
index ab2135701..589ebd2b4 100644
--- a/horilla_backup/admin.py
+++ b/horilla_backup/admin.py
@@ -1,9 +1,8 @@
from django.contrib import admin
+
from .models import *
# Register your models here.
admin.site.register(LocalBackup)
admin.site.register(GoogleDriveBackup)
-
-
\ No newline at end of file
diff --git a/horilla_backup/apps.py b/horilla_backup/apps.py
index 776d88db9..6b9267819 100644
--- a/horilla_backup/apps.py
+++ b/horilla_backup/apps.py
@@ -1,15 +1,16 @@
-from django.apps import AppConfig
+from django.apps import AppConfig
+
class BackupConfig(AppConfig):
- default_auto_field = 'django.db.models.BigAutoField'
- name = 'horilla_backup'
-
+ default_auto_field = "django.db.models.BigAutoField"
+ name = "horilla_backup"
+
def ready(self):
from django.urls import include, path
+
from horilla.urls import urlpatterns
urlpatterns.append(
path("backup/", include("horilla_backup.urls")),
)
super().ready()
-
diff --git a/horilla_backup/forms.py b/horilla_backup/forms.py
index 6767c1cd4..de313f6e2 100644
--- a/horilla_backup/forms.py
+++ b/horilla_backup/forms.py
@@ -1,28 +1,39 @@
+import os
+from pathlib import Path
+
from django import forms
-from .models import *
-from base.forms import ModelForm
-from django.template.loader import render_to_string
from django.core.exceptions import ValidationError
+from django.core.files.base import ContentFile
+from django.core.files.storage import default_storage
+from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _
-from pathlib import Path
+
+from base.forms import ModelForm
+
from .gdrive import authenticate
-from django.core.files.storage import default_storage
-from django.core.files.base import ContentFile
-import os
+from .models import *
class LocalBackupSetupForm(ModelForm):
verbose_name = "Server Backup"
- backup_db = forms.BooleanField(required=False, help_text="Enable to backup database to server.")
- backup_media = forms.BooleanField(required=False, help_text="Enable to backup all media files to server.")
- interval = forms.BooleanField(required=False, help_text="Enable to automate the backup in a period of seconds.")
- fixed = forms.BooleanField(required=False, help_text="Enable to automate the backup in a fixed time.")
+ backup_db = forms.BooleanField(
+ required=False, help_text="Enable to backup database to server."
+ )
+ backup_media = forms.BooleanField(
+ required=False, help_text="Enable to backup all media files to server."
+ )
+ interval = forms.BooleanField(
+ required=False,
+ help_text="Enable to automate the backup in a period of seconds.",
+ )
+ fixed = forms.BooleanField(
+ required=False, help_text="Enable to automate the backup in a fixed time."
+ )
class Meta:
model = LocalBackup
- exclude = ['active']
+ exclude = ["active"]
-
def as_p(self):
"""
Render the form fields as HTML table rows with Bootstrap styling.
@@ -30,64 +41,65 @@ def as_p(self):
context = {"form": self}
table_html = render_to_string("common_form.html", context)
return table_html
-
-
+
def clean(self):
cleaned_data = super().clean()
- backup_db = cleaned_data.get('backup_db')
- backup_media = cleaned_data.get('backup_media')
- interval = cleaned_data.get('interval')
- fixed = cleaned_data.get('fixed')
- seconds = cleaned_data.get('seconds')
- hour = cleaned_data.get('hour')
- minute = cleaned_data.get('minute')
- backup_path = cleaned_data.get('backup_path')
+ backup_db = cleaned_data.get("backup_db")
+ backup_media = cleaned_data.get("backup_media")
+ interval = cleaned_data.get("interval")
+ fixed = cleaned_data.get("fixed")
+ seconds = cleaned_data.get("seconds")
+ hour = cleaned_data.get("hour")
+ minute = cleaned_data.get("minute")
+ backup_path = cleaned_data.get("backup_path")
path = Path(backup_path)
if not path.exists():
- raise ValidationError({
- 'backup_path': _('The directory does not exist.')
- })
+ raise ValidationError({"backup_path": _("The directory does not exist.")})
if backup_db == False and backup_media == False:
raise forms.ValidationError("Please select any backup option.")
if interval == False and fixed == False:
raise forms.ValidationError("Please select any backup automate option.")
- if interval == True and seconds == None:
- raise ValidationError({
- 'seconds': _('This field is required.')
- })
- if fixed == True and hour == None:
- raise ValidationError({
- 'hour': _('This field is required.')
- })
+ if interval == True and seconds == None:
+ raise ValidationError({"seconds": _("This field is required.")})
+ if fixed == True and hour == None:
+ raise ValidationError({"hour": _("This field is required.")})
if seconds:
if seconds < 0:
- raise ValidationError({
- 'seconds': _('Negative value is not accepatable.')
- })
+ raise ValidationError(
+ {"seconds": _("Negative value is not accepatable.")}
+ )
if hour:
if hour < 0 or hour > 24:
- raise ValidationError({
- 'hour': _('Enter a hour between 0 to 24.')
- })
- if minute:
+ raise ValidationError({"hour": _("Enter a hour between 0 to 24.")})
+ if minute:
if minute < 0 or minute > 60:
- raise ValidationError({
- 'minute': _('Enter a minute between 0 to 60.')
- })
- return cleaned_data
-
+ raise ValidationError({"minute": _("Enter a minute between 0 to 60.")})
+ return cleaned_data
+
class GdriveBackupSetupForm(ModelForm):
verbose_name = "Gdrive Backup"
- backup_db = forms.BooleanField(required=False, label="Backup DB", help_text="Enable to backup database to Gdrive")
- backup_media = forms.BooleanField(required=False, label="Backup Media", help_text="Enable to backup all media files to Gdrive")
- interval = forms.BooleanField(required=False, help_text="Enable to automate the backup in a period of seconds.")
- fixed = forms.BooleanField(required=False, help_text="Enable to automate the backup in a fixed time.")
+ backup_db = forms.BooleanField(
+ required=False,
+ label="Backup DB",
+ help_text="Enable to backup database to Gdrive",
+ )
+ backup_media = forms.BooleanField(
+ required=False,
+ label="Backup Media",
+ help_text="Enable to backup all media files to Gdrive",
+ )
+ interval = forms.BooleanField(
+ required=False,
+ help_text="Enable to automate the backup in a period of seconds.",
+ )
+ fixed = forms.BooleanField(
+ required=False, help_text="Enable to automate the backup in a fixed time."
+ )
class Meta:
model = GoogleDriveBackup
- exclude = ['active']
-
+ exclude = ["active"]
def as_p(self):
"""
@@ -96,18 +108,18 @@ def as_p(self):
context = {"form": self}
table_html = render_to_string("common_form.html", context)
return table_html
-
+
def clean(self):
cleaned_data = super().clean()
- backup_db = cleaned_data.get('backup_db')
- backup_media = cleaned_data.get('backup_media')
- interval = cleaned_data.get('interval')
- fixed = cleaned_data.get('fixed')
- seconds = cleaned_data.get('seconds')
- hour = cleaned_data.get('hour')
- minute = cleaned_data.get('minute')
- service_account_file = cleaned_data.get('service_account_file')
-
+ backup_db = cleaned_data.get("backup_db")
+ backup_media = cleaned_data.get("backup_media")
+ interval = cleaned_data.get("interval")
+ fixed = cleaned_data.get("fixed")
+ seconds = cleaned_data.get("seconds")
+ hour = cleaned_data.get("hour")
+ minute = cleaned_data.get("minute")
+ service_account_file = cleaned_data.get("service_account_file")
+
try:
if GoogleDriveBackup.objects.exists():
authenticate(service_account_file.path)
@@ -115,41 +127,35 @@ def clean(self):
file_data = service_account_file.read()
# Save the processed file to the desired location
file_name = service_account_file.name
- new_file_name = file_name
+ new_file_name = file_name
# Save using Django's default storage system
- relative_path = default_storage.save(new_file_name, ContentFile(file_data))
+ relative_path = default_storage.save(
+ new_file_name, ContentFile(file_data)
+ )
# Get the full absolute path
- full_path = default_storage.path(relative_path)
+ full_path = default_storage.path(relative_path)
authenticate(full_path)
os.remove(full_path)
-
+
except Exception as e:
raise forms.ValidationError("Please provide a valid service account file.")
if backup_db == False and backup_media == False:
raise forms.ValidationError("Please select any backup option.")
if interval == False and fixed == False:
raise forms.ValidationError("Please select any backup automate option.")
- if interval == True and seconds == None:
- raise ValidationError({
- 'seconds': _('This field is required.')
- })
- if fixed == True and hour == None:
- raise ValidationError({
- 'hour': _('This field is required.')
- })
+ if interval == True and seconds == None:
+ raise ValidationError({"seconds": _("This field is required.")})
+ if fixed == True and hour == None:
+ raise ValidationError({"hour": _("This field is required.")})
if seconds:
if seconds < 0:
- raise ValidationError({
- 'seconds': _('Negative value is not accepatable.')
- })
+ raise ValidationError(
+ {"seconds": _("Negative value is not accepatable.")}
+ )
if hour:
if hour < 0 or hour > 24:
- raise ValidationError({
- 'hour': _('Enter a hour between 0 to 24.')
- })
- if minute:
+ raise ValidationError({"hour": _("Enter a hour between 0 to 24.")})
+ if minute:
if minute < 0 or minute > 60:
- raise ValidationError({
- 'minute': _('Enter a minute between 0 to 60.')
- })
- return cleaned_data
\ No newline at end of file
+ raise ValidationError({"minute": _("Enter a minute between 0 to 60.")})
+ return cleaned_data
diff --git a/horilla_backup/gdrive.py b/horilla_backup/gdrive.py
index 3a375fa81..d39baeee6 100644
--- a/horilla_backup/gdrive.py
+++ b/horilla_backup/gdrive.py
@@ -1,29 +1,28 @@
-from googleapiclient.discovery import build
+import os
+
from google.oauth2 import service_account
+from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
-import os
-
-SCOPES = ['https://www.googleapis.com/auth/drive']
-
-
+SCOPES = ["https://www.googleapis.com/auth/drive"]
+
+
def authenticate(service_account_file):
- creds = service_account.Credentials.from_service_account_file(service_account_file, scopes=SCOPES)
+ creds = service_account.Credentials.from_service_account_file(
+ service_account_file, scopes=SCOPES
+ )
return creds
-
-def upload_file(file_path, service_account_file, parent_folder_id):
+
+def upload_file(file_path, service_account_file, parent_folder_id):
creds = authenticate(service_account_file)
- service = build('drive', 'v3', credentials=creds)
+ service = build("drive", "v3", credentials=creds)
parent_folder_id = parent_folder_id
- file_metadata = {
- 'name' : os.path.basename(file_path),
- 'parents' : [parent_folder_id]
- }
+ file_metadata = {"name": os.path.basename(file_path), "parents": [parent_folder_id]}
media = MediaFileUpload(file_path, resumable=True)
- file = service.files().create(
- body=file_metadata,
- media_body=media,
- fields='id'
- ).execute()
+ file = (
+ service.files()
+ .create(body=file_metadata, media_body=media, fields="id")
+ .execute()
+ )
diff --git a/horilla_backup/migrations/__init__.py b/horilla_backup/migrations/__init__.py
index 63c57730a..4898c42f8 100644
--- a/horilla_backup/migrations/__init__.py
+++ b/horilla_backup/migrations/__init__.py
@@ -3,16 +3,18 @@
def shutdown_function():
from horilla_backup.models import GoogleDriveBackup, LocalBackup
+
if GoogleDriveBackup.objects.exists():
google_drive_backup = GoogleDriveBackup.objects.first()
- google_drive_backup.active = False
+ google_drive_backup.active = False
google_drive_backup.save()
if LocalBackup.objects.exists():
local_backup = LocalBackup.objects.first()
local_backup.active = False
local_backup.save()
+
try:
atexit.register(shutdown_function)
except:
- pass
\ No newline at end of file
+ pass
diff --git a/horilla_backup/models.py b/horilla_backup/models.py
index 42c88bee7..f5917bf84 100644
--- a/horilla_backup/models.py
+++ b/horilla_backup/models.py
@@ -1,24 +1,27 @@
from django.db import models
-#Create your models here.
+# Create your models here.
+
class LocalBackup(models.Model):
- backup_path = models.CharField(max_length=255, help_text="Specify the path in the server were the backup files should keep")
+ backup_path = models.CharField(
+ max_length=255,
+ help_text="Specify the path in the server were the backup files should keep",
+ )
backup_media = models.BooleanField(blank=True, null=True)
backup_db = models.BooleanField(blank=True, null=True)
interval = models.BooleanField(blank=True, null=True)
fixed = models.BooleanField(blank=True, null=True)
seconds = models.IntegerField(blank=True, null=True)
hour = models.IntegerField(blank=True, null=True)
- minute = models.IntegerField(blank=True, null=True)
- active = models.BooleanField(default=False)
-
+ minute = models.IntegerField(blank=True, null=True)
+ active = models.BooleanField(default=False)
def save(self, *args, **kwargs):
# Check if there's an existing instance
if self.interval == False:
self.seconds = None
- if self.fixed == False:
+ if self.fixed == False:
self.hour = None
self.minute = None
if LocalBackup.objects.exists():
@@ -26,7 +29,7 @@ def save(self, *args, **kwargs):
existing_instance = LocalBackup.objects.first()
# Update the fields of the existing instance with the new data
for field in self._meta.fields:
- if field.name != 'id': # Avoid changing the primary key
+ if field.name != "id": # Avoid changing the primary key
setattr(existing_instance, field.name, getattr(self, field.name))
# Save the updated instance
super(LocalBackup, existing_instance).save(*args, **kwargs)
@@ -38,22 +41,25 @@ def save(self, *args, **kwargs):
class GoogleDriveBackup(models.Model):
- service_account_file = models.FileField(upload_to="gdrive_service_account_file",
- verbose_name="Service Account File",
- help_text="Make sure your file is in JSON format and contains your Google Service Account credentials")
- gdrive_folder_id = models.CharField(max_length=255,
- verbose_name="Gdrive Folder ID",
- help_text="Shared Gdrive folder Id with access granted to Gmail service account. Enable full permissions for seamless connection.")
+ service_account_file = models.FileField(
+ upload_to="gdrive_service_account_file",
+ verbose_name="Service Account File",
+ help_text="Make sure your file is in JSON format and contains your Google Service Account credentials",
+ )
+ gdrive_folder_id = models.CharField(
+ max_length=255,
+ verbose_name="Gdrive Folder ID",
+ help_text="Shared Gdrive folder Id with access granted to Gmail service account. Enable full permissions for seamless connection.",
+ )
backup_media = models.BooleanField(blank=True, null=True)
- backup_db = models.BooleanField(blank=True, null=True)
+ backup_db = models.BooleanField(blank=True, null=True)
interval = models.BooleanField(blank=True, null=True)
- fixed = models.BooleanField(blank=True, null=True)
- seconds = models.IntegerField(blank=True, null=True)
+ fixed = models.BooleanField(blank=True, null=True)
+ seconds = models.IntegerField(blank=True, null=True)
hour = models.IntegerField(blank=True, null=True)
- minute = models.IntegerField(blank=True, null=True)
+ minute = models.IntegerField(blank=True, null=True)
active = models.BooleanField(default=False)
-
def save(self, *args, **kwargs):
# Check if there's an existing instance
if self.interval == False:
@@ -66,7 +72,7 @@ def save(self, *args, **kwargs):
existing_instance = GoogleDriveBackup.objects.first()
# Update the fields of the existing instance with the new data
for field in self._meta.fields:
- if field.name != 'id': # Avoid changing the primary key
+ if field.name != "id": # Avoid changing the primary key
setattr(existing_instance, field.name, getattr(self, field.name))
# Save the updated instance
super(GoogleDriveBackup, existing_instance).save(*args, **kwargs)
@@ -74,4 +80,4 @@ def save(self, *args, **kwargs):
else:
# If no existing instance, proceed with regular save
super(GoogleDriveBackup, self).save(*args, **kwargs)
- return self
\ No newline at end of file
+ return self
diff --git a/horilla_backup/pgdump.py b/horilla_backup/pgdump.py
index a42346d8d..3c62c81df 100644
--- a/horilla_backup/pgdump.py
+++ b/horilla_backup/pgdump.py
@@ -1,30 +1,38 @@
-import subprocess
import os
+import subprocess
+
-def dump_postgres_db(db_name, username, output_file, password=None, host='localhost', port=5432):
+def dump_postgres_db(
+ db_name, username, output_file, password=None, host="localhost", port=5432
+):
# Set environment variable for the password if provided
- if password:
- os.environ['PGPASSWORD'] = password
-
+ if password:
+ os.environ["PGPASSWORD"] = password
+
# Construct the pg_dump command
dump_command = [
- 'pg_dump',
- '-h', host,
- '-p', str(port),
- '-U', username,
- '-F', 'c', # Custom format
- '-f', output_file,
- db_name
+ "pg_dump",
+ "-h",
+ host,
+ "-p",
+ str(port),
+ "-U",
+ username,
+ "-F",
+ "c", # Custom format
+ "-f",
+ output_file,
+ db_name,
]
try:
# Execute the pg_dump command
- result = subprocess.run(dump_command, check=True, text=True, capture_output=True)
- except subprocess.CalledProcessError as e:
- pass
- finally:
+ result = subprocess.run(
+ dump_command, check=True, text=True, capture_output=True
+ )
+ except subprocess.CalledProcessError as e:
+ pass
+ finally:
# Clean up the environment variable
- if password:
- del os.environ['PGPASSWORD']
-
-
+ if password:
+ del os.environ["PGPASSWORD"]
diff --git a/horilla_backup/scheduler.py b/horilla_backup/scheduler.py
index fcdb345ce..1fd5f2a82 100644
--- a/horilla_backup/scheduler.py
+++ b/horilla_backup/scheduler.py
@@ -1,11 +1,15 @@
+import os
+
from apscheduler.schedulers.background import BackgroundScheduler
from django.core.management import call_command
-import os
+
+from horilla import settings
+
+from .gdrive import *
+
# from horilla.settings import DBBACKUP_STORAGE_OPTIONS
from .models import *
-from .gdrive import *
from .pgdump import *
-from horilla import settings
from .zip import *
scheduler = BackgroundScheduler()
@@ -17,7 +21,7 @@
# DBBACKUP_STORAGE_OPTIONS['location'] = local_backup.backup_path
# folder_path = DBBACKUP_STORAGE_OPTIONS['location']
# if local_backup.backup_db:
-# call_command('dbbackup')
+# call_command('dbbackup')
# if local_backup.backup_media:
# call_command("mediabackup")
# files = sorted(os.listdir(folder_path), key=lambda x: os.path.getctime(os.path.join(folder_path, x)))
@@ -32,7 +36,7 @@
# except:
# pass
-
+
# def start_backup_job():
# """
# Start the backup job based on the LocalBackup configuration.
@@ -45,25 +49,25 @@
# try:
# scheduler.remove_job('backup_job')
# except:
-# pass
-
+# pass
+
# # Add new job based on LocalBackup configuration
# if local_backup.interval:
# scheduler.add_job(backup_database, 'interval', seconds=local_backup.seconds, id='backup_job')
-# else:
+# else:
# scheduler.add_job(backup_database, trigger='cron', hour=local_backup.hour, minute=local_backup.minute, id='backup_job')
# # Start the scheduler if it's not already running
-# if not scheduler.running:
-# scheduler.start()
-# else:
+# if not scheduler.running:
+# scheduler.start()
+# else:
# stop_backup_job()
# def stop_backup_job():
-# """
+# """
# Stop the backup job if it exists.
-# """
-# try:
+# """
+# try:
# scheduler.remove_job('backup_job')
# except:
# pass
@@ -83,19 +87,19 @@ def google_drive_backup():
service_account_file = google_drive.service_account_file.path
gdrive_folder_id = google_drive.gdrive_folder_id
if google_drive.backup_db:
- db = settings.DATABASES['default']
+ db = settings.DATABASES["default"]
dump_postgres_db(
- db_name=db['NAME'],
- username=db['USER'],
- output_file='backupdb.dump',
- password=db['PASSWORD']
+ db_name=db["NAME"],
+ username=db["USER"],
+ output_file="backupdb.dump",
+ password=db["PASSWORD"],
)
- upload_file('backupdb.dump', service_account_file, gdrive_folder_id)
- os.remove('backupdb.dump')
+ upload_file("backupdb.dump", service_account_file, gdrive_folder_id)
+ os.remove("backupdb.dump")
if google_drive.backup_media:
folder_to_zip = settings.MEDIA_ROOT
output_zip_file = "media.zip"
- zip_folder(folder_to_zip, output_zip_file)
+ zip_folder(folder_to_zip, output_zip_file)
upload_file("media.zip", service_account_file, gdrive_folder_id)
os.remove("media.zip")
@@ -108,31 +112,42 @@ def start_gdrive_backup_job():
if GoogleDriveBackup.objects.exists():
gdrive_backup = GoogleDriveBackup.objects.first()
- # Remove existing job if it exists
+ # Remove existing job if it exists
try:
- scheduler.remove_job('backup_job')
+ scheduler.remove_job("backup_job")
except:
- pass
+ pass
# Add new job based on Gdrive Backup configuration
if gdrive_backup.interval:
- scheduler.add_job(google_drive_backup, 'interval', seconds=gdrive_backup.seconds, id='gdrive_backup_job')
- else:
- scheduler.add_job(google_drive_backup, trigger='cron', hour=gdrive_backup.hour, minute=gdrive_backup.minute, id='gdrive_backup_job')
+ scheduler.add_job(
+ google_drive_backup,
+ "interval",
+ seconds=gdrive_backup.seconds,
+ id="gdrive_backup_job",
+ )
+ else:
+ scheduler.add_job(
+ google_drive_backup,
+ trigger="cron",
+ hour=gdrive_backup.hour,
+ minute=gdrive_backup.minute,
+ id="gdrive_backup_job",
+ )
# Start the scheduler if it's not already running
- if not scheduler.running:
- scheduler.start()
+ if not scheduler.running:
+ scheduler.start()
- else:
+ else:
stop_gdrive_backup_job()
def stop_gdrive_backup_job():
- """
+ """
Stop the backup job if it exists.
- """
- try:
- scheduler.remove_job('gdrive_backup_job')
+ """
+ try:
+ scheduler.remove_job("gdrive_backup_job")
except:
pass
@@ -143,4 +158,3 @@ def stop_gdrive_backup_job():
# """
# stop_gdrive_backup_job()
# start_gdrive_backup_job()
-
diff --git a/horilla_backup/templates/backup/404.html b/horilla_backup/templates/backup/404.html
index 97a40b704..f01f01ad8 100644
--- a/horilla_backup/templates/backup/404.html
+++ b/horilla_backup/templates/backup/404.html
@@ -4,4 +4,4 @@