aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blog_admin/views.py6
-rw-r--r--ignis/admin.py4
-rw-r--r--ignis/migrations/0001_initial.py33
-rw-r--r--ignis/migrations/0002_alter_object_data.py18
-rw-r--r--ignis/migrations/0003_remove_objectdirectory_name_objectdirectory_slug.py25
-rw-r--r--ignis/migrations/0004_remove_objectdirectory_slug_objectdirectory_name.py22
-rw-r--r--ignis/migrations/0005_remove_objectdirectory_name_and_more.py22
-rw-r--r--ignis/migrations/0006_rename_post_slug_objectdirectory_name.py18
-rw-r--r--ignis/models.py19
-rw-r--r--ignis/objectstorage.py35
-rw-r--r--ignis/urls.py3
-rw-r--r--ignis/views.py63
-rw-r--r--static/images/site/repositories.pngbin0 -> 139288 bytes
-rw-r--r--templates/blog/post.html8
-rw-r--r--templates/blog_admin/edit_post.html53
-rw-r--r--templates/blog_admin/new_post.html45
-rw-r--r--templates/dev_status/home.html23
17 files changed, 371 insertions, 26 deletions
diff --git a/blog_admin/views.py b/blog_admin/views.py
index ab087e62..75b58507 100644
--- a/blog_admin/views.py
+++ b/blog_admin/views.py
@@ -5,8 +5,6 @@ from django.contrib.auth.models import User
from django.contrib import messages
from blog.models import Post, Category, Tag
import re
-from io import BytesIO
-from PIL import Image
# Create your views here.
@@ -48,6 +46,8 @@ def new_post(request):
title = request.POST.get('title')
body = request.POST.get('body')
body = re.sub(r'<p><br></p>', '', body)
+ body = re.sub(r'<p class="ql-align-justify"><br></p>', '', body)
+ body = re.sub(r'<p class="ql-align-center"><br></p>', '', body)
category = request.POST.get('category')
tags = request.POST.get('tags')
slug = request.POST.get('slug')
@@ -86,6 +86,8 @@ def edit_post(request, slug):
title = request.POST.get('title')
body = request.POST.get('body')
body = re.sub(r'<p><br></p>', '', body)
+ body = re.sub(r'<p class="ql-align-justify"><br></p>', '', body)
+ body = re.sub(r'<p class="ql-align-center"><br></p>', '', body)
category = request.POST.get('category')
tags = request.POST.get('tags')
slug = request.POST.get('slug')
diff --git a/ignis/admin.py b/ignis/admin.py
index 8c38f3f3..0e97a0e9 100644
--- a/ignis/admin.py
+++ b/ignis/admin.py
@@ -1,3 +1,7 @@
from django.contrib import admin
# Register your models here.
+from .models import Object, ObjectDirectory
+
+admin.site.register(Object)
+admin.site.register(ObjectDirectory) \ No newline at end of file
diff --git a/ignis/migrations/0001_initial.py b/ignis/migrations/0001_initial.py
new file mode 100644
index 00000000..1cf08fda
--- /dev/null
+++ b/ignis/migrations/0001_initial.py
@@ -0,0 +1,33 @@
+# Generated by Django 4.0.6 on 2022-11-22 06:31
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='ObjectDirectory',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=255)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Object',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('md5', models.CharField(max_length=32)),
+ ('metadata', models.CharField(max_length=255)),
+ ('data', models.BinaryField()),
+ ('created', models.DateTimeField(auto_now_add=True)),
+ ('location', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='ignis.objectdirectory')),
+ ],
+ ),
+ ]
diff --git a/ignis/migrations/0002_alter_object_data.py b/ignis/migrations/0002_alter_object_data.py
new file mode 100644
index 00000000..e4685b4c
--- /dev/null
+++ b/ignis/migrations/0002_alter_object_data.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.0.6 on 2022-11-22 06:35
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ignis', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='object',
+ name='data',
+ field=models.TextField(),
+ ),
+ ]
diff --git a/ignis/migrations/0003_remove_objectdirectory_name_objectdirectory_slug.py b/ignis/migrations/0003_remove_objectdirectory_name_objectdirectory_slug.py
new file mode 100644
index 00000000..72fea363
--- /dev/null
+++ b/ignis/migrations/0003_remove_objectdirectory_name_objectdirectory_slug.py
@@ -0,0 +1,25 @@
+# Generated by Django 4.0.6 on 2022-11-22 06:40
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('blog', '0004_alter_post_post_image'),
+ ('ignis', '0002_alter_object_data'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='objectdirectory',
+ name='name',
+ ),
+ migrations.AddField(
+ model_name='objectdirectory',
+ name='slug',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.post'),
+ preserve_default=False,
+ ),
+ ]
diff --git a/ignis/migrations/0004_remove_objectdirectory_slug_objectdirectory_name.py b/ignis/migrations/0004_remove_objectdirectory_slug_objectdirectory_name.py
new file mode 100644
index 00000000..e8a01d37
--- /dev/null
+++ b/ignis/migrations/0004_remove_objectdirectory_slug_objectdirectory_name.py
@@ -0,0 +1,22 @@
+# Generated by Django 4.0.6 on 2022-11-22 06:41
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ignis', '0003_remove_objectdirectory_name_objectdirectory_slug'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='objectdirectory',
+ name='slug',
+ ),
+ migrations.AddField(
+ model_name='objectdirectory',
+ name='name',
+ field=models.CharField(default='root', max_length=255),
+ ),
+ ]
diff --git a/ignis/migrations/0005_remove_objectdirectory_name_and_more.py b/ignis/migrations/0005_remove_objectdirectory_name_and_more.py
new file mode 100644
index 00000000..d2193140
--- /dev/null
+++ b/ignis/migrations/0005_remove_objectdirectory_name_and_more.py
@@ -0,0 +1,22 @@
+# Generated by Django 4.0.6 on 2022-11-22 06:44
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ignis', '0004_remove_objectdirectory_slug_objectdirectory_name'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='objectdirectory',
+ name='name',
+ ),
+ migrations.AddField(
+ model_name='objectdirectory',
+ name='post_slug',
+ field=models.CharField(max_length=255, null=True),
+ ),
+ ]
diff --git a/ignis/migrations/0006_rename_post_slug_objectdirectory_name.py b/ignis/migrations/0006_rename_post_slug_objectdirectory_name.py
new file mode 100644
index 00000000..7781a552
--- /dev/null
+++ b/ignis/migrations/0006_rename_post_slug_objectdirectory_name.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.0.6 on 2022-11-22 07:30
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ignis', '0005_remove_objectdirectory_name_and_more'),
+ ]
+
+ operations = [
+ migrations.RenameField(
+ model_name='objectdirectory',
+ old_name='post_slug',
+ new_name='name',
+ ),
+ ]
diff --git a/ignis/models.py b/ignis/models.py
index 71a83623..9c99de5d 100644
--- a/ignis/models.py
+++ b/ignis/models.py
@@ -1,3 +1,22 @@
from django.db import models
+from blog.models import Post
# Create your models here.
+class Object(models.Model):
+ md5 = models.CharField(max_length=32)
+ metadata = models.CharField(max_length=255)
+ data = models.TextField()
+ created = models.DateTimeField(auto_now_add=True)
+ location = models.OneToOneField(
+ 'ObjectDirectory',
+ on_delete=models.CASCADE,
+ )
+
+ def __str__(self):
+ return self.md5
+
+class ObjectDirectory(models.Model):
+ name = models.CharField(max_length=255, null=True)
+
+ def __str__(self):
+ return self.name
diff --git a/ignis/objectstorage.py b/ignis/objectstorage.py
new file mode 100644
index 00000000..84d3a5c0
--- /dev/null
+++ b/ignis/objectstorage.py
@@ -0,0 +1,35 @@
+from .models import Object, ObjectDirectory
+
+class ObjectStorage:
+ def create_directory(self, name):
+ if not ObjectDirectory.objects.filter(name=name).exists():
+ ObjectDirectory.objects.create(name=name)
+
+ def rename_directory(self, old_name, new_name):
+ if not ObjectDirectory.objects.filter(name=old_name).exists():
+ ObjectDirectory.objects.create(name=old_name)
+ ObjectDirectory.objects.filter(name=old_name).update(name=new_name)
+
+ def delete_directory(self, name):
+ Object.objects.filter(location=ObjectDirectory.objects.get(name=name)).delete()
+ ObjectDirectory.objects.filter(name=name).delete()
+
+ def create_object(self, md5, metadata, data, name):
+ if not ObjectDirectory.objects.filter(name=name).exists():
+ ObjectDirectory.objects.create(name=name)
+ Object.objects.create(md5=md5, metadata=metadata, data=data, location=ObjectDirectory.objects.get(name=name))
+
+ def delete_object(self, slug, md5):
+ Object.objects.filter(location=ObjectDirectory.objects.get(name=slug), md5=md5).delete()
+
+ def get_object(self, slug, md5):
+ return Object.objects.get(location=ObjectDirectory.objects.get(name=slug), md5=md5)
+
+ def object_exists(self, slug, md5):
+ return Object.objects.filter(location=ObjectDirectory.objects.get(name=slug), md5=md5).exists()
+
+ def get_directory_contents(self, name):
+ return Object.objects.filter(location=ObjectDirectory.objects.get(name=name))
+
+ def get_directories(self):
+ return ObjectDirectory.objects.all()
diff --git a/ignis/urls.py b/ignis/urls.py
index b3b1eace..c35845d0 100644
--- a/ignis/urls.py
+++ b/ignis/urls.py
@@ -5,4 +5,7 @@ app_name = 'ignis'
urlpatterns = [
path('/tex', views.tex, name='tex'),
path('/post_image/<int:post_id>/', views.post_image, name='post_image'),
+ path('/upload', views.upload_image, name='upload_image'),
+ path('/image/<str:slug>/<str:md5>', views.get_image, name='get_image'),
+ path('/su/mvdir', views.mvdir, name='mvdir'),
]
diff --git a/ignis/views.py b/ignis/views.py
index ffbce848..d904217c 100644
--- a/ignis/views.py
+++ b/ignis/views.py
@@ -1,10 +1,13 @@
-from django.shortcuts import render
from PIL import Image
from io import BytesIO
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
import base64
from blog.models import Post
+from .objectstorage import ObjectStorage
+import base64
+import _md5
+import json
# Create your views here.
@csrf_exempt
@@ -37,3 +40,61 @@ def post_image(request, post_id):
# convert base64 data src to image
image = base64.b64decode(pi.split(',')[1])
return HttpResponse(image, content_type='image/png')
+
+@csrf_exempt
+def get_image(request, slug, md5):
+ object_storage = ObjectStorage()
+ image = object_storage.get_object(slug, md5)
+ return HttpResponse(base64.b64decode(image.data), content_type=image.metadata)
+
+def upload_image(request):
+ if request.method == 'POST':
+ if not request.user.is_authenticated and not request.user.is_staff:
+ return HttpResponse('Unauthorized', status=401)
+ if not request.FILES.get('image'):
+ return HttpResponse('No image provided!', status=400)
+ if not request.POST.get('slug'):
+ return HttpResponse('No slug provided!', status=400)
+
+ # upload image to object storage
+ image = request.FILES['image']
+ slug = request.POST.get('slug')
+ object_storage = ObjectStorage()
+ object_storage.create_directory(slug)
+
+
+ image_data = image.read()
+ metadata = image.content_type
+
+ image_hash = _md5.md5(image_data).hexdigest()
+ data = base64.b64encode(image_data).decode('utf-8')
+
+ if not object_storage.object_exists(slug, image_hash):
+ object_storage.create_object(md5=image_hash, metadata=metadata, data=data, name=slug)
+
+ # return json response
+ response = {
+ 'url': "/ignis/image/{}/{}".format(slug, image_hash)
+ }
+
+ return HttpResponse(json.dumps(response), content_type='application/json', status=200)
+
+
+def mvdir(request):
+ if not request.user.is_authenticated and not request.user.is_staff:
+ return HttpResponse('Unauthorized', status=401)
+ object_storage = ObjectStorage()
+
+ # get from query params
+ old_name = request.GET.get('old')
+ new_name = request.GET.get('new')
+
+ if not old_name or not new_name:
+ return HttpResponse('No name provided!', status=400)
+
+ if old_name == "":
+ object_storage.create_directory(new_name)
+ return HttpResponse(json.dumps({'status': 'success'}), content_type='application/json', status=200)
+ else:
+ object_storage.rename_directory(old_name, new_name)
+ return HttpResponse(json.dumps({'status': 'success'}), content_type='application/json', status=200)
diff --git a/static/images/site/repositories.png b/static/images/site/repositories.png
new file mode 100644
index 00000000..b8162a03
--- /dev/null
+++ b/static/images/site/repositories.png
Binary files differ
diff --git a/templates/blog/post.html b/templates/blog/post.html
index edc7d32a..b4055ac4 100644
--- a/templates/blog/post.html
+++ b/templates/blog/post.html
@@ -1,9 +1,9 @@
{% extends 'blog/partials/base.html' %} {% block content %}
-<link
+ <link
rel="stylesheet"
- href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/monokai-sublime.min.css"
+ href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/monokai-sublime.min.css"
/>
-<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet" />
+{% comment %}<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet" /> {% endcomment %}
<div class="main">
<article>
{% load subdomain %}
@@ -72,7 +72,7 @@
{% endif %}
</div>
</article>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
+ {% comment %} <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script> {% endcomment %}
<script>
function editComment(id) {
document.getElementById('comment-body-' + id).style.display = 'none';
diff --git a/templates/blog_admin/edit_post.html b/templates/blog_admin/edit_post.html
index a6191e7c..b50848e3 100644
--- a/templates/blog_admin/edit_post.html
+++ b/templates/blog_admin/edit_post.html
@@ -32,12 +32,12 @@
value="{{ blog_title }}"
/>
</div>
- <br>
+ {% comment %} <br> {% endcomment %}
<div class="form-group">
- <label for="slug">Slug</label>
+ {% comment %} <label for="slug">Slug</label> {% endcomment %}
<input
style="display: inline-block"
- type="text"
+ type="hidden"
class="form-control"
id="slug"
name="slug"
@@ -138,7 +138,6 @@
</section>
</div>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-svg.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script src="https://cdn.quilljs.com/1.3.6/quill.min.js"></script>
<script>
@@ -232,6 +231,52 @@
"formula-block": function () {
insertFormula(quill, true);
},
+ image: function () {
+ // open image upload dialog
+ let fileInput = this.container.querySelector('input.ql-image[type=file]');
+ if (fileInput == null) {
+ fileInput = document.createElement('input');
+ fileInput.setAttribute('type', 'file');
+ fileInput.setAttribute('accept', 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon');
+ fileInput.classList.add('ql-image');
+ fileInput.addEventListener('change', () => {
+ if (fileInput.files != null && fileInput.files[0] != null) {
+ let range = this.quill.getSelection(true);
+ const url = "/ignis/upload";
+ const formData = new FormData();
+ formData.append("image", fileInput.files[0]);
+ formData.append("slug", document.getElementById("slug").value);
+ // append csrf token in header
+ const headers = new Headers();
+ headers.append("X-CSRFToken", "{{ csrf_token }}");
+
+ fetch(url, {
+ method: "POST",
+ headers: headers,
+ body: formData,
+ }).then((response) => response.json()).then((result) => {
+ this.quill.updateContents(new Delta()
+ .retain(range.index)
+ .delete(range.length)
+ .insert({ image: result.url })
+ , Quill.sources.USER);
+ fileInput.value = "";
+ }).catch((error) => {
+ console.error("Error:", error);
+ });
+
+ /* let reader = new FileReader();
+ reader.onload = (e) => {
+ // this.quill.insertEmbed(range.index, "image", result.url);
+ // this.quill.setSelection(range.index + 1);
+ }
+ reader.readAsDataURL(fileInput.files[0]); */
+ }
+ });
+ this.container.appendChild(fileInput);
+ }
+ fileInput.click();
+ },
},
},
},
diff --git a/templates/blog_admin/new_post.html b/templates/blog_admin/new_post.html
index ecff5f82..7972cc87 100644
--- a/templates/blog_admin/new_post.html
+++ b/templates/blog_admin/new_post.html
@@ -26,12 +26,12 @@
value="{{ blog_title }}"
/>
</div>
- <br>
+ {% comment %} <br> {% endcomment %}
<div class="form-group">
- <label for="slug">Slug</label>
+ {% comment %} <label for="slug">Slug</label> {% endcomment %}
<input
style="display: inline-block"
- type="text"
+ type="hidden"
class="form-control"
id="slug"
name="slug"
@@ -224,6 +224,45 @@
"formula-block": function () {
insertFormula(quill, true);
},
+ image: function () {
+ // open image upload dialog
+ let fileInput = this.container.querySelector('input.ql-image[type=file]');
+ if (fileInput == null) {
+ fileInput = document.createElement('input');
+ fileInput.setAttribute('type', 'file');
+ fileInput.setAttribute('accept', 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon');
+ fileInput.classList.add('ql-image');
+ fileInput.addEventListener('change', () => {
+ if (fileInput.files != null && fileInput.files[0] != null) {
+ let range = this.quill.getSelection(true);
+ const url = "/ignis/upload";
+ const formData = new FormData();
+ formData.append("image", fileInput.files[0]);
+ formData.append("slug", document.getElementById("slug").value);
+ // append csrf token in header
+ const headers = new Headers();
+ headers.append("X-CSRFToken", "{{ csrf_token }}");
+
+ fetch(url, {
+ method: "POST",
+ headers: headers,
+ body: formData,
+ }).then((response) => response.json()).then((result) => {
+ this.quill.updateContents(new Delta()
+ .retain(range.index)
+ .delete(range.length)
+ .insert({ image: result.url })
+ , Quill.sources.USER);
+ fileInput.value = "";
+ }).catch((error) => {
+ console.error("Error:", error);
+ });
+ }
+ });
+ this.container.appendChild(fileInput);
+ }
+ fileInput.click();
+ },
},
},
},
diff --git a/templates/dev_status/home.html b/templates/dev_status/home.html
index 770aad59..962d85ad 100644
--- a/templates/dev_status/home.html
+++ b/templates/dev_status/home.html
@@ -1,17 +1,17 @@
{% extends 'blog/partials/base.html' %} {% block content %}
<div class="main">
<div class="area">
- <p class="titlebar">Repositories (<em>Showing {{ repo_length }} repositories</em>) </p>
- <div class="area-content area-bg">
- {% if not user.is_authenticated %}
- <p style="margin: 0 auto 10px auto;">
- You are not logged in. You can only view public repositories. Please login or register
- using the sidebar on the left to view both public and private repositories.
- </p>
- {% endif %}
-
+ {% load static %}
+ {% load times %}
+ {% if not user.is_authenticated %}
+ <p style="padding: 15px 10px;" class="alert">
+ You are not logged in. You can only view public repositories. Please login or register
+ using the sidebar on the left to view both public and private repositories.
+ </p>
+ {% endif %}
+ <div style="background-image: url({% static 'images/site/repositories.png' %}); width: 720px; height: 173px; background-repeat: no-repeat; background-position: center;">
{% comment %} Search and Filter {% endcomment %}
- <table style="margin: 0 auto;">
+ <table style="margin: 0 auto; position: relative; top: 125px;">
<form action="" method="get">
<tr>
<td>
@@ -63,8 +63,7 @@
</div>
<hr>
<div class='repositories'>
- {% load static %}
- {% load times %}
+
<table style="width: 720px; table-layout: fixed; border-spacing: 12px; border-collapse: separate;">
{% for repo in repos %}
<tr style="vertical-align: middle;">