diff --git a/README.md b/README.md index c90c36d..5edea66 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,6 @@ this is all off the top of my head so if you try to run it got help you - luaossl i think thats it + +# icons +the icons in the `icons/` folder are by [Gabriele Malaspina](https://www.figma.com/community/file/1136337054881623512/iconcino-v2-0-0-free-icons-cc0-1-0-license) diff --git a/app.lua b/app.lua index 535c5e8..174d765 100644 --- a/app.lua +++ b/app.lua @@ -11,14 +11,21 @@ local util = require("util") app:enable("etlua") app.layout = require "views.base" +local function inject_constants(req) + req.constants = constants +end + local function inject_methods(req) req.avatar_url = util.get_user_avatar_url req.ntob = function(_, v) return util.ntob(v) end req.PermissionLevelString = constants.PermissionLevelString + + util.pop_infobox(req) end +app:before_filter(inject_constants) app:before_filter(inject_methods) app:include("apps.users", {path = "/user"}) diff --git a/apps/threads.lua b/apps/threads.lua index 004ba86..417f8ad 100644 --- a/apps/threads.lua +++ b/apps/threads.lua @@ -14,7 +14,7 @@ local POSTS_PER_PAGE = 10 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."} + util.inject_err_infobox(self, "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;") @@ -30,7 +30,7 @@ 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."} + util.inject_err_infobox(self, "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) diff --git a/apps/users.lua b/apps/users.lua index 1d98165..0d11dde 100644 --- a/apps/users.lua +++ b/apps/users.lua @@ -66,11 +66,6 @@ app:get("user", "/:username", function(self) return {status = 404} end - if self.session.flash ~= nil and self.session.flash.just_logged_in then - self.just_logged_in = true - self.session.flash = {} - end - local me = util.get_logged_in_user_or_transient(self) self.user = user self.me = me @@ -110,7 +105,7 @@ app:post("user_delete", "/:username/delete", function(self) -- i might make a separate route for it later, but guesting users is possible local me = util.get_logged_in_user(self) if me == nil then - self.session.flash = {error = "You must be logged in to perform this action."} + util.inject_err_infobox(self, "You must be logged in to perform this action.") return {redirect_to = self:url_for("user_login")} end local target_user = Users:find({username = self.params.username}) @@ -120,29 +115,25 @@ app:post("user_delete", "/:username/delete", function(self) end if not authenticate_user(target_user, self.params.password) then - self.session.flash = {error = "The password you entered is incorrect."} + util.inject_err_infobox(self, "The password you entered is incorrect.") return {redirect_to = self:url_for("user_delete_confirm", {username = me.username})} end util.transfer_and_delete_user(target_user) - self.session.flash = {error = "Your account has been added to the deletion queue."} + util.inject_infobox(self, "Your account has been added to the deletion queue.") return {redirect_to = self:url_for("user_signup")} end) app:get("user_delete_confirm", "/:username/delete_confirm", function(self) local me = util.get_logged_in_user(self) if me == nil then - self.session.flash = {error = "You must be logged in to perform this action."} + -- util.inject_err_infobox(self, "You must be logged in to perform this action.") return {redirect_to = self:url_for("user_login")} end local target_user = Users:find({username = self.params.username}) if me.id ~= target_user.id then return {redirect_to = self:url_for("user", {username = self.params.username})} end - if self.session.flash then - self.err = self.session.flash.error - self.session.flash = {} - end self.me = target_user self.page_title = "confirm deletion" @@ -152,7 +143,7 @@ end) app:post("user_clear_avatar", "/:username/clear_avatar", function(self) local me = util.get_logged_in_user(self) if me == nil then - self.session.flash = {error = "You must be logged in to perform this action."} + util.inject_err_infobox(self, "You must be logged in to perform this action.") return {redirect_to = self:url_for("user_login")} end local target_user = Users:find({username = self.params.username}) @@ -162,14 +153,14 @@ app:post("user_clear_avatar", "/:username/clear_avatar", function(self) target_user:update({ avatar_id = db.NULL, }) - self.session.flash = {success = true, msg = "Avatar cleared."} + util.inject_infobox(self, "Avatar cleared.") return {redirect_to = self:url_for("user_settings", {username = self.params.username})} end) app:post("user_set_avatar", "/:username/set_avatar", function(self) local me = util.get_logged_in_user(self) if me == nil then - self.session.flash = {error = "You must be logged in to perform this action."} + util.inject_err_infobox(self, "You must be logged in to perform this action.") return {redirect_to = self:url_for("user_login")} end local target_user = Users:find({username = self.params.username}) @@ -178,7 +169,7 @@ app:post("user_set_avatar", "/:username/set_avatar", function(self) end local file = self.params.avatar if not file then - self.session.flash = {error = "Something went wrong. Try again later."} + util.inject_warn_infobox(self, "Something went wrong. Try again later.") return {redirect_to = self:url_for("user_settings", {username = self.params.username})} end local time = os.time() @@ -187,11 +178,11 @@ app:post("user_set_avatar", "/:username/set_avatar", function(self) local save_path = "static" .. proxied_filename local res = util.validate_and_create_image(file.content, save_path) if not res then - self.session.flash = {error = "Something went wrong. Try again later."} + util.inject_warn_infobox(self, "Something went wrong. Try again later.") return {redirect_to = self:url_for("user_settings", {username = self.params.username})} end - self.session.flash = {success = true, msg = "Avatar updated."} + util.inject_infobox(self, "Avatar updated.") local avatar = Avatars:create({ file_path = proxied_filename, uploaded_at = time, @@ -207,22 +198,13 @@ end) app:get("user_settings", "/:username/settings", function(self) local me = util.get_logged_in_user(self) if me == nil then - self.session.flash = {error = "You must be logged in to perform this action."} + util.inject_err_infobox(self, "You must be logged in to perform this action.") return {redirect_to = self:url_for("user_login")} end local target_user = Users:find({username = self.params.username}) if me.id ~= target_user.id then return {redirect_to = self:url_for("user", {username = self.params.username})} end - if self.session.flash then - local flash = self.session.flash - self.session.flash = nil - if flash.success then - self.flash_msg = flash.msg - elseif flash.error then - self.flash_msg = flash.error - end - end self.me = target_user self.page_title = "settings" @@ -232,7 +214,7 @@ end) app:post("user_settings", "/:username/settings", function(self) local me = util.get_logged_in_user(self) if me == nil then - self.session.flash = {error = "You must be logged in to perform this action."} + util.inject_err_infobox(self, "You must be logged in to perform this action.") return {redirect_to = self:url_for("user_login")} end local target_user = Users:find({username = self.params.username}) @@ -245,10 +227,7 @@ app:post("user_settings", "/:username/settings", function(self) target_user:update({ status = status, }) - self.session.flash = { - success = true, - msg = "Settings updated." - } + util.inject_infobox(self, "Status updated.") return {redirect_to = self:url_for("user_settings", {username = self.params.username})} end) @@ -260,11 +239,6 @@ app:get("user_login", "/login", function(self) end end - if self.session.flash then - self.err = self.session.flash.error - self.session.flash = {} - end - self.page_title = "log in" return {render = "user.login"} @@ -281,19 +255,19 @@ app:post("user_login", "/login", function(self) local password = self.params.password local user = Users:find({username = username}) if not user then - self.session.flash = {error = "Invalid username or password"} + util.inject_err_infobox(self, "Invalid username or password") return {redirect_to = self:url_for("user_login")} end if user.permission == constants.PermissionLevel.SYSTEM then - self.session.flash = {error = "Invalid username or password"} + util.inject_err_infobox(self, "Invalid username or password") return {redirect_to = self:url_for("user_login")} end if not authenticate_user(user, password) then - self.session.flash = {error = "Invalid username or password"} + util.inject_err_infobox(self, "Invalid username or password") return {redirect_to = self:url_for("user_login")} end local session = create_session(user.id) - self.session.flash = {just_logged_in = true} + util.inject_infobox(self, "Logged in successfully.") self.session.session_key = session.key return {redirect_to = self:url_for("user", {username = username})} end) @@ -305,10 +279,6 @@ app:get("user_signup", "/signup", function(self) return {redirect_to = self:url_for("user", {username = user.username})} end end - if self.session.flash then - self.err = self.session.flash.error - self.session.flash = {} - end self.page_title = "sign up" @@ -328,22 +298,22 @@ app:post("user_signup", "/signup", function(self) local password2 = self.params.password2 local user = Users:find({username = username}) if user then - self.session.flash = {error = "Username '" .. username .. "' is already taken."} + util.inject_err_infobox(self, "Username '" .. username .. "' is already taken.") return {redirect_to = self:url_for("user_signup")} end if not validate_username(username) then - self.session.flash = {error = "Username must be 3-20 characters with only upper and lowercase letters, hyphens, and underscores."} + util.inject_err_infobox(self, "Username must be 3-20 characters with only upper and lowercase letters, hyphens, and underscores.") return {redirect_to = self:url_for("user_signup")} end - + if not validate_password(password) then - self.session.flash = {error = "Password must be 10+ chars with: 1 uppercase, 1 lowercase, 1 number, 1 special char, and no spaces."} + util.inject_err_infobox(self, "Password must be 10+ chars with: 1 uppercase, 1 lowercase, 1 number, 1 special char, and no spaces.") return {redirect_to = self:url_for("user_signup")} end - + if password ~= password2 then - self.session.flash = {error = "Passwords do not match."} + util.inject_err_infobox(self, "Passwords do not match.") return {redirect_to = self:url_for("user_signup")} end @@ -354,7 +324,7 @@ app:post("user_signup", "/signup", function(self) }) local session = create_session(new_user.id) - self.session.flash = {just_logged_in = true} + util.inject_infobox(self, "Siged up successfully.") self.session.session_key = session.key return {redirect_to = self:url_for("user", {username = username})} end) diff --git a/constants.lua b/constants.lua index 3cf0658..e949217 100644 --- a/constants.lua +++ b/constants.lua @@ -16,6 +16,26 @@ Constants.PermissionLevelString = { [Constants.PermissionLevel.ADMIN] = "Administrator", } +Constants.InfoboxKind = { + INFO = 0, + LOCK = 1, + WARN = 2, + ERROR = 3, +} + +Constants.InfoboxIcons = { + [Constants.InfoboxKind.INFO] = "svg-icons.info", + [Constants.InfoboxKind.LOCK] = "svg-icons.lock", + [Constants.InfoboxKind.WARN] = "svg-icons.warn", + [Constants.InfoboxKind.ERROR] = "svg-icons.error", +} +Constants.InfoboxHTMLClass = { + [Constants.InfoboxKind.INFO] = "", + [Constants.InfoboxKind.LOCK] = "warn", + [Constants.InfoboxKind.WARN] = "warn", + [Constants.InfoboxKind.ERROR] = "critical", +} + Constants.BCRYPT_ROUNDS = 10 return Constants diff --git a/sass/style.scss b/sass/style.scss index 7c3cbd6..05aaae3 100644 --- a/sass/style.scss +++ b/sass/style.scss @@ -253,3 +253,27 @@ input[type="text"], input[type="password"] { box-sizing: border-box; background-color: $lighter; } + +.infobox { + border: 2px solid black; + background-color: $accent_color; + padding: 20px 15px; + + &.critical { + background-color: rgb(237, 129, 129); + } + + &.warn { + background-color: #fbfb8d; + } +} + +.infobox > span { + display: flex; + align-items: center; +} + +.infobox-icon-container { + min-width: 60px; + padding-right: 15px; +} diff --git a/static/style.css b/static/style.css index d47f189..f13b69a 100644 --- a/static/style.css +++ b/static/style.css @@ -245,3 +245,25 @@ input[type=text], input[type=password] { box-sizing: border-box; background-color: rgb(229.84, 231.92, 227.28); } + +.infobox { + border: 2px solid black; + background-color: #c1ceb1; + padding: 20px 15px; +} +.infobox.critical { + background-color: rgb(237, 129, 129); +} +.infobox.warn { + background-color: #fbfb8d; +} + +.infobox > span { + display: flex; + align-items: center; +} + +.infobox-icon-container { + min-width: 60px; + padding-right: 15px; +} diff --git a/svg-icons/error.etlua b/svg-icons/error.etlua new file mode 100644 index 0000000..c9ea78a --- /dev/null +++ b/svg-icons/error.etlua @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/svg-icons/info.etlua b/svg-icons/info.etlua new file mode 100644 index 0000000..fece45b --- /dev/null +++ b/svg-icons/info.etlua @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/svg-icons/lock.etlua b/svg-icons/lock.etlua new file mode 100644 index 0000000..d628b13 --- /dev/null +++ b/svg-icons/lock.etlua @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/svg-icons/warn.etlua b/svg-icons/warn.etlua new file mode 100644 index 0000000..d4b2c93 --- /dev/null +++ b/svg-icons/warn.etlua @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/util.lua b/util.lua index e4e3f04..044b8b0 100644 --- a/util.lua +++ b/util.lua @@ -2,6 +2,7 @@ local util = {} local magick = require("magick") local db = require("lapis.db") local html_escape = require("lapis.html").escape +local constants = require("constants") local Avatars = require("models").Avatars local Users = require("models").Users @@ -147,4 +148,37 @@ function util.transfer_and_delete_user(user) db.query("COMMIT") end +function util.pop_infobox(req) + print("1") + if not req.session.infobox then return end + print("2") + req.infobox = req.session.infobox + req.session.infobox = nil +end + +function util.inject_infobox(req, message, kind) + kind = kind or constants.InfoboxKind.INFO + local ib = { + msg = message, + kind = kind, + } + req.session.infobox = ib +end + +function util.inject_err_infobox(req, message) + local ib = { + msg = message, + kind = constants.InfoboxKind.ERROR, + } + req.session.infobox = ib +end + +function util.inject_warn_infobox(req, message) + local ib = { + msg = message, + kind = constants.InfoboxKind.WARN, + } + req.session.infobox = ib +end + return util diff --git a/views/common/infobox.etlua b/views/common/infobox.etlua new file mode 100644 index 0000000..b5c851e --- /dev/null +++ b/views/common/infobox.etlua @@ -0,0 +1,13 @@ +<% + local class = "infobox " .. constants.InfoboxHTMLClass[kind] + local icon = constants.InfoboxIcons[kind] +%> + +
+ +
+ <% render(icon) %> +
+ <%= msg %> +
+
diff --git a/views/threads/thread.etlua b/views/threads/thread.etlua index 3b33158..f4d5344 100644 --- a/views/threads/thread.etlua +++ b/views/threads/thread.etlua @@ -1,4 +1,5 @@ <% render("views.common.topnav") -%> +<% local is_locked = ntob(thread.is_locked) %>
-<% if not me:is_guest() then %> +<% if is_locked then -%> + <% render("views.common.infobox", {kind = constants.InfoboxKind.LOCK, msg = "This thread is locked."}) %> +<% end -%> +<% if not me:is_guest() and not is_locked then %>

Respond to "<%= thread.title %>"


- +
<% end %> diff --git a/views/user/delete_confirm.etlua b/views/user/delete_confirm.etlua index 2f447fd..66114b9 100644 --- a/views/user/delete_confirm.etlua +++ b/views/user/delete_confirm.etlua @@ -4,8 +4,8 @@

This cannot be undone. This will not delete your posts, only anonymize them.

If you are sure, please type your password below.

- <% if err then %> -

<%= err %>

+ <% if infobox then %> + <% render("views.common.infobox", infobox) %> <% end %>
"> diff --git a/views/user/login.etlua b/views/user/login.etlua index 5f47e6d..fcd710a 100644 --- a/views/user/login.etlua +++ b/views/user/login.etlua @@ -1,8 +1,8 @@ <% render("views.common.topnav") -%>