User reviews & rate limiting refactor

master
E. Almqvist 3 years ago
parent 3f06407631
commit 7bf26f30bc
  1. 2
      src/TODO.md
  2. 4
      src/app.rb
  3. 7
      src/const.rb
  4. 16
      src/lib/db_models.rb
  5. 13
      src/lib/func.rb
  6. 32
      src/routes/user.rb
  7. 8
      src/views/stylesheets/style.sass
  8. 10
      src/views/user/profile.slim
  9. 10
      src/views/user/rep.slim

@ -1,6 +1,4 @@
# TODO # TODO
- Ratelimiting
- User reviews (+rep / -rep)
- Yardoc 50% - Yardoc 50%
- Film - Film

@ -58,7 +58,7 @@ def error(ret=back)
end end
def ratelimit(delta_time, ret="/") def ratelimit(delta_time, ret="/")
auth_denied "You are doing that a bit too fast... Please try again in #{delta_time}s.", 429, ret auth_denied "You must wait #{format_time(delta_time)} to do that again!", 429, ret
end end
before do before do
@ -69,7 +69,7 @@ before do
RATE_LIMIT_ROUTES.each do |t, cfg| RATE_LIMIT_ROUTES.each do |t, cfg|
if request.path_info.start_with?(*cfg[:routes]) then if request.path_info.start_with?(*cfg[:routes]) then
dt = Time.now.to_i - RATE_LIMITS[t][request.ip] dt = Time.now.to_i - RATE_LIMITS[t][request.ip]
ratelimit(dt) unless dt > cfg[:time] # send a rate limit response if rate limited ratelimit cfg[:time] - dt, back unless dt > cfg[:time] # send a rate limit response if rate limited
RATE_LIMITS[t][request.ip] = Time.now.to_i RATE_LIMITS[t][request.ip] = Time.now.to_i
end end
end end

@ -81,15 +81,18 @@ TIME_FORMATS = {
# Routes that needs auth # Routes that needs auth
AUTH_ROUTES = %w[/settings /auction /user /admin] AUTH_ROUTES = %w[/settings /auction /user /admin]
# Limit for +rep/-rep
USER_REP_LIMIT_TIME = 86400 # 1 day
# Rate limits in seconds for each route category # Rate limits in seconds for each route category
RATE_LIMIT_ROUTES = { RATE_LIMIT_ROUTES = {
user: { user: {
routes: %w[/user /settings /register /login /logout], routes: %w[/user /settings /register /login /logout],
time: 1 time: 2
}, },
auction: { auction: {
routes: %w[/auctions], routes: %w[/auctions],
time: 1 time: 2
} }
} }

@ -68,6 +68,11 @@ class User < EntityModel
User.update({balance: val}, "id = ?", @id) User.update({balance: val}, "id = ?", @id)
end end
def reputation=(val)
@reputation = val
User.update({reputation: val}, "id = ?", @id)
end
def update_creds(data) def update_creds(data)
# Validate input # Validate input
return false, SETTINGS_ERRORS[:name_len] unless data[:name].length.between?(MIN_NAME_LEN, MAX_NAME_LEN) return false, SETTINGS_ERRORS[:name_len] unless data[:name].length.between?(MIN_NAME_LEN, MAX_NAME_LEN)
@ -420,16 +425,7 @@ class Auction < EntityModel
def time_left_s def time_left_s
left = self.time_left left = self.time_left
result = [] return format_time(left)
TIME_FORMATS.each do |sym, count|
amount = left.to_i / count
if amount > 0 then
result << "#{amount}#{sym.to_s}"
left -= count*amount
end
end
result = result[0...2]
return result.join ", "
end end
def bids def bids

@ -11,6 +11,19 @@ def get_current_user
session[:userid] && User.find_by_id(session[:userid]) session[:userid] && User.find_by_id(session[:userid])
end end
def format_time(seconds)
result = []
TIME_FORMATS.each do |sym, count|
amount = seconds.to_i / count
if amount > 0 then
result << "#{amount}#{sym.to_s}"
seconds -= count*amount
end
end
result = result[0...2]
return result.join ", "
end
# Serve templates # Serve templates
def serve(template, locals={}, layout: :layout) def serve(template, locals={}, layout: :layout)
locals[:session_user] = get_current_user unless !is_logged_in locals[:session_user] = get_current_user unless !is_logged_in

@ -26,10 +26,34 @@ get "/profile" do
end end
# Reputation # Reputation
get "/profile/:id/rep" do USER_REP_LIMIT ||= Hash.new(Hash.new(0))
userobj = User.find_by_id params[:id].to_i get "/user/rep/:id" do
if userobj then if !is_logged_in then
serve :"user/rep", {user: userobj} session[:ret] = request.fullpath
session[:status] = 403
flash[:error] = AUTH_ERRORS[:needed]
redirect "/login"
end
user = User.find_by_id params[:id].to_i
if user then
redirect "/profile/#{user.id}" unless params[:type]
auth_denied "You can not give yourself reputation points!" if user.id == session[:userid]
# Check the delta time and if we can ±rep again
dt = Time.now.to_i - USER_REP_LIMIT[session[:userid]][user.id]
ratelimit USER_REP_LIMIT_TIME - dt, "/profile/#{user.id}" unless dt > USER_REP_LIMIT_TIME
# Update rate limit
USER_REP_LIMIT[session[:userid]][user.id] = Time.now.to_i
# Add to user rep
delta = params[:type] == "plus" ? 1 : -1
user.reputation += delta
flash[:success] = "Gave '#{user.name.strip}' #{delta > 0 ? "+" : ""}#{delta} rep"
redirect "/profile/#{user.id}"
else else
raise Sinatra::NotFound raise Sinatra::NotFound
end end

@ -335,13 +335,13 @@ ul.list-container
margin-bottom: 1rem margin-bottom: 1rem
.green .green
color: $green_clr color: $green_clr !important
.red .red
color: $red_clr color: $red_clr !important
.yellow .yellow
color: $yellow_clr color: $yellow_clr !important
.gray .gray
color: $gray_clr color: $gray_clr !important
.card-container .card-container
padding: 0 1rem padding: 0 1rem

@ -38,8 +38,14 @@
- else - else
h3.gray = user.reputation_text h3.gray = user.reputation_text
h4 Based on user reviews h4 Based on user reviews
a.button href="/profile/#{user.id}/rep"
| + Write a review - unless user.id == session[:userid]
span
a.button.green href="/user/rep/#{user.id}?type=plus"
| +rep
| /
a.button.red href="/user/rep/#{user.id}?type=minus"
| -rep
#posts.card #posts.card
h2 Recent posts h2 Recent posts

@ -1,10 +0,0 @@
div
h1 = "#{user.name}'s reputation reviews"
h2 Not implemented yet.
- if user.rep_score == GOOD_REP
h3.green = user.reputation_text
- elsif user.rep_score == BAD_REP
h3.red = user.reputation_text
- else
h3.gray = user.reputation_text
Loading…
Cancel
Save