diff options
| -rw-r--r-- | blog/migrations/0005_alter_post_post_image.py | 18 | ||||
| -rw-r--r-- | blog/migrations/0006_remove_post_post_image.py | 17 | ||||
| -rw-r--r-- | blog/models.py | 1 | ||||
| -rw-r--r-- | blog/views.py | 14 | ||||
| -rw-r--r-- | blog_admin/views.py | 17 | ||||
| -rw-r--r-- | ignis/admin.py | 3 | ||||
| -rw-r--r-- | ignis/migrations/0012_coverimage.py | 40 | ||||
| -rw-r--r-- | ignis/models.py | 8 | ||||
| -rw-r--r-- | ignis/views.py | 59 | ||||
| -rw-r--r-- | static/css/main.css | 8 | ||||
| -rw-r--r-- | templates/blog/articles.html | 33 | ||||
| -rw-r--r-- | thatcomputerscientist/settings.py | 1 |
12 files changed, 164 insertions, 55 deletions
diff --git a/blog/migrations/0005_alter_post_post_image.py b/blog/migrations/0005_alter_post_post_image.py new file mode 100644 index 00000000..6e58db75 --- /dev/null +++ b/blog/migrations/0005_alter_post_post_image.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.4 on 2022-12-31 17:13 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("blog", "0004_alter_post_post_image"), + ] + + operations = [ + migrations.AlterField( + model_name="post", + name="post_image", + field=models.ImageField(blank=True, upload_to="images/post-covers"), + ), + ] diff --git a/blog/migrations/0006_remove_post_post_image.py b/blog/migrations/0006_remove_post_post_image.py new file mode 100644 index 00000000..0913f97c --- /dev/null +++ b/blog/migrations/0006_remove_post_post_image.py @@ -0,0 +1,17 @@ +# Generated by Django 4.1.4 on 2022-12-31 17:21 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("blog", "0005_alter_post_post_image"), + ] + + operations = [ + migrations.RemoveField( + model_name="post", + name="post_image", + ), + ] diff --git a/blog/models.py b/blog/models.py index 044f2e15..d9d41eeb 100644 --- a/blog/models.py +++ b/blog/models.py @@ -26,7 +26,6 @@ class Post(models.Model): slug = models.SlugField(max_length=100, unique=True) body = models.TextField() date = models.DateTimeField() - post_image = models.TextField(blank=True) author = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, diff --git a/blog/views.py b/blog/views.py index 50f3b3f6..d31b3f8f 100644 --- a/blog/views.py +++ b/blog/views.py @@ -208,17 +208,25 @@ def search(request): from django.core.paginator import Paginator def articles(request): page = request.GET.get('page') if request.GET.get('page') else 1 + order_by = request.GET.get('order_by') if request.GET.get('order_by') else 'date' + direction = request.GET.get('direction') if request.GET.get('direction') else 'desc' + categories = Category.objects.all() + category = request.GET.get('category') try: page = int(page) except: page = 1 - posts = Post.objects.filter(is_public=True).order_by('-date') + posts = Post.objects.filter(is_public=True).order_by('-' + order_by) if direction == 'desc' else Post.objects.filter(is_public=True).order_by(order_by) + if category and category != 'all': + posts = posts.filter(category__slug=category) + else: + category = 'all' posts = Paginator(posts, 10) posts = posts.page(page) - # add excerpt to each post + for post in posts: post.excerpt = add_excerpt(post) post.num_comments = add_num_comments(post) num_pages = posts.paginator.num_pages - return render(request, 'blog/articles.html', {'title': 'Articles', 'posts': posts, 'num_pages': num_pages, 'page': page}) + return render(request, 'blog/articles.html', {'title': 'Articles', 'posts': posts, 'num_pages': num_pages, 'page': page, 'order_by': order_by, 'direction': direction, 'categories': categories, 'category': category}) diff --git a/blog_admin/views.py b/blog_admin/views.py index 53d24107..8bcf78ed 100644 --- a/blog_admin/views.py +++ b/blog_admin/views.py @@ -1,10 +1,8 @@ import base64 from django.shortcuts import render, redirect -from users.models import UserProfile -from django.contrib.auth.models import User from django.contrib import messages from blog.models import Post, Category, Tag -from ignis.models import PostImage +from ignis.models import PostImage, CoverImage import re import random import string @@ -58,11 +56,8 @@ def new_post(request): tags = [Tag.objects.get_or_create(slug = tag, name = tag)[0] for tag in tags] post = Post.objects.create(title = title, body = body, category = category, slug = slug, author = request.user) post.tags.set(tags) - # convert post_image to base64 and save it in post.post_image - post_image = post_image.read() - post_image = base64.b64encode(post_image) - post.post_image = "data:image/png;base64," + post_image.decode('utf-8') - post.save() + # save post image to cover image + post_image = CoverImage.objects.create(image = post_image, post = post, name = 'cover image for post {}'.format(post.slug)) PostImage.objects.filter(temp_post_id = random_post_identifier).update(post = post) PostImage.objects.filter(temp_post_id = random_post_identifier).update(temp_post_id = None) # replace all random_post_identifier with post.id in post.body @@ -112,10 +107,8 @@ def edit_post(request, slug): post.author = request.user post.tags.set(tags) if post_image: - # convert to data string src and save it in post.post_image - post_image = post_image.read() - post_image = base64.b64encode(post_image) - post.post_image = "data:image/png;base64," + post_image.decode('utf-8') + # update post image to cover image + post_image = CoverImage.objects.create(image = post_image, post = post, name = 'cover image for {}'.format(post.slug)) post.save() messages.success(request, 'Post edited successfully!') return redirect('blog-admin:posts') diff --git a/ignis/admin.py b/ignis/admin.py index eb188185..b262f0d0 100644 --- a/ignis/admin.py +++ b/ignis/admin.py @@ -1,7 +1,8 @@ from django.contrib import admin # Register your models here. -from .models import PostImage, RepositoryTitle +from .models import PostImage, RepositoryTitle, CoverImage admin.site.register(PostImage) admin.site.register(RepositoryTitle) +admin.site.register(CoverImage) diff --git a/ignis/migrations/0012_coverimage.py b/ignis/migrations/0012_coverimage.py new file mode 100644 index 00000000..0a35a322 --- /dev/null +++ b/ignis/migrations/0012_coverimage.py @@ -0,0 +1,40 @@ +# Generated by Django 4.1.4 on 2022-12-31 17:21 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("blog", "0006_remove_post_post_image"), + ("ignis", "0011_postimage_name"), + ] + + operations = [ + migrations.CreateModel( + name="CoverImage", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("image", models.ImageField(upload_to="images//cover_images")), + ("name", models.CharField(default=None, max_length=100, null=True)), + ( + "post", + models.ForeignKey( + default=None, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="blog.post", + ), + ), + ], + ), + ] diff --git a/ignis/models.py b/ignis/models.py index 048f1ea5..dd8443bc 100644 --- a/ignis/models.py +++ b/ignis/models.py @@ -5,6 +5,14 @@ UPLOAD_ROOT = 'images/' # Only For Storing Images +class CoverImage(models.Model): + image = models.ImageField(upload_to="{}/cover_images".format(UPLOAD_ROOT)) + name = models.CharField(max_length=100, default=None, null=True) + post = models.ForeignKey(Post, default=None, on_delete=models.CASCADE, null=True) + + def __str__(self): + return self.name + class PostImage(models.Model): post = models.ForeignKey(Post, default=None, on_delete=models.CASCADE, null=True) image = models.ImageField(upload_to="{}/post_images".format(UPLOAD_ROOT)) diff --git a/ignis/views.py b/ignis/views.py index fd127d55..9a081c46 100644 --- a/ignis/views.py +++ b/ignis/views.py @@ -5,7 +5,7 @@ from django.views.decorators.csrf import csrf_exempt import base64 from blog.models import Post import base64 -from .models import PostImage, RepositoryTitle +from .models import PostImage, RepositoryTitle, CoverImage import json import requests from django.core.files.base import ContentFile @@ -38,41 +38,36 @@ def tex(request): @csrf_exempt def post_image(request, size, post_id): post_id = post_id.replace('.gif', '') - pi = Post.objects.get(id=post_id).post_image + pi = CoverImage.objects.filter(post=Post.objects.get(id=post_id)) if not pi: return HttpResponse('No image found!', status=404) - # convert base64 data src to image - image = base64.b64decode(pi.split(',')[1]) - - size = int(size) - if size != 0: - image = Image.open(BytesIO(image)) - - # set min and max size - if size < 100: - size = 100 - elif size > 1000: - size = 1000 - - # resize width to size, compute height - width, height = image.size - height = int(height * (size / width)) - width = size - + # open image and return + image = pi[0].image + with open(image.path, 'rb') as f: # resize image - image = image.resize((width, height), Image.ANTIALIAS) - - # Convert back to gif and return - output = BytesIO() - image.save(output, format='GIF') - - return HttpResponse(output.getvalue(), content_type='image/gif') - else: - # Convert back to gif and return - output = BytesIO() - output.write(image) - return HttpResponse(output.getvalue(), content_type='image/gif') + size = int(size) + if size != 0: + + # set min and max size + if size < 100: + size = 100 + elif size > 1000: + size = 1000 + + image = Image.open(f) + # resize width to size, compute height + width, height = image.size + height = int(height * (size / width)) + width = size + + # resize image + image = image.resize((width, height), Image.ANTIALIAS) + output = BytesIO() + image.save(output, format='GIF') + return HttpResponse(output.getvalue(), content_type='image/gif') + else: + return HttpResponse(f.read(), content_type='image/gif') @csrf_exempt def get_image(request, post_id, image_name): diff --git a/static/css/main.css b/static/css/main.css index a3d7c516..ea7a7a6a 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -37,7 +37,7 @@ h2, #editor-container h2 { margin-bottom: 15px; } -input, textarea { +input, textarea, select { padding: 5px 10px; border: none; outline: none; @@ -46,6 +46,12 @@ input, textarea { font-family: Verdana,Helvetica,Arial,Sans-Serif; } +textarea { + background: transparent; + border: solid 1px whitesmoke; + color: white; +} + /* Full width auto spacing table... ellipsis if text overflows */ #posts { width: 100%; diff --git a/templates/blog/articles.html b/templates/blog/articles.html index ab07891c..23646015 100644 --- a/templates/blog/articles.html +++ b/templates/blog/articles.html @@ -1,28 +1,53 @@ {% extends 'blog/partials/base.html' %} {% block content %} <h2 style="margin-top:0px;"> All Posts</h2> +<form id="filters" method="get"> + <span><b>Filters:</b> </span> + <label for="order_by">Order By: </label> + <select name="order_by"> + <option value="date" {% if order_by == 'date' %}selected{% endif %}>Date</option> + <option value="title" {% if order_by == 'title' %}selected{% endif %}>Title</option> + </select> + <label for="direction"> Direction: </label> + <select name="direction"> + <option value="asc" {% if direction == 'asc' %}selected{% endif %}>Ascending</option> + <option value="desc" {% if direction == 'desc' %}selected{% endif %}>Descending</option> + </select> + <label for="category"> In Category: </label> + <select name="category"> + <option value="all" {% if category == 'all' %}selected{% endif %}>All</option> + {% for cat in categories %} + <option value="{{ cat.slug }}" {% if category == cat.slug %}selected{% endif %}>{{ cat.name }}</option> + {% endfor %} + </select> + <span> </span> + <input type="submit" value="Apply" class="button button-special" /> +</form> + {% if posts %} <div id="recent-posts" class="mtctitem"> {% for post in posts %} + <br> <div class="post" style="clear: both;"> - <h1> - <a href="{% url 'blog:post' post.slug %}">{{ post.title }}</a> - </h1> <div style="text-align: justify; font-size: 13px; margin-bottom: 0px;"> <span> <img src="{% url 'ignis:post_image' '320' post.id %}.gif" alt="Cover image for {{ post.title }}" style="float: left; margin-right: 11px; width: 320px; height: auto;"> </span> + <h1 style="margin-top: 0px; margin-bottom: 0px;"> + <a href="{% url 'blog:post' post.slug %}">{{ post.title }}</a> + </h1> {{ post.excerpt | safe }} </div> <div class="post-actions" style="clear: both;"> <a href="{% url 'blog:post' post.slug %}">Continue Reading</a> | <a href="{% url 'blog:post' post.slug %}#comments">{{ post.num_comments }} Comments</a> </div> </div> + <br> {% endfor %} </div> {% endif %} <div> - <table id="pagination"> + <table id="pagination" style="clear: both;"> <tr> {% if page == 1 %} <td><a class="disabled">«</a></td> diff --git a/thatcomputerscientist/settings.py b/thatcomputerscientist/settings.py index 40ba8040..fd231fa5 100644 --- a/thatcomputerscientist/settings.py +++ b/thatcomputerscientist/settings.py @@ -10,7 +10,6 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/4.0/ref/settings/ """ -from cgitb import handler from pathlib import Path from dotenv import load_dotenv import os |
