add subscribing and unsubscribing to threads
This commit is contained in:
parent
1e23959e52
commit
bd1ba6c087
@ -9,6 +9,7 @@ local models = require("models")
|
|||||||
local Topics = models.Topics
|
local Topics = models.Topics
|
||||||
local Threads = models.Threads
|
local Threads = models.Threads
|
||||||
local Posts = models.Posts
|
local Posts = models.Posts
|
||||||
|
local Subscriptions = models.Subscriptions
|
||||||
|
|
||||||
local POSTS_PER_PAGE = 10
|
local POSTS_PER_PAGE = 10
|
||||||
|
|
||||||
@ -98,6 +99,17 @@ app:get("thread", "/:slug", function(self)
|
|||||||
self.me = util.get_logged_in_user_or_transient(self)
|
self.me = util.get_logged_in_user_or_transient(self)
|
||||||
self.posts = posts
|
self.posts = posts
|
||||||
|
|
||||||
|
if self.me:is_logged_in() then
|
||||||
|
self.is_subscribed = false
|
||||||
|
local subscription = Subscriptions:find({user_id = self.me.id, thread_id = thread.id})
|
||||||
|
if subscription then
|
||||||
|
self.is_subscribed = true
|
||||||
|
if posts[#posts].created_at > subscription.last_seen then
|
||||||
|
subscription:update({last_seen = os.time()})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
self.page_title = thread.title
|
self.page_title = thread.title
|
||||||
|
|
||||||
return {render = "threads.thread"}
|
return {render = "threads.thread"}
|
||||||
@ -133,6 +145,10 @@ app:post("thread", "/:slug", function(self)
|
|||||||
return {redirect_to = self:url_for("thread", {slug = thread.slug}, {page = last_page}) .. "#latest-post"}
|
return {redirect_to = self:url_for("thread", {slug = thread.slug}, {page = last_page}) .. "#latest-post"}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self.params.subscribe == "on" then
|
||||||
|
Subscriptions:create({user_id = user.id, thread_id = thread.id, last_seen = os.time()})
|
||||||
|
end
|
||||||
|
|
||||||
return {redirect_to = self:url_for("thread", {slug = thread.slug}, {page = last_page}) .. "#latest-post"}
|
return {redirect_to = self:url_for("thread", {slug = thread.slug}, {page = last_page}) .. "#latest-post"}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@ -206,4 +222,32 @@ app:post("thread_move", "/:slug/move", function(self)
|
|||||||
return {redirect_to = self:url_for("thread", {slug = self.params.slug})}
|
return {redirect_to = self:url_for("thread", {slug = self.params.slug})}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
app:post("thread_subscribe", "/:slug/subscribe", function(self)
|
||||||
|
local user = util.get_logged_in_user(self)
|
||||||
|
if not user then
|
||||||
|
return {status = 403}
|
||||||
|
end
|
||||||
|
local thread = Threads:find({slug = self.params.slug})
|
||||||
|
if not thread then
|
||||||
|
return {status = 404}
|
||||||
|
end
|
||||||
|
local subscription = Subscriptions:find({user_id = user.id, thread_id = thread.id})
|
||||||
|
if self.params.subscribe == "subscribe" then
|
||||||
|
local now = os.time()
|
||||||
|
if subscription then
|
||||||
|
subscription:delete()
|
||||||
|
end
|
||||||
|
Subscriptions:create({user_id = user.id, thread_id = thread.id, last_seen = now})
|
||||||
|
return {redirect_to = self:url_for("thread", {slug = thread.slug}, {after = self.params.first_visible_post})}
|
||||||
|
elseif self.params.subscribe == "unsubscribe" then
|
||||||
|
if not subscription then
|
||||||
|
return {status = 404}
|
||||||
|
end
|
||||||
|
subscription:delete()
|
||||||
|
return {redirect_to = self:url_for("thread", {slug = thread.slug}, {after = self.params.first_visible_post})}
|
||||||
|
end
|
||||||
|
|
||||||
|
return {status = 400}
|
||||||
|
end)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
@ -102,4 +102,15 @@ return {
|
|||||||
|
|
||||||
db.query("CREATE INDEX idx_rate_limit_user_method ON api_rate_limits (user_id, method)")
|
db.query("CREATE INDEX idx_rate_limit_user_method ON api_rate_limits (user_id, method)")
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
[13] = function ()
|
||||||
|
schema.create_table("subscriptions", {
|
||||||
|
{"id", types.integer{primary_key = true}},
|
||||||
|
{"user_id", "INTEGER REFERENCES users(id) ON DELETE CASCADE"},
|
||||||
|
{"thread_id", "INTEGER REFERENCES threads(id) ON DELETE CASCADE"},
|
||||||
|
{"last_seen", "INTEGER DEFAULT (unixepoch(CURRENT_TIMESTAMP)) NOT NULL"},
|
||||||
|
})
|
||||||
|
|
||||||
|
db.query("CREATE INDEX idx_subscription_user_thread ON subscriptions (user_id, thread_id)")
|
||||||
|
end,
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ local ret = {
|
|||||||
PostHistory = Model:extend("post_history"),
|
PostHistory = Model:extend("post_history"),
|
||||||
Sessions = Model:extend("sessions"),
|
Sessions = Model:extend("sessions"),
|
||||||
Avatars = Model:extend("avatars"),
|
Avatars = Model:extend("avatars"),
|
||||||
|
Subscriptions = Model:extend("subscriptions"),
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
7
util.lua
7
util.lua
@ -105,13 +105,16 @@ function util.split_sentences(sentences, max_sentences)
|
|||||||
end
|
end
|
||||||
|
|
||||||
---@return string
|
---@return string
|
||||||
function util.get_post_url(req, post_id)
|
function util.get_post_url(req, post_id, hash)
|
||||||
|
hash = hash ~= false
|
||||||
local post = Posts:find({id = post_id})
|
local post = Posts:find({id = post_id})
|
||||||
if not post then return "" end
|
if not post then return "" end
|
||||||
local thread = Threads:find({id = post.thread_id})
|
local thread = Threads:find({id = post.thread_id})
|
||||||
if not thread then return "" end
|
if not thread then return "" end
|
||||||
|
|
||||||
return req:url_for("thread", {slug = thread.slug}, {after = post_id}) .. "#post-" .. post_id
|
local url = req:url_for("thread", {slug = thread.slug}, {after = post_id})
|
||||||
|
if not hash then return url end
|
||||||
|
return url .. "#post-" .. post_id
|
||||||
end
|
end
|
||||||
|
|
||||||
function util.infobox_message(msg)
|
function util.infobox_message(msg)
|
||||||
|
@ -6,6 +6,12 @@
|
|||||||
%>
|
%>
|
||||||
<form class="post-edit-form" method="post" action="<%= url or "" %>">
|
<form class="post-edit-form" method="post" action="<%= url or "" %>">
|
||||||
<% render ("views.common.babycode-editor-component", {ta_name = ta_name, prefill = prefill}) %>
|
<% render ("views.common.babycode-editor-component", {ta_name = ta_name, prefill = prefill}) %>
|
||||||
|
<% if not cancel_url then %>
|
||||||
|
<span>
|
||||||
|
<input type="checkbox" id="subscribe" name="subscribe" checked>
|
||||||
|
<label for="subscribe">Subscribe to thread</label>
|
||||||
|
</span>
|
||||||
|
<% end %>
|
||||||
<span>
|
<span>
|
||||||
<input type=submit value="<%= save_button_text %>">
|
<input type=submit value="<%= save_button_text %>">
|
||||||
<% if cancel_url then %>
|
<% if cancel_url then %>
|
||||||
|
@ -14,29 +14,36 @@
|
|||||||
<% if is_stickied then %> • <i>stickied, so it's probably important</i>
|
<% if is_stickied then %> • <i>stickied, so it's probably important</i>
|
||||||
<% end %>
|
<% end %>
|
||||||
</span>
|
</span>
|
||||||
<% if can_lock then %>
|
|
||||||
<div>
|
<div>
|
||||||
<form class="modform" action="<%= url_for("thread_lock", {slug = thread.slug}) %>" method="post">
|
<% if me:is_logged_in() then %>
|
||||||
<input type=hidden value="<%= not is_locked %>" name="target_op">
|
<form class="modform" action="<%= url_for("thread_subscribe", {slug = thread.slug}) %>" method="post">
|
||||||
<input class="warn" type="submit" value="<%= is_locked and "Unlock thread" or "Lock thread" %>">
|
<input type="hidden" name="first_visible_post" value=<%= posts[1].id %>>
|
||||||
</form>
|
<input type="hidden" name="subscribe" value=<%= is_subscribed and "unsubscribe" or "subscribe" %>>
|
||||||
<% if me:is_mod() then %>
|
<input type="submit" value="<%= is_subscribed and "Unsubscribe" or "Subscribe" %>">
|
||||||
<form class="modform" action="<%= url_for("thread_sticky", {slug = thread.slug}) %>" method="post">
|
|
||||||
<input type=hidden value="<%= not is_stickied %>" name="target_op">
|
|
||||||
<input class="warn" type="submit" value="<%= is_stickied and "Unsticky thread" or "Sticky thread" %>">
|
|
||||||
</form>
|
|
||||||
<form class="modform" action="<%= url_for("thread_move", {slug = thread.slug}) %>" method="post">
|
|
||||||
<label for="new_topic_id">Move to topic:</label>
|
|
||||||
<select style="width:200px;" id="new_topic_id" name="new_topic_id" autocomplete="off">
|
|
||||||
<% for _, topic in ipairs(other_topics) do %>
|
|
||||||
<option value="<%= topic.id %>" <%- thread.topic_id == topic.id and "selected disabled" or "" %>><%= topic.name %></option>
|
|
||||||
<% end %>
|
|
||||||
</select>
|
|
||||||
<input class="warn" type="submit" value="Move thread">
|
|
||||||
</form>
|
</form>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<% if can_lock then %>
|
||||||
|
<form class="modform" action="<%= url_for("thread_lock", {slug = thread.slug}) %>" method="post">
|
||||||
|
<input type=hidden value="<%= not is_locked %>" name="target_op">
|
||||||
|
<input class="warn" type="submit" value="<%= is_locked and "Unlock thread" or "Lock thread" %>">
|
||||||
|
</form>
|
||||||
|
<% if me:is_mod() then %>
|
||||||
|
<form class="modform" action="<%= url_for("thread_sticky", {slug = thread.slug}) %>" method="post">
|
||||||
|
<input type=hidden value="<%= not is_stickied %>" name="target_op">
|
||||||
|
<input class="warn" type="submit" value="<%= is_stickied and "Unsticky thread" or "Sticky thread" %>">
|
||||||
|
</form>
|
||||||
|
<form class="modform" action="<%= url_for("thread_move", {slug = thread.slug}) %>" method="post">
|
||||||
|
<label for="new_topic_id">Move to topic:</label>
|
||||||
|
<select style="width:200px;" id="new_topic_id" name="new_topic_id" autocomplete="off">
|
||||||
|
<% for _, topic in ipairs(other_topics) do %>
|
||||||
|
<option value="<%= topic.id %>" <%- thread.topic_id == topic.id and "selected disabled" or "" %>><%= topic.name %></option>
|
||||||
|
<% end %>
|
||||||
|
</select>
|
||||||
|
<input class="warn" type="submit" value="Move thread">
|
||||||
|
</form>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
|
||||||
</nav>
|
</nav>
|
||||||
<% for i, post in ipairs(posts) do %>
|
<% for i, post in ipairs(posts) do %>
|
||||||
<% render("views.threads.post", {post = post, render_sig = true, is_latest = i == #posts}) %>
|
<% render("views.threads.post", {post = post, render_sig = true, is_latest = i == #posts}) %>
|
||||||
|
Loading…
Reference in New Issue
Block a user