Basic comments working, Login working.

This commit is contained in:
Victorious Children Studios 2024-11-23 22:34:11 +02:00
parent 08e55ccdfe
commit 6a1689a239
6 changed files with 431 additions and 15 deletions

BIN
icons/lock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 B

BIN
icons/unlock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 844 B

View file

@ -48,11 +48,14 @@ clr = {
"bbwh":"\033[108m" # Bright White
}
def Simplify(text):
def Simplify(text, extrasimple=True):
good = "qwertyuiopasdfghjklzxcvbnm.1234567890-_:"
good = "QWERTYUIOPLKJHGFDSAZXCVBNMqwertyuiopasdfghjklzxcvbnm.1234567890-_:* "
text = text.lower()
if extrasimple:
good = "qwertyuiopasdfghjklzxcvbnm.1234567890-_:"
text = text.lower()
ntext = ""
for i in text:
if i in good:

View file

@ -93,8 +93,8 @@ def Transfer(location):
commentdata = json.load(o)
comments = {
"comments":commentdata["comments"].get(tab+"/"+article),
"requests":commentdata["requests"].get(tab+"/"+article)
"comments":commentdata["comments"].get(tab+"/"+article, []),
"requests":commentdata["requests"].get(tab+"/"+article, [])
}
@ -145,7 +145,7 @@ def Transfer(location):
account["contact"] = "" # Contact info
account["website"] = "" # Website
account["mastodon"] = "" # Mastodon ( useful for fediverse tags )
account["sessions"] = [] # List of cookies accosiated with this account
account["sessions"] = {} # List of cookies accosiated with this account
# We are saving the accounts in a different way too.

View file

