diff --git a/app.lua b/app.lua index 2751c67..6e0cd14 100644 --- a/app.lua +++ b/app.lua @@ -21,6 +21,9 @@ local function inject_methods(req) return util.ntob(v) end req.PermissionLevelString = constants.PermissionLevelString + req.infobox_message = function (_, s) + return util.infobox_message(s) + end util.pop_infobox(req) end diff --git a/apps/threads.lua b/apps/threads.lua index fbb7e1b..271c875 100644 --- a/apps/threads.lua +++ b/apps/threads.lua @@ -37,6 +37,9 @@ app:post("thread_create", "/create", function(self) if not topic then return {redirect_to = self:url_for("topics")} end + if util.is_topic_locked(topic) then + return {redirect_to = self:url_for("topics")} + end local title = lapis_util.trim(self.params.title) local time = os.time() diff --git a/util.lua b/util.lua index 38d29ae..22c3d30 100644 --- a/util.lua +++ b/util.lua @@ -3,6 +3,7 @@ local magick = require("magick") local db = require("lapis.db") local html_escape = require("lapis.html").escape local constants = require("constants") +local string_trim = require("lapis.util").trim local Avatars = require("models").Avatars local Users = require("models").Users @@ -33,10 +34,131 @@ util.TransientUser = { username = "Deleted User", } +-- PURE API + function util.get_user_avatar_url(req, user) return Avatars:find(user.avatar_id).file_path end +---split a string +---@param s string subject +---@param delimiter string? string to split by, can be empty to split by character +---@param max_matches integer? the maximum number of returned elements +---@param trim boolean? whether to trim whitespace off matches +---@param allow_empty boolean? should empty matches be in the resulting table +---@return string[] +function util.s_split(s, delimiter, max_matches, trim, allow_empty) + local result = {} + if s == "" then + return result + end + trim = trim == nil and true or trim + local tr = function(subj) + if trim then return string_trim(subj) else return subj end + end + max_matches = max_matches or -1 + allow_empty = allow_empty == nil and true or allow_empty + + if delimiter == "" then + for i=1, #s do + local c = s:sub(i, 1) + if allow_empty or c ~= "" then + table.insert(result, c) + if max_matches > 0 and #result == max_matches then + break + end + end + end + return result + end + + local current_pos = 1 + local delim_len = #delimiter + + while true do + if max_matches > 0 and #result >= max_matches then + break + end +---@diagnostic disable-next-line: param-type-mismatch + local start_pos, end_pos = s:find(delimiter, current_pos, true) + if not start_pos then + break + end + local substr = s:sub(current_pos, start_pos - 1) + if allow_empty or substr ~= "" then + table.insert(result, tr(substr)) + end + current_pos = end_pos + 1 + end + + local substr = s:sub(current_pos) + if allow_empty or substr ~= "" then + table.insert(result, tr(substr)) + end + + return result +end + +function util.split_sentences(sentences, max_sentences) + return util.s_split(sentences, ".", max_sentences or 2, true, false) +end + +function util.infobox_message(msg) + local sentences = util.split_sentences(msg) + if #sentences == 1 then + return "" .. sentences[1] .. ". " .. "" + end + return "" .. sentences[1] .. ". " .. " " .. sentences[2] .. "." +end + +function util.get_logged_in_user(req) + if req.session.session_key == nil then + return nil + end + + local session = db.select('* FROM "sessions" WHERE "key" = ? AND "expires_at" > "?" LIMIT 1', req.session.session_key, os.time()) + if #session > 0 then + return Users:find({id = session[1].user_id}) + end + + return nil +end + +function util.get_logged_in_user_or_transient(req) + return util.get_logged_in_user(req) or util.TransientUser +end + +function util.ntob(v) + return v ~= 0 +end + +function util.bton(b) + return 1 and b or 0 +end + +function util.stob(s) + if s == "true" then + return true + end + if s == "false" then + return false + end +end + +function util.form_bool_to_sqlite(s) + return util.bton(util.stob(s)) +end + +function util.is_thread_locked(thread) + return util.ntob(thread.is_locked) +end + +function util.is_topic_locked(topic) + return util.ntob(topic.is_locked) +end + +-- OTHER API + function util.validate_and_create_image(input_image, filename) local img = magick.load_image_from_blob(input_image) @@ -92,48 +214,6 @@ function util.destroy_avatar(avatar_id) end end -function util.get_logged_in_user(req) - if req.session.session_key == nil then - return nil - end - - local session = db.select('* FROM "sessions" WHERE "key" = ? AND "expires_at" > "?" LIMIT 1', req.session.session_key, os.time()) - if #session > 0 then - return Users:find({id = session[1].user_id}) - end - - return nil -end - -function util.get_logged_in_user_or_transient(req) - return util.get_logged_in_user(req) or util.TransientUser -end - -function util.ntob(v) - return v ~= 0 -end - -function util.bton(b) - return 1 and b or 0 -end - -function util.stob(s) - if s == "true" then - return true - end - if s == "false" then - return false - end -end - -function util.form_bool_to_sqlite(s) - return util.bton(util.stob(s)) -end - -function util.is_thread_locked(thread) - return util.ntob(thread.is_locked) -end - function util.create_post(thread_id, user_id, content) db.query("BEGIN") local post = Posts:create({ diff --git a/views/common/infobox.etlua b/views/common/infobox.etlua index b5c851e..54e4c0d 100644 --- a/views/common/infobox.etlua +++ b/views/common/infobox.etlua @@ -1,6 +1,7 @@ <% local class = "infobox " .. constants.InfoboxHTMLClass[kind] local icon = constants.InfoboxIcons[kind] + local sentences = infobox_message(msg) %>
There are no threads in this topic.
<% else %> <% for _, thread in ipairs(threads_list) do %> <% local is_stickied = ntob(thread.is_stickied) %> - <% local is_locked = ntob(thread.is_locked) %> + <% local thread_is_locked = ntob(thread.is_locked) %>