diff --git a/apps/threads.lua b/apps/threads.lua index 93ef3fc..6aa84be 100644 --- a/apps/threads.lua +++ b/apps/threads.lua @@ -1,7 +1,119 @@ local app = require("lapis").Application() +local lapis_util = require("lapis.util") + +local db = require("lapis.db") +local util = require("util") + +local models = require("models") +local Topics = models.Topics +local Threads = models.Threads +local Posts = models.Posts app:get("thread_create", "/create", function(self) + local user = util.get_logged_in_user(self) + if not user then + self.session.flash = {error = "You must be logged in to perform this action."} + return {redirect_to = self:url_for("user_login")} + end + local all_topics = db.query("select * from topics limit 25;") + if #all_topics == 0 then + return "how did you get here?" + end + self.all_topics = all_topics + return {render = "threads.create"} +end) +app:post("thread_create", "/create", function(self) + local user = util.get_logged_in_user(self) + if not user then + self.session.flash = {error = "You must be logged in to perform this action."} + return {redirect_to = self:url_for("user_login")} + end + local topic = Topics:find(self.params.topic_id) + if not topic then + return {redirect_to = self:url_for("topics")} + end + + local title = lapis_util.trim(self.params.title) + local time = os.time() + local slug = lapis_util.slugify(title) .. "-" .. time + + local post_content = self.params.initial_post + + local thread = Threads:create({ + topic_id = topic.id, + user_id = user.id, + title = title, + slug = slug, + created_at = time, + }) + + local post = util.create_post(thread.id, user.id, post_content) + if not post then + return {redirect_to = self:url_for("topics")} + end + + return {redirect_to = self:url_for("thread", {slug = slug})} +end) + +app:get("thread", "/:slug", function(self) + local thread = Threads:find({ + slug = self.params.slug + }) + if not thread then + return {status = 404} + end + self.thread = thread + local posts = db.query([[ + SELECT + posts.id, post_history.content, users.username, avatars.file_path AS avatar_path + FROM + posts + JOIN + post_history ON posts.current_revision_id = post_history.id + JOIN + users ON posts.user_id = users.id + LEFT JOIN + avatars ON users.avatar_id = avatars.id + WHERE + posts.thread_id = ? and posts.id > ? + ORDER BY + posts.created_at ASC + LIMIT 20 + ]], thread.id, tonumber(self.params.cursor or 0)) + self.user = util.get_logged_in_user_or_transient(self) + self.posts = posts + self.next_cursor = #posts > 0 and posts[#posts].id or nil + return {render = "threads.thread"} +end) + +app:post("thread", "/:slug", function(self) + local thread = Threads:find({ + slug = self.params.slug + }) + if not thread then + return {redirect_to = self:url_for("all_topics")} + end + local user = util.get_logged_in_user(self) + if not user then + return {redirect_to = self:url_for("all_topics")} + end + + if user:is_guest() then + return {redirect_to = self:url_for("thread", {slug = thread.slug})} + end + + if util.is_thread_locked(thread) and not user:is_admin() then + return {redirect_to = self:url_for("thread", {slug = thread.slug})} + end + + local post_content = self.params.post_content + local post = util.create_post(thread.id, user.id, post_content) + if not post then + return {redirect_to = self:url_for("thread", {slug = thread.slug})} + end + + return {redirect_to = self:url_for("thread", {slug = thread.slug})} end) return app diff --git a/apps/topics.lua b/apps/topics.lua index 5674285..b093749 100644 --- a/apps/topics.lua +++ b/apps/topics.lua @@ -19,7 +19,7 @@ local ThreadCreateError = { TOPIC_LOCKED = 3, } -app:get("all_topics", "/", function(self) +app:get("all_topics", "", function(self) self.topic_list = db.query("select * from topics limit 25;") self.user = util.get_logged_in_user(self) or util.TransientUser return {render = "topics.topics"} diff --git a/migrations.lua b/migrations.lua index aba90d7..74e3491 100644 --- a/migrations.lua +++ b/migrations.lua @@ -41,4 +41,11 @@ return { -- will appear on top of non-stickied threads in topic view schema.add_column("threads", "is_stickied", "BOOLEAN DEFAULT FALSE") end, + + [5] = function () + db.query("CREATE INDEX idx_posts_thread ON posts(thread_id, created_at, id)") + db.query("CREATE INDEX idx_users_avatar ON users(avatar_id)") + db.query("CREATE INDEX idx_topics_slug ON topics(slug)") + db.query("CREATE INDEX idx_threads_slug ON threads(slug)") + end, } diff --git a/util.lua b/util.lua index cf693f4..4e37e13 100644 --- a/util.lua +++ b/util.lua @@ -4,6 +4,8 @@ local db = require("lapis.db") local Avatars = require("models").Avatars local Users = require("models").Users +local Posts = require("models").Posts +local PostHistory = require("models").PostHistory util.TransientUser = { is_admin = function (self) @@ -15,6 +17,7 @@ util.TransientUser = { is_logged_in_guest = function (self) return false end, + username = "Deleted User", } function util.get_user_avatar_url(req, user) @@ -94,4 +97,29 @@ 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({ + thread_id = thread_id, + user_id = user_id, + current_revision_id = db.NULL, + }) + + local revision = PostHistory:create({ + post_id = post.id, + user_id = user_id, + content = content, + is_initial_revision = true, + }) + + post:update({current_revision_id = revision.id}) + + db.query("COMMIT") + return post +end + return util \ No newline at end of file diff --git a/views/threads/create.etlua b/views/threads/create.etlua new file mode 100644 index 0000000..2f4d205 --- /dev/null +++ b/views/threads/create.etlua @@ -0,0 +1,13 @@ +
<%- require("lapis.html").escape(post.content):gsub("\n", "
") %>