view src/lib/Post.luan @ 44:96f0c3d65698

add /bbcode
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 10 Nov 2022 23:18:58 -0700
parents 298c71e0c854
children 289718f121e4
line wrap: on
line source

local Luan = require "luan:Luan.luan"
local error = Luan.error
local ipairs = Luan.ipairs or error()
local set_metatable = Luan.set_metatable or error()
local set_local_only = Luan.set_local_only or error()
local get_local_only = Luan.get_local_only or error()
local Time = require "luan:Time.luan"
local time_now = Time.now or error()
local Html = require "luan:Html.luan"
local html_encode = Html.encode or error()
local Number = require "luan:Number.luan"
local long = Number.long or error()
local Db = require "site:/lib/Db.luan"


local Post = {}

local times = {
	{
		time = 1000*60*60*24*365
		unit = "year"
	}
	{
		time = 1000*60*60*24*7
		unit = "week"
	}
	{
		time = 1000*60*60*24
		unit = "day"
	}
	{
		time = 1000*60*60
		unit = "hour"
	}
	{
		time = 1000*60
		unit = "minute"
	}
}

local posts_by_id = {}

local function from_doc(doc)
	doc.type == "post" or error "wrong type"
	local post = Post.new {
		id = doc.id
		content = doc.content
		date = doc.date
		author_name = doc.post_author_name
		root_id = doc.post_root_id
		is_root = doc.post_is_root == "true"

		-- root only
		subject = doc.subject
	}
	set_local_only(posts_by_id,post.id,post)
	return post
end

local function to_doc(post)
	return {
		type = "post"
		id = post.id
		content = post.content or error()
		date = long(post.date)
		post_author_name = post.author_name or error()
		post_root_id = long(post.root_id)
		post_is_root = post.is_root and "true" or nil

		-- root only
		subject = post.subject
	}
end

local metatable = {}
function metatable.__index(post,key)
	if key == "author" then
		local User = require "site:/lib/User.luan"
		return User.get_by_name(post.author_name)
	end
	if key == "subject_html" then
		return post.subject and html_encode(post.subject)
	end
	if key == "root" then
		return post.is_root and post or Post.get_by_id(post.root_id)
	end
	return nil
end

function Post.new(post)
	post.date = post.date or time_now()

	function post.save()
		local doc = to_doc(post)
		Db.save(doc)
		post.id = doc.id
	end

	function post.delete()
		Db.run_in_transaction( function()
			not post.is_root or Post.thread_size(post.root_id) == 1 or error "can't delete root post with replies"
			Db.delete("id:"..post.id)
		end )
	end

	function post.author_is_current()
		local User = require "site:/lib/User.luan"
		local user = User.current()
		return user ~= nil and user.name == post.author_name
	end

	function post.ago(now)
		local diff = now - post.date
		for _, t in ipairs(times) do
			local n = diff // t.time
			if n > 0 then
				%><%=n%> <%=t.unit%><%
				if n > 1 then
					%>s<%
				end
				return
			end
		end
		%>0 minutes<%
	end

	set_metatable(post,metatable)
	return post
end

function Post.get_by_id(id)
	local post = get_local_only(posts_by_id,id)
	if post ~= nil then return post end
	local doc = Db.get_document("id:"..id)
	return doc and from_doc(doc)
end

function Post.new_thread(author,subject,content)
	return Db.run_in_transaction( function()
		local post = Post.new{
			subject = subject or error()
			content = content
			author_name = author.name
			is_root = true
		}
		post.save()
		post.root_id = post.id or error()
		post.save()
		return post
	end )
end

function Post.from_docs(docs)
	local posts = {}
	for _, doc in ipairs(docs) do
		local post = from_doc(doc)
		posts[#posts+1] = post
	end
	return posts
end

function Post.thread_size(root_id)
	return Db.count("post_root_id:"..root_id)
end

return Post