@ -4,6 +4,8 @@
import os
import json
import random
import hashlib
from datetime import datetime
from modules import Set
@ -45,6 +47,9 @@ def head(title="", description="", image="", config={}):
favicon = config.get("favicon", "/icon/internet")
html = """
<head>
<!-- The head. Part of the HTML code where metadata about the page is storred.
Including the metadata readable by social media websites, when generating link
previwews, which are called mata-tags in HTML. -->
@ -58,8 +63,8 @@ def head(title="", description="", image="", config={}):
<!-- Now meta tags for social media -->
<meta property="og:site_name" content=\""""+config.get("title", "My Website")+"""">
<meta property="og:title" content=\""""+title+"""">
<meta property="og:description" content=\""""+description+"""">
<meta property="og:title" content=\""""+Simplify(title, False)+"""">
<meta property="og:description" content=\""""+Simplify(description, False)+"""">
<meta property="og:image" content=\""""+image+"""">
<!-- This meta tag is needed for pretty rendering on phones -->
@ -69,6 +74,7 @@ def head(title="", description="", image="", config={}):
<body>
"""
return html
@ -103,14 +109,35 @@ def accounts():
try:
with open(folder+"/"+account) as o:
data = json.load(o)
data["username"] = account.replace(".json","")
accounts[account.replace(".json","")] = data
except Exception as e:
print(e)
pass
return accounts
def validate(cookie):
Accounts = accounts()
for account in Accounts:
if cookie in Accounts[account].get("sessions", []):
return Accounts[account]
return {}
def moderates(moderator, user):
Accounts = accounts()
if moderator not in Accounts:
return False
if user not in Accounts:
return True
if moderator == user:
return True
def articles(tab):
folder = Set.Folder()+"/tabs/"+tab
@ -209,7 +236,7 @@ def previewsToSize(text):
# given article.
# A thousand character article is about 4 articles.
return int(round(len(text)/2500))
return len(text)/2200
###
@ -226,6 +253,8 @@ def MainPage(server):
)
html = html + LoginButton(server)
html = html + """
<br>
@ -268,6 +297,8 @@ def MainPage(server):
html = html + '</div>'
html = html + Footer()
html = html + LoginButton(server)
send(server, html, 200)
@ -292,6 +323,7 @@ def ListPage(server, tab):
config = config
)
html = html + Button(config.get("title", "My Website"), "/", image=config.get("favicon", "/icon/internet"))
# Scroll thingie
@ -342,11 +374,13 @@ def ListPage(server, tab):
if To < len(Articles)-1:
html = html + Button(str(page+1), tab+"?page="+str(page+1), "right")
html = html + LoginButton(server)
send(server, html, 200)
def ArticlePage(server, url):
user = validate(server.cookie)
if url.endswith(".md"):
url = url.replace(".md", "")
@ -363,6 +397,7 @@ def ArticlePage(server, url):
config = config
)
html = html + Button(config.get("title", "My Website"), "/", image=config.get("favicon", "/icon/internet"))
html = html + Button(Tabs.get(tab, {}).get("title", tab), "/"+tab, Tabs.get(tab, {}).get("icon", "folder"))
@ -405,8 +440,41 @@ def ArticlePage(server, url):
html = html + markdown.convert(f+"/tabs/"+tab+"/"+article+"/text.md")
html = html + '</div>'
html = html + '</div>'
# Comments
html = html + CommentInput(server, url)
comments = Articles.get(article, {}).get("comments", {}).get("comments", [])
commentsTextLength = 0
comment_edit = server.parsed.get("comment_edit", [""])[0]
if comments:
for n, comment in enumerate(comments):
if str(n) == comment_edit and moderates(user.get("username"), comment.get("username")):
html = html + CommentEditInput(server, comment, url, n, user)
else:
html = html + Comment(comment, url, n, user)
# Needed to extend the suggestion for pages with many comments
commentsTextLength += previewsToSize(comment.get("text", ""))
# Requests
requests = Articles.get(article, {}).get("comments", {}).get("requests", [])
if requests:
for n, comment in enumerate(requests):
if comment.get("cookie") == server.cookie:
html = html + Comment(comment, url, n, user, request=True)
elif moderates(user.get("username"), comment.get("username")):
html = html + CommentEditInput(server, comment, url, n, user, request=str(n))
html = html + '</div>'
# Thumbnail and suggestions
html = html + '<div class="checklist_section_article">'
@ -420,6 +488,7 @@ def ArticlePage(server, url):
suggestions = suggestedArticles(server.cookie, random=True)
toomuch = previewsToSize(open(f+"/tabs/"+tab+"/"+article+"/text.md").read())
toomuch += commentsTextLength
for n, title in enumerate(suggestions):
@ -434,6 +503,7 @@ def ArticlePage(server, url):
html = html + ""
html = html + LoginButton(server)
send(server, html, 200)
@ -451,6 +521,7 @@ def AccountPage(server, account):
config = config
)
html = html + Button(config.get("title", "My Website"), "/", image=config.get("favicon", "/icon/internet"))
# Name and bio
@ -506,9 +577,62 @@ def AccountPage(server, account):
html = html + '<div class="dark_box">'
html = html + '<center>' + User(username) + '</center>\n'
html = html + '</div>'
html = html + LoginButton(server)
send(server, html, 200)
def LoginPage(server):
config = Set.Load()
Accounts = accounts()
f = Set.Folder()
wrongname = server.parsed.get("wrong", [""])[0]
# Generating <head>
html = head(title = "Login",
description = "Login",
config = config
)
html = html + Button(config.get("title", "My Website"), "/", image=config.get("favicon", "/icon/internet"))
html = html + '<center>'
if wrongname:
html = html + '\n<br>Wrong Username / Password<br>\n'
html = html + """
<form action="do_login">
<img style="vertical-align: middle" src="/icon/user">
<input class="button" style="width:36.5%" maxlength="500" id="user_name" required="" name="user_name" pattern="[A-Za-z0-9]*" placeholder="Username..."></input>
<br>
<img style="vertical-align: middle" src="/icon/lock">
<input class="button" style="width:36.5%" maxlength="500" id="password" type="password" required="" name="password" placeholder="Password..."></input><br>
<button class="button" type="submit">
<img style="vertical-align: middle" src="/icon/unlock">
Login
</button>
</form>
<br>
Don't have an account? <a href="/register">Register</a>.
"""
html = html + '</center>'
send(server, html, 200)
###
def Button(text, link, icon="", image=""):
@ -593,7 +717,10 @@ def User(username, stretch=False):
if not avatar: avatar = "/pictures/monkey.png"
username = Safe(username)
title = Safe(account.get("title", username))
html = '<img style="height:50px;vertical-align: middle" src="'+avatar+'">&nbsp;&nbsp;<a href="/account/'+username+'">'+title+'</a></center>\n'
if account:
html = '<img style="height:50px;vertical-align: middle" src="'+avatar+'">&nbsp;&nbsp;<a href="/account/'+username+'">'+title+'</a></center>\n'
else:
html = '<img style="height:50px;vertical-align: middle" src="'+avatar+'">&nbsp;&nbsp;'+title+'</center>\n'
return html
@ -659,3 +786,279 @@ def Graph(server, url):
send(server, html, 200)
def CommentInput(server, url):
user = validate(server.cookie)
html = """
<div class="dark_box" id="comments">
<br><center>
<form action="/comment">
<input type="hidden" id="url" name="url" value=\""""+url+"""">
"""
if not user:
html = html + '<img style="vertical-align: middle" src="/icon/user">'
html = html + '<input class="button" style="width:90%" maxlength="200" name="username" placeholder="Optional Nick Name">'
else:
html = html + User(user.get("username", ""))+'<center>'
html = html + """
<br>
<img style="vertical-align: middle" src="/icon/bug">
<input class="button" maxlength="200" style="width:90%" name="warning" placeholder="Optional Trigger Warning">
<textarea class="toot" rows="10" required="" style="width:95%" maxlength="10000" name="text">In my opinion </textarea>
<br>
<button class="button" type="submit">
<img style="vertical-align: middle" src="/icon/frase">
Post
</button>
</form>
</center>
</div>
"""
return html
def CommentEditInput(server, comment, url, n=0, user=None, request=None):
Accounts = accounts()
html = '<div class="dark_box" id="comment_'+str(n)+'">'
html = html + """
<form action="/comment">
<input type="hidden" id="url" name="url" value=\""""+url+"""">
<input type="hidden" id="number" name="number" value=\""""+str(n)+"""">
"""
if request:
html = html + '<input type="hidden" id="request" name="request" value=\"'+request+'">'
account = comment.get("username", "")
if account in accounts():
html = html + User(Safe(account))
elif account:
html = html + '<img style="vertical-align: middle" src="/icon/user">'
html = html + '<input class="button" style="width:90%" maxlength="200" name="username" placeholder="Optional Nick Name" value="'+account+'">'
warning = comment.get("warning", "")
html = html + """
<br>
<img style="vertical-align: middle" src="/icon/bug">
<input class="button" maxlength="200" style="width:90%" name="warning" placeholder="Optional Trigger Warning" value=\""""+warning+"""">
"""
html = html + """<textarea class="toot" rows="20" required="" style="width:95%" maxlength="10000" name="text">"""
html = html + Safe(comment.get("text", ""))
html = html + '</textarea>'
html = html + """
<button class="button" type="submit">
<img style="vertical-align: middle" src="/icon/ok">
Save
</button>
"""
html = html + '</form>'
html = html + '</div>'
return html
def Comment(comment, url, n=0, user=None, request=False):
html = '<div class="dark_box" id="comment_'+str(n)+'">'
account = comment.get("username", "Anonymous User")
html = html + User(account) + '<br>\n'
if request:
html = html + '<center><sup><b> &nbsp; Pending Approval &nbsp; </b></sup></center><br>'
warning = comment.get("warning", "")
if warning:
html = html + '<details>'
html = html + '<summary class="button" title="Click to show anyway.">'
html = html + '<img src="/icon/bug" style="vertical-align: middle">'
html = html + warning
html = html + '</summary>'
html = html + markdown.convert(Safe(comment.get("text", "")), False)+'<br>'
if warning:
html = html + '</details>'
if moderates(user.get("username"), account):
html = html + '<a class="button" href="/'+url+'?comment_edit='+str(n)+'#comment_'+str(n)+'">'
html = html + '<img src="/icon/edit" style="vertical-align: middle"> Edit'
html = html + '</a>'
html = html + '<a class="button" href="/">'
html = html + '<img src="/icon/cancel" style="vertical-align: middle"> Delete'
html = html + '</a>'
html = html + '</div>\n'
return html
def LoginButton(server):
user = validate(server.cookie)
html = '<div class="login_fixed">'
if not user:
html = html + '<a class="button" href="/login">'
html = html + '<img style="vertical-align: middle" src="/icon/user"> Login'
html = html + '</a>'
else:
html = html + '<a class="button" href="/settings">'
avatar = Safe(user.get("avatar", ""))
if not avatar: avatar = "/pictures/monkey.png"
html = html + '<img style="height:40px;vertical-align: middle" src="'+avatar+'"> '
html = html + user.get("title", user.get("username", "Anonymous"))
html = html + '</a>'
html = html + '</div>'
return html
###
def Redirect(server, url):
html = """<meta http-equiv="Refresh" content="0; url='"""+url+"""'" />"""
send(server, html, 200)
def Login(server):
username = server.parsed.get("user_name", [""])[0]
password = server.parsed.get("password" , [""])[0]
hashed = hashlib.sha512(password.encode("utf-8")).hexdigest()
Accounts = accounts()
if username not in Accounts or hashed != Accounts[username].get("password"):
Redirect(server, "/login?wrong=username")
else:
account = Accounts[username]
if "sessions" not in account:
account["sessions"] = {}
account["sessions"][server.cookie] = server.headers.get("User-Agent")
folder = Set.Folder()+"/accounts"
with open(folder+"/"+username+".json", "w") as save:
json.dump(account, save, indent=4)
Redirect(server, "/")
def DoComment(server):
user = validate(server.cookie)
Accounts = accounts()
url = server.parsed.get("url", ["/"])[0]
if not url.startswith("/"): url = "/" + url
text = server.parsed.get("text", [""])[0]
nick = server.parsed.get("username", [""])[0]
warn = server.parsed.get("warning", [""])[0]
number = server.parsed.get("number", [""])[0]
request = server.parsed.get("request", [""])[0]
metadata = Set.Folder()+"/tabs"+url+"/metadata.json"
try:
with open(metadata) as o:
article = json.load(o)
except:
Redirect(server, "/")
return
if "comments" not in article:
article["comments"] = {}
if "comments" not in article["comments"]:
article["comments"]["comments"] = []
if "requests" not in article["comments"]:
article["comments"]["requests"] = []
comment = {
"text":text
}
if warn:
comment["warning"] = warn
if not nick and user:
comment["username"] = user.get("username", "")
place = "comments"
elif request:
if nick in Accounts or not nick:
nick = "Anonymous Guest"
comment["username"] = nick
del article["comments"]["requests"][int(request)]
place = "comments"
number = ""
else:
if nick in Accounts or not nick:
nick = "Anonymous Guest"
comment["username"] = nick
place = "requests"
if not user:
comment["cookie"] = server.cookie
if not number:
article["comments"][place].append(comment)
number = len(article["comments"]["comments"])-1
else:
number = int(number)
if moderates(user.get("username"), article["comments"]["comments"][number]["username"]):
article["comments"]["comments"][number] = comment
try:
with open(metadata, "w") as save:
json.dump(article, save, indent=4)
except:
pass
Redirect(server, url+"#comment_"+str(number))

View file

@ -71,6 +71,15 @@ class handler(BaseHTTPRequestHandler):
if "?" in url: url = url[:url.find("?")]
Render.AccountPage(self, url)
elif self.path[1:].startswith("login"):
Render.LoginPage(self)
elif self.path[1:].startswith("comment"):
Render.DoComment(self)
elif self.path[1:].startswith("do_login"):
Render.Login(self)
elif self.path.startswith("/graph/"):
url = self.path[6:]
if "?" in url: url = url[:url.find("?")]
@ -102,7 +111,8 @@ class handler(BaseHTTPRequestHandler):
Render.headers(self, 200)
self.wfile.write(f)
else:
Render.Redirect(self, "/")
config = Set.Load()
PORT = config.get("port", 8080)