Compare commits

...

5 Commits

13 changed files with 57 additions and 13 deletions

View File

@ -1,4 +1,5 @@
local lapis = require("lapis") local lapis = require("lapis")
local date = require("date")
local app = lapis.Application() local app = lapis.Application()
local constants = require("constants") local constants = require("constants")
local babycode = require("lib.babycode") local babycode = require("lib.babycode")
@ -14,6 +15,13 @@ local util = require("util")
app:enable("etlua") app:enable("etlua")
app.layout = require "views.base" app.layout = require "views.base"
app.cookie_attributes = function (self, name, value)
if name == config.session_name then
local expires = date(true):adddays(30):fmt("${http}")
return "Expires="..expires.."; Path=/; HttpOnly; Secure"
end
end
local function inject_constants(req) local function inject_constants(req)
req.constants = constants req.constants = constants
math.randomseed(os.time()) math.randomseed(os.time())

View File

@ -4,7 +4,6 @@ local secrets = require("secrets.secrets")
local commit = nil local commit = nil
local f = io.open(".git/refs/heads/main", "r") local f = io.open(".git/refs/heads/main", "r")
if f then if f then
print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!read commit")
commit = f:read(8) commit = f:read(8)
f:close() f:close()
end end

View File

@ -435,6 +435,12 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus
width: 50%; width: 50%;
} }
.block-img {
object-fit: contain;
max-width: 400px;
max-height: 400px;
}
.thread-info-container { .thread-info-container {
grid-area: thread-info-container; grid-area: thread-info-container;
background-color: #c1ceb1; background-color: #c1ceb1;

10
js/date-fmt.js Normal file
View File

@ -0,0 +1,10 @@
document.addEventListener("DOMContentLoaded", () => {
const timestampSpans = document.getElementsByClassName("timestamp");
for (let timestampSpan of timestampSpans) {
const timestamp = parseInt(timestampSpan.dataset.utc);
if (!isNaN(timestamp)) {
const date = new Date(timestamp * 1000);
timestampSpan.textContent = date.toLocaleString();
}
}
})

View File

@ -96,6 +96,13 @@ function babycode.to_html(s, escape_html)
return "<ol>" .. get_list_items(list_body, escape_html) .. "</ol>" return "<ol>" .. get_list_items(list_body, escape_html) .. "</ol>"
end) end)
-- images
local images = {}
text = text:gsub("%[img=(.-)%](.-)%[/img%]", function (img, alt)
table.insert(images, {img = img, alt = alt})
return "\1IMG:"..#images.."\1"
end)
-- normalize newlines, attempt #4 -- normalize newlines, attempt #4
text = text:gsub(" +%s*\r?\n", "<br>") text = text:gsub(" +%s*\r?\n", "<br>")
text = text:gsub("(%S)(\r?\n\r?\n)\r?\n*", "%1<br><br>") text = text:gsub("(%S)(\r?\n\r?\n)\r?\n*", "%1<br><br>")
@ -131,6 +138,11 @@ function babycode.to_html(s, escape_html)
-- rule -- rule
text = text:gsub("\n+%-%-%-", "<hr>") text = text:gsub("\n+%-%-%-", "<hr>")
-- <div class=\"post-img-container\"><img src=%1 alt=%2></div>
text = text:gsub("\1IMG:(%d+)\1", function (n)
local img = images[tonumber(n)]
return ("<div class=\"block-img-container\"><img class=\"block-img\" src=\"%s\" alt=\"%s\"></div>"):format(img.img, img.alt)
end)
-- replace code block placeholders back with their original contents -- replace code block placeholders back with their original contents
text = text:gsub("\1CODE:(%d+)\1", function(n) text = text:gsub("\1CODE:(%d+)\1", function(n)
local code = code_blocks[tonumber(n)] local code = code_blocks[tonumber(n)]

View File

@ -447,6 +447,12 @@ input[type="text"], input[type="password"], textarea, select {
width: 50%; width: 50%;
} }
.block-img {
object-fit: contain;
max-width: 400px;
max-height: 400px;
}
.thread-info-container { .thread-info-container {
grid-area: thread-info-container; grid-area: thread-info-container;
background-color: $accent_color; background-color: $accent_color;

View File

@ -17,5 +17,6 @@
</span> </span>
</footer> </footer>
<script src="/static/js/copy-code.js"></script> <script src="/static/js/copy-code.js"></script>
<script src="/static/js/date-fmt.js"></script>
</body> </body>
</html> </html>

View File

@ -5,6 +5,7 @@
<li>[b]<b>bold</b>[/b]</li> <li>[b]<b>bold</b>[/b]</li>
<li>[i]<i>italic</i>[/i]</li> <li>[i]<i>italic</i>[/i]</li>
<li>[s]<del>strikethrough</del>[/s]</li> <li>[s]<del>strikethrough</del>[/s]</li>
<li>[img=https://example.com/some-image]alt text[/img] creates an image</li>
<li>[url=https://example.com]<a href="https://example.com">labeled URL</a>[/url]</li> <li>[url=https://example.com]<a href="https://example.com">labeled URL</a>[/url]</li>
<li> <li>
[ul] and [ol] are unordered and ordered lists: [ul] and [ol] are unordered and ordered lists:

View File

@ -0,0 +1 @@
<span class="timestamp" data-utc="<%= timestamp %>"><%= os.date("%c", timestamp) %></span>

View File

@ -22,14 +22,14 @@
%> %>
<a href="<%= post_url %>" title="Permalink"><i> <a href="<%= post_url %>" title="Permalink"><i>
<% if tonumber(post.edited_at) > tonumber(post.created_at) then -%> <% if tonumber(post.edited_at) > tonumber(post.created_at) then -%>
Edited at <%= os.date("%c", post.edited_at) %> Edited at <% render("views.common.timestamp", {timestamp = post.edited_at}) -%>
<% else -%> <% else -%>
Posted on <%= os.date("%c", post.created_at) %> Posted on <% render("views.common.timestamp", {timestamp = post.created_at}) -%>
<% end -%> <% end -%>
</i></a> </i></a>
<span> <span>
<% <%
local show_edit = me.id == post.user_id and not me:is_guest() and not ntob(thread.is_locked) and not no_reply local show_edit = me.id == post.user_id and not me:is_guest() and (not ntob(thread.is_locked) or me:is_mod()) and not no_reply
if show_edit then if show_edit then
%> %>
<a class="linkbutton" href="<%= url_for("edit_post", {post_id = post.id}) %>">Edit</a> <a class="linkbutton" href="<%= url_for("edit_post", {post_id = post.id}) %>">Edit</a>
@ -47,8 +47,8 @@
end end
if show_reply then if show_reply then
local d = post.created_at < post.edited_at and post.edited_at or post.created_at local d = post.created_at < post.edited_at and post.edited_at or post.created_at
local quote_src_text = ("On [url=%s]%s[/url], [url=%s]%s[/url] said:"):format( local quote_src_text = ("[url=%s]%s said:[/url]"):format(
post_url, os.date("%c", d), url_for("user", {username = post.username}), post.username post_url, post.username
) )
local reply_text = ("%s\n[quote]%s[/quote]\n---\n\n"):format(quote_src_text, post.original_markup) local reply_text = ("%s\n[quote]%s[/quote]\n---\n\n"):format(quote_src_text, post.original_markup)
%> %>

View File

@ -48,11 +48,11 @@
<span class="thread-title"><a href="<%= url_for("thread", {slug = thread.slug}) %>"><%= thread.title %></a></span> <span class="thread-title"><a href="<%= url_for("thread", {slug = thread.slug}) %>"><%= thread.title %></a></span>
&bullet; &bullet;
Started by <a href=<%= url_for("user", {username = thread.started_by}) %>><%= thread.started_by %></a> Started by <a href=<%= url_for("user", {username = thread.started_by}) %>><%= thread.started_by %></a>
on <%= os.date("%c", thread.created_at) %> on <% render("views.common.timestamp", {timestamp = thread.created_at}) -%>
</span> </span>
<span> <span>
Latest post by <a href="<%= url_for("user", {username = thread.latest_post_username}) %>"><%= thread.latest_post_username %></a> Latest post by <a href="<%= url_for("user", {username = thread.latest_post_username}) %>"><%= thread.latest_post_username %></a>
<a href="<%= url_for("thread", {slug = thread.slug}, {after = thread.latest_post_id}) .. "#post-" .. thread.latest_post_id %>">on <%= os.date("%c", thread.latest_post_created_at) %></a>: <a href="<%= url_for("thread", {slug = thread.slug}, {after = thread.latest_post_id}) .. "#post-" .. thread.latest_post_id %>">on <% render("views.common.timestamp", {timestamp = thread.latest_post_created_at}) -%></a>:
</span> </span>
<span class="thread-info-post-preview"> <span class="thread-info-post-preview">
<%- thread.latest_post_content %> <%- thread.latest_post_content %>

View File

@ -21,7 +21,7 @@
<%= topic.description %> <%= topic.description %>
<% if topic.latest_thread_username then %> <% if topic.latest_thread_username then %>
<span> <span>
Latest thread: <a href="<%= url_for("thread", {slug = topic.latest_thread_slug}) %>"><%= topic.latest_thread_title %></a> by <a href="<%= url_for("user", {username = topic.latest_thread_username}) %>"><%= topic.latest_thread_username %></a> on <%= os.date("%c", topic.latest_thread_created_at) %> Latest thread: <a href="<%= url_for("thread", {slug = topic.latest_thread_slug}) %>"><%= topic.latest_thread_title %></a> by <a href="<%= url_for("user", {username = topic.latest_thread_username}) %>"><%= topic.latest_thread_username %></a> on <% render("views.common.timestamp", {timestamp = topic.latest_thread_created_at}) -%>
</span> </span>
<% else %> <% else %>
<i>No threads yet.</i> <i>No threads yet.</i>

View File

@ -27,9 +27,9 @@
<div class="post-info"> <div class="post-info">
<div><a href="<%= url_for("thread", {slug = post.thread_slug}, {after = post.id}) .. "#post-" .. post.id %>" title="Permalink"><i> <div><a href="<%= url_for("thread", {slug = post.thread_slug}, {after = post.id}) .. "#post-" .. post.id %>" title="Permalink"><i>
<% if tonumber(post.edited_at) > tonumber(post.created_at) then -%> <% if tonumber(post.edited_at) > tonumber(post.created_at) then -%>
Edited in <%= post.thread_title %> at <%= os.date("%c", post.edited_at) %> Edited in <%= post.thread_title %> at <% render("views.common.timestamp", {timestamp = post.edited_at}) -%>
<% else -%> <% else -%>
Posted in <%= post.thread_title %> on <%= os.date("%c", post.created_at) %> Posted in <%= post.thread_title %> on <% render("views.common.timestamp", {timestamp = post.created_at}) -%>
<% end -%> <% end -%>
</i></a></div> </i></a></div>
</div> </div>
@ -48,12 +48,12 @@
<div class="darkbg"> <div class="darkbg">
<h1>Moderator controls</h2> <h1>Moderator controls</h2>
<% if user:is_guest() then %> <% if user:is_guest() then %>
<p>This user is a guest. They signed up on <%= os.date("%c", user.created_at) %>.</p> <p>This user is a guest. They signed up on <% render("views.common.timestamp", {timestamp = user.created_at}) -%>.</p>
<form class="modform" method="post" action="<%= url_for("confirm_user", {user_id = user.id}) %>"> <form class="modform" method="post" action="<%= url_for("confirm_user", {user_id = user.id}) %>">
<input type="submit" value="Confirm user"> <input type="submit" value="Confirm user">
</form> </form>
<% else %> <% --[[ user is not guest ]] %> <% else %> <% --[[ user is not guest ]] %>
<p>This user signed up on <%= os.date("%c", user.created_at) %> and was confirmed on <%= os.date("%c", user.confirmed_on) %>.</p> <p>This user signed up on <% render("views.common.timestamp", {timestamp = user.created_at}) -%> and was confirmed on <% render("views.common.timestamp", {timestamp = user.confirmed_on}) %>.</p>
<% if user.permission < me.permission then %> <% if user.permission < me.permission then %>
<form class="modform" method="post" action="<%= url_for("guest_user", {user_id = user.id}) %>"> <form class="modform" method="post" action="<%= url_for("guest_user", {user_id = user.id}) %>">
<input class="warn" type="submit" value="Demote user to guest (soft ban)"> <input class="warn" type="submit" value="Demote user to guest (soft ban)">