From 951c149a7fa6d5fbd9eb16e9281ac36045c9d7a2 Mon Sep 17 00:00:00 2001 From: HugoNeveux Date: Tue, 28 Apr 2020 14:09:22 +0200 Subject: [PATCH] Add ModuleDetail page and view + README.md handling on upload --- PDMI/PDMI/settings.py | 1 + PDMI/PDMI/urls.py | 1 + .../migrations/0008_auto_20200428_0821.py | 30 ++++++++ PDMI/store/migrations/0009_version_readme.py | 19 +++++ PDMI/store/models.py | 7 +- PDMI/store/templates/store/index.html | 77 ------------------- PDMI/store/templates/store/module_detail.html | 53 +++++++++++++ PDMI/store/templates/store/module_list.html | 52 +++++++++++++ PDMI/store/urls.py | 6 +- PDMI/store/views.py | 45 ++++++++++- Pipfile | 1 + 11 files changed, 209 insertions(+), 83 deletions(-) create mode 100644 PDMI/store/migrations/0008_auto_20200428_0821.py create mode 100644 PDMI/store/migrations/0009_version_readme.py delete mode 100644 PDMI/store/templates/store/index.html create mode 100644 PDMI/store/templates/store/module_detail.html create mode 100644 PDMI/store/templates/store/module_list.html diff --git a/PDMI/PDMI/settings.py b/PDMI/PDMI/settings.py index 96f94bd..b1564b1 100644 --- a/PDMI/PDMI/settings.py +++ b/PDMI/PDMI/settings.py @@ -43,6 +43,7 @@ INSTALLED_APPS = [ 'front', 'bootstrap_modal_forms', 'widget_tweaks', + 'markdownx', ] MIDDLEWARE = [ diff --git a/PDMI/PDMI/urls.py b/PDMI/PDMI/urls.py index 3bb0efd..2e0e0a3 100644 --- a/PDMI/PDMI/urls.py +++ b/PDMI/PDMI/urls.py @@ -23,4 +23,5 @@ urlpatterns = [ path('', include('front.urls'), name='front'), path('store/', include('store.urls'), name='store'), path('doc/', include('doc.urls'), name='doc'), + path('markdownx/', include('markdownx.urls')), ] diff --git a/PDMI/store/migrations/0008_auto_20200428_0821.py b/PDMI/store/migrations/0008_auto_20200428_0821.py new file mode 100644 index 0000000..792ddf7 --- /dev/null +++ b/PDMI/store/migrations/0008_auto_20200428_0821.py @@ -0,0 +1,30 @@ +# Generated by Django 3.0 on 2020-04-28 08:21 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('store', '0007_remove_version_dependencies'), + ] + + operations = [ + migrations.AddField( + model_name='module', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='module', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AlterField( + model_name='module', + name='name', + field=models.CharField(max_length=255, unique=True), + ), + ] diff --git a/PDMI/store/migrations/0009_version_readme.py b/PDMI/store/migrations/0009_version_readme.py new file mode 100644 index 0000000..6f0271c --- /dev/null +++ b/PDMI/store/migrations/0009_version_readme.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0 on 2020-04-28 11:00 + +from django.db import migrations +import markdownx.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('store', '0008_auto_20200428_0821'), + ] + + operations = [ + migrations.AddField( + model_name='version', + name='readme', + field=markdownx.models.MarkdownxField(default='No readme provided.'), + ), + ] diff --git a/PDMI/store/models.py b/PDMI/store/models.py index 3d027ae..e633c85 100644 --- a/PDMI/store/models.py +++ b/PDMI/store/models.py @@ -1,14 +1,16 @@ from django.db import models from django.db.models.signals import pre_save from django.dispatch import receiver +from django.utils import timezone import PDMI.settings as settings import os from django.contrib.auth.models import User +from markdownx.models import MarkdownxField def upload_path(instance, filename): path = os.path.join( - 'modules', instance.module.name.lower(), instance.ver, filename) + 'modules', instance.module.name.lower(), instance.ver, instance.module.name+'.zip') if os.path.isfile(os.path.join(settings.MEDIA_ROOT, path)): # Delete file if already exists os.remove(os.path.join(settings.MEDIA_ROOT, path)) @@ -19,6 +21,8 @@ class Module(models.Model): name = models.CharField(max_length=255, unique=True) desc = models.TextField(max_length=2048, null=True) creator = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) def __str__(self): return self.name @@ -30,6 +34,7 @@ class Version(models.Model): bot_ver = models.CharField(max_length=15) metamodule = models.BooleanField(default=False) file = models.FileField(upload_to=upload_path) + readme = MarkdownxField(default="No readme provided.") def __str__(self): return self.ver diff --git a/PDMI/store/templates/store/index.html b/PDMI/store/templates/store/index.html deleted file mode 100644 index 19f0fd5..0000000 --- a/PDMI/store/templates/store/index.html +++ /dev/null @@ -1,77 +0,0 @@ -{% extends "store/base.html" %} - -{% block main %} -
-
-
-

PDMI Store

- -
- - -
-
-
-
-
- {% for i in '123'|make_list %} -
-
-
-
Card title
-
-
-
Card subtitle - Description
-

Donec id elit non mi porta gravida at eget metus. Fusce dapibus, - tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo - sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. -

-

View details »

-
-
-
- {% endfor %} -
- -
- {% for i in '123'|make_list %} -
-
-
-
Card title
-
-
-
Card subtitle - Description
-

Donec id elit non mi porta gravida at eget metus. Fusce dapibus, - tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo - sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. -

-

View details »

-
-
-
- {% endfor %} -
- -
- {% for i in '123'|make_list %} -
-
-
-
Card title
-
-
-
Card subtitle - Description
-

Donec id elit non mi porta gravida at eget metus. Fusce dapibus, - tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo - sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. -

-

View details »

-
-
-
- {% endfor %} -
-
-
-{% endblock main %} diff --git a/PDMI/store/templates/store/module_detail.html b/PDMI/store/templates/store/module_detail.html new file mode 100644 index 0000000..536f472 --- /dev/null +++ b/PDMI/store/templates/store/module_detail.html @@ -0,0 +1,53 @@ +{% extends "store/base.html" %} + +{% block main %} +
+
+
+

{{ module.name|title }}

+

{{ module.desc }}

+
+
+
+
+
+

Versions

+

+ {% for version in versions %} + {% if version.ver == view_version.ver %} +

{{ version.ver }}

+ {% else %} +

{{ version.ver }}

+ {% endif %} +
Dependencies
+ {% for deps in dependencies %} + {% for dep in deps %} + {% if dep.version.ver == version.ver %} + {{ dep.dep_module }} + {{ dep.dep_version }} + {% endif %} + {% endfor %} + {% endfor %} + {% endfor %} +

+
+
+ {{ mdreadme|safe }} +
+
+

+ +

+

+ Module by {{ module.creator }} +

+

Created on {{ module.created_at }}

+

Last edit on {{ module.updated_at }}

+
+
+

+
+
+{% endblock main %} diff --git a/PDMI/store/templates/store/module_list.html b/PDMI/store/templates/store/module_list.html new file mode 100644 index 0000000..0673048 --- /dev/null +++ b/PDMI/store/templates/store/module_list.html @@ -0,0 +1,52 @@ +{% extends "store/base.html" %} + +{% block main %} +
+
+
+

PDMI Store

+ +
+ + +
+
+
+
+ +
+ {% for module in object_list %} +
+
+
{{ module.name|title }}
+
+
+ +

{{ module.desc }} +

+

View details »

+
+
+ {% endfor %} +
+ + +
+
+{% endblock main %} diff --git a/PDMI/store/urls.py b/PDMI/store/urls.py index 406becf..974fc72 100644 --- a/PDMI/store/urls.py +++ b/PDMI/store/urls.py @@ -19,9 +19,11 @@ from django.contrib.auth.views import LoginView, LogoutView from . import views urlpatterns = [ - path('', TemplateView.as_view(template_name='store/index.html'), name='store_front_page'), + path('', views.ModuleListView.as_view(), name='store_front_page'), path('login/', views.CustomLoginView.as_view(), name='login_modal'), path('signup/', views.SignUpView.as_view(), name='signup_modal'), - #path('logout/', LogoutView.as_view(), name='logout'), + path('logout/', LogoutView.as_view(), name='logout'), path('upload/', views.UploadView.as_view(), name='upload'), + path('module//', views.ModuleDetailView.as_view(), name='mod_detail'), + path('module///', views.ModuleDetailView.as_view(), name='mod_detail'), ] diff --git a/PDMI/store/views.py b/PDMI/store/views.py index f300370..053d1ef 100644 --- a/PDMI/store/views.py +++ b/PDMI/store/views.py @@ -1,21 +1,28 @@ from django.contrib.auth.mixins import LoginRequiredMixin -from django.shortcuts import render +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 .response import response_mimetype, JsonResponse from .models import Module, Version, Dependency from PDMI import settings from packaging.specifiers import SpecifierSet from django.http import HttpResponse +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 @@ -30,8 +37,33 @@ class CustomLoginView(BSModalLoginView): success_message = 'Success: You were successfully logged in.' extra_content = dict(success_url=reverse_lazy('index')) +class ModuleListView(ListView): + model = Module + paginate_by = 100 -REQUIRED_FIELDS = ['name', 'description', 'version', 'bot_version'] + 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 @@ -59,6 +91,12 @@ class UploadView(LoginRequiredMixin, FormView): 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}\ @@ -82,11 +120,12 @@ class UploadView(LoginRequiredMixin, FormView): 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) + file=file, readme=readme) module.save() version.save() for dependency in module_info['dependencies']: diff --git a/Pipfile b/Pipfile index d4de018..1324877 100644 --- a/Pipfile +++ b/Pipfile @@ -10,6 +10,7 @@ django = "*" django-widget-tweaks = "*" django-bootstrap-modal-forms = "*" python-magic = "*" +django-markdownx = "3.0.1" [requires] python_version = "3.8"