PDMI/PDMI/store/views.py

140 lines
6.3 KiB
Python

from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render, get_object_or_404
from django.urls import reverse_lazy
from django.utils import timezone
from bootstrap_modal_forms.generic import BSModalCreateView, BSModalLoginView
from .forms import CustomUserCreationForm, CustomAuthenticationForm
from django.views.generic.edit import FormView
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
from django.views import View
from .forms import FileFieldForm
from .models import Module, Version, Dependency
from PDMI import settings
from packaging.specifiers import SpecifierSet
from django.http import HttpResponse, JsonResponse
from django.utils import timezone
from markdownx.utils import markdownify
import os
import zipfile
import toml
import shutil
import magic
REQUIRED_FIELDS = ['name', 'description', 'version', 'bot_version']
class SignUpView(BSModalCreateView):
form_class = CustomUserCreationForm
template_name = 'store/signup_modal.html'
success_message = 'Success: Sign up succeeded. You can now Log in.'
success_url = reverse_lazy('store_front_page')
class CustomLoginView(BSModalLoginView):
authentication_form = CustomAuthenticationForm
template_name = 'store/login_modal.html'
success_message = 'Success: You were successfully logged in.'
extra_content = dict(success_url=reverse_lazy('index'))
class ModuleListView(ListView):
model = Module
paginate_by = 100
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['now'] = timezone.now()
return context
class ModuleDetailView(View):
def get(self, request, pk, req_ver="latest"):
module = get_object_or_404(Module, id=pk)
versions = Version.objects.filter(module=module)
deps = []
for version in versions:
deps.append(Dependency.objects.filter(version=version))
if req_ver == "latest":
view_version = Version.objects.filter(module=module).order_by('-id')[0]
else:
view_version = Version.objects.get(module=module, ver=req_ver)
return render(request, 'store/module_detail.html', {
'module': module,
'versions': versions,
'dependencies': deps,
'view_version': view_version,
'mdreadme': markdownify(view_version.readme),
})
class UploadView(LoginRequiredMixin, FormView):
form_class = FileFieldForm
template_name = 'store/upload.html'
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('file')
if form.is_valid():
for file in files:
zip_path = os.path.join(settings.MEDIA_ROOT, file.name)
extract_path = os.path.splitext(zip_path)[0]
with open(zip_path, "wb+") as f: # Writing archive
for chunk in file.chunks():
f.write(chunk)
# Check if uploaded file is a zip archive
if magic.from_file(zip_path, mime=True) != 'application/zip':
print(magic.from_file(zip_path))
os.remove(zip_path)
return JsonResponse({'error': 'You must upload a zip archive.'}, status=500)
with zipfile.ZipFile(zip_path, 'r') as zip: # Unzip archive
zip.extractall(extract_path)
with open(os.path.join(extract_path, 'infos.toml'), 'r') as f:
# Reading and parsing toml file
module_info = toml.loads(f.read())
if os.path.isfile(os.path.join(extract_path, 'README.md')):
with open(os.path.join(extract_path, 'README.md'), 'r') as f:
# Reading README.md file
readme = f.read()
else:
readme = "No readme provided."
for required_field in REQUIRED_FIELDS:
if not required_field in module_info.keys():
return JsonResponse({'error': f'Field {required_field}\
is missing in infos.toml.'}, status=500)
shutil.rmtree(extract_path)
os.remove(zip_path)
if Module.objects.filter(name=module_info['name'].lower(),
creator=request.user):
# If module exists
module = Module.objects.get(name=module_info['name'].lower(),
creator=request.user)
else:
# Else, creating module
module = Module(name=module_info['name'].lower(),
desc=module_info['description'],
creator=request.user)
if Version.objects.filter(module=module, ver=module_info['version']).exists():
# If version already exists, edit existing version
version = Version.objects.get(
module=module, ver=module_info['version'])
version.file = file
version.metamodule = module_info['metamodule']
version.bot_ver = module_info['bot_version']
version.readme = readme
else:
version = Version(module=module, ver=module_info['version'],
bot_ver=module_info['bot_version'],
metamodule=module_info['metamodule'],
file=file, readme=readme)
module.save()
version.save()
for dependency in module_info['dependencies']:
if not Dependency.objects.filter(version=version, dep_module=dependency,
dep_version=module_info['dependencies'][dependency]).exists():
dep = Dependency(version=version, dep_module=dependency,
dep_version=module_info['dependencies'][dependency])
dep.save()
return JsonResponse({'form': True})
else:
return JsonResponse({'form': False})