add login, signup, settings, delete confirm markup
This commit is contained in:
		@@ -106,31 +106,27 @@ app:get("user", "/:username", function(self)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
app:post("user_delete", "/:username/delete", function(self)
 | 
			
		||||
  -- this route explicitly does not handle admins deleting other users
 | 
			
		||||
  -- 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."}
 | 
			
		||||
    return {redirect_to = self:url_for("user_login")}
 | 
			
		||||
  end
 | 
			
		||||
  local target_user = Users:find({username = self.params.username})
 | 
			
		||||
  if not me:is_mod() then
 | 
			
		||||
    if me.id ~= target_user.id then
 | 
			
		||||
      return {redirect_to = self:url_for("user", {username = self.params.username})}
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    if not authenticate_user(target_user, self.params.password) then
 | 
			
		||||
      self.session.flash = {error = "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."}
 | 
			
		||||
    return {redirect_to = self:url_for("user_signup")}
 | 
			
		||||
  else
 | 
			
		||||
    if target_user.permission >= me.permission then
 | 
			
		||||
      self.session.flash = {error = "You can not delete another moderator."}
 | 
			
		||||
      return {redirect_to = self:url_for("user", {username = me.username})}
 | 
			
		||||
    end
 | 
			
		||||
  
 | 
			
		||||
  if me.id ~= target_user.id then
 | 
			
		||||
    return {redirect_to = self:url_for("user", {username = self.params.username})}
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
  if not authenticate_user(target_user, self.params.password) then
 | 
			
		||||
    self.session.flash = {error = "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."}
 | 
			
		||||
  return {redirect_to = self:url_for("user_signup")}
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
app:get("user_delete_confirm", "/:username/delete_confirm", function(self)
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ $dark_bg: color.scale($accent_color, $lightness: -25%, $saturation: -97%);
 | 
			
		||||
$dark2: color.scale($accent_color, $lightness: -30%, $saturation: -60%);
 | 
			
		||||
 | 
			
		||||
$light: color.scale($accent_color, $lightness: 40%, $saturation: -60%);
 | 
			
		||||
$lighter: color.scale($accent_color, $lightness: 60%, $saturation: -60%);
 | 
			
		||||
 | 
			
		||||
$main_bg: color.scale($accent_color, $lightness: -10%, $saturation: -40%);
 | 
			
		||||
$button_color: color.adjust($accent_color, $hue: 90);
 | 
			
		||||
@@ -66,6 +67,7 @@ body {
 | 
			
		||||
.darkbg {
 | 
			
		||||
  padding-bottom: 10px;
 | 
			
		||||
  padding-left: 10px;
 | 
			
		||||
  padding-right: 10px;
 | 
			
		||||
  background-color: $dark_bg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -75,8 +77,11 @@ body {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.site-title {
 | 
			
		||||
  display: inline;
 | 
			
		||||
  padding-right: 30px;
 | 
			
		||||
  font-size: 1.5rem;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  color: black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thread-title {
 | 
			
		||||
@@ -197,6 +202,7 @@ button, input[type="submit"], .linkbutton {
 | 
			
		||||
// not sure why this one has to be separate, but if it's included in the rule above everything breaks
 | 
			
		||||
input[type="file"]::file-selector-button {
 | 
			
		||||
  @include button($button_color);
 | 
			
		||||
  margin: 10px 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.pagebutton {
 | 
			
		||||
@@ -221,3 +227,29 @@ input[type="file"]::file-selector-button {
 | 
			
		||||
.modform {
 | 
			
		||||
  display: inline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-container > * {
 | 
			
		||||
  width: 25%;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.settings-container > * {
 | 
			
		||||
  width: 40%;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.avatar-form {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding: 20px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input[type="text"], input[type="password"] {
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  border-radius: 3px;
 | 
			
		||||
  padding: 7px 10px;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  background-color: $lighter;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@ body {
 | 
			
		||||
.darkbg {
 | 
			
		||||
  padding-bottom: 10px;
 | 
			
		||||
  padding-left: 10px;
 | 
			
		||||
  padding-right: 10px;
 | 
			
		||||
  background-color: rgb(143.7039271654, 144.3879625984, 142.8620374016);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -48,8 +49,11 @@ body {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.site-title {
 | 
			
		||||
  display: inline;
 | 
			
		||||
  padding-right: 30px;
 | 
			
		||||
  font-size: 1.5rem;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  color: black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thread-title {
 | 
			
		||||
@@ -179,6 +183,7 @@ button.warn:active, input[type=submit].warn:active, .linkbutton.warn:active {
 | 
			
		||||
 | 
			
		||||
input[type=file]::file-selector-button {
 | 
			
		||||
  background-color: rgb(177, 206, 204.5);
 | 
			
		||||
  margin: 10px 10px;
 | 
			
		||||
}
 | 
			
		||||
input[type=file]::file-selector-button:hover {
 | 
			
		||||
  background-color: rgb(192.6, 215.8, 214.6);
 | 
			
		||||
@@ -214,3 +219,29 @@ input[type=file]::file-selector-button:active {
 | 
			
		||||
.modform {
 | 
			
		||||
  display: inline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-container > * {
 | 
			
		||||
  width: 25%;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.settings-container > * {
 | 
			
		||||
  width: 40%;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.avatar-form {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding: 20px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input[type=text], input[type=password] {
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  border-radius: 3px;
 | 
			
		||||
  padding: 7px 10px;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  background-color: rgb(229.84, 231.92, 227.28);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,11 @@
 | 
			
		||||
<nav id="topnav">
 | 
			
		||||
  <span>
 | 
			
		||||
    <h1 class="site-title">Porom</h1>
 | 
			
		||||
    <a href="<%= url_for("all_topics") %>">All topics</a>
 | 
			
		||||
    <% local topics_url = url_for("all_topics") %>
 | 
			
		||||
    <a class="site-title" href="<%= topics_url %>">Porom</a>
 | 
			
		||||
    <a href="<%= topics_url %>">All topics</a>
 | 
			
		||||
  </span>
 | 
			
		||||
  <span>
 | 
			
		||||
    <% if me:is_logged_in() then -%>
 | 
			
		||||
    <% if me and me:is_logged_in() then -%>
 | 
			
		||||
      Welcome, <a href="<%= url_for("user", {username = me.username}) %>"><%= me.username %></a>
 | 
			
		||||
    <% else -%>
 | 
			
		||||
      Welcome, guest. Please <a href="<%= url_for("user_signup") %>">sign up</a> or <a href="<%= url_for("user_login") %>">log in</a>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,15 @@
 | 
			
		||||
<h1>Are you sure you want to delete your account, <%= me.username %>?</h1>
 | 
			
		||||
<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>
 | 
			
		||||
<% render("views.common.topnav") -%>
 | 
			
		||||
<div class="darkbg settings-container">
 | 
			
		||||
  <h1>Are you sure you want to delete your account, <%= me.username %>?</h1>
 | 
			
		||||
  <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>
 | 
			
		||||
<% end %>
 | 
			
		||||
  <% if err then %>
 | 
			
		||||
    <h2><%= err %></h2>
 | 
			
		||||
  <% end %>
 | 
			
		||||
 | 
			
		||||
<form method="post" action="<%= url_for("user_delete", {username = me.username}) %>">
 | 
			
		||||
  <input type="password" name="password" id="password" autocomplete="current-password" placeholder="Password" required><br>
 | 
			
		||||
  <input class="critical" type="submit" value="Delete my account (NO UNDO)">
 | 
			
		||||
</form>
 | 
			
		||||
  <form method="post" action="<%= url_for("user_delete", {username = me.username}) %>">
 | 
			
		||||
    <input type="password" name="password" id="password" autocomplete="current-password" placeholder="Password" required><br>
 | 
			
		||||
    <input class="critical" type="submit" value="Delete my account (NO UNDO)">
 | 
			
		||||
  </form>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -1,12 +1,14 @@
 | 
			
		||||
<h1>Log In</h1>
 | 
			
		||||
 | 
			
		||||
<% if err then %>
 | 
			
		||||
<h2><%= err %></h2>
 | 
			
		||||
<% end %>
 | 
			
		||||
<form method="post" action="<%= url_for('user_login') %>" enctype="multipart/form-data">
 | 
			
		||||
  <label for="username">Username</label><br>
 | 
			
		||||
  <input type="text" id="username" name="username" required autocomplete="username"><br>
 | 
			
		||||
  <label for="password">Password</label><br>
 | 
			
		||||
  <input type="password" id="password" name="password" required autocomplete="current-password"><br>
 | 
			
		||||
  <input type="submit" value="Log in">
 | 
			
		||||
</form>
 | 
			
		||||
<% render("views.common.topnav") -%>
 | 
			
		||||
<div class="darkbg login-container">
 | 
			
		||||
  <h1>Log In</h1>
 | 
			
		||||
  <% if err then %>
 | 
			
		||||
    <h2><%= err %></h2>
 | 
			
		||||
  <% end %>
 | 
			
		||||
  <form method="post" action="<%= url_for('user_login') %>" enctype="multipart/form-data">
 | 
			
		||||
    <label for="username">Username</label><br>
 | 
			
		||||
    <input type="text" id="username" name="username" required autocomplete="username"><br>
 | 
			
		||||
    <label for="password">Password</label><br>
 | 
			
		||||
    <input type="password" id="password" name="password" required autocomplete="current-password"><br>
 | 
			
		||||
    <input type="submit" value="Log in">
 | 
			
		||||
  </form>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,20 +1,25 @@
 | 
			
		||||
<h1>User settings</h1>
 | 
			
		||||
<% if flash_msg then %>
 | 
			
		||||
  <h2><%= flash_msg %></h2>
 | 
			
		||||
<% end %>
 | 
			
		||||
<form method="post" action="<%= url_for("user_set_avatar", {username = me.username}) %>" enctype="multipart/form-data">
 | 
			
		||||
  <img src="<%= avatar_url(me) %>"><br>
 | 
			
		||||
  <input id="file" type="file" name="avatar" accept="image/*">
 | 
			
		||||
  <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}) %>">
 | 
			
		||||
<% end %>
 | 
			
		||||
<br>
 | 
			
		||||
</form>
 | 
			
		||||
<form method="post" action="">
 | 
			
		||||
  <label for="status">Status</label>
 | 
			
		||||
  <input type="text" id="status" name="status" value="<%= me.status %>" maxlength="30"><br>
 | 
			
		||||
  <input type="submit" value="Save status">
 | 
			
		||||
</form>
 | 
			
		||||
<br>
 | 
			
		||||
<a class="linkbutton critical" href="<%= url_for("user_delete_confirm", {username = me.username}) %>">Delete account</a>
 | 
			
		||||
<% render("views.common.topnav") -%>
 | 
			
		||||
<div class="darkbg settings-container">
 | 
			
		||||
  <h1>User settings</h1>
 | 
			
		||||
  <% if flash_msg then %>
 | 
			
		||||
    <h2><%= flash_msg %></h2>
 | 
			
		||||
  <% 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) %>">
 | 
			
		||||
    <input id="file" type="file" name="avatar" accept="image/*" required>
 | 
			
		||||
    <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}) %>">
 | 
			
		||||
  <% end %>
 | 
			
		||||
  </div>
 | 
			
		||||
  </form>
 | 
			
		||||
  <form method="post" action="">
 | 
			
		||||
    <label for="status">Status</label>
 | 
			
		||||
    <input type="text" id="status" name="status" value="<%= me.status %>" maxlength="30">
 | 
			
		||||
    <input type="submit" value="Save status">
 | 
			
		||||
  </form>
 | 
			
		||||
  <div>
 | 
			
		||||
  <a class="linkbutton critical" href="<%= url_for("user_delete_confirm", {username = me.username}) %>">Delete account</a>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,17 @@
 | 
			
		||||
<h1>Sign up</h1>
 | 
			
		||||
 | 
			
		||||
<% if err then %>
 | 
			
		||||
<h2><%= err %></h2>
 | 
			
		||||
<% end %>
 | 
			
		||||
<form method="post" action="<%= url_for('user_signup') %>" enctype="multipart/form-data">
 | 
			
		||||
  <label for="username">Username</label><br>
 | 
			
		||||
  <input type="text" id="username" name="username" pattern="[\w\-]{3,20}" title="3-20 characters. Only upper and lowercase letters, hyphens, and underscores" required autocomplete="username"><br>
 | 
			
		||||
  <label for="password">Password</label><br>
 | 
			
		||||
  <input type="password" id="password" name="password" pattern="(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_])(?!.*\s).{10,}" title="10+ chars with: 1 uppercase, 1 lowercase, 1 number, 1 special char, and no spaces" required autocomplete="new-password"><br>
 | 
			
		||||
  <label for="password2">Confirm Password</label><br>
 | 
			
		||||
  <input type="password" id="password2" name="password2" pattern="(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_])(?!.*\s).{10,}" title="10+ chars with: 1 uppercase, 1 lowercase, 1 number, 1 special char, and no spaces" required autocomplete="new-password"><br>
 | 
			
		||||
  <input type="submit" value="Sign up">
 | 
			
		||||
</form>
 | 
			
		||||
<p>After you sign up, a moderator will need to confirm your account before you will be allowed to post.</p>
 | 
			
		||||
<% render("views.common.topnav") -%>
 | 
			
		||||
<div class="darkbg login-container">
 | 
			
		||||
  <h1>Sign up</h1>
 | 
			
		||||
  <% if err then %>
 | 
			
		||||
    <h2><%= err %></h2>
 | 
			
		||||
  <% end %>
 | 
			
		||||
  <form method="post" action="<%= url_for('user_signup') %>" enctype="multipart/form-data">
 | 
			
		||||
    <label for="username">Username</label><br>
 | 
			
		||||
    <input type="text" id="username" name="username" pattern="[\w\-]{3,20}" title="3-20 characters. Only upper and lowercase letters, hyphens, and underscores" required autocomplete="username"><br>
 | 
			
		||||
    <label for="password">Password</label><br>
 | 
			
		||||
    <input type="password" id="password" name="password" pattern="(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_])(?!.*\s).{10,}" title="10+ chars with: 1 uppercase, 1 lowercase, 1 number, 1 special char, and no spaces" required autocomplete="new-password"><br>
 | 
			
		||||
    <label for="password2">Confirm Password</label><br>
 | 
			
		||||
    <input type="password" id="password2" name="password2" pattern="(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_])(?!.*\s).{10,}" title="10+ chars with: 1 uppercase, 1 lowercase, 1 number, 1 special char, and no spaces" required autocomplete="new-password"><br>
 | 
			
		||||
    <input type="submit" value="Sign up">
 | 
			
		||||
  </form>
 | 
			
		||||
  <p>After you sign up, a moderator will need to confirm your account before you will be allowed to post.</p>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user