login/register/post
This commit is contained in:
parent
6f18890739
commit
6fc506df2f
6 changed files with 283 additions and 108 deletions
|
@ -8,6 +8,7 @@ from django.conf import settings
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.utils.timesince import timesince
|
||||||
|
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
@ -133,6 +134,12 @@ class Comment(models.Model):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def date(self):
|
def date(self):
|
||||||
|
now = timezone.now()
|
||||||
|
difference = now - self.created
|
||||||
|
if difference <= timedelta(minutes=1):
|
||||||
|
return "just now"
|
||||||
|
return '%(time)s ago' % {'time': timesince(self.created).split(', ')[0]}
|
||||||
|
return self.created.strftime('%B %d, %Y at %H:%M')
|
||||||
return self.created.strftime('%Y-%m-%d %H:%M')
|
return self.created.strftime('%Y-%m-%d %H:%M')
|
||||||
|
|
||||||
def json(self):
|
def json(self):
|
||||||
|
@ -143,5 +150,7 @@ class Comment(models.Model):
|
||||||
data['name'] = self.name
|
data['name'] = self.name
|
||||||
data['date'] = self.date
|
data['date'] = self.date
|
||||||
data['text'] = self.text
|
data['text'] = self.text
|
||||||
|
data['id'] = self.id
|
||||||
|
data['published'] = self.is_published
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
|
@ -43,13 +43,7 @@ def item(request, id):
|
||||||
qs = qs.filter(q)
|
qs = qs.filter(q)
|
||||||
comments = []
|
comments = []
|
||||||
for comment in qs:
|
for comment in qs:
|
||||||
comments.append({
|
comments.append(comment.json())
|
||||||
"id": comment.id,
|
|
||||||
"name": comment.name,
|
|
||||||
"date": comment.date,
|
|
||||||
"text": comment.text,
|
|
||||||
"published": comment.is_published,
|
|
||||||
})
|
|
||||||
context['comments'] = mark_safe(json.dumps(comments))
|
context['comments'] = mark_safe(json.dumps(comments))
|
||||||
user = {}
|
user = {}
|
||||||
if request.user.is_staff:
|
if request.user.is_staff:
|
||||||
|
|
|
@ -22,15 +22,32 @@
|
||||||
padding-top: 8px;
|
padding-top: 8px;
|
||||||
padding-left: 4px;
|
padding-left: 4px;
|
||||||
|
|
||||||
}
|
.buttons {
|
||||||
@media(max-width:768px) {
|
display: none;
|
||||||
.add-comment {
|
&.active {
|
||||||
padding-left: 4px;
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input, button {
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
width: calc(50% - 8px);
|
||||||
|
}
|
||||||
|
.buttons {
|
||||||
|
&.login {
|
||||||
|
input {
|
||||||
|
width: calc(100% - 8px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input.invalid,
|
||||||
|
textarea.invalid {
|
||||||
|
border-bottom: 1px solid purple;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.add-comment textarea,
|
textarea,
|
||||||
.add-comment input {
|
input {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
|
@ -39,30 +56,35 @@
|
||||||
background: none;
|
background: none;
|
||||||
color: white;
|
color: white;
|
||||||
border: 1px solid green;
|
border: 1px solid green;
|
||||||
}
|
}
|
||||||
.add-comment input {
|
textarea {
|
||||||
width: calc(50% - 8px);
|
|
||||||
}
|
|
||||||
.add-comment textarea {
|
|
||||||
width: calc(100% - 8px);
|
width: calc(100% - 8px);
|
||||||
height: 100px;
|
height: 100px;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.add-comment button {
|
button {
|
||||||
background: black;
|
background: black;
|
||||||
color: white;
|
color: white;
|
||||||
border: solid 1px green;
|
border: solid 1px green;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
.add-comment button:hover {
|
button:hover,
|
||||||
|
button:active {
|
||||||
border: solid 1px lightgreen;
|
border: solid 1px lightgreen;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.add-comment {
|
@media(max-width:768px) {
|
||||||
|
.add-comment {
|
||||||
|
padding-left: 4px;
|
||||||
|
input {
|
||||||
|
width: calc(100% - 8px);
|
||||||
|
}
|
||||||
.buttons {
|
.buttons {
|
||||||
&.login {
|
&.login {
|
||||||
input {
|
input {
|
||||||
width: calc(25% - 8px);
|
width: calc(100% - 8px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,3 +121,4 @@ button.publish-comment {
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,42 @@
|
||||||
async function publish_comment(id) {
|
function getCookie(name) {
|
||||||
var csrf
|
var cookieValue = null;
|
||||||
|
if (document.cookie && document.cookie !== '') {
|
||||||
|
var cookies = document.cookie.split(';');
|
||||||
|
for (var i = 0; i < cookies.length; i++) {
|
||||||
|
var cookie = cookies[i].trim();
|
||||||
|
// Does this cookie string begin with the name we want?
|
||||||
|
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
||||||
|
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cookieValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCSRF() {
|
||||||
|
return document.querySelector('input[name="csrfmiddlewaretoken"]').value
|
||||||
|
}
|
||||||
|
|
||||||
|
function serializeData(fields) {
|
||||||
|
var data = {};
|
||||||
document.querySelector('.add-comment').querySelectorAll('input,textarea').forEach(input => {
|
document.querySelector('.add-comment').querySelectorAll('input,textarea').forEach(input => {
|
||||||
if (input.name == 'csrfmiddlewaretoken') {
|
if (fields && !fields.includes(input.name)) {
|
||||||
csrf = input.value.trim()
|
return
|
||||||
|
}
|
||||||
|
if (input.name != 'csrfmiddlewaretoken') {
|
||||||
|
var value = input.value.trim()
|
||||||
|
if (value) {
|
||||||
|
data[input.name] = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
var data = {
|
return data
|
||||||
"comment": id
|
}
|
||||||
}
|
|
||||||
return fetch("/comment/publish/", {
|
async function api(url, data) {
|
||||||
|
var csrf = getCSRF()
|
||||||
|
return fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
@ -19,30 +47,26 @@ async function publish_comment(id) {
|
||||||
return response.json()
|
return response.json()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
async function publish_comment(id) {
|
||||||
|
return api("/comment/publish/", {
|
||||||
|
"comment": id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async function login(username, password) {
|
async function logout() {
|
||||||
var csrf
|
return api("/logout/", {}).then(response => {
|
||||||
document.querySelector('.add-comment').querySelectorAll('input,textarea').forEach(input => {
|
delete user.username
|
||||||
if (input.name == 'csrfmiddlewaretoken') {
|
|
||||||
csrf = input.value.trim()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
var data = {
|
|
||||||
"username": username,
|
|
||||||
"password": password,
|
|
||||||
}
|
|
||||||
return fetch("/login/", {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': csrf
|
|
||||||
},
|
|
||||||
body: JSON.stringify(data)
|
|
||||||
}).then(response => {
|
|
||||||
return response.json()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function login(data) {
|
||||||
|
return api("/login/", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function register(data) {
|
||||||
|
return api("/register/", data)
|
||||||
|
}
|
||||||
|
|
||||||
function renderComments(cdiv, data) {
|
function renderComments(cdiv, data) {
|
||||||
cdiv.innerHTML = `
|
cdiv.innerHTML = `
|
||||||
<h3>
|
<h3>
|
||||||
|
@ -70,7 +94,6 @@ function renderComments(cdiv, data) {
|
||||||
<div class="text">${comment.text}</div>
|
<div class="text">${comment.text}</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
by <span class="name">${comment.name}</span>
|
by <span class="name">${comment.name}</span>
|
||||||
on
|
|
||||||
<span class="date">${comment.date}</span>
|
<span class="date">${comment.date}</span>
|
||||||
${extra}
|
${extra}
|
||||||
</div>
|
</div>
|
||||||
|
@ -101,29 +124,31 @@ function renderComments(cdiv, data) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function clearInvalid() {
|
||||||
|
document.querySelectorAll('input.invalid, textarea.invalid').forEach(invalid => {
|
||||||
|
invalid.classList.remove('invalid')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
document.querySelector('button#add-comment').addEventListener('click', event => {
|
document.querySelector('button#add-comment').addEventListener('click', event => {
|
||||||
var data = {}, csrf;
|
event.preventDefault()
|
||||||
document.querySelector('.add-comment').querySelectorAll('input,textarea').forEach(input => {
|
event.stopPropagation()
|
||||||
if (input.name == 'csrfmiddlewaretoken') {
|
var valid = true, fields = ['text', 'name', 'email']
|
||||||
csrf = input.value.trim()
|
var element = document.querySelector('.add-comment .comment-fields')
|
||||||
} else {
|
element.querySelectorAll('input:invalid, textarea:invalid').forEach(invalid => {
|
||||||
data[input.name] = input.value.trim()
|
if (fields.includes(invalid.name)) {
|
||||||
if (!data[input.name]) {
|
invalid.classList.add('invalid')
|
||||||
delete data[input.name]
|
valid = false
|
||||||
}
|
console.log('invalid', invalid)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
if (!valid) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var data = serializeData(fields);
|
||||||
data.item = pandora.comment
|
data.item = pandora.comment
|
||||||
fetch("/comment/", {
|
api("/comment/", data).then(response => {
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': csrf
|
|
||||||
},
|
|
||||||
body: JSON.stringify(data)
|
|
||||||
}).then(response => {
|
|
||||||
return response.json()
|
|
||||||
}).then(response => {
|
|
||||||
var comment = document.createElement('div')
|
var comment = document.createElement('div')
|
||||||
comment.classList.add('comment')
|
comment.classList.add('comment')
|
||||||
comment.innerHTML = `
|
comment.innerHTML = `
|
||||||
|
@ -139,5 +164,119 @@ document.querySelector('button#add-comment').addEventListener('click', event =>
|
||||||
comment.querySelector('.text').innerText = response.text
|
comment.querySelector('.text').innerText = response.text
|
||||||
document.querySelector('.comments .comments-content').append(comment)
|
document.querySelector('.comments .comments-content').append(comment)
|
||||||
document.querySelector('.add-comment textarea').value = ''
|
document.querySelector('.add-comment textarea').value = ''
|
||||||
|
if (!user.username) {
|
||||||
|
localStorage.name = data.name
|
||||||
|
localStorage.email = data.email
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function afterLogin() {
|
||||||
|
document.querySelector('input[name="csrfmiddlewaretoken"]').value = getCookie('csrftoken')
|
||||||
|
user.username = data.username
|
||||||
|
document.querySelectorAll('.add-comment input[name="email"]').forEach(input => {
|
||||||
|
input.required = false
|
||||||
|
})
|
||||||
|
document.querySelectorAll('.add-comment input[type="password"]').forEach(input => {
|
||||||
|
input.value = ""
|
||||||
|
input.required = false
|
||||||
|
})
|
||||||
|
document.querySelector('.add-comment .buttons.login').classList.remove('active')
|
||||||
|
var buttons = document.querySelector('.add-comment .buttons.guest')
|
||||||
|
buttons.querySelector('#add-comment').innerText = "Add comment"
|
||||||
|
buttons.querySelector('#login').remove()
|
||||||
|
buttons.classList.remove('guest')
|
||||||
|
buttons.classList.add('active')
|
||||||
|
var textarea = document.querySelector('.add-comment textarea')
|
||||||
|
textarea.style.display = ""
|
||||||
|
textarea.required = true
|
||||||
|
document.querySelector('.add-comment .login .error').innerText = ''
|
||||||
|
delete localStorage.name
|
||||||
|
delete localStorage.email
|
||||||
|
}
|
||||||
|
|
||||||
|
var btnLogin = document.querySelector('.add-comment .buttons.guest button#login')
|
||||||
|
if (btnLogin) {
|
||||||
|
btnLogin.addEventListener('click', event => {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
clearInvalid()
|
||||||
|
document.querySelector('.add-comment .buttons.guest').classList.remove('active')
|
||||||
|
document.querySelector('.add-comment .user-info').style.display = "none"
|
||||||
|
document.querySelector('.add-comment .buttons.login').classList.add('active')
|
||||||
|
var textarea = document.querySelector('.add-comment textarea')
|
||||||
|
textarea.style.display = "none"
|
||||||
|
textarea.required = false
|
||||||
|
|
||||||
|
})
|
||||||
|
document.querySelector('.add-comment .buttons.login button#login').addEventListener("click", event => {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
clearInvalid()
|
||||||
|
if (!document.querySelectorAll('.add-comment .login input:invalid').length) {
|
||||||
|
event.target.disabled = true
|
||||||
|
var data = serializeData()
|
||||||
|
login({
|
||||||
|
"username": data.username,
|
||||||
|
"password": data.password,
|
||||||
|
}).then(response => {
|
||||||
|
if (response.error) {
|
||||||
|
document.querySelector('.add-comment .login .error').innerText = response.error
|
||||||
|
event.target.disabled = false
|
||||||
|
} else {
|
||||||
|
afterLogin()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
document.querySelectorAll('.add-comment .login input:invalid').forEach(invalid => {
|
||||||
|
invalid.classList.add('invalid')
|
||||||
|
})
|
||||||
|
document.querySelector('.add-comment .login .error').innerText = ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
document.querySelector('.add-comment .buttons.login button#register').addEventListener("click", event => {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
clearInvalid()
|
||||||
|
var login = document.querySelector('.add-comment .buttons.login button#login')
|
||||||
|
var email = document.querySelector('.add-comment .buttons.login input[name="email"]')
|
||||||
|
if (login.style.display == "none") {
|
||||||
|
if (!document.querySelectorAll('.add-comment .login input:invalid').length) {
|
||||||
|
event.target.disabled = true
|
||||||
|
var data = serializeData()
|
||||||
|
register({
|
||||||
|
"username": data.username,
|
||||||
|
"password": data.password,
|
||||||
|
"email": data.email,
|
||||||
|
}).then(response => {
|
||||||
|
if (response.error) {
|
||||||
|
document.querySelector('.add-comment .login .error').innerText = response.error
|
||||||
|
event.target.disabled = false
|
||||||
|
} else {
|
||||||
|
afterLogin()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
} else {
|
||||||
|
document.querySelectorAll('.add-comment .login input:invalid').forEach(invalid => {
|
||||||
|
invalid.classList.add('invalid')
|
||||||
|
})
|
||||||
|
document.querySelector('.add-comment .login .error').innerText = ''
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
document.querySelector('.add-comment .login .error').innerText = ''
|
||||||
|
login.style.display = "none"
|
||||||
|
email.required = true
|
||||||
|
email.style.display = "block"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user.username) {
|
||||||
|
if (localStorage.name) {
|
||||||
|
document.querySelector('.add-comment .comment-fields input[name="name"]').value = localStorage.name
|
||||||
|
}
|
||||||
|
if (localStorage.email) {
|
||||||
|
document.querySelector('.add-comment .comment-fields input[name="email"]').value = localStorage.email
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,31 +5,36 @@
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<div class="content">
|
<div class="content">
|
||||||
</div>
|
</div>
|
||||||
<div class="add-comment" style="display: none">
|
<form class="add-comment" style="display: none">
|
||||||
|
<div class="comment-fields">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<textarea name="text" placeholder="your comment"></textarea>
|
<textarea name="text" placeholder="your comment" required></textarea>
|
||||||
<div class="user">
|
<div class="user">
|
||||||
{% if request.user.is_anonymous %}
|
{% if request.user.is_anonymous %}
|
||||||
<input name="name" type="text" placeholder="your name"></input>
|
<div class="user-info">
|
||||||
<input name="email" type="email" placeholder="your email"></input>
|
<input name="name" type="text" placeholder="your name" required></input>
|
||||||
<br>
|
<input name="email" type="email" placeholder="your email" required></input>
|
||||||
<div class="buttons">
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="buttons guest active">
|
||||||
<button id="add-comment">Add comment as guest</button>
|
<button id="add-comment">Add comment as guest</button>
|
||||||
<button>Login</button>
|
<button id="login">Login</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons login">
|
<div class="buttons login">
|
||||||
<input name="username" type="text" placeholder="your username"></input>
|
<input name="username" type="text" placeholder="your username" required></input>
|
||||||
<input name="password" type="password" placeholder="your password"></input>
|
<input name="password" type="password" placeholder="your password" required></input>
|
||||||
<button>Login</button>
|
<input name="email" type="email" placeholder="your email" style="display: none"></input>
|
||||||
<button>Register</button>
|
<button id="login">Login</button>
|
||||||
|
<button id="register">Register</button>
|
||||||
|
<div class="error"></div>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="buttons">
|
<div class="buttons active">
|
||||||
<button id="add-comment">Add comment</button>
|
<button id="add-comment">Add comment</button>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block end %}
|
{% block end %}
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -12,7 +12,7 @@ from brake.decorators import ratelimit
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
@ratelimit(method="POST", block=True, rate="1/m")
|
@ratelimit(method="POST", block=True, rate="5/m")
|
||||||
def register(request):
|
def register(request):
|
||||||
response = {}
|
response = {}
|
||||||
data = json.loads(request.body)
|
data = json.loads(request.body)
|
||||||
|
@ -33,7 +33,7 @@ def register(request):
|
||||||
return render_to_json(response)
|
return render_to_json(response)
|
||||||
|
|
||||||
|
|
||||||
@ratelimit(method="POST", block=True, rate="1/m")
|
@ratelimit(method="POST", block=True, rate="5/m")
|
||||||
def login(request):
|
def login(request):
|
||||||
response = {}
|
response = {}
|
||||||
data = json.loads(request.body)
|
data = json.loads(request.body)
|
||||||
|
@ -41,10 +41,15 @@ def login(request):
|
||||||
if user is not None and user.is_active:
|
if user is not None and user.is_active:
|
||||||
django.contrib.auth.login(request, user)
|
django.contrib.auth.login(request, user)
|
||||||
response['user'] = user.username
|
response['user'] = user.username
|
||||||
|
else:
|
||||||
|
response['error'] = 'login failed'
|
||||||
return render_to_json(response)
|
return render_to_json(response)
|
||||||
|
|
||||||
|
|
||||||
def logout(request):
|
def logout(request):
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
django.contrib.auth.logout(request)
|
django.contrib.auth.logout(request)
|
||||||
redirect('/')
|
if request.method == "POST":
|
||||||
|
data = json.loads(request.body)
|
||||||
|
return render_to_json({})
|
||||||
|
return redirect('/')
|
||||||
|
|
Loading…
Reference in a new issue