You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

227 lines
6.6 KiB
Lua

local db = require "lapis.db"
local giflib = require "giflib"
local lfs = require "lfs"
local magick = require "magick"
local Model = require("lapis.db.model").Model
local Boards = Model:extend("boards", {
relations = {
{ "announcements", has_many="Announcements" },
{ "bans", has_many="Bans" },
{ "posts", has_many="Posts" },
{ "reports", has_many="Reports" },
{ "threads", has_many="Threads", where={ archive=false }, order="sticky desc, last_active desc" },
{ "archived", has_many="Threads", where={ archive=true }, order="last_active desc" },
}
})
Boards.valid_record = {
{ "name", max_length=255, exists=true },
{ "title", max_length=255, exists=true },
{ "subtext", max_length=255 },
{ "ban_message", max_length=255 },
{ "anon_name", max_length=255 },
{ "theme", max_length=255 },
{ "pages", exists=true },
{ "threads_per_page", exists=true },
{ "thread_file_limit", exists=true },
{ "post_limit", exists=true },
{ "archive_time", exists=true },
{ "group", exists=true }
}
--- Create a board
-- @tparam table params Board parameters
-- @treturn boolean success
-- @treturn string error
function Boards:new(params)
local board = self:create(params)
if not board then
return false, { "err_create_board", { params.name, params.title } }
end
lfs.mkdir(string.format("./static/%s/", board.name))
return board
end
--- Modify a board
-- @tparam table params Board parameters
-- @tparam old_name Board's current short name
-- @treturn boolean success
-- @treturn string error
function Boards:modify(params, old_name)
local board = self:get(old_name)
if not board then
return false, { "err_create_board", { params.name, params.title } } -- FIXME: wrong error message
end
local success, err = board:update(params)
if not success then
return false, "FIXME: " .. tostring(err)
end
if board.name ~= old_name then
local old = string.format("./static/%s/", old_name)
local new = string.format("./static/%s/", board.name)
os.rename(old, new)
end
return board
end
--- Delete a board
-- @tparam string name Board's short name
-- @treturn boolean success
-- @treturn string error
function Boards:delete(name)
local board = self:get(name)
if not board then
return false, { "err_create_board", { name, name } } -- FIXME: wrong error message
end
local announcements = board:get_announcements()
local bans = board:get_bans()
local posts = board:get_posts()
local reports = board:get_reports()
local threads = board:get_threads()
local dir = string.format("./static/%s/", board.name)
-- Clear data
for _, announcement in ipairs(announcements) do announcement:delete() end
for _, ban in ipairs(bans) do ban:delete() end
for _, post in ipairs(posts) do post:delete() end
for _, report in ipairs(reports) do report:delete() end
for _, thread in ipairs(threads) do thread:delete() end
-- Clear filesystem
if lfs.attributes(dir, "mode") == "directory" then
-- Delete files
for file in lfs.dir(dir) do
os.remove(dir .. file)
end
-- Delete directory
lfs.rmdir(dir)
end
-- Clear board
local success = board:delete()
return success and board or false, { "err_delete_board", { board.name, board.title } }
end
--- Get all boards
-- @treturn table boards
function Boards:get_all()
local boards = self:select("order by boards.group asc, name asc")
return boards and boards or false, "FIXME: ALART!"
end
--- Get board data
-- @tparam string name Board's short name
-- @treturn table board
function Boards:get(name)
local board = self:find { name=name }
return board and board or false, "FIXME: ALART!"
end
--- Format board paramaters for DB insertion
-- @tparam table params Board parameters
function Boards.format_to_db(_, params)
-- Convert archive_time from days to seconds
params.archive_time = (tonumber(params.archive_time) or 0) * 86400
end
--- Format board parameters for User consumption
-- @tparam table params Board parameters
function Boards.format_from_db(_, params)
-- Convert archive_time from seconds to days
params.archive_time = tonumber(params.archive_time) / 86400
end
--- Regenerate thumbnails for all posts
-- @treturn none
function Boards.regen_thumbs(_)
local sql = [[
select
boards.name as board,
posts.thread_id,
posts.file_path,
posts.file_width,
posts.file_height,
posts.file_type
from posts
left join boards on
board_id = boards.id
where
file_path is not null and
file_width is not null and
file_height is not null and
file_type = 'image' and
file_spoiler = false
order by
board_id asc,
thread_id asc,
post_id asc
]]
local dir
local board
local thread = 0
local results = db.query(sql)
for _, result in ipairs(results) do
-- Change board, reset thread counter and image directory
if result.board ~= board then
board = result.board
thread = 0
dir = string.format("./static/%s/", board)
end
-- Filesystem paths
local name, ext = result.file_path:match("^(.+)(%..+)$")
ext = string.lower(ext)
local full_path = dir .. result.file_path
local thumb_path = dir .. "s" .. result.file_path
-- Generate a thumbnail
if ext == ".webm" then
thumb_path = dir .. "s" .. name .. ".png"
-- Create screenshot of first frame
os.execute(string.format("ffmpeg -i %s -ss 00:00:01 -vframes 1 %s -y", full_path, thumb_path))
end
-- Save thumbnail
local w, h
if result.thread_id > thread then
thread = result.thread_id
w = result.file_width < 250 and result.file_width or 250
h = result.file_height < 250 and result.file_height or 250
else
w = result.file_width < 125 and result.file_width or 125
h = result.file_height < 125 and result.file_height or 125
end
-- Grab first frame from video
if ext == ".webm" then
magick.thumb(thumb_path, string.format("%sx%s", w, h), thumb_path)
elseif ext == ".svg" then
thumb_path = dir .. "s" .. name .. ".png"
os.execute(string.format("convert -background none -resize %dx%d %s %s", w, h, full_path, thumb_path))
elseif ext == ".gif" then
-- Grab first frame of a gif instead of the last
local gif, err = giflib.load_gif(full_path)
if err then
magick.thumb(full_path, string.format("%sx%s", w, h), thumb_path)
else
gif:write_first_frame(thumb_path)
magick.thumb(thumb_path, string.format("%sx%s", w, h), thumb_path)
end
else
magick.thumb(full_path, string.format("%sx%s", w, h), thumb_path)
end
end
end
return Boards