diff options
| author | Bobby <[email protected]> | 2023-05-31 18:00:28 -0400 |
|---|---|---|
| committer | Bobby <[email protected]> | 2023-05-31 18:00:28 -0400 |
| commit | aa41643172a32dc81cf6d214289e1dedf998953d (patch) | |
| tree | 49b8ca61d5d6cad866fa7fd09ebc4bf2f7f94259 | |
| parent | 6c683c5b067b019e93619557a358e7f67c2e4d7b (diff) | |
| download | thatcomputerscientist-aa41643172a32dc81cf6d214289e1dedf998953d.tar.xz thatcomputerscientist-aa41643172a32dc81cf6d214289e1dedf998953d.zip | |
Allow Anonymous Commenting
| -rw-r--r-- | blog/admin.py | 3 | ||||
| -rw-r--r-- | blog/migrations/0014_anonymouscommentuser_alter_comment_user_and_more.py | 53 | ||||
| -rw-r--r-- | blog/models.py | 25 | ||||
| -rw-r--r-- | blog/urls.py | 3 | ||||
| -rw-r--r-- | blog/views.py | 119 | ||||
| -rw-r--r-- | middleware/tz.py | 32 | ||||
| -rw-r--r-- | middleware/uuidmiddleware.py | 4 | ||||
| -rw-r--r-- | static/css/phone_compatibility.css | 10 | ||||
| -rw-r--r-- | static/css/styles.css | 14 | ||||
| -rw-r--r-- | templates/blog/post.html | 161 | ||||
| -rw-r--r-- | thatcomputerscientist/settings.py | 2 | ||||
| -rw-r--r-- | thatcomputerscientist/templatetags/sha256.py | 9 |
12 files changed, 423 insertions, 12 deletions
diff --git a/blog/admin.py b/blog/admin.py index e81f0b56..dd35e8cb 100644 --- a/blog/admin.py +++ b/blog/admin.py @@ -1,9 +1,10 @@ from django.contrib import admin # Register your models here. -from .models import Category, Comment, Post, Tag +from .models import AnonymousCommentUser, Category, Comment, Post, Tag admin.site.register(Post) admin.site.register(Comment) admin.site.register(Category) admin.site.register(Tag) +admin.site.register(AnonymousCommentUser) diff --git a/blog/migrations/0014_anonymouscommentuser_alter_comment_user_and_more.py b/blog/migrations/0014_anonymouscommentuser_alter_comment_user_and_more.py new file mode 100644 index 00000000..f05252b8 --- /dev/null +++ b/blog/migrations/0014_anonymouscommentuser_alter_comment_user_and_more.py @@ -0,0 +1,53 @@ +# Generated by Django 4.1.4 on 2023-05-31 18:34 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("blog", "0013_post_views"), + ] + + operations = [ + migrations.CreateModel( + name="AnonymousCommentUser", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=32)), + ("email", models.CharField(max_length=32)), + ("token", models.CharField(max_length=128, unique=True)), + ("avatar", models.CharField(blank=True, max_length=128)), + ], + ), + migrations.AlterField( + model_name="comment", + name="user", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="comment", + name="anonymous_user", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="blog.anonymouscommentuser", + ), + ), + ] diff --git a/blog/models.py b/blog/models.py index 771a9561..e8c0eb10 100644 --- a/blog/models.py +++ b/blog/models.py @@ -1,3 +1,5 @@ +import hashlib + from django.conf import settings from django.db import models from django.utils.text import slugify @@ -58,6 +60,21 @@ class Post(models.Model): def __str__(self): return str(self.title) + +class AnonymousCommentUser(models.Model): + name = models.CharField(max_length=32) + email = models.CharField(max_length=32) + token = models.CharField(max_length=128, unique=True) + avatar = models.CharField(max_length=128, blank=True) + + @classmethod + def get_or_create(cls, email, token, avatar=''): + email_hash = hashlib.md5(email.encode('utf-8')).hexdigest() + token_hash = hashlib.sha256(token.encode('utf-8')).hexdigest() + return cls(email=email_hash, token=token_hash, avatar=avatar) + + def __str__(self): + return self.name class Comment(models.Model): post = models.ForeignKey( @@ -67,6 +84,14 @@ class Comment(models.Model): user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, + blank=True, + null=True, + ) + anonymous_user = models.ForeignKey( + 'AnonymousCommentUser', + on_delete=models.CASCADE, + blank=True, + null=True, ) body = models.TextField() created_at = models.DateTimeField(auto_now_add=True) diff --git a/blog/urls.py b/blog/urls.py index d07ef152..eda17e20 100644 --- a/blog/urls.py +++ b/blog/urls.py @@ -12,8 +12,11 @@ urlpatterns = [ path('weblog', views.articles, name='articles'), path('weblog/<str:slug>', views.post, name='post'), path('weblog/<str:slug>/comment', views.comment, name='comment'), + path('weblog/<str:slug>/anon_comment', views.anon_comment, name='anon_comment'), path('weblog/<str:slug>/edit_comment', views.edit_comment, name='edit_comment'), + path('weblog/<str:slug>/anon_edit_comment', views.anon_edit_comment, name='anon_edit_comment'), path('weblog/<str:slug>/delete_comment/<int:comment_id>', views.delete_comment, name='delete_comment'), + path('weblog/<str:slug>/anon_delete_comment/<int:comment_id>', views.anon_delete_comment, name='anon_delete_comment'), path('archives', views.archives, name='archives'), path('archives/<str:date>', views.articles, name='archive_posts'), path('categories', views.categories, name='categories'), diff --git a/blog/views.py b/blog/views.py index 1c2b9ca2..c5d9db5e 100644 --- a/blog/views.py +++ b/blog/views.py @@ -1,5 +1,8 @@ +import hashlib import os +import random import re +import string from datetime import datetime from random import choice from string import ascii_letters, digits @@ -9,7 +12,7 @@ from django.contrib import messages from django.contrib.auth.models import User from django.core.cache import cache from django.core.paginator import Paginator -from django.http import Http404, HttpResponse +from django.http import Http404, HttpResponse, HttpResponseRedirect from django.shortcuts import redirect, render, reverse from dotenv import load_dotenv from haystack.query import SearchQuerySet @@ -23,11 +26,10 @@ from users.tokens import CaptchaTokenGenerator from .context_processors import (add_excerpt, add_num_comments, avatar_list, comment_processor, highlight_code_blocks, recent_posts) -from .models import Category, Comment, Post +from .models import AnonymousCommentUser, Category, Comment, Post load_dotenv() - def atoi(text): return int(text) if text.isdigit() else text @@ -156,9 +158,15 @@ def post(request, slug): tags = post.tags.all() comments = Comment.objects.filter(post=post) for comment in comments: - user_profile = UserProfile.objects.get(user=comment.user) - comment.avatar_url = user_profile.avatar_url - comment.processed_body = comment_processor(comment.body) + if comment.user: + user_profile = UserProfile.objects.get(user=comment.user) + comment.avatar_url = user_profile.avatar_url + comment.processed_body = comment_processor(comment.body) + + if comment.anonymous_user: + user_profile = comment.anonymous_user + comment.avatar_url = user_profile.avatar + comment.processed_body = comment_processor(comment.body) if post.is_public: # modify request.meta description (only text) and image @@ -195,6 +203,63 @@ def comment(request, slug): return redirect('blog:home') else: return redirect('blog:home') + +def anon_comment(request, slug): + if request.method == 'POST': + if request.user.is_authenticated: + # not allowed this is anonymous comment form + return redirect(reverse('blog:post', kwargs={'slug': slug})) + else: + anonymous_user = request.POST.get('anonymous-name') + anonymous_email = request.POST.get('anonymous-email') + anonymous_token, at = request.POST.get('anonymous-token'), request.POST.get('anonymous-token') + new_anonymous_token = request.POST.get('new-anonymous-token') + anonymous_comment = request.POST.get('anonymous-comment') + if not anonymous_user: + messages.error(request, 'Please enter a name!') + return redirect(reverse('blog:post', kwargs={'slug': slug})) + if not anonymous_comment: + messages.error(request, 'Please enter a comment!') + return redirect(reverse('blog:post', kwargs={'slug': slug})) + if not anonymous_email: + anonymous_email = ''.join(random.choice(string.ascii_lowercase) for i in range(10)) + '@anonymous.thatcomputerscientist.com' + if not anonymous_token: + anonymous_token = ''.join(random.choice(string.ascii_lowercase) for i in range(10)) + at = anonymous_token + + # generate a random avatar for the anonymous user + avatarlist = avatar_list() + for key in avatarlist: + avatarlist[key] = [re.sub(r'\.gif$', '', string) for string in avatarlist[key]] + avatarlist[key].sort(key=natural_keys) + avatarlist = {k: avatarlist[k] for k in sorted(avatarlist)} + avatar_dir = choice(list(avatarlist.keys())) + avatar_file = choice(avatarlist[avatar_dir]) + anonymous_avatar = avatar_dir + '/' + avatar_file + anonymous_token = hashlib.sha256(anonymous_token.encode('utf-8')).hexdigest() + try: + anonymous_user = AnonymousCommentUser.objects.get(name=anonymous_user, email=anonymous_email, token=anonymous_token) + except AnonymousCommentUser.DoesNotExist: + anonymous_user = AnonymousCommentUser.objects.create(name=anonymous_user, email=anonymous_email, token=anonymous_token, + avatar=anonymous_avatar) + if new_anonymous_token: + at = new_anonymous_token + new_anonymous_token = hashlib.sha256(new_anonymous_token.encode('utf-8')).hexdigest() + anonymous_user.token = new_anonymous_token + anonymous_user.save() + + comment = Comment.objects.create(anonymous_user=anonymous_user, post=Post.objects.get(slug=slug), body=anonymous_comment) + + # redirect to the post with the comment but set the anonymous user cookie + response = redirect(reverse('blog:post', kwargs={'slug': slug}) + '#comment-' + str(comment.id)) + response.set_cookie('anonymous_name', anonymous_user.name, max_age=60*60*24*365) + response.set_cookie('anonymous_email', anonymous_user.email, max_age=60*60*24*365) + response.set_cookie('anonymous_token', at, max_age=60*60*24*365) + + return response + + else: + return redirect('blog:home') def edit_comment(request, slug): if request.method == 'POST': @@ -215,6 +280,31 @@ def edit_comment(request, slug): return redirect('blog:home') else: return redirect('blog:home') + +def anon_edit_comment(request, slug): + if request.method == 'POST': + if request.user.is_authenticated: + # not allowed this is anonymous comment form + return redirect(reverse('blog:post', kwargs={'slug': slug})) + else: + anonymous_token = request.COOKIES.get('anonymous_token') + if not anonymous_token: + return HttpResponse('Unauthorized!', status=401) + try: + anonymous_token = hashlib.sha256(anonymous_token.encode('utf-8')).hexdigest() + comment = Comment.objects.get(id=request.POST.get('comment_id')) + if comment.anonymous_user.token == anonymous_token: + comment.body = request.POST.get('body') + comment.edited = True + comment.edited_at = datetime.now() + comment.save() + return redirect(reverse('blog:post', kwargs={'slug': slug}) + '#comment-' + str(comment.id)) + else: + return HttpResponse('Unauthorized!', status=401) + except Comment.DoesNotExist: + return HttpResponse('Comment not found!', status=404) + else: + return redirect('blog:home') def delete_comment(request, slug, comment_id): if request.user.is_authenticated: @@ -228,8 +318,23 @@ def delete_comment(request, slug, comment_id): except Comment.DoesNotExist: return HttpResponse('Comment not found!', status=404) else: - return redirect('blog:home') + return HttpResponseRedirect(request.META.get('HTTP_REFERER')) +def anon_delete_comment(request, slug, comment_id): + if request.user.is_authenticated: + # not allowed this is anonymous comment form + return HttpResponseRedirect(request.META.get('HTTP_REFERER')) + else: + anonymous_token = request.COOKIES.get('anonymous_token') + if not anonymous_token: + return HttpResponse('Unauthorized!', status=401) + anonymous_token = hashlib.sha256(anonymous_token.encode('utf-8')).hexdigest() + try: + comment = Comment.objects.get(id=comment_id, anonymous_user__token=anonymous_token) + comment.delete() + return redirect(reverse('blog:post', kwargs={'slug': slug}) + '#comments') + except Comment.DoesNotExist: + return HttpResponse('Comment not found!', status=404) def search(request): query = request.GET.get('q') diff --git a/middleware/tz.py b/middleware/tz.py new file mode 100644 index 00000000..4aa3087a --- /dev/null +++ b/middleware/tz.py @@ -0,0 +1,32 @@ +import requests + + +# make sure you add `TimezoneMiddleware` appropriately in settings.py +class TimezoneMiddleware(object): + """ + Middleware to properly handle the users timezone + """ + + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + # get the user's timezone from the cookie + user_timezone = request.COOKIES.get('user_timezone') + + if not user_timezone: + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + + if x_forwarded_for: + remote_ip = x_forwarded_for.split(',')[0] + else: + remote_ip = request.META.get('REMOTE_ADDR') + + geo_data = requests.get(f'http://ip-api.com/json/{remote_ip}').json() + user_timezone = geo_data['timezone'] + + if user_timezone: + response = self.get_response(request) + response.set_cookie('user_timezone', user_timezone, max_age=31536000) + return response + return self.get_response(request) diff --git a/middleware/uuidmiddleware.py b/middleware/uuidmiddleware.py index fc97cd58..bf920718 100644 --- a/middleware/uuidmiddleware.py +++ b/middleware/uuidmiddleware.py @@ -1,6 +1,8 @@ import uuid -from django.core.cache import cache + from django.conf import settings +from django.core.cache import cache + class UserUUIDMiddleware: # assign a uuid to the user if they don't have one diff --git a/static/css/phone_compatibility.css b/static/css/phone_compatibility.css index becbdf93..d973acbc 100644 --- a/static/css/phone_compatibility.css +++ b/static/css/phone_compatibility.css @@ -252,6 +252,16 @@ I am not sure yet. width: auto !important; float: none !important; } + + #anonymous-profile-info > div > label { + display: block; + } + + #anonymous-profile-info > div > input { + width: calc(100% - 20px); + display: block; + margin: 10px 0; + } } #ham { diff --git a/static/css/styles.css b/static/css/styles.css index 40f9e90a..7b0db28f 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -441,6 +441,20 @@ blockquote { z-index: 1; } +#anonymous-profile-info > div { + margin: 10px 0; +} + +#anonymous-profile-info > div > label { + width: 200px; + display: inline-block; +} + +#anonymous-profile-info > div > input { + width: 300px; + display: inline-block; +} + @media only screen and (min-width: 481px) { .post-body { line-height: 15px; diff --git a/templates/blog/post.html b/templates/blog/post.html index 4b60160d..0aac1ecd 100644 --- a/templates/blog/post.html +++ b/templates/blog/post.html @@ -1,6 +1,7 @@ {% extends 'blog/partials/base.html' %} {% block content %} {% load static %} {% load tz %} +{% load sha256 %} <div id="post-actions-bar" class="mtsbitem"> <a class="pa-btn" href="{% url 'blog:home' %}">Home</a> <a class="pa-btn" href="#comments">Opinions</a> @@ -62,7 +63,17 @@ </td> <td style="vertical-align: top; width: 668px;"> <div style="margin-bottom: 13px; border-bottom: dashed 1px white; padding-bottom: 13px;"> - <a href="{% url 'blog:user_activity' comment.user.username %}">{{ comment.user.username }}</a> on <em>{{ comment.created_at | date:"M d, Y" }}</em> + <a href="{% if comment.user%}{% url 'blog:user_activity' comment.user.username %}{% else %}#{% endif %}"> + {% if comment.user %} + {{ comment.user.username }} + {% else %} + {{ comment.anonymous_user.name }} + {% endif %} + </a> on <em> + {% timezone request.COOKIES.user_timezone %} + {{ comment.created_at | date:"M d, Y h:i A" }} + {% endtimezone %} + </em> {% if comment.edited %} <em>(Edited)</em> {% endif %} @@ -72,6 +83,12 @@ <a href="{% url 'blog:delete_comment' post.slug comment.id %}" onclick="return confirm('Are you sure you want to delete this comment?')">Delete</a> {% endif %} + {% if comment.anonymous_user.name and comment.anonymous_user.email and comment.anonymous_user.token and comment.anonymous_user.token == request.COOKIES.anonymous_token|sha256 %} + + <a href="javascript:;" onclick="editComment({{ comment.id }})">Edit</a> + + <a href="{% url 'blog:anon_delete_comment' post.slug comment.id %}" onclick="return confirm('Are you sure you want to delete this comment?')">Delete</a> + {% endif %} </div> <div id="comment-body-{{ comment.id }}" class="comment"> {{ comment.processed_body|safe }} @@ -87,6 +104,17 @@ </form> </div> {% endif %} + {% if comment.anonymous_user.name and comment.anonymous_user.email and comment.anonymous_user.token and comment.anonymous_user.token == request.COOKIES.anonymous_token|sha256 %} + <div id="edit-form-{{ comment.id }}" style="display: none; margin-bottom: 20px;"> + <form action="{% url 'blog:anon_edit_comment' post.slug %}" method="POST"> + {% csrf_token %} + <input type = "hidden" name="comment_id" value="{{ comment.id }}"> + <textarea name="body" id="body" cols="78" rows="10" style="width: 640px; display: block; margin-bottom: 10px;">{{ comment.body }}</textarea> + <input type="submit" value="Update" class="button button-special"> + <input type="button" value="Cancel" onclick="cancelEdit({{ comment.id }})" class="button"> + </form> + </div> + {% endif %} </td> </tr> </table> @@ -104,7 +132,7 @@ <h2>Leave a Comment</h2> <form action="{% url 'blog:comment' post.slug %}" method="POST"> {% csrf_token %} - <textarea name="comment" id="comment" cols="88" rows="10" style="width: 710px; display: block; margin-bottom: 15px;" placeholder="Your comment here..."></textarea> + <textarea required name="comment" id="comment" cols="88" rows="10" style="width: 710px; display: block; margin-bottom: 15px;" placeholder="Your comment here..."></textarea> <div id="comment-tips" style=" /* background-color: #2d1d3d; */ padding: 10px; margin-bottom: 15px; @@ -167,8 +195,113 @@ {% else %} <div id="new-comment" class="mtsbitem"> <h2>Leave a Comment</h2> - <p><em>You must be logged in to leave a comment.</em></p> + <p id="ancmClick">You must be <em>logged in</em> to leave a comment. Or, you can <a href="javascript:;" onclick="toggleAnon()">leave an anonymous comment</a>.</p> + <div id="anonymous-comment-form" style="display: none;"> + <form action="{% url 'blog:anon_comment' post.slug %}" method="POST"> + {% csrf_token %} + <div id="anonymous-comment"> + <div id="anonymous-profile-info"> + <div> + <label for="anonymous-name"><b>Name </b> <i>{% if request.COOKIES.anonymous_name %}(Pre-Filled){% else %}(Required){% endif %}</i>:</label> + <input required type="text" name="anonymous-name" id="anonymous-name" value="{{ request.COOKIES.anonymous_name }}" placeholder="Display name"> + </div> + <div> + <label for="anonymous-email"><b>Email</b> <i>{% if request.COOKIES.anonymous_email %}(Pre-Filled){% else %}(Optional){% endif %}</i>:</label> + <input type="text" name="anonymous-email" id="anonymous-email" value="{{ request.COOKIES.anonymous_email }}" placeholder="Your email address"> + </div> + <div> + <input type="hidden" name="anonymous-token" id="anonymous-token" value="{{ request.COOKIES.anonymous_token }}"> + <label for="new-anonymous-token"><b>New Secret Token</b> <i>{% if request.COOKIES.anonymous_token %}(Pre-Filled){% else %}(Optional){% endif %}</i>:</label> + <input type="text" name="new-anonymous-token" id="new-anonymous-token" value="" placeholder="New Secret Token"> + <p><small>You do not fill your secret token everytime you comment. Set it only once and change when needed.</small></p> + </div> + </div> + </div> + <textarea required name="anonymous-comment" id="anonymous-comment" cols="88" rows="10" style="width: 710px; display: block; margin: 15px 0;" placeholder="Your comment here..."></textarea> + <div id="comment-tips" style=" /* background-color: #2d1d3d; */ + padding: 10px; + margin-bottom: 15px; + border-radius: 6px; + margin-top: -10px; + border: solid 1px white; width: calc(100% - 20px);"> + <p onclick="toggleTips()" style="cursor: pointer; margin: 0;"><span style="border-bottom: dotted 1px white;" class="noselect">Text Markup Tips ></span></p> + <div id="tips" style="display: none;"> + <p> + This site uses a custom built markup format for comments. It's very similar to Markdown. Only certain types of markup are allowed. Here's a list of what you can do: + </p> + + <ul style="list-style-type: disc; margin: 0;padding: 0; margin: 5px 0px 0px 30px;"> + <li>Wrap text in double underscores (__) to make it <i>italic</i>. + <br> + e.g. <code>__italic__</code> + <br><br> + </li> + <li>Wrap text in double asterisks (**) to make it <b>bold</b>. + <br> + e.g. <code>**bold**</code> + <br><br> + </li> + <li>Wrap text in double tildes (~~) to <s>strikethrough</s> it. + <br> + e.g. <code>~~strikethrough~~</code> + <br><br> + </li> + <li>Wrap text in triple backticks (<code>```</code>) to make it a code block: + <br> + e.g. +<pre> + ``` + code block + ``` +</pre> + or define with language as: +<pre> + ```lang-<language> + code block + ``` +</pre> + e.g. lang-python, lang-java, lang-javascript, etc. + <br><br><b>PS:</b> Tags for code block (<code>```</code>) must be contained on their respective individual lines. Only the language definition tag can be on the same line as the opening tag. + <br><br> + </li> + <li>Wrap text in double dollar sign ($$) to make it a math block and single dollar sign ($) to make it inline math. You can use LaTeX syntax. + <br> + e.g. <code>$$\frac{1}{2}$$</code> or <code>$\frac{1}{2}$</code> + <br><br> + </li> + </ul> + <p style="margin-top: -7px;">Any links, images or other markup will be kept as plain text. Also, free speech is good and all, but please keep it civil. Sufficient JavaScript support will be required to bind shortkeys. Please type the markup manually if you are on an older browser.</p> + </div> + </div> + <div id="comment-gotchas" style=" /* background-color: #2d1d3d; */ + padding: 10px; + margin-bottom: 15px; + border-radius: 6px; + margin-top: -10px; + border: solid 1px white; width: calc(100% - 20px);"> + <p onclick="toggleGotchas()" style="cursor: pointer; margin: 0;"><span style="border-bottom: dotted 1px white;" class="noselect">Anonymous Commenting Gotchas ></span></p> + <div id="gotchas" style="display: none;"> + <p>Athough its cool to be anonymous, there are a few things which will not work if you choose to comment anonymously:</p> + <ul> + <li>If you do not set a Email and secret token, you will not be able to edit your comment later. This information will be stored locally and the site will remember your information, so you don't have to enter it again.</li> + <li>If you lose your secret token, that's basically permanent damage. You can always set a new secret token for the same email, but you will not be able to edit your previous comments.</li> + <li>You will not be able to customize your avatar. You will be assigned a random site specific avatar.</li> + <li>Anytime, you wish to change your secret token, this can be done by entering your email and new secret token. Also, you do not fill your secret token everytime you comment. It will be stored locally and the site will remember your information, so you don't have to enter it again.</li> + <li>If you do not fill the email and secret token fields, a random (non-existent) email and secret token will be generated for you. As long as you do not clear your browser data, you will be able to edit your comment later.</li> + {% comment %} <li>All comments will be passed through Akismet spam filter. If your comment is marked as spam, it will be immediately rejected. If you think this is a mistake, please contact me.</li> {% endcomment %} + <li>If anytime, you wish to <a href="{% url 'blog:register' %}">register</a> for a full account, you can do so with the same email address. All your previous comments will be automatically migrated to your new account.</li> + </ul> + </div> + </div> + <input type="submit" value="Submit" class="button button-special"> + <input type="button" value="Cancel" class="button" onclick="document.getElementById('anonymous-comment-form').style.display = 'none'; document.getElementById('ancmClick').style.display = 'block';"> + </form> + <br> + <button class="button" onclick="cd()">Clear Form Data</button> + </div> </div> + + {% endif %} {% endblock %} {% block scripts %} @@ -183,10 +316,32 @@ document.getElementById('edit-form-' + id).style.display = 'none'; } + function cd() { + // we will clear the user cookies + document.cookie = 'anonymous_name=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; + document.cookie = 'anonymous_email=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; + document.cookie = 'anonymous_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; + window.location.reload(); + } + function toggleTips() { var tips = document.getElementById('tips'); $('#tips').slideToggle('fast'); } + + function toggleGotchas() { + var gotchas = document.getElementById('gotchas'); + $('#gotchas').slideToggle('fast'); + } + + function toggleAnon() { + $('#ancmClick').hide(); + $('#anonymous-comment-form').show(); + }; + + {% if request.COOKIES.anonymous_name %} + toggleAnon(); + {% endif %} </script> {% include 'blog/partials/mathjax.html' %} diff --git a/thatcomputerscientist/settings.py b/thatcomputerscientist/settings.py index 00b2b9b1..ce55f931 100644 --- a/thatcomputerscientist/settings.py +++ b/thatcomputerscientist/settings.py @@ -87,6 +87,7 @@ MIDDLEWARE = [ 'middleware.oldbrowsermiddleware.OldBrowserMiddleware', 'middleware.globalmetamiddleware.GlobalMetaMiddleware', 'middleware.uuidmiddleware.UserUUIDMiddleware', + 'middleware.tz.TimezoneMiddleware', ] CONFIGURED_SUBDOMAINS = { @@ -171,6 +172,7 @@ CACHES = { } } from django.core.cache import cache + # clear the cache for key in cache.keys('presence_*'): cache.delete(key) diff --git a/thatcomputerscientist/templatetags/sha256.py b/thatcomputerscientist/templatetags/sha256.py new file mode 100644 index 00000000..cb820ece --- /dev/null +++ b/thatcomputerscientist/templatetags/sha256.py @@ -0,0 +1,9 @@ +import hashlib + +from django import template + +register = template.Library() + [email protected](name='sha256') +def sha256(value): + return hashlib.sha256(value.encode('utf-8')).hexdigest()
\ No newline at end of file |
