Fediversity/panel/src/panel/views.py

140 lines
4.5 KiB
Python

from enum import Enum
import json
from os.path import expanduser
import subprocess
import os
from django.urls import reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User
from django.views.generic import TemplateView, DetailView
from django.views.generic.edit import FormView
from panel import models, settings
from panel import models
from panel.configuration import forms
class Index(TemplateView):
template_name = 'index.html'
class AccountDetail(LoginRequiredMixin, DetailView):
model = User
template_name = 'account_detail.html'
def get_object(self):
return self.request.user
class ServiceList(TemplateView):
template_name = 'service_list.html'
class ConfigurationForm(LoginRequiredMixin, FormView):
template_name = 'configuration_form.html'
success_url = reverse_lazy('configuration_form')
form_class = forms.Form
def get_object(self):
"""Get or create the configuration object for the current user"""
obj, created = models.Configuration.objects.get_or_create(
operator=self.request.user,
)
return obj
# TODO(@fricklerhandwerk):
# this should probably live somewhere else
def convert_enums_to_names(self, data_dict):
"""
Recursively convert all enum values in a dictionary to their string names.
This handles nested dictionaries and lists as well.
Needed for converting a Pydantic `BaseModel` instance to a `Form` input.
"""
if isinstance(data_dict, dict):
result = {}
for key, value in data_dict.items():
if isinstance(value, Enum):
# Convert Enum to its name
result[key] = value.name
elif isinstance(value, (dict, list)):
# Recursively process nested structures
result[key] = self.convert_enums_to_names(value)
else:
# Keep other values as is
result[key] = value
return result
elif isinstance(data_dict, list):
# Process each item in the list
return [self.convert_enums_to_names(item) for item in data_dict]
elif isinstance(data_dict, Enum):
# Convert single Enum value
return data_dict.name
else:
# Return non-dict, non-list, non-Enum values as is
return data_dict
def get_initial(self):
initial = super().get_initial()
config = self.get_object()
config_dict = config.parsed_value.model_dump()
initial.update(self.convert_enums_to_names(config_dict))
return initial
class Save(ConfigurationForm):
def form_valid(self, form):
obj = self.get_object()
obj.value = form.to_python().model_dump_json()
obj.save()
return super().form_valid(form)
class DeploymentStatus(ConfigurationForm):
def form_valid(self, form):
obj = self.get_object()
obj.value = form.to_python().model_dump_json()
obj.save()
# Check for deploy button
if "deploy" in self.request.POST.keys():
self.deployment(obj)
return super().form_valid(form)
def deployment(self, obj):
submission = obj.parsed_value.model_dump_json()
# FIXME: let the user specify these from the form (#190)
dummy_user = {
"initialUser": {
"displayName": "Testy McTestface",
"username": "test",
"password": "testtest",
"email": "test@test.com",
},
}
# serialize back and forth now we still need to manually inject the dummy user
deployment = dummy_user | json.loads(submission)
env = {
"PATH": settings.bin_path,
# used in nixos-anywhere for ssh-copy-id
"HOME": expanduser("~"),
} | {
# pass in form info to our deployment
# FIXME: ensure sensitive info is protected
f"TF_VAR_{k}": v if isinstance(v, str) else json.dumps(v) for k, v in deployment.items()
}
cwd = f"{settings.repo_dir}/launch"
# FIXME: move init to packaging phase
cmd = [
"tofu",
# f"-chdir={cwd}",
"apply",
f"-state={cwd}/terraform.tfstate", # FIXME: separate users' state
"--auto-approve",
"-lock=false",
]
deployment_result = subprocess.run(cmd, cwd=cwd, env=env)
print(deployment_result)
return deployment_result