twtxtlist/src/twtxtlist.nim

250 lines
6.4 KiB
Nim

import asyncdispatch, db_sqlite, httpclient, jester, json, moustachu, os, shorturl,
strutils, tables, templates/all, times, tweet/parse, twtxt, typetraits
let
db = open("data/twtxt.db", nil, nil, nil)
try:
db.exec sql"""create table if not exists users (
id INTEGER PRIMARY KEY,
username TEXT UNIQUE,
url TEXT UNIQUE
);"""
db.exec sql"""create table if not exists tweets (
id INTEGER PRIMARY KEY,
username TEXT,
time REAL,
tweet TEXT,
UNIQUE (username, time, tweet)
);"""
except:
quit getCurrentExceptionMsg()
template renderMustache*(title: string, templ: string, ctx: Context): expr =
var
layoutCtx = moustachu.newContext()
layoutCtx["title"] = title
layoutCtx["body"] = render(templ, ctx)
resp render(baseTemplate, layoutCtx)
template fail*(): expr =
var ctx = newContext()
ctx["exception"] = getCurrentExceptionMsg()
var
layoutCtx = moustachu.newContext()
layoutCtx["title"] = "fail"
layoutCtx["body"] = render(errorTemplate, ctx)
halt render(baseTemplate, layoutCtx)
template pagination(ctx: Context, isnt1: bool, prev, next: string): expr =
ctx["paging"] = true
ctx["isnt1"] = isnt1
ctx["prev"] = prev
ctx["next"] = next
settings:
port = getEnv("PORT").parseInt().Port
bindAddr = "0.0.0.0"
routes:
get "/":
var ctx = newContext()
let
users = db.getValue sql"select count(*) from users"
tweets = db.getValue sql"select count(*) from tweets"
ctx["users"] = users
ctx["tweets"] = tweets
renderMustache("home", indexTemplate, ctx)
get "/changelog":
const log = staticExec "git log -10"
var ctx = newContext()
ctx["changelog"] = log
renderMustache("changelog", changelogTemplate, ctx)
get "/content/system":
let
myHeaders = {
"Content-Type": "text/plain",
}
tweets = db.getAllRows(sql"select * from tweets where username='system'")
var res = ""
for tweet in tweets.items():
res &= $(tweet.fromDBRow()) & "\r\n"
resp Http200, myHeaders, res
get "/timeline":
redirect "/timeline/0"
get "/submit":
renderMustache "submit", submitTemplate, newContext()
post "/submit":
try:
var
username = $(request.formData.mget "username").body
url = $(request.formData.mget "url").body
db.updateTweetsByUser(username, url)
db.exec(sql"insert into users values (null, ?, ?)", username, url)
db.exec(sql"insert into tweets values (null, 'twtxtlist', ?, ?)",
$(getTime().getGMTime().timeinfoToTime().toSeconds()),
"Added user @<" & username & " " & url & ">")
redirect "/users/" & username & "/0"
except: fail()
get "/users":
var
users = db.getAllRows(sql"select username, url from users order by username")
ctx = newContext()
userList = newSeq[Context]()
for user in users.items():
var c = newContext()
c["username"] = user[0]
c["url"] = user[1]
userList.add c
ctx["users"] = userList
renderMustache "users", usersTemplate, ctx
get "/users.txt":
let
headers = {
"Content-Type": "text/plain"
}
users = db.getAllRows(sql"select username, url from users order by username")
var outBuf = ""
for user in users.items():
outBuf &= "twtxt follow " & user[0] & " " & user[1] & "\r\n"
resp Http200, headers, outBuf
get "/users/@name/@page":
try:
var
tweets = db.getAllRows(sql"select * from tweets where username=? order by time desc limit 20 offset ?", @"name", (@"page").parseInt() * 20)
ctx = newContext()
tweetList = newSeq[Context]()
if len(tweets) == 0:
raise newException(ValueError, "no such page")
var
userctx = newContext()
userurl = db.getValue(sql"select url from users where username=?", @"name")
userctx["url"] = userurl
userctx["username"] = @"name"
ctx["user"] = userctx
for tweet in tweets.items():
var c = newContext()
let time = tweet[2].split(".")[0].parseInt()
c["id"] = tweet[0]
c["permalink"] = tweet[0].parseInt().encodeURLSimple()
c["username"] = tweet[1]
c["time"] = time
c["tweet"] = $tweet[3].prettyfyTweet()
tweetList.add c
ctx["tweets"] = tweetList
let id = (@"page").parseInt()
if @"page" == "0":
ctx.pagination(false, "", "/users/" & @"name" & "/" & $(id + 1))
else:
ctx.pagination(true, "/users/" & @"name" & "/" & $(id - 1), "/users/" & @"name" & "/" & $(id + 1))
renderMustache(@"name" & " page " & @"page", tweetsTemplate, ctx)
except: fail()
get "/timeline/@page":
try:
var
tweets = db.getAllRows(sql"select * from tweets where username <> 'twtxtlist' and username <> 'directory' order by time desc limit 20 offset ?", (@"page").parseInt() * 20)
ctx = newContext()
tweetList = newSeq[Context]()
if tweets.len == 0:
raise newException(ValueError, "no such page")
for tweet in tweets.items():
var c = newContext()
let time = tweet[2].split(".")[0].parseInt()
c["id"] = tweet[0]
c["permalink"] = tweet[0].parseInt().encodeURLSimple()
c["username"] = tweet[1]
c["time"] = time
c["tweet"] = $tweet[3].prettyfyTweet()
tweetList.add c
ctx["tweets"] = tweetList
let id = (@"page").parseInt()
if @"page" == "0":
ctx.pagination(false, "", "/timeline/" & $(id + 1))
else:
ctx.pagination(true, "/timeline/" & $(id - 1), "/timeline/" & $(id + 1))
renderMustache("timeline page " & @"page", tweetsTemplate, ctx)
except: fail()
get "/tweet/@tid":
try:
var
tweets = db.getAllRows(sql"select * from tweets where id=? limit 1", (@"tid").decodeURLSimple())
ctx = newContext()
tweetList = newSeq[Context]()
if tweets.len == 0:
raise newException(ValueError, "no such tweet")
for tweet in tweets.items():
var c = newContext()
let time = tweet[2].split(".")[0].parseInt()
c["id"] = tweet[0]
c["permalink"] = tweet[0].parseInt().encodeURLSimple()
c["username"] = tweet[1]
c["time"] = time
c["tweet"] = $tweet[3].prettyfyTweet()
tweetList.add c
ctx["tweets"] = tweetList
renderMustache("tweet " & @"tid", tweetsTemplate, ctx)
except: fail()
runForever()