add userboxes and use them instead of flash
This commit is contained in:
		@@ -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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								app.lua
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								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"})
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								svg-icons/error.etlua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								svg-icons/error.etlua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
<!-- https://www.figma.com/community/file/1136337054881623512/iconcino-v2-0-0-free-icons-cc0-1-0-license -->
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<svg width="60px" height="60px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
 | 
			
		||||
<path d="M18.364 5.63604C19.9926 7.26472 21 9.51472 21 12C21 16.9706 16.9706 21 12 21C9.51472 21 7.26472 19.9926 5.63604 18.364M18.364 5.63604C16.7353 4.00736 14.4853 3 12 3C7.02944 3 3 7.02944 3 12C3 14.4853 4.00736 16.7353 5.63604 18.364M18.364 5.63604L5.63604 18.364" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
 | 
			
		||||
</svg>
 | 
			
		||||
							
								
								
									
										5
									
								
								svg-icons/info.etlua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								svg-icons/info.etlua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
<!-- https://www.figma.com/community/file/1136337054881623512/iconcino-v2-0-0-free-icons-cc0-1-0-license -->
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<svg width="60px" height="60px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
 | 
			
		||||
<path d="M12 8V8.5M12 12V16M12 21C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
 | 
			
		||||
</svg>
 | 
			
		||||
							
								
								
									
										5
									
								
								svg-icons/lock.etlua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								svg-icons/lock.etlua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
<!-- https://www.figma.com/community/file/1136337054881623512/iconcino-v2-0-0-free-icons-cc0-1-0-license -->
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<svg width="60px" height="60px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
 | 
			
		||||
<path d="M12 14V16M8 9V6C8 3.79086 9.79086 2 12 2C14.2091 2 16 3.79086 16 6V9M7 21H17C18.1046 21 19 20.1046 19 19V11C19 9.89543 18.1046 9 17 9H7C5.89543 9 5 9.89543 5 11V19C5 20.1046 5.89543 21 7 21Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
 | 
			
		||||
</svg>
 | 
			
		||||
							
								
								
									
										5
									
								
								svg-icons/warn.etlua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								svg-icons/warn.etlua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
<!-- https://www.figma.com/community/file/1136337054881623512/iconcino-v2-0-0-free-icons-cc0-1-0-license -->
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<svg width="60px" height="60px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
 | 
			
		||||
<path d="M12 15H12.01M12 12V9M4.98207 19H19.0179C20.5615 19 21.5233 17.3256 20.7455 15.9923L13.7276 3.96153C12.9558 2.63852 11.0442 2.63852 10.2724 3.96153L3.25452 15.9923C2.47675 17.3256 3.43849 19 4.98207 19Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
 | 
			
		||||
</svg>
 | 
			
		||||
							
								
								
									
										34
									
								
								util.lua
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								views/common/infobox.etlua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								views/common/infobox.etlua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
<%
 | 
			
		||||
  local class = "infobox " .. constants.InfoboxHTMLClass[kind]
 | 
			
		||||
  local icon = constants.InfoboxIcons[kind]
 | 
			
		||||
%>
 | 
			
		||||
 | 
			
		||||
<div class="<%= class %>">
 | 
			
		||||
  <span>
 | 
			
		||||
  <div class="infobox-icon-container">
 | 
			
		||||
  <% render(icon) %>
 | 
			
		||||
  </div>
 | 
			
		||||
    <%= msg %>
 | 
			
		||||
  </span>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
<% render("views.common.topnav") -%>
 | 
			
		||||
<% local is_locked = ntob(thread.is_locked) %>
 | 
			
		||||
<main>
 | 
			
		||||
  <nav class="darkbg">
 | 
			
		||||
    <h1 class="thread-title"><%= thread.title %></h1>
 | 
			
		||||
@@ -13,10 +14,13 @@
 | 
			
		||||
  <% render("views.common.pagination", {page_count = pages, current_page = page}) %>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<% 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 %>
 | 
			
		||||
