napkin/main.lua

230 lines
5.8 KiB
Lua
Raw Normal View History

2025-02-19 18:10:37 -03:00
local weblit = require('weblit')
2025-03-06 19:48:52 -03:00
local cookie = require('weblit-cookie')
--local multipart = require('weblit-multipart')
2025-03-08 00:07:37 -03:00
local timer = require("timer")
local radon = require("radon")
2025-02-27 13:10:42 -03:00
local foppy = require("./foppy")
2025-03-08 00:07:37 -03:00
local database = require("./database")
local errors = require("./errors")
local utils = require("./utils")
2025-02-27 13:10:42 -03:00
local blogs = require("blogs")
local authors = require("authors")
2025-03-03 00:27:45 -03:00
local templater = function(template, rate)
2025-02-27 13:10:42 -03:00
return function(req, res)
2025-03-03 00:27:45 -03:00
if rate then
local coro = coroutine.running()
timer.setTimeout(rate, function()
if coroutine.status(coro) ~= "dead" then
coroutine.resume(coro)
end
end)
end
2025-02-27 13:10:42 -03:00
local func = dofile("template/" .. template .. ".lua")
res.code = 200
res.body = radon.compile(func, {
request = req,
response = res
2025-02-27 13:10:42 -03:00
})
res.headers["Content-Type"] = "text/html"
2025-03-03 00:27:45 -03:00
if rate then
coroutine.yield()
end
2025-02-27 13:10:42 -03:00
end
end
2025-02-19 18:10:37 -03:00
weblit.app
2025-02-27 13:10:42 -03:00
.bind({ host = "0.0.0.0", port = 1337 })
2025-02-19 18:10:37 -03:00
-- Configure weblit server
.use(weblit.logger)
.use(weblit.autoHeaders)
2025-03-06 19:48:52 -03:00
.use(utils.forms)
.use(cookie)
2025-02-19 18:10:37 -03:00
.route(
2025-03-08 00:07:37 -03:00
{ path = "/static/:path" },
weblit.static("static")
)
.route(
2025-03-06 19:34:12 -03:00
{ path = "/media/:path:", method = "GET" },
weblit.static("database/media")
)
--.route(
-- { path = "/media", method = "POST" },
-- multipart { writeTo = "database/media" }
--)
2025-03-08 00:07:37 -03:00
-- TODO: CLONE ALL OF THIS AS A REST API EVENTUALLY,
.route({ path = "/signup" }, templater("signup"))
2025-03-03 00:27:45 -03:00
.route({ path = "/signup2" }, templater("signup2", 3000))
-- LOGIN ------------------------
.route({ path = "/login", method = "GET" }, templater("login"))
.route({ path = "/login" }, function(req, res)
local token = req.cookies.auth_token
local form = req.form
local data = {
request = req,
response = res
}
if (not token) and form and form.id and form.password then
if form.id:sub(1, 1) == "@" then
local blog = blogs.from_handle(form.id:sub(2))
if not blog then
return errors.handle(data, "blog_not_found", "/login")
end
form.id = blog.owner
end
token = authors.auth(form.id, form.password)
if not token then
return errors.handle(data, "wrong_credentials", "/login")
end
res.setCookie(
"auth_token", token, {
Path = "/", SameSite = "Strict"
}
)
req.cookies.auth_token = token
end
res.code = 302
res.headers["Location"] = "/"
return ""
end)
.route({ path = "/logout" }, function(req, res)
res.clearCookie("auth_token")
res.headers["Location"] = "/"
res.code = 302
end)
-- BLOGS ------------------------
2025-03-02 10:45:22 -03:00
.route({ path = "/new-blog" }, templater("new-blog"))
.route({ path = "/@" }, function(req, res)
local form = req.form
if not (form and form.handle) then
res.code = 302
res.headers["Location"] = "/"
return
end
local handle = form.handle
local data = {
request = req,
response = res
}
local prev = req.headers["referer"] or "/"
if #handle == 0 then
return errors.handle(data, "blog_handle_invalid", prev)
end
if req.method ~= "POST" then
local blog = blogs.from_handle(handle)
if not blog then
return errors.handle(data, "blog_not_found", prev)
end
end
res.code = 307
res.headers["Location"] = "/@" .. handle
end)
.route({ path = "/@:blog:", method = "GET" }, templater("blog"))
.route({ path = "/@:blog:", method = "POST" }, function(req, res)
local form = req.form
if not form then
res.headers["Location"] = "/"
res.code = 302
return
end
local data = {
request = req,
response = res
}
local token = req.cookies.auth_token
if not token then
return errors.handle(data, "not_logged_in", "/login")
end
local author_id = authors.id_from_token(token)
if not author_id then
return errors.handle(data, "invalid_token", "/login")
end
local blog = req.params.blog
if not (blog and utils.is_valid_handle(blog)) then
return errors.handle(data, "blog_handle_invalid", "/new-blog")
end
local ok, err = blogs.new_blog(
author_id,
blog,
form.title,
form.about
)
if not ok then
return errors.handle(data, err, "/new-blog")
end
res.code = 302
res.headers["Location"] = "/@" .. blog
end)
-- POSTS ------------------------
.route({ path = "/@:blog:/:post:" }, templater("post"))
.route({ path = "/p/:path:", method = "GET" }, function(req, res)
local path = req.params.path
if #path == 0 then
res.code = 301
res.headers["Location"] = "/"
return
end
local redirects = foppy.open("database/redirects.json")
assert(redirects)
local redirect = redirects[path]
if redirect then
res.code = 301
res.headers["Location"] = redirect
2025-02-27 13:10:42 -03:00
return
end
return errors.handle({
2025-03-03 00:27:45 -03:00
request = req,
response = res
}, "post_not_found", "/")
end)
2025-02-27 13:10:42 -03:00
.route({ path = "/" }, templater("index"))
2025-03-03 00:27:45 -03:00
.route({ path = "/rules" }, templater("rules"))
2025-02-19 18:10:37 -03:00
-- Start the server
.start()