Files
ihrm/horilla_backup/forms.py

205 lines
7.7 KiB
Python

import os
import tempfile
from pathlib import Path
from django import forms
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 base.forms import ModelForm
from .gdrive import authenticate
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."
)
class Meta:
model = LocalBackup
exclude = ["active"]
def as_p(self):
"""
Render the form fields as HTML table rows with Bootstrap styling.
"""
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")
path = Path(backup_path)
if not path.exists():
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 seconds:
if seconds < 0:
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:
if minute < 0 or minute > 60:
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."
)
class Meta:
model = GoogleDriveBackup
exclude = [
"active",
"access_token",
"refresh_token",
"token_expiry",
] # Exclude token fields
def as_p(self):
"""
Render the form fields as HTML table rows with Bootstrap styling.
"""
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")
oauth_credentials_file = cleaned_data.get("oauth_credentials_file")
# Get instance if updating
instance = self.instance if hasattr(self, "instance") else None
# Only validate file if it's provided (new file upload) or if creating new instance
if oauth_credentials_file:
try:
# Read file content from InMemoryUploadedFile
file_data = oauth_credentials_file.read()
file_name = oauth_credentials_file.name
# Always write to temp file for validation (because .path isn't supported)
with tempfile.NamedTemporaryFile(
delete=False, suffix=".json", mode="w+b"
) as tmp_file:
tmp_file.write(file_data)
tmp_file.flush()
temp_path = tmp_file.name
# Validate OAuth credentials file format
import json
with open(temp_path, "r") as f:
oauth_config = json.load(f)
# Check if it's a valid OAuth 2.0 web application credentials file
if "web" not in oauth_config:
raise ValueError(
"OAuth credentials file must contain 'web' key for web application type."
)
if "client_id" not in oauth_config.get("web", {}):
raise ValueError(
"OAuth credentials file must contain 'client_id' in 'web' section."
)
if "client_secret" not in oauth_config.get("web", {}):
raise ValueError(
"OAuth credentials file must contain 'client_secret' in 'web' section."
)
# Clean up temp file
os.remove(temp_path)
except json.JSONDecodeError:
raise forms.ValidationError(
"Please provide a valid OAuth credentials file (must be valid JSON)."
)
except Exception as e:
raise forms.ValidationError(
f"Please provide a valid OAuth credentials file. Error: {str(e)}"
)
elif not instance or not instance.pk:
# If creating new instance and no file provided, raise error
raise forms.ValidationError(
"Please provide a valid OAuth credentials 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 seconds:
if seconds < 0:
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:
if minute < 0 or minute > 60:
raise ValidationError({"minute": _("Enter a minute between 0 to 60.")})
return cleaned_data