local app = require("lapis").Application() local lapis_util = require("lapis.util") local db = require("lapis.db") local constants = require("constants") local util = require("util") local models = require("models") local Users = models.Users local Avatars = models.Avatars local Topics = models.Topics local Threads = models.Threads local THREADS_PER_PAGE = 10 local ThreadCreateError = { OK = 0, GUEST = 1, LOGGED_OUT = 2, TOPIC_LOCKED = 3, } app:get("all_topics", "", function(self) self.topic_list = db.query([[ SELECT topics.name, topics.slug, topics.description, topics.is_locked, users.username AS latest_thread_username, threads.title AS latest_thread_title, threads.slug AS latest_thread_slug, threads.created_at AS latest_thread_created_at FROM topics LEFT JOIN ( SELECT *, row_number() OVER (PARTITION BY threads.topic_id ORDER BY threads.created_at DESC) as rn FROM threads ) threads ON threads.topic_id = topics.id AND threads.rn = 1 LEFT JOIN users on users.id = threads.user_id ORDER BY topics.sort_order ASC ]]) self.me = util.get_logged_in_user_or_transient(self) return {render = "topics.topics"} end) app:get("topic_create", "/create", function(self) local user = util.get_logged_in_user(self) or util.TransientUser if not user:is_mod() then return {status = 403} end self.page_title = "creating a topic" self.me = user return {render = "topics.create"} end) app:post("topic_create", "/create", function(self) local user = util.get_logged_in_user(self) or util.TransientUser if not user:is_mod() then return {redirect_to = "all_topics"} end local topic_name = lapis_util.trim(self.params.name) local topic_description = self.params.description local time = os.time() local slug = lapis_util.slugify(topic_name) .. "-" .. time local topic_count = Topics:count() local topic = Topics:create({ name = topic_name, description = topic_description, slug = slug, sort_order = topic_count + 1, }) util.inject_infobox(self, "Topic created.") return {redirect_to = self:url_for("topic", {slug = topic.slug})} end) app:get("topic", "/:slug", function(self) local topic = Topics:find({ slug = self.params.slug }) if not topic then return {status = 404} end local threads_count = Threads:count(db.clause({ topic_id = topic.id })) self.topic = topic self.pages = math.max(math.ceil(threads_count / THREADS_PER_PAGE), 1) self.page = math.max(1, math.min(tonumber(self.params.page) or 1, self.pages)) -- self.threads_list = db.query("SELECT * FROM threads WHERE topic_id = ? ORDER BY is_stickied DESC, created_at DESC", topic.id) self.threads_list = db.query([[ SELECT threads.title, threads.slug, threads.created_at, threads.is_locked, threads.is_stickied, users.username AS started_by, u.username AS latest_post_username, ph.content AS latest_post_content, posts.created_at AS latest_post_created_at, posts.id AS latest_post_id FROM threads JOIN users ON users.id = threads.user_id JOIN ( SELECT posts.thread_id, posts.id, posts.user_id, posts.created_at, posts.current_revision_id, ROW_NUMBER() OVER (PARTITION BY posts.thread_id ORDER BY posts.created_at DESC) AS rn FROM posts ) posts ON posts.thread_id = threads.id AND posts.rn = 1 JOIN post_history ph ON ph.id = posts.current_revision_id JOIN users u ON u.id = posts.user_id WHERE threads.topic_id = ? ORDER BY threads.is_stickied DESC, threads.created_at DESC LIMIT ? OFFSET ? ]], topic.id, THREADS_PER_PAGE, (self.page - 1) * THREADS_PER_PAGE) local user = util.get_logged_in_user_or_transient(self) self.me = user self.ThreadCreateError = ThreadCreateError self.thread_create_error = ThreadCreateError.OK if user:is_logged_in_guest() then self.thread_create_error = ThreadCreateError.GUEST elseif user:is_guest() then self.thread_create_error = ThreadCreateError.LOGGED_OUT elseif util.ntob(topic.is_locked) and not user:is_mod() then self.thread_create_error = ThreadCreateError.TOPIC_LOCKED end self.page_title = "browsing topic " .. topic.name return {render = "topics.topic"} end) app:get("topic_edit", "/:slug/edit", function(self) local user = util.get_logged_in_user_or_transient(self) if not user:is_mod() then return {redirect_to = self:url_for("topic", {slug = self.params.slug})} end local topic = Topics:find({ slug = self.params.slug }) if not topic then return {redirect_to = self:url_for("all_topics")} end self.topic = topic self.me = user self.page_title = "editing topic " .. topic.name return {render = "topics.edit"} end) app:post("topic_edit", "/:slug/edit", function(self) local user = util.get_logged_in_user_or_transient(self) if not user:is_mod() then return {redirect_to = self:url_for("topic", {slug = self.params.slug})} end local topic = Topics:find({ slug = self.params.slug }) if not topic then return {redirect_to = self:url_for("all_topics")} end local name = self.params.name or topic.name local description = self.params.description or topic.description local is_locked = topic.is_locked if self.params.is_locked ~= nil then is_locked = util.form_bool_to_sqlite(self.params.is_locked) end topic:update({ name = name, description = description, is_locked = is_locked, }) return {redirect_to = self:url_for("topic", {slug = self.params.slug})} end) return app