base menu, about page, atom feed
This commit is contained in:
parent
013ca30765
commit
0b64fd58a1
21 changed files with 284 additions and 47 deletions
|
@ -9,6 +9,10 @@ class ItemAdmin(admin.ModelAdmin):
|
||||||
list_filter = (
|
list_filter = (
|
||||||
("published", admin.EmptyFieldListFilter),
|
("published", admin.EmptyFieldListFilter),
|
||||||
)
|
)
|
||||||
|
raw_id_fields = ['user']
|
||||||
|
|
||||||
|
def get_changeform_initial_data(self, request):
|
||||||
|
return {'user': request.user}
|
||||||
|
|
||||||
admin.site.register(models.Item, ItemAdmin)
|
admin.site.register(models.Item, ItemAdmin)
|
||||||
|
|
||||||
|
@ -25,5 +29,6 @@ class CommentAdmin(admin.ModelAdmin):
|
||||||
list_filter = (
|
list_filter = (
|
||||||
("published", admin.EmptyFieldListFilter),
|
("published", admin.EmptyFieldListFilter),
|
||||||
)
|
)
|
||||||
|
raw_id_fields = ['item', 'user']
|
||||||
|
|
||||||
admin.site.register(models.Comment, CommentAdmin)
|
admin.site.register(models.Comment, CommentAdmin)
|
||||||
|
|
|
@ -26,14 +26,14 @@ class Item(models.Model):
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
modified = models.DateTimeField(auto_now=True)
|
modified = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
user = models.ForeignKey(User, null=True, related_name='items', on_delete=models.CASCADE)
|
|
||||||
|
|
||||||
url = models.CharField(max_length=1024, unique=True)
|
|
||||||
title = models.CharField(max_length=1024)
|
title = models.CharField(max_length=1024)
|
||||||
description = models.TextField(default="", blank=True)
|
url = models.CharField(max_length=1024, unique=True)
|
||||||
|
description = models.TextField(default="", blank=True, editable=False)
|
||||||
published = models.DateTimeField(default=timezone.now, null=True, blank=True)
|
published = models.DateTimeField(default=timezone.now, null=True, blank=True)
|
||||||
announced = models.DateTimeField(null=True, default=None, blank=True)
|
announced = models.DateTimeField(null=True, default=None, blank=True, editable=False)
|
||||||
data = models.JSONField(default=dict, editable=False)
|
data = models.JSONField(default=dict, editable=False)
|
||||||
|
user = models.ForeignKey(User, null=True, related_name='items', on_delete=models.CASCADE)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if self.url and not self.data:
|
if self.url and not self.data:
|
||||||
|
@ -105,14 +105,16 @@ class Comment(models.Model):
|
||||||
modified = models.DateTimeField(auto_now=True)
|
modified = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
item = models.ForeignKey(Item, related_name='comments', on_delete=models.CASCADE)
|
item = models.ForeignKey(Item, related_name='comments', on_delete=models.CASCADE)
|
||||||
user = models.ForeignKey(User, null=True, related_name='comments', on_delete=models.CASCADE, blank=True)
|
text = models.TextField(default="")
|
||||||
session_key = models.CharField(max_length=60, null=True, default=None, blank=True)
|
|
||||||
|
name = models.CharField(max_length=1024, blank=True)
|
||||||
|
email = models.CharField(max_length=1024, blank=True)
|
||||||
|
|
||||||
|
user = models.ForeignKey(User, null=True, related_name='comments', on_delete=models.CASCADE, blank=True)
|
||||||
|
session_key = models.CharField(max_length=60, null=True, default=None, blank=True, editable=False)
|
||||||
|
|
||||||
name = models.CharField(max_length=1024)
|
|
||||||
email = models.CharField(max_length=1024)
|
|
||||||
text = models.TextField(default="", blank=True)
|
|
||||||
data = models.JSONField(default=dict, editable=False)
|
data = models.JSONField(default=dict, editable=False)
|
||||||
published = models.DateTimeField(null=True, default=None)
|
published = models.DateTimeField(null=True, default=None, blank=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
permissions = [
|
permissions = [
|
||||||
|
|
|
@ -12,7 +12,7 @@ from ..celery import app
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
@app.task(queue="default")
|
@app.task(queue="default", ignore_results=True)
|
||||||
def announce_items():
|
def announce_items():
|
||||||
if not getattr(settings, 'SIGNAL_ANNOUNCE_GROUP'):
|
if not getattr(settings, 'SIGNAL_ANNOUNCE_GROUP'):
|
||||||
return
|
return
|
||||||
|
@ -42,18 +42,27 @@ def announce_items():
|
||||||
os.unlink(f.name)
|
os.unlink(f.name)
|
||||||
|
|
||||||
|
|
||||||
@app.task(queue="default")
|
@app.task(queue="default", ignore_results=True)
|
||||||
def notify_moderators(id, link):
|
def notify_moderators(id, link):
|
||||||
comment = models.Comment.objects.filter(id=id).first()
|
comment = models.Comment.objects.filter(id=id).first()
|
||||||
if comment:
|
if comment:
|
||||||
message = "%s commented on %s (%s)\n\n%s" % (comment.name, comment.item.title, link, comment.text)
|
message = "%s commented on %s (%s)\n\n%s" % (
|
||||||
|
comment.name, comment.item.title, link, comment.text
|
||||||
|
)
|
||||||
r = rpc.send(message, group=settings.SIGNAL_MODERATORS_GROUP)
|
r = rpc.send(message, group=settings.SIGNAL_MODERATORS_GROUP)
|
||||||
if r and "timestamp" in r:
|
if r and "timestamp" in r:
|
||||||
comment.data["moderator_ts"] = r["timestamp"]
|
comment.data["moderator_ts"] = r["timestamp"]
|
||||||
comment.save()
|
comment.save()
|
||||||
|
if comment.published:
|
||||||
|
account = settings.SIGNAL_ACCOUNT
|
||||||
|
group = settings.SIGNAL_MODERATORS_GROUP
|
||||||
|
rpc.send_reaction(
|
||||||
|
account, comment.data["moderator_ts"], "🎉", group=group
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
print("failed to notify", r)
|
print("failed to notify", r)
|
||||||
|
|
||||||
|
|
||||||
@app.on_after_finalize.connect
|
@app.on_after_finalize.connect
|
||||||
def setup_periodic_tasks(sender, **kwargs):
|
def setup_periodic_tasks(sender, **kwargs):
|
||||||
sender.add_periodic_task(crontab(minute="*/2"), announce_items.s())
|
sender.add_periodic_task(crontab(minute="*/2"), announce_items.s())
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
from datetime import date, datetime, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
@ -6,6 +8,7 @@ from django.shortcuts import render
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.utils.html import mark_safe
|
from django.utils.html import mark_safe
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.http import HttpResponse
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
from . import tasks
|
from . import tasks
|
||||||
|
@ -14,7 +17,7 @@ from .utils import render_to_json
|
||||||
|
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
context = {}
|
context = {"settings": settings}
|
||||||
week, archive = models.Item.public()
|
week, archive = models.Item.public()
|
||||||
context['items'] = week
|
context['items'] = week
|
||||||
context['archive'] = archive.exists()
|
context['archive'] = archive.exists()
|
||||||
|
@ -22,7 +25,7 @@ def index(request):
|
||||||
|
|
||||||
|
|
||||||
def archive(request):
|
def archive(request):
|
||||||
context = {}
|
context = {"settings": settings}
|
||||||
qs = models.Item.public()
|
qs = models.Item.public()
|
||||||
week, archive = models.Item.public()
|
week, archive = models.Item.public()
|
||||||
context['items'] = archive
|
context['items'] = archive
|
||||||
|
@ -30,7 +33,7 @@ def archive(request):
|
||||||
|
|
||||||
|
|
||||||
def item(request, id):
|
def item(request, id):
|
||||||
context = {}
|
context = {"settings": settings}
|
||||||
item = models.Item.objects.get(id=id)
|
item = models.Item.objects.get(id=id)
|
||||||
context['item'] = item
|
context['item'] = item
|
||||||
qs = item.comments.order_by('created')
|
qs = item.comments.order_by('created')
|
||||||
|
@ -71,9 +74,8 @@ def comment(request):
|
||||||
comment.session_key = request.session.session_key
|
comment.session_key = request.session.session_key
|
||||||
comment.text = data['text']
|
comment.text = data['text']
|
||||||
comment.save()
|
comment.save()
|
||||||
if not comment.published:
|
link = request.build_absolute_uri(comment.item.get_absolute_url())
|
||||||
link = request.build_absolute_uri(comment.item.get_absolute_url())
|
tasks.notify_moderators.delay(comment.id, link)
|
||||||
tasks.notify_moderators.delay(comment.id, link)
|
|
||||||
response = comment.json()
|
response = comment.json()
|
||||||
return render_to_json(response)
|
return render_to_json(response)
|
||||||
|
|
||||||
|
@ -88,8 +90,61 @@ def publish_comment(request):
|
||||||
if comment.data.get("moderator_ts"):
|
if comment.data.get("moderator_ts"):
|
||||||
account = settings.SIGNAL_ACCOUNT
|
account = settings.SIGNAL_ACCOUNT
|
||||||
group = settings.SIGNAL_MODERATORS_GROUP
|
group = settings.SIGNAL_MODERATORS_GROUP
|
||||||
send_reaction(account, comment.data["moderator_ts"], "🎉", group=group)
|
send_reaction(
|
||||||
|
account, comment.data["moderator_ts"], "🎉", group=group
|
||||||
|
)
|
||||||
response['status'] = 'ok'
|
response['status'] = 'ok'
|
||||||
else:
|
else:
|
||||||
response['error'] = 'permission denied'
|
response['error'] = 'permission denied'
|
||||||
return render_to_json(response)
|
return render_to_json(response)
|
||||||
|
|
||||||
|
|
||||||
|
def atom_xml(request):
|
||||||
|
feed = ET.Element("feed")
|
||||||
|
feed.attrib['xmlns'] = 'http://www.w3.org/2005/Atom'
|
||||||
|
feed.attrib['xmlns:media'] = 'http://search.yahoo.com/mrss/'
|
||||||
|
feed.attrib['xml:lang'] = 'en'
|
||||||
|
title = ET.SubElement(feed, "title")
|
||||||
|
title.text = settings.SITENAME
|
||||||
|
title.attrib['type'] = 'text'
|
||||||
|
link = ET.SubElement(feed, "link")
|
||||||
|
link.attrib['rel'] = 'self'
|
||||||
|
link.attrib['type'] = 'application/atom+xml'
|
||||||
|
atom_link = request.build_absolute_uri('/atom.xml')
|
||||||
|
link.attrib['href'] = atom_link
|
||||||
|
el = ET.SubElement(feed, 'id')
|
||||||
|
el.text = atom_link
|
||||||
|
|
||||||
|
week, archive = models.Item.public()
|
||||||
|
for item in week:
|
||||||
|
page_link = request.build_absolute_uri(item.get_absolute_url())
|
||||||
|
|
||||||
|
entry = ET.Element("entry")
|
||||||
|
title = ET.SubElement(entry, "title")
|
||||||
|
title.text = item.title
|
||||||
|
link = ET.SubElement(entry, "link")
|
||||||
|
link.attrib['rel'] = 'alternate'
|
||||||
|
link.attrib['href'] = page_link
|
||||||
|
updated = ET.SubElement(entry, "updated")
|
||||||
|
updated.text = item.modified.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
published = ET.SubElement(entry, "published")
|
||||||
|
published.text = item.created.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
el = ET.SubElement(entry, "id")
|
||||||
|
el.text = page_link
|
||||||
|
print(item.data)
|
||||||
|
if 'title' in item.data and 'thumbnail' in item.data:
|
||||||
|
html = f'''
|
||||||
|
<p>
|
||||||
|
{item.data['title']}
|
||||||
|
</p>
|
||||||
|
<img src={ item.data['thumbnail'] }>
|
||||||
|
'''.strip()
|
||||||
|
content = ET.SubElement(entry, "content")
|
||||||
|
content.attrib['type'] = 'html'
|
||||||
|
content.text = html
|
||||||
|
feed.append(entry)
|
||||||
|
return HttpResponse(
|
||||||
|
'<?xml version="1.0" encoding="utf-8" ?>\n' + ET.tostring(feed).decode(),
|
||||||
|
'application/atom+xml'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
0
app/page/__init__.py
Normal file
0
app/page/__init__.py
Normal file
7
app/page/admin.py
Normal file
7
app/page/admin.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
from . import models
|
||||||
|
|
||||||
|
@admin.decorators.register(models.Page)
|
||||||
|
class PageAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('slug', 'title', 'created', 'modified')
|
||||||
|
search_fields = ['title', 'slug']
|
6
app/page/apps.py
Normal file
6
app/page/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class PageConfig(AppConfig):
|
||||||
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
|
name = "app.page"
|
34
app/page/migrations/0001_initial.py
Normal file
34
app/page/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# Generated by Django 4.2.3 on 2023-07-25 18:51
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = []
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Page",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("created", models.DateTimeField(auto_now_add=True)),
|
||||||
|
("modified", models.DateTimeField(auto_now=True)),
|
||||||
|
(
|
||||||
|
"slug",
|
||||||
|
models.CharField(max_length=255, unique=True, verbose_name="Slug"),
|
||||||
|
),
|
||||||
|
("title", models.CharField(max_length=1024)),
|
||||||
|
("content", models.TextField(blank=True, default="")),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
0
app/page/migrations/__init__.py
Normal file
0
app/page/migrations/__init__.py
Normal file
16
app/page/models.py
Normal file
16
app/page/models.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class Page(models.Model):
|
||||||
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
|
modified = models.DateTimeField(auto_now=True)
|
||||||
|
slug = models.CharField('Slug', max_length=255, unique=True)
|
||||||
|
|
||||||
|
title = models.CharField(max_length=1024)
|
||||||
|
content = models.TextField(default='', blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.slug
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return '/%s' % self.slug
|
3
app/page/tests.py
Normal file
3
app/page/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
13
app/page/views.py
Normal file
13
app/page/views.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
from django.conf import settings
|
||||||
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
|
|
||||||
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
|
def page(request, slug):
|
||||||
|
page = get_object_or_404(models.Page, slug=slug)
|
||||||
|
context = {
|
||||||
|
'settings': settings,
|
||||||
|
'page': page,
|
||||||
|
}
|
||||||
|
return render(request, 'page.html', context)
|
|
@ -60,6 +60,7 @@ INSTALLED_APPS = [
|
||||||
"app.user",
|
"app.user",
|
||||||
"app.item",
|
"app.item",
|
||||||
"app.signalbot",
|
"app.signalbot",
|
||||||
|
"app.page",
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
@ -86,6 +87,9 @@ TEMPLATES = [
|
||||||
"django.contrib.auth.context_processors.auth",
|
"django.contrib.auth.context_processors.auth",
|
||||||
"django.contrib.messages.context_processors.messages",
|
"django.contrib.messages.context_processors.messages",
|
||||||
],
|
],
|
||||||
|
"builtins": [
|
||||||
|
"django.templatetags.static",
|
||||||
|
]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -159,3 +163,5 @@ CELERY_RESULT_BACKEND = 'django-db'
|
||||||
SIGNAL_MODERATORS = []
|
SIGNAL_MODERATORS = []
|
||||||
|
|
||||||
RATELIMIT_CACHE_BACKEND = "app.brake_backend.BrakeBackend"
|
RATELIMIT_CACHE_BACKEND = "app.brake_backend.BrakeBackend"
|
||||||
|
|
||||||
|
SITENAME = "phantas.ma"
|
||||||
|
|
|
@ -50,3 +50,24 @@ header {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.burger {
|
||||||
|
cursor: pointer;
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav.overlay {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
top: 42px;
|
||||||
|
left: 0;
|
||||||
|
background: rgb(16, 16, 16);
|
||||||
|
opacity: 0;
|
||||||
|
z-index: 100;
|
||||||
|
padding: 4px;
|
||||||
|
display: none;
|
||||||
|
&.active {
|
||||||
|
display: block;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ video, .poster {
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 100vh;
|
min-height: max(100vh, 100%);
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,6 +155,9 @@ const getVideoURL = function(id, resolution, part, track, streamId) {
|
||||||
.replace('{resolution}', resolution)
|
.replace('{resolution}', resolution)
|
||||||
.replace('{uid}', uid)
|
.replace('{uid}', uid)
|
||||||
.replace('{uid42}', uid % 42);
|
.replace('{uid42}', uid % 42);
|
||||||
|
if (!prefix) {
|
||||||
|
prefix = pandoraURL
|
||||||
|
}
|
||||||
return prefix + '/' + getVideoURLName(id, resolution, part, track, streamId);
|
return prefix + '/' + getVideoURLName(id, resolution, part, track, streamId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<!DOCTYPE html>{% load static sass_tags compress %}
|
<!DOCTYPE html>{% load sass_tags compress %}
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
@ -15,8 +15,35 @@
|
||||||
<body>
|
<body>
|
||||||
{% block header %}
|
{% block header %}
|
||||||
<header>
|
<header>
|
||||||
<a href="/">phantas.ma</a>
|
<span class="burger">[=]</span> <a href="/">{{ settings.SITENAME }}</a>
|
||||||
</header>
|
</header>
|
||||||
|
<nav class="overlay">
|
||||||
|
<a href="/about/">about</a><br>
|
||||||
|
{% if request.user.is_authenticated %}
|
||||||
|
<div>You are logged in as {{ request.user.username }}</div>
|
||||||
|
<a href="/logout/">logout</a><br>
|
||||||
|
{% else %}
|
||||||
|
<a href="/login/">login</a><br>
|
||||||
|
{% endif %}
|
||||||
|
</nav>
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
document.querySelector('.burger').addEventListener('click', event => {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
var overlay = document.querySelector('nav.overlay')
|
||||||
|
if (overlay.classList.contains('active')) {
|
||||||
|
overlay.classList.remove('active')
|
||||||
|
document.body.style.overflow = ''
|
||||||
|
document.querySelector('.burger').innerText = '[=]'
|
||||||
|
} else {
|
||||||
|
overlay.classList.add('active')
|
||||||
|
document.body.style.overflow = 'hidden'
|
||||||
|
document.querySelector('.burger').innerText = '[x]'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% block head %}
|
||||||
|
<link rel="alternate" type="application/atom+xml" title="{{ settings.SITENAME }}" href="/atom.xml" />
|
||||||
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<style>
|
<style>
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
pandora.url = new URL('{{ item.url|escapejs }}');
|
pandora.url = new URL('{{ item.url|escapejs }}');
|
||||||
pandora.comment = '{{ item.id | escapejs }}';
|
pandora.comment = '{{ item.id | escapejs }}';
|
||||||
pandora.hostname = pandora.url.hostname
|
pandora.hostname = pandora.url.hostname
|
||||||
pandoraURL = `https://${pandora.hostname}`
|
pandoraURL = `${pandora.url.protocol}//${pandora.hostname}`
|
||||||
</script>
|
</script>
|
||||||
<script src="/static/js/overwrite.js"></script>
|
<script src="/static/js/overwrite.js"></script>
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,14 @@ from django.urls import path, re_path
|
||||||
|
|
||||||
from .item import views as item_views
|
from .item import views as item_views
|
||||||
from .user import views as user_views
|
from .user import views as user_views
|
||||||
|
from .page import views as page_views
|
||||||
|
from . import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("admin/", admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
|
path('robots.txt', views.robots_txt, name='robots_txt'),
|
||||||
|
path('sitemap.xml', views.sitemap_xml, name='sitemap_xml'),
|
||||||
|
path('atom.xml', item_views.atom_xml, name='atom_xml'),
|
||||||
path('login/', user_views.login, name='login'),
|
path('login/', user_views.login, name='login'),
|
||||||
path('logout/', user_views.logout, name='logout'),
|
path('logout/', user_views.logout, name='logout'),
|
||||||
path('register/', user_views.register, name='register'),
|
path('register/', user_views.register, name='register'),
|
||||||
|
@ -29,5 +34,6 @@ urlpatterns = [
|
||||||
path('comment/publish/', item_views.publish_comment, name='publish-comment'),
|
path('comment/publish/', item_views.publish_comment, name='publish-comment'),
|
||||||
path('comment/', item_views.comment, name='comment'),
|
path('comment/', item_views.comment, name='comment'),
|
||||||
path('<int:id>/', item_views.item, name='item'),
|
path('<int:id>/', item_views.item, name='item'),
|
||||||
|
path('<str:slug>/', page_views.page, name='page'),
|
||||||
path('', item_views.index, name='index'),
|
path('', item_views.index, name='index'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -2,6 +2,7 @@ import json
|
||||||
|
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
|
from django.conf import settings
|
||||||
import django.contrib.auth
|
import django.contrib.auth
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
|
@ -15,35 +16,55 @@ User = get_user_model()
|
||||||
@ratelimit(method="POST", block=True, rate="5/m")
|
@ratelimit(method="POST", block=True, rate="5/m")
|
||||||
def register(request):
|
def register(request):
|
||||||
response = {}
|
response = {}
|
||||||
data = json.loads(request.body)
|
if request.method == "POST":
|
||||||
if User.objects.filter(username__iexact=data['username']).exists():
|
data = json.loads(request.body)
|
||||||
response['error'] = 'username not allowed'
|
if User.objects.filter(username__iexact=data['username']).exists():
|
||||||
elif User.objects.filter(email__iexact=data['email']).exists():
|
response['error'] = 'username not allowed'
|
||||||
response['error'] = 'username not allowed'
|
elif User.objects.filter(email__iexact=data['email']).exists():
|
||||||
elif not data['password']:
|
response['error'] = 'username not allowed'
|
||||||
response['error'] = 'password too simple'
|
elif not data['password']:
|
||||||
if not response:
|
response['error'] = 'password too simple'
|
||||||
user = User(username=data['username'], email=data['email'].lower())
|
if not response:
|
||||||
user.set_password(data['password'])
|
user = User(username=data['username'], email=data['email'].lower())
|
||||||
user.is_active = True
|
user.set_password(data['password'])
|
||||||
user.save()
|
user.is_active = True
|
||||||
user = django.contrib.auth.authenticate(username=data['username'], password=data['password'])
|
user.save()
|
||||||
django.contrib.auth.login(request, user)
|
user = django.contrib.auth.authenticate(username=data['username'], password=data['password'])
|
||||||
response['user'] = user.username
|
django.contrib.auth.login(request, user)
|
||||||
return render_to_json(response)
|
response['user'] = user.username
|
||||||
|
return render_to_json(response)
|
||||||
|
else:
|
||||||
|
context = {'settings': settings}
|
||||||
|
return render(request, 'register.html', context)
|
||||||
|
|
||||||
|
|
||||||
@ratelimit(method="POST", block=True, rate="5/m")
|
@ratelimit(method="POST", block=True, rate="5/m")
|
||||||
def login(request):
|
def login(request):
|
||||||
|
context = {'settings': settings}
|
||||||
response = {}
|
response = {}
|
||||||
data = json.loads(request.body)
|
request_type = 'json'
|
||||||
user = django.contrib.auth.authenticate(username=data['username'], password=data['password'])
|
if request.method == "POST":
|
||||||
if user is not None and user.is_active:
|
if "username" in request.POST and "password" in request.POST:
|
||||||
django.contrib.auth.login(request, user)
|
data = request.POST
|
||||||
response['user'] = user.username
|
request_type = 'html'
|
||||||
|
else:
|
||||||
|
data = json.loads(request.body)
|
||||||
|
user = django.contrib.auth.authenticate(username=data['username'], password=data['password'])
|
||||||
|
if user is not None and user.is_active:
|
||||||
|
django.contrib.auth.login(request, user)
|
||||||
|
response['user'] = user.username
|
||||||
|
if request_type == 'html':
|
||||||
|
return redirect('/')
|
||||||
|
else:
|
||||||
|
response['error'] = 'login failed'
|
||||||
|
if request_type == 'html':
|
||||||
|
context['error'] = response['error']
|
||||||
|
return render(request, 'login.html', context)
|
||||||
|
return render_to_json(response)
|
||||||
else:
|
else:
|
||||||
response['error'] = 'login failed'
|
if request.user.is_authenticated:
|
||||||
return render_to_json(response)
|
return redirect('/')
|
||||||
|
return render(request, 'login.html', context)
|
||||||
|
|
||||||
|
|
||||||
def logout(request):
|
def logout(request):
|
||||||
|
|
Loading…
Reference in a new issue