<h1>Respond to "<%= thread.title %>"</h1>
 | 
			
		||||
<form method="post">
 | 
			
		||||
  <textarea id="post_content" name="post_content" placeholder="Response body" required></textarea><br>
 | 
			
		||||
  <input type="submit" value="Reply">
 | 
			
		||||
  <input type="submit" value="Post reply">
 | 
			
		||||
</form>
 | 
			
		||||
<% end %>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,8 +4,8 @@
 | 
			
		||||
  <p>This cannot be undone. This will not delete your posts, only anonymize them.</p>
 | 
			
		||||
  <p>If you are sure, please type your password below.</p>
 | 
			
		||||
 | 
			
		||||
  <% if err then %>
 | 
			
		||||
    <h2><%= err %></h2>
 | 
			
		||||
  <% if infobox then %>
 | 
			
		||||
    <% render("views.common.infobox", infobox) %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
 | 
			
		||||
  <form method="post" action="<%= url_for("user_delete", {username = me.username}) %>">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<% render("views.common.topnav") -%>
 | 
			
		||||
<div class="darkbg login-container">
 | 
			
		||||
  <h1>Log In</h1>
 | 
			
		||||
  <% if err then %>
 | 
			
		||||
    <h2><%= err %></h2>
 | 
			
		||||
  <% if infobox then %>
 | 
			
		||||
    <% render("views.common.infobox", infobox) %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
  <form method="post" action="<%= url_for('user_login') %>" enctype="multipart/form-data">
 | 
			
		||||
    <label for="username">Username</label><br>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<% render("views.common.topnav") -%>
 | 
			
		||||
<div class="darkbg settings-container">
 | 
			
		||||
  <h1>User settings</h1>
 | 
			
		||||
  <% if flash_msg then %>
 | 
			
		||||
    <h2><%= flash_msg %></h2>
 | 
			
		||||
  <% if infobox then %>
 | 
			
		||||
    <% render("views.common.infobox", infobox) %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
  <form class="avatar-form" method="post" action="<%= url_for("user_set_avatar", {username = me.username}) %>" enctype="multipart/form-data">
 | 
			
		||||
    <img src="<%= avatar_url(me) %>">
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
    <div>
 | 
			
		||||
    <input type="submit" value="Update avatar">
 | 
			
		||||
  <% if not me:is_default_avatar() then %>
 | 
			
		||||
    <input type="submit" value="Clear avatar" formaction="<%= url_for("user_clear_avatar", {username = me.username}) %>">
 | 
			
		||||
    <input type="submit" value="Clear avatar" formaction="<%= url_for("user_clear_avatar", {username = me.username}) %>" formnovalidate>
 | 
			
		||||
  <% end %>
 | 
			
		||||
  </div>
 | 
			
		||||
  </form>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<% render("views.common.topnav") -%>
 | 
			
		||||
<div class="darkbg login-container">
 | 
			
		||||
  <h1>Sign up</h1>
 | 
			
		||||
  <% if err then %>
 | 
			
		||||
    <h2><%= err %></h2>
 | 
			
		||||
  <% if infobox then %>
 | 
			
		||||
    <% render("views.common.infobox", infobox) %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
  <form method="post" action="<%= url_for('user_signup') %>" enctype="multipart/form-data">
 | 
			
		||||
    <label for="username">Username</label><br>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<% if just_logged_in then %>
 | 
			
		||||
  <h1>Logged in successfully.</h1>
 | 
			
		||||
<% end %>
 | 
			
		||||
<% render("views.common.topnav") -%>
 | 
			
		||||
<% if infobox then %>
 | 
			
		||||
  <% render("views.common.infobox", pop_infobox) %>
 | 
			
		||||
<% end %>
 | 
			
		||||
<div class="darkbg">
 | 
			
		||||
  <h1 class="thread-title">Latest posts by <i><%= user.username %></i></h1>
 | 
			
		||||
  <div>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user