user page (finished?!?!)
This commit is contained in:
parent
17fc3d6ffe
commit
79379ee7b2
10 changed files with 131 additions and 22 deletions
|
@ -3,7 +3,7 @@ let timelineElement = document.getElementById("messages");
|
||||||
let moreButton = document.getElementById("more-button");
|
let moreButton = document.getElementById("more-button");
|
||||||
|
|
||||||
function escapeHTML(content) {
|
function escapeHTML(content) {
|
||||||
return content.replaceAll("&", "&").replaceAll("<", ">").replaceAll(">", "<");
|
return content.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMessageHTML(messageJSON, canRespond) {
|
function getMessageHTML(messageJSON, canRespond) {
|
||||||
|
@ -11,7 +11,7 @@ function getMessageHTML(messageJSON, canRespond) {
|
||||||
el.classList.add("message-container");
|
el.classList.add("message-container");
|
||||||
el.dataset.messageId = messageJSON.id;
|
el.dataset.messageId = messageJSON.id;
|
||||||
el.innerHTML = `
|
el.innerHTML = `
|
||||||
<p>Messaging <a href="/u/${messageJSON.to}/">${messageJSON.to}</a>: ${messageJSON.response ? `<small>${timeSince(messageJSON.response_timestamp)}</small>` : ""}</p>
|
<p>Messaging <a href="/u/${messageJSON.to}/">${messageJSON.to}</a>: <small data-timestamp-here>${messageJSON.response ? timeSince(messageJSON.response_timestamp) : ""}</small></p>
|
||||||
<blockquote class="message">
|
<blockquote class="message">
|
||||||
<div><${messageJSON.from ? "a" : "b"} href="/u/${messageJSON.from}/">${messageJSON.from || "Anony­mous"}</${messageJSON.from ? "a" : "b"}> writes: <small>${timeSince(messageJSON.timestamp)}</small></div>
|
<div><${messageJSON.from ? "a" : "b"} href="/u/${messageJSON.from}/">${messageJSON.from || "Anony­mous"}</${messageJSON.from ? "a" : "b"}> writes: <small>${timeSince(messageJSON.timestamp)}</small></div>
|
||||||
<a class="fake-link" href="/msg/${messageJSON.id}/"><pre class="not-code">${escapeHTML(messageJSON.content)}</pre></a>
|
<a class="fake-link" href="/msg/${messageJSON.id}/"><pre class="not-code">${escapeHTML(messageJSON.content)}</pre></a>
|
||||||
|
@ -25,7 +25,7 @@ function getMessageHTML(messageJSON, canRespond) {
|
||||||
${messageJSON.response ? "" : `<button class="reply-button" onclick="replyTo(${messageJSON.id})">Reply</button>`}
|
${messageJSON.response ? "" : `<button class="reply-button" onclick="replyTo(${messageJSON.id})">Reply</button>`}
|
||||||
<button onclick="deleteMessage(${messageJSON.id})">Delete</button>
|
<button onclick="deleteMessage(${messageJSON.id})">Delete</button>
|
||||||
</div>
|
</div>
|
||||||
` : `<i>No response</i>`
|
` : (messageJSON.response ? "" : `<i>No response</i>`)
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
return el
|
return el
|
||||||
|
@ -48,8 +48,13 @@ function replyTo(messageID) {
|
||||||
.then((response) => (response.json()))
|
.then((response) => (response.json()))
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
if (json.success) {
|
if (json.success) {
|
||||||
let response = document.createElement("div");
|
let response = document.createElement("pre");
|
||||||
response.innerHTML = `<small>${timeSince(json.timestamp)}</small><pre class="not-code no-margin">${escapeHTML(json.content)}</pre>`;
|
response.classList.add("not-code");
|
||||||
|
response.classList.add("no-margin");
|
||||||
|
response.innerText = json.content;
|
||||||
|
|
||||||
|
msgContainer.querySelector("[data-timestamp-here]").innerHTML = timeSince(json.timestamp);
|
||||||
|
|
||||||
err.innerHTML = "";
|
err.innerHTML = "";
|
||||||
|
|
||||||
msgContainer.querySelector("textarea").replaceWith(response);
|
msgContainer.querySelector("textarea").replaceWith(response);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Page Not Found - {% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<h1>Hmm. That doesn't look right.</h1>
|
<h1>Hmm. That doesn't look right.</h1>
|
||||||
Make sure the URL is correct and try again.
|
Make sure the URL is correct and try again.
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if username %}
|
{% if username %}
|
||||||
Logged in as <a href="/u/{{ username }}/">{{ username }}</b>
|
Logged in as <a href="/u/{{ username }}/">{{ username }}</a>
|
||||||
<p><a href="/messages/">View your messages</a></p>
|
<p><a href="/messages/">View your messages</a></p>
|
||||||
{% else %}
|
{% else %}
|
||||||
Not logged in.
|
Not logged in.
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<p><textarea class="auto-size" name="message" id="message" required maxlength="10000" placeholder="Your message"></textarea></p>
|
<p><textarea class="auto-size" name="message" id="message" required maxlength="10000" placeholder="Your message"></textarea></p>
|
||||||
{% if self_username %}
|
{% if self_username %}
|
||||||
Logged in as <a href="/u/{{ username }}/">{{ username }}</b>
|
Logged in as <a href="/u/{{ username }}/">{{ username }}</a>
|
||||||
<div>
|
<div>
|
||||||
<input name="anonymous" id="anonymous" type="checkbox">
|
<input name="anonymous" id="anonymous" type="checkbox">
|
||||||
<label data-fake-checkbox for="anonymous">Don't attach your username</label>
|
<label data-fake-checkbox for="anonymous">Don't attach your username</label>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<link rel="stylesheet" href="/static/css/messages.css">
|
<link rel="stylesheet" href="/static/css/messages.css">
|
||||||
<script>let url = "/api/messages/";</script>
|
<script>let url = "/api/messages/?unread";</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
<p><button id="refresh" onclick="fetchMessages(true);">Refresh</button></p>
|
<p><button id="refresh" onclick="fetchMessages(true);">Refresh</button></p>
|
||||||
<p id="switch">
|
<p id="switch">
|
||||||
<b data-url="/api/messages/" data-id="all" href="javascript:(() => { updateURL('all'); })()">All messages</b> -
|
<a data-url="/api/messages/" data-id="all" class="not-bold" href="javascript:(() => { updateURL('all'); })()">All messages</a> -
|
||||||
<a data-url="/api/messages/?unread" data-id="unread" class="not-bold" href="javascript:(() => { updateURL('unread'); })()">Not responded</a>
|
<b data-url="/api/messages/?unread" data-id="unread" href="javascript:(() => { updateURL('unread'); })()">Not responded</b>
|
||||||
</p>
|
</p>
|
||||||
<div id="messages"><i class="delete-if-more-messages">Loading...</i></div>
|
<div id="messages"><i class="delete-if-more-messages">Loading...</i></div>
|
||||||
<button hidden id="more-button" onclick="fetchMessages(false);">Load more</button>
|
<p><button hidden id="more-button" onclick="fetchMessages(false);">Load more</button><p>
|
||||||
<script src="{{ config.services.common.url.pub }}/static/js/base.js?v={{ config.version_str }}"></script>
|
<script src="{{ config.services.common.url.pub }}/static/js/base.js?v={{ config.version_str }}"></script>
|
||||||
<script src="/static/js/messages.js?v={{ config.version_str }}"></script>
|
<script src="/static/js/messages.js?v={{ config.version_str }}"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
33
tmessage/templates/user.html
Normal file
33
tmessage/templates/user.html
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
<link rel="stylesheet" href="/static/css/messages.css">
|
||||||
|
<script>let url = "/api/user/{{ username }}/?resp";</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<h1>{{ username }}'s Messages</h1>
|
||||||
|
<p><a href="/m/{{ username }}">Message {{ username }}</a></p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<p><button id="refresh" onclick="fetchMessages(true);">Refresh</button></p>
|
||||||
|
<p id="switch">
|
||||||
|
<a data-url="/api/user/{{ username }}/?all" data-id="all" class="not-bold" href="javascript:(() => { updateURL('all'); })()">All messages</a> -
|
||||||
|
<b data-url="/api/user/{{ username }}/" data-id="resp" href="javascript:(() => { updateURL('resp'); })()">With response</b>
|
||||||
|
</p>
|
||||||
|
<div id="messages"><i class="delete-if-more-messages">Loading...</i></div>
|
||||||
|
<p><button hidden id="more-button" onclick="fetchMessages(false);">Load more</button><p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
{% if self_username %}
|
||||||
|
<p>Logged in as <a href="/u/{{ self_username }}/">{{ self_username }}</a></p>
|
||||||
|
<p><a href="/messages/">View your messages</a></p>
|
||||||
|
{% else %}
|
||||||
|
Not logged in.
|
||||||
|
{% if config.new_users %}<a href="{{ config.services.auth.url.pub }}/signup/">Sign up</a>{% else %}<a href="{{ config.services.auth.url.pub }}/login/">Log in</a>{% endif %}?
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<script src="{{ config.services.common.url.pub }}/static/js/base.js?v={{ config.version_str }}"></script>
|
||||||
|
<script src="/static/js/messages.js?v={{ config.version_str }}"></script>
|
||||||
|
{% endblock %}
|
|
@ -1,8 +1,8 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
|
|
||||||
from .views import (api_messages, auth, index, message, message_page, messages,
|
from .views import (api_messages, api_user, auth, index, message, message_page,
|
||||||
profile)
|
messages, profile)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", index),
|
path("", index),
|
||||||
|
@ -12,6 +12,7 @@ urlpatterns = [
|
||||||
path("m/<str:username>/", message),
|
path("m/<str:username>/", message),
|
||||||
path("msg/<int:message_id>/", message_page),
|
path("msg/<int:message_id>/", message_page),
|
||||||
path("api/messages/", api_messages),
|
path("api/messages/", api_messages),
|
||||||
|
path("api/user/<str:username>/", api_user),
|
||||||
path("static/", include("tmessage.views.static")),
|
path("static/", include("tmessage.views.static")),
|
||||||
path("django-admin/", admin.site.urls)
|
path("django-admin/", admin.site.urls)
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
from .api import api_messages # noqa: F401
|
from .api import api_messages, api_user # noqa: F401
|
||||||
from .templates import (auth, index, message, message_page, # noqa: F401
|
from .templates import (auth, index, message, message_page, # noqa: F401
|
||||||
messages, profile)
|
messages, profile)
|
||||||
|
|
|
@ -3,10 +3,11 @@ import math
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from django.core.handlers.wsgi import WSGIRequest
|
from django.core.handlers.wsgi import WSGIRequest
|
||||||
|
from django.db.models import Q
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
|
||||||
from tmessage.models import tMMessage
|
from tmessage.models import tMMessage, tMUser
|
||||||
|
|
||||||
from .helper import get_user_object, get_username
|
from .helper import get_user_object, get_username
|
||||||
|
|
||||||
|
@ -18,6 +19,11 @@ def _json_response(data: dict | list, /, *, status: int=200, content_type: str="
|
||||||
content_type=content_type
|
content_type=content_type
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _add_qF(original: None | Q, new: Q) -> Q:
|
||||||
|
if original is None:
|
||||||
|
return new
|
||||||
|
return original | new
|
||||||
|
|
||||||
RESPONSE_400 = _json_response({ "success": False }, status=400)
|
RESPONSE_400 = _json_response({ "success": False }, status=400)
|
||||||
RESPONSE_401 = _json_response({ "success": False }, status=401)
|
RESPONSE_401 = _json_response({ "success": False }, status=401)
|
||||||
RESPONSE_403 = _json_response({ "success": False }, status=403)
|
RESPONSE_403 = _json_response({ "success": False }, status=403)
|
||||||
|
@ -35,19 +41,23 @@ def api_messages(request: WSGIRequest) -> HttpResponse:
|
||||||
body = json.loads(request.body)
|
body = json.loads(request.body)
|
||||||
reply = body["content"].strip()
|
reply = body["content"].strip()
|
||||||
message_id = body["id"]
|
message_id = body["id"]
|
||||||
|
print(reply)
|
||||||
|
|
||||||
if not (isinstance(message_id, int) and isinstance(reply, str)):
|
if not (isinstance(message_id, int) and isinstance(reply, str) and reply):
|
||||||
|
print("1")
|
||||||
return RESPONSE_400
|
return RESPONSE_400
|
||||||
|
|
||||||
try:
|
try:
|
||||||
message = tMMessage.objects.get(message_id=message_id)
|
message = tMMessage.objects.get(message_id=message_id)
|
||||||
except tMMessage.DoesNotExist:
|
except tMMessage.DoesNotExist:
|
||||||
|
print("2")
|
||||||
return RESPONSE_400
|
return RESPONSE_400
|
||||||
|
|
||||||
if username != message.u_to.username:
|
if username != message.u_to.username:
|
||||||
return RESPONSE_403
|
return RESPONSE_403
|
||||||
|
|
||||||
if message.response is not None:
|
if message.response is not None:
|
||||||
|
print("3")
|
||||||
return RESPONSE_400
|
return RESPONSE_400
|
||||||
|
|
||||||
message.response = reply
|
message.response = reply
|
||||||
|
@ -81,16 +91,16 @@ def api_messages(request: WSGIRequest) -> HttpResponse:
|
||||||
"success": True
|
"success": True
|
||||||
})
|
})
|
||||||
|
|
||||||
queryFilter = {}
|
queryFilter = None
|
||||||
|
|
||||||
if "offset" in request.GET and (request.GET.get("offset") or "").isdigit():
|
if "offset" in request.GET and (request.GET.get("offset") or "").isdigit():
|
||||||
queryFilter["message_id__lt"] = int(request.GET.get("offset") or "")
|
queryFilter = _add_qF(queryFilter, Q(message_id__lt=int(request.GET.get("offset") or "")))
|
||||||
|
|
||||||
if "unread" in request.GET:
|
if "unread" in request.GET:
|
||||||
queryFilter["response"] = None
|
queryFilter = _add_qF(queryFilter, Q(response=None))
|
||||||
|
|
||||||
if queryFilter:
|
if queryFilter:
|
||||||
msgObjects = user.received.filter(**queryFilter)
|
msgObjects = user.received.filter(queryFilter) # type: ignore
|
||||||
else:
|
else:
|
||||||
msgObjects = user.received.all() # type: ignore
|
msgObjects = user.received.all() # type: ignore
|
||||||
|
|
||||||
|
@ -116,3 +126,47 @@ def api_messages(request: WSGIRequest) -> HttpResponse:
|
||||||
"messages": output,
|
"messages": output,
|
||||||
"more": msgObjects.count() > 50
|
"more": msgObjects.count() > 50
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def api_user(request: WSGIRequest, username: str) -> HttpResponse:
|
||||||
|
queryFilter = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
user = get_user_object(username)
|
||||||
|
except tMUser.DoesNotExist:
|
||||||
|
return RESPONSE_400
|
||||||
|
|
||||||
|
queryFilter = None
|
||||||
|
|
||||||
|
if "offset" in request.GET and (request.GET.get("offset") or "").isdigit():
|
||||||
|
queryFilter = _add_qF(queryFilter, Q(message_id__lt=int(request.GET.get("offset") or "")))
|
||||||
|
|
||||||
|
if "all" not in request.GET:
|
||||||
|
queryFilter = _add_qF(queryFilter, ~Q(response=None))
|
||||||
|
|
||||||
|
if queryFilter:
|
||||||
|
msgObjects = user.received.filter(queryFilter) # type: ignore
|
||||||
|
else:
|
||||||
|
msgObjects = user.received.all() # type: ignore
|
||||||
|
|
||||||
|
output = []
|
||||||
|
messages = msgObjects.order_by("-sent_timestamp" if "all" in request.GET else "-response_timestamp")[:50].values_list(
|
||||||
|
"message_id", "content", "response", "anonymous", "u_from", "u_to", "sent_timestamp", "response_timestamp"
|
||||||
|
)
|
||||||
|
|
||||||
|
for message in messages:
|
||||||
|
output.append({
|
||||||
|
"id": message[0],
|
||||||
|
"content": message[1],
|
||||||
|
"response": message[2],
|
||||||
|
"from": message[4] if not message[3] and message[4] else None,
|
||||||
|
"to": message[5],
|
||||||
|
"timestamp": message[6],
|
||||||
|
"response_timestamp": message[7]
|
||||||
|
})
|
||||||
|
|
||||||
|
return _json_response({
|
||||||
|
"success": True,
|
||||||
|
"canRespond": username == get_username(request),
|
||||||
|
"messages": output,
|
||||||
|
"more": msgObjects.count() > 50
|
||||||
|
})
|
||||||
|
|
|
@ -5,7 +5,7 @@ from datetime import datetime
|
||||||
from django.core.handlers.wsgi import WSGIRequest
|
from django.core.handlers.wsgi import WSGIRequest
|
||||||
from django.http import HttpResponse, HttpResponseRedirect
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
|
|
||||||
from tmessage.models import tMMessage
|
from tmessage.models import tMMessage, tMUser
|
||||||
|
|
||||||
from .helper import (get_user_object, get_username, render_template,
|
from .helper import (get_user_object, get_username, render_template,
|
||||||
username_exists)
|
username_exists)
|
||||||
|
@ -36,7 +36,21 @@ def index(request: WSGIRequest) -> HttpResponse:
|
||||||
)
|
)
|
||||||
|
|
||||||
def profile(request: WSGIRequest, username: str) -> HttpResponse:
|
def profile(request: WSGIRequest, username: str) -> HttpResponse:
|
||||||
...
|
try:
|
||||||
|
get_user_object(username)
|
||||||
|
except tMUser.DoesNotExist:
|
||||||
|
return render_template(
|
||||||
|
request, "404.html"
|
||||||
|
)
|
||||||
|
|
||||||
|
self_username = get_username(request)
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
request, "user.html",
|
||||||
|
title=username,
|
||||||
|
username=username,
|
||||||
|
self_username=self_username
|
||||||
|
)
|
||||||
|
|
||||||
def message_page(request: WSGIRequest, message_id: int) -> HttpResponse:
|
def message_page(request: WSGIRequest, message_id: int) -> HttpResponse:
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Reference in a new issue