A LOT of docs

master
E. Almqvist 3 years ago
parent 7bf26f30bc
commit bea7f3692c
  1. 23
      src/Gemfile
  2. 58
      src/Gemfile.lock
  3. 12
      src/app.rb
  4. 76
      src/lib/database.rb
  5. 179
      src/lib/db_models.rb
  6. 23
      src/routes/auction.rb
  7. 24
      src/routes/user.rb

@ -1,23 +0,0 @@
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
# gem "rails"
gem "sinatra"
gem "sinatra-reloader"
gem "sqlite3"
gem "slim"
gem "sassc"
gem "colorize"
gem "bcrypt"
gem "rmagick", "~> 4.2"
gem "sinatra-flash", "~> 0.3.0"
gem "fileutils", "~> 1.6"
gem "webrick", "~> 1.7"

@ -1,58 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
bcrypt (3.1.17)
colorize (0.8.1)
ffi (1.15.5)
fileutils (1.6.0)
multi_json (1.15.0)
mustermann (1.1.1)
ruby2_keywords (~> 0.0.1)
rack (2.2.3)
rack-protection (2.2.0)
rack
rmagick (4.2.5)
ruby2_keywords (0.0.5)
sassc (2.4.0)
ffi (~> 1.9)
sinatra (2.2.0)
mustermann (~> 1.0)
rack (~> 2.2)
rack-protection (= 2.2.0)
tilt (~> 2.0)
sinatra-contrib (2.2.0)
multi_json
mustermann (~> 1.0)
rack-protection (= 2.2.0)
sinatra (= 2.2.0)
tilt (~> 2.0)
sinatra-flash (0.3.0)
sinatra (>= 1.0.0)
sinatra-reloader (1.0)
sinatra-contrib
slim (4.1.0)
temple (>= 0.7.6, < 0.9)
tilt (>= 2.0.6, < 2.1)
sqlite3 (1.4.2)
temple (0.8.2)
tilt (2.0.10)
webrick (1.7.0)
PLATFORMS
x86_64-linux
DEPENDENCIES
bcrypt
colorize
fileutils (~> 1.6)
rmagick (~> 4.2)
sassc
sinatra
sinatra-flash (~> 0.3.0)
sinatra-reloader
slim
sqlite3
webrick (~> 1.7)
BUNDLED WITH
2.3.10

@ -38,6 +38,10 @@ not_found do
serve :"404" serve :"404"
end end
# Return a flash with some error message
# @param [String] msg Message
# @param [Integer] status HTTP Status Code
# @param [String] ret Return route
def auth_denied(msg=AUTH_ERRORS[:denied], status=403, ret=back) def auth_denied(msg=AUTH_ERRORS[:denied], status=403, ret=back)
session[:status] = status session[:status] = status
session[:ret] = ret session[:ret] = ret
@ -45,18 +49,26 @@ def auth_denied(msg=AUTH_ERRORS[:denied], status=403, ret=back)
redirect ret redirect ret
end end
# Wrapper for auth_denied when something goes wrong
# @see #auth_denied
def no_go_away(ret=back) def no_go_away(ret=back)
auth_denied "No! GO AWAY!", 403, ret auth_denied "No! GO AWAY!", 403, ret
end end
# Banned response
# @see #auth_denied
def banned(ret=back) def banned(ret=back)
auth_denied "You are banned!", 403, ret auth_denied "You are banned!", 403, ret
end end
# Error response
# @see #auth_denied
def error(ret=back) def error(ret=back)
auth_denied "Internal server error.", 500, ret auth_denied "Internal server error.", 500, ret
end end
# Ratelimit response
# @see #auth_denied
def ratelimit(delta_time, ret="/") def ratelimit(delta_time, ret="/")
auth_denied "You must wait #{format_time(delta_time)} to do that again!", 429, ret auth_denied "You must wait #{format_time(delta_time)} to do that again!", 429, ret
end end

@ -12,7 +12,8 @@ class EntityModel
@data = data @data = data
end end
# Creates the table # Initializes the table on startup
# @return [void]
def self.init_table def self.init_table
sql_file = "sql/tables/#{self.name}.sql" sql_file = "sql/tables/#{self.name}.sql"
@ -24,24 +25,38 @@ class EntityModel
end end
end end
# Generates a sql update query filter
# @param [Array<String>] vars strings that are the sql table attributes
# @return [String] Query filter
def self.gen_update_query(vars) # generates part of the update query string def self.gen_update_query(vars) # generates part of the update query string
out = vars.join " = ?, " out = vars.join " = ?, "
out += " = ?" out += " = ?"
end end
def self.gen_insert_query(vars) # generates part of the insert query string # Generates a SQL insert query filter
# @param [Array<String>] vars strings that are the SQL table attributes
# @return [String] Query filter
def self.gen_insert_query(vars)
entstr = "(#{vars.join ", "})" entstr = "(#{vars.join ", "})"
valstr = "(#{(["?"] * vars.length).join ", "})" valstr = "(#{(["?"] * vars.length).join ", "})"
return entstr, valstr return entstr, valstr
end end
# Applies a filter to a query
# @param [String] query The query
# @param [String] filter The filter
# @return [String] Full query SQL string with filter
def self.apply_filter(query, filter) def self.apply_filter(query, filter)
if filter != "" then query += " WHERE #{filter}" end if filter != "" then query += " WHERE #{filter}" end
query query
end end
def self.query(q, *args) # query table with query string # Query the table with given SQL query string
# @param [String] q The query
# @param [Array] args Other arguments (such as variable values etc)
# @return [Hash] Query result
def self.query(q, *args)
Console.debug("Running SQL -> #{q}", *args) Console.debug("Running SQL -> #{q}", *args)
begin begin
db.execute( q, args ) db.execute( q, args )
@ -51,6 +66,11 @@ class EntityModel
end end
# Extended query that also returns database instance # Extended query that also returns database instance
# @see EntityModel#query
# @param [String] q The query
# @param [Array] args Other arguments (such as variable values etc)
# @return [SQLite3::Database] SQLite3 Database instance
# @return [Hash] Query result
def self.equery(q, *args) def self.equery(q, *args)
Console.debug("Running extended SQL -> #{q}", *args) Console.debug("Running extended SQL -> #{q}", *args)
begin begin
@ -62,6 +82,11 @@ class EntityModel
end end
end end
# Get data from table with given filter
# @see EntityModel#query
# @param [String] attr The table attribute name
# @param [Array] args Other arguments (such as variable values etc)
# @return [Hash] Query result
def self.get(attr, filter="", *args) # get data from table def self.get(attr, filter="", *args) # get data from table
q = "SELECT #{attr} FROM #{self.name}" # create the query string q = "SELECT #{attr} FROM #{self.name}" # create the query string
q = apply_filter(q, filter) q = apply_filter(q, filter)
@ -69,16 +94,32 @@ class EntityModel
self.query q, *args # execute query self.query q, *args # execute query
end end
# Update data in table with given filter
# @see EntityModel#equery
# @param [Hash] data Hash of new data
# @param [String] filter Query filter
# @param [Array] args Other arguments (such as variable values etc)
# @return [Hash] Query result
def self.update(data, filter="", *args) # Updates the table with specified data hash def self.update(data, filter="", *args) # Updates the table with specified data hash
q = "UPDATE #{self.name} SET #{self.gen_update_query(data.keys)}" q = "UPDATE #{self.name} SET #{self.gen_update_query(data.keys)}"
q = apply_filter(q, filter) q = apply_filter(q, filter)
self.query(q, *data.values, *args) self.query(q, *data.values, *args)
end end
# Update data in table where id = something
# @see EntityModel#update
# @param [Integer] id Selected primary key
# @param [Hash] data Hash of new data
# @return [Hash] Query result
def self.edit(id, data) def self.edit(id, data)
self.update(data, "id=?", id) self.update(data, "id=?", id)
end end
# Insert data in table
# @see EntityModel#equery
# @param [Hash] data Hash of new data
# @return [Integer] New primary key that was generated
# @return [String] Response string
def self.insert(data) # Inserts new data into the table def self.insert(data) # Inserts new data into the table
entstr, valstr = self.gen_insert_query data.keys entstr, valstr = self.gen_insert_query data.keys
begin begin
@ -90,41 +131,52 @@ class EntityModel
return newid, resp return newid, resp
end end
# Delete entry with given filter
# @see EntityModel#query
# @param [String] filter Query filter
# @param [Array] args Variable values etc
def self.delete(filter="", *args) def self.delete(filter="", *args)
q = "DELETE FROM #{self.name}" q = "DELETE FROM #{self.name}"
q = self.apply_filter(q, filter) q = self.apply_filter(q, filter)
self.query q, *args self.query q, *args
end end
def self.set(attr, data, filter="") # slower but more lazy # Checks if primary key exists in table
if self.get(attr, filter).length > 0 then # @param [Integer] id The primary key
self.update(data, filter) # @return [Bool] If it exists or not
else
self.insert(data, filter)
end
end
def self.exists?(id) def self.exists?(id)
resp = self.get "id", "id = ?", id resp = self.get "id", "id = ?", id
resp.length > 0 resp.length > 0
end end
# Find object by id
# @param [Integer] id Primary key
# @return [Object] Model object
def self.find_by_id(id) def self.find_by_id(id)
data = self.get("*", "id = ?", id).first data = self.get("*", "id = ?", id).first
data && self.new(data) data && self.new(data)
end end
# Get all ids in table
# @param [String] filter Query filter
# @param [Array] args Other arguments (such as variable values etc)
# @return [Array<Integer>] Array of all the primary keys
def self.get_all_ids filter="", *args def self.get_all_ids filter="", *args
ids = self.get "id", *args ids = self.get "id", *args
ids.map! {|k, id| id.to_i} ids.map! {|k, id| id.to_i}
end end
# Get all objects in table
# @param [String] filter Query filter
# @param [Array] args Other arguments (such as variable values etc)
# @return [Array<Object>] Array of all the primary keys
def self.get_all filter="", *args def self.get_all filter="", *args
data = self.get "*", filter, *args data = self.get "*", filter, *args
data && data.map! {|r| self.new(r)} data && data.map! {|r| self.new(r)}
end end
end end
=begin
class RelationModel < EntityModel # TODO: make this work class RelationModel < EntityModel # TODO: make this work
def self.tables = nil def self.tables = nil
@ -138,3 +190,5 @@ class RelationModel < EntityModel # TODO: make this work
end end
end end
end end
=end

@ -13,14 +13,18 @@ class User < EntityModel
@pw_hash = data["pw_hash"] @pw_hash = data["pw_hash"]
end end
# Get user avatar url
def avatar def avatar
return @avatar_url return @avatar_url
end end
# Get all of the users auctions
def auctions def auctions
Auction.get_all "user_id = ?", @id Auction.get_all "user_id = ?", @id
end end
# Get the most dominant roles name
# @return [String] Role name
def role def role
return Role.find_by_id( ROLES[:admin][:id] ).name if self.admin? return Role.find_by_id( ROLES[:admin][:id] ).name if self.admin?
@ -32,47 +36,55 @@ class User < EntityModel
return "" return ""
end end
# Get all of the users role ids
# @see User#roles
# @return [Array<Integer>] Array of all the primary keys for the roles
def role_ids def role_ids
User_Role_relation.get_user_roles_ids @id User_Role_relation.get_user_roles_ids @id
end end
# Get all of the users role ids
# @see User#role_ids
# @return [Array<Role>] Array of all the users role objects
def roles def roles
User_Role_relation.get_user_roles @id User_Role_relation.get_user_roles @id
end end
# Gets the reputation enum for the user
# @return [Integer] Reputation score enum
def rep_score def rep_score
return BAD_REP if @reputation < 0 return BAD_REP if @reputation < 0
return GOOD_REP if @reputation > 0 return GOOD_REP if @reputation > 0
return NEUTRAL_REP return NEUTRAL_REP
end end
def bio_html # Reputation text for the user
md_parser = Redcarpet::Markdown.new(Redcarpet::Render::HTML) # @return [String] Reputation score string
md_parser.render @bio_text
end
def reputation_text def reputation_text
sign = @reputation > 0 ? "+" : "" sign = @reputation > 0 ? "+" : ""
return "#{sign}#{@reputation}" return "#{sign}#{@reputation}"
end end
# Sets the users reputation to given value
# @see EntityModel#update
# @param [Integer] val The value
def reputation=(val) def reputation=(val)
val = val.clamp MIN_REP, MAX_REP val = val.clamp MIN_REP, MAX_REP
@reputation = val @reputation = val
User.update({reputation: val}, "id = ?", @id) User.update({reputation: val}, "id = ?", @id)
end end
# Sets the users balance
# @see EntityModel#update
# @param [Float] val The value
def balance=(val) def balance=(val)
val = val >= 0 ? val : 0 val = val >= 0 ? val : 0
@balance = val @balance = val
User.update({balance: val}, "id = ?", @id) User.update({balance: val}, "id = ?", @id)
end end
def reputation=(val) # Updates the user credentials
@reputation = val # @see EntityModel#update
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)
@ -86,12 +98,21 @@ class User < EntityModel
return true, nil return true, nil
end end
# Find user by email, same as above but for emails. # Find user by email, same as EntityModel#find_by_id but for emails.
# @see EntityModel#query
# @see EntityModel#find_by_id
def self.find_by_email(email) def self.find_by_email(email)
data = self.get("*", "email = ?", email).first data = self.get("*", "email = ?", email).first
data && User.new(data) data && User.new(data)
end end
# Verify user registration credentials
# @param [String] email The email
# @param [String] name The users name
# @param [String] password Password
# @param [String] password_confirm Password confirmation
# @return [Boolean] Failed?
# @return [String] Error message
def self.validate_register_creds(email, name, password, password_confirm) def self.validate_register_creds(email, name, password, password_confirm)
# Field check # Field check
check_all_fields = email != "" && name != "" && password != "" && password_confirm != "" check_all_fields = email != "" && name != "" && password != "" && password_confirm != ""
@ -117,12 +138,21 @@ class User < EntityModel
return true, "" return true, ""
end end
# Verify password
# @param [String] pw_hash Digested password
# @param [String] password Password
# @return [Boolean] Passwords are equal
def self.validate_password(pw_hash, password) def self.validate_password(pw_hash, password)
BCrypt::Password.new(pw_hash) == password BCrypt::Password.new(pw_hash) == password
end end
# Register a new user # Register a new user
# Returns: success?, data # @param [String] email Email
# @param [String] name Users name
# @param [String] password Password
# @param [String] password_confirm Password confirm
# @return [Boolean] success?
# @return [String] Error string
def self.register(email, name, password, password_confirm) def self.register(email, name, password, password_confirm)
check, errorstr = self.validate_register_creds(email, name, password, password_confirm) check, errorstr = self.validate_register_creds(email, name, password, password_confirm)
@ -142,7 +172,10 @@ class User < EntityModel
end end
# Log in user # Log in user
# Returns: success?, user id # @param [String] email Users email
# @param [String] password Users password
# @return [Boolean] Success?
# @return [Integer] Users id
def self.login(email, password) def self.login(email, password)
user = self.find_by_email email # get the user info user = self.find_by_email email # get the user info
@ -154,8 +187,8 @@ class User < EntityModel
return true, user.id return true, user.id
end end
# Get a users flags # Get a users combined flags
# Returns: bitmap int thingie # @return [Integer Bitmap] A bitmap of all the flags
def flags def flags
flags = 0 flags = 0
self.roles.each do |role| self.roles.each do |role|
@ -166,12 +199,15 @@ class User < EntityModel
return flags return flags
end end
# Check if user is an admin
# @return [Boolean]
def admin? def admin?
return self.flags[1] == 1 return self.flags[1] == 1
end end
# Check if user has flags # Check if user is permitted with certian flag
# Returns: true or false depending whether the user has those flags # @param [Symbol] flag Flag symbol
# @return [Boolean] true or false depending whether the user has those flags
def permitted?(flag, *other_flags) def permitted?(flag, *other_flags)
return true if self.admin? return true if self.admin?
@ -183,10 +219,14 @@ class User < EntityModel
return self.flags & flag_mask == flag_mask return self.flags & flag_mask == flag_mask
end end
# Check if user is banned
# @return [Boolean]
def banned? def banned?
return self.flags[ PERM_LEVELS.keys.index(:banned) ] == 1 return self.flags[ PERM_LEVELS.keys.index(:banned) ] == 1
end end
# Set users "banned" status
# @return [String] Error/info string
def banned=(b) def banned=(b)
if b then if b then
# Add the "banned" role # Add the "banned" role
@ -208,6 +248,7 @@ class Role < EntityModel
@flags = data["flags"] @flags = data["flags"]
end end
# Check if role has a flag
def has_flag?(flag, *other_flags) def has_flag?(flag, *other_flags)
flag_mask = PERM_LEVELS[flag] flag_mask = PERM_LEVELS[flag]
@ -221,11 +262,18 @@ class Role < EntityModel
return @flags & flag_mask == flag_mask # f AND m = m => flags exists return @flags & flag_mask == flag_mask # f AND m = m => flags exists
end end
# Find role by name
# @see EntityModel#find_by_id
# @return [Role] Role object
def self.find_by_name(name) def self.find_by_name(name)
data = self.get("*", "name = ?", name).first data = self.get("*", "name = ?", name).first
data && Role.new(data) data && Role.new(data)
end end
# Create a role
# @param [String] name Role name
# @param [Color String] color Role color in hex
# @param [Integer Bitmap] flags Flags bitmap
def self.create(name, color="#ffffff", flags=0) def self.create(name, color="#ffffff", flags=0)
return false, REGISTER_ERRORS[:name_len] unless name.length.between?(MIN_NAME_LEN, MAX_NAME_LEN) return false, REGISTER_ERRORS[:name_len] unless name.length.between?(MIN_NAME_LEN, MAX_NAME_LEN)
@ -251,6 +299,10 @@ class User_Role_relation < EntityModel
end end
end end
# Give role to user
# @param [Integer] user_id User id
# @param [Integer] role_id Role id
# @see EntityModel#insert
def self.give_role(user_id, role_id) def self.give_role(user_id, role_id)
user = User.find_by_id user_id user = User.find_by_id user_id
@ -263,6 +315,10 @@ class User_Role_relation < EntityModel
end end
end end
# Revoke role from user
# @param [Integer] user_id User id
# @param [Integer] role_id Role id
# @see EntityModel#delete
def self.revoke_role(user_id, role_id) def self.revoke_role(user_id, role_id)
user = User.find_by_id user_id user = User.find_by_id user_id
@ -271,6 +327,10 @@ class User_Role_relation < EntityModel
end end
end end
# Gets users role ids in an array
# @see User_Role_relation#get_user_roles
# @param [Integer] user_id User id
# @return [Array<Integer>] Role ids
def self.get_user_roles_ids(user_id) def self.get_user_roles_ids(user_id)
ids = self.get "role_id", "user_id = ?", user_id ids = self.get "role_id", "user_id = ?", user_id
ids.map! do |ent| ids.map! do |ent|
@ -278,6 +338,10 @@ class User_Role_relation < EntityModel
end end
end end
# Gets users roles in an array
# @see User_Role_relation#get_user_roles_ids
# @param [Integer] user_id User id
# @return [Array<Role>] Roles
def self.get_user_roles(user_id) def self.get_user_roles(user_id)
roleids = self.get_user_roles_ids user_id roleids = self.get_user_roles_ids user_id
roles = roleids.map do |id| roles = roleids.map do |id|
@ -300,6 +364,9 @@ class Auction < EntityModel
@end_time = data["end_time"].to_i @end_time = data["end_time"].to_i
end end
# Validates auction params
# @return [Boolean] Success?
# @return [String] Error string
def self.validate_ah(title, description, init_price, delta_time) def self.validate_ah(title, description, init_price, delta_time)
return false, AUCTION_ERRORS[:titlelen] unless title.length.between?(MIN_TITLE_LEN, MAX_TITLE_LEN) return false, AUCTION_ERRORS[:titlelen] unless title.length.between?(MIN_TITLE_LEN, MAX_TITLE_LEN)
return false, AUCTION_ERRORS[:initprice] unless init_price >= MIN_INIT_PRICE return false, AUCTION_ERRORS[:initprice] unless init_price >= MIN_INIT_PRICE
@ -308,6 +375,14 @@ class Auction < EntityModel
return true, "" return true, ""
end end
# Creates an auction post
# @param [Integer] user_id Posters id
# @param [String] title
# @param [String] description
# @param [Float] init_price Initial price offering
# @param [Integer] delta_time Auction duration in seconds
# @see EntityModel#insert
# @see Auction#validate_ah
def self.create(user_id, title, description, init_price, delta_time) def self.create(user_id, title, description, init_price, delta_time)
# Validate the input # Validate the input
check, errorstr = self.validate_ah(title, description, init_price, delta_time) check, errorstr = self.validate_ah(title, description, init_price, delta_time)
@ -330,6 +405,8 @@ class Auction < EntityModel
self.insert data self.insert data
end end
# Composes SQL query filters for the auction searching function
# @return [string] Query filters
def self.compose_query_filters(title=nil, categories=nil, min_price=nil, max_price=nil, expired=nil) def self.compose_query_filters(title=nil, categories=nil, min_price=nil, max_price=nil, expired=nil)
querystr = "SELECT * FROM Auction WHERE " querystr = "SELECT * FROM Auction WHERE "
filters = [] filters = []
@ -366,17 +443,28 @@ class Auction < EntityModel
return querystr return querystr
end end
# Searches the database for related auctions that fit the params
# @param [String] title
# @param [Array<Integer>] categories Category ids
# @param [Integer] min_price
# @param [Integer] max_price
# @param [Boolean] expired
# @return [Array<Auction>] Array of auctions
def self.search(title=nil, categories=nil, min_price=nil, max_price=nil, expired=nil) def self.search(title=nil, categories=nil, min_price=nil, max_price=nil, expired=nil)
q = self.compose_query_filters title, categories, min_price, max_price, expired q = self.compose_query_filters title, categories, min_price, max_price, expired
data = self.query(q) data = self.query(q)
data.map! {|dat| self.new(dat)} data.map! {|dat| self.new(dat)}
end end
# Checks if expired
# @return [Boolean]
def self.expired?(id) def self.expired?(id)
ah = self.find_by_id id ah = self.find_by_id id
ah && ah.expired? ah && ah.expired?
end end
# Edits auction title and description
# @see EntityModel#update
def edit(title, description) def edit(title, description)
return false, AUCTION_ERRORS[:titlelen] unless title.length.between?(MIN_TITLE_LEN, MAX_TITLE_LEN) return false, AUCTION_ERRORS[:titlelen] unless title.length.between?(MIN_TITLE_LEN, MAX_TITLE_LEN)
return false, AUCTION_ERRORS[:desclen] unless description.length.between?(MIN_DESC_LEN, MAX_DESC_LEN) return false, AUCTION_ERRORS[:desclen] unless description.length.between?(MIN_DESC_LEN, MAX_DESC_LEN)
@ -388,6 +476,7 @@ class Auction < EntityModel
Auction.update data, "id = ?", @id Auction.update data, "id = ?", @id
end end
# Deletes the auction
def delete def delete
FileUtils.rm_rf("./public/auctions/#{@id}") # delete all images FileUtils.rm_rf("./public/auctions/#{@id}") # delete all images
@ -397,49 +486,74 @@ class Auction < EntityModel
Bid.delete "auction_id = ?", @id Bid.delete "auction_id = ?", @id
end end
# Auction poster object
# @return [User]
def poster def poster
User.find_by_id @user_id User.find_by_id @user_id
end end
# Auction images
# @return [Array<Image>]
def images def images
Image.get_relation @id Image.get_relation @id
end end
# Auctions category ids
# @see Auction#categories
# @return [Array<Integer>] Array of ids
def category_ids def category_ids
data = Auction_Category_relation.get "category_id", "auction_id = ?", @id data = Auction_Category_relation.get "category_id", "auction_id = ?", @id
data && data.map! {|category| category["category_id"].to_i} data && data.map! {|category| category["category_id"].to_i}
end end
# Auctions categories
# @see Auction#category_ids
# @return [Array<Category>] Array of categories
def categories def categories
data = self.category_ids data = self.category_ids
data && data.map! { |catid| Category.find_by_id catid} data && data.map! { |catid| Category.find_by_id catid}
end end
# @see Auction#expired?
def expired? def expired?
Time.now.to_i > @end_time Time.now.to_i > @end_time
end end
# Time left
# @return [Integer] Time left in seconds
def time_left def time_left
@end_time - Time.now.to_i @end_time - Time.now.to_i
end end
# Time left
# @return [String] Formatted time string
def time_left_s def time_left_s
left = self.time_left left = self.time_left
return format_time(left) return format_time(left)
end end
# Get auctions bids
# @return [Array<Bid>] Bids
def bids def bids
Bid.get_bids(@id) Bid.get_bids(@id)
end end
# Place bid on auction
# @param [Integer] uid Bidders id (user)
# @param [Float] amount
# @param [String] message
# @see Bid#place
def place_bid(uid, amount, message) def place_bid(uid, amount, message)
Bid.place(@id, uid, amount, message) Bid.place(@id, uid, amount, message)
end end
# Get the dominant bid object
# @return [Bid]
def max_bid def max_bid
max_bid = self.bids.max_by {|bid| bid.amount} max_bid = self.bids.max_by {|bid| bid.amount}
end end
# Current bid
def current_bid def current_bid
mbid = self.max_bid mbid = self.max_bid
if mbid != nil then if mbid != nil then
@ -449,6 +563,7 @@ class Auction < EntityModel
end end
end end
# Minimum required new bid
def min_new_bid def min_new_bid
max_bid = self.max_bid max_bid = self.max_bid
amount = max_bid.nil? ? @init_price : max_bid.amount amount = max_bid.nil? ? @init_price : max_bid.amount
@ -467,35 +582,40 @@ class Bid < EntityModel
@message = data["message"] @message = data["message"]
end end
# Gets auctions bids
def self.get_bids(ahid) def self.get_bids(ahid)
data = self.get "*", "auction_id = ?", ahid data = self.get "*", "auction_id = ?", ahid
data && data.map! {|dat| self.new(dat)} data && data.map! {|dat| self.new(dat)}
end end
# Get users bids
def self.get_user_bids(uid) def self.get_user_bids(uid)
data = self.get "*", "user_id = ?", uid data = self.get "*", "user_id = ?", uid
data && data.map! {|dat| self.new(dat)} data && data.map! {|dat| self.new(dat)}
end end
# Users bids active amount
def self.get_user_active_amount(uid) def self.get_user_active_amount(uid)
bids = self.get_user_bids uid bids = self.get_user_bids uid
return bids.sum {|bid| bid.amount} return bids.sum {|bid| bid.amount}
end end
# How much more the users new bid is from their last bid
# @return [Float]
def self.get_delta_amount(ahid, uid, amount) def self.get_delta_amount(ahid, uid, amount)
data = self.get "*", "auction_id = ? AND user_id = ?", ahid, uid data = self.get "*", "auction_id = ? AND user_id = ?", ahid, uid
if data and data.length > 0 then if data and data.length > 0 then
data.map! {|dat| self.new(dat)} data.map! {|dat| self.new(dat)}
max_bid = data.max_by {|bid| bid.amount} max_bid = data.max_by {|bid| bid.amount}
p "sgiodfhgiodfhioghoi"
p data
p "sgiodfhgiodfhioghoi"
return amount - max_bid.amount return amount - max_bid.amount
else else
return amount return amount
end end
end end
# Validate a new bid
# @return [Boolean] Success?
# @return [String] Error message
def self.validate_bid(ahid, uid, amount, message) def self.validate_bid(ahid, uid, amount, message)
ah = Auction.find_by_id ahid ah = Auction.find_by_id ahid
return false, "Invalid auction" unless ah.is_a? Auction return false, "Invalid auction" unless ah.is_a? Auction
@ -506,6 +626,15 @@ class Bid < EntityModel
return true, "" return true, ""
end end
# Place a new bid
# @param [Integer] ahid Auction id
# @param [Integer] uid User id
# @param [Float] amount
# @param [String] message
# @see EntityModel#insert
# @see Bid#validate_bid
# @return [Boolean] Success?
# @return [String, Hash] Error message or insert query data
def self.place(ahid, uid, amount, message) def self.place(ahid, uid, amount, message)
check, resp = self.validate_bid(ahid, uid, amount, message) check, resp = self.validate_bid(ahid, uid, amount, message)
if check then if check then
@ -535,6 +664,8 @@ class Category < EntityModel
@color = data["color"] @color = data["color"]
end end
# Create a new category
# @see EntityModel#insert
def self.create(name, color) def self.create(name, color)
data = { data = {
name: name, name: name,
@ -552,6 +683,8 @@ class Auction_Category_relation < EntityModel
@category_id = data["category_id"] @category_id = data["category_id"]
end end
# Get all auctions that have the specified category
# @return [Array<Integer>] Auction ids
def self.category_auction_ids(catid) def self.category_auction_ids(catid)
ids = self.get "auction_id", "category_id = ?", catid ids = self.get "auction_id", "category_id = ?", catid
ids && ids.map! {|id| id["auction_id"].to_i} ids && ids.map! {|id| id["auction_id"].to_i}
@ -568,6 +701,10 @@ class Image < EntityModel
@url = data["url"] @url = data["url"]
end end
# Save an image to the DB and disk
# @param [Image Data] imgdata
# @param [Integer] ah_id Auction id
# @param [Integer] order Image order on the auction page
def self.save(imgdata, ah_id, order) def self.save(imgdata, ah_id, order)
FileUtils.mkdir_p "./public/auctions/#{ah_id}" FileUtils.mkdir_p "./public/auctions/#{ah_id}"
@ -588,6 +725,8 @@ class Image < EntityModel
end end
end end
# Gets the auction image relation
# @return [Array<Image>] Auction images
def self.get_relation(ah_id) def self.get_relation(ah_id)
imgs = self.get "*", "auction_id = ?", ah_id imgs = self.get "*", "auction_id = ?", ah_id
imgs.map! do |img| imgs.map! do |img|

@ -1,4 +1,4 @@
# Auction stuff # Auction index & searching page
get "/auctions" do get "/auctions" do
title = params[:title] and params[:title] != "" ? params[:title].strip : nil title = params[:title] and params[:title] != "" ? params[:title].strip : nil
categories = params[:categories] categories = params[:categories]
@ -11,10 +11,17 @@ get "/auctions" do
serve :"auction/index", {auctions: auctions} serve :"auction/index", {auctions: auctions}
end end
# Auction creation form
get "/auctions/new" do get "/auctions/new" do
serve :"auction/new" serve :"auction/new"
end end
# Create an auction
# @param [String] title
# @param [String] description
# @param [Float] init_price Initial price offering
# @param [Integer] delta_time Auction duration in hours
# @param [Array<Tempfile>] images
post "/auctions" do post "/auctions" do
user_id = session[:userid] user_id = session[:userid]
@ -55,6 +62,8 @@ post "/auctions" do
end end
end end
# View auction
# @param [Integer] id
get "/auctions/:id" do get "/auctions/:id" do
id = params[:id].to_i id = params[:id].to_i
auction = Auction.find_by_id id auction = Auction.find_by_id id
@ -66,6 +75,8 @@ get "/auctions/:id" do
end end
end end
# Edit auction form
# @param [Integer] id
get "/auctions/:id/edit" do get "/auctions/:id/edit" do
id = params[:id].to_i id = params[:id].to_i
auction = Auction.find_by_id id auction = Auction.find_by_id id
@ -81,6 +92,8 @@ get "/auctions/:id/edit" do
end end
end end
# Delete auction
# @param [Integer] id
get "/auctions/:id/delete" do get "/auctions/:id/delete" do
id = params[:id].to_i id = params[:id].to_i
auction = Auction.find_by_id id auction = Auction.find_by_id id
@ -99,6 +112,10 @@ get "/auctions/:id/delete" do
end end
end end
# Update auction credentials
# @param [Integer] id
# @param [String] title New title
# @param [String] description New description
post "/auctions/:id/update" do post "/auctions/:id/update" do
id = params[:id].to_i id = params[:id].to_i
auction = Auction.find_by_id id auction = Auction.find_by_id id
@ -118,6 +135,10 @@ post "/auctions/:id/update" do
end end
end end
# Bid on an auction
# @param [Integer] id Auction id
# @param [Float] amount Must be greater than the current highest bid (min 1%)
# @param [String, nil] message
post "/auctions/:id/bids" do post "/auctions/:id/bids" do
id = params[:id].to_i id = params[:id].to_i
auction = Auction.find_by_id id auction = Auction.find_by_id id

@ -1,11 +1,15 @@
# Login page for the user
get "/login" do get "/login" do
serve :"user/login", layout: :empty serve :"user/login", layout: :empty
end end
# Register page for the user
get "/register" do get "/register" do
serve :"user/register", layout: :empty serve :"user/register", layout: :empty
end end
# Profile for user
# @param [Integer] id User id
get "/profile/:id" do get "/profile/:id" do
id = params[:id].to_i id = params[:id].to_i
userobj = User.find_by_id id userobj = User.find_by_id id
@ -17,6 +21,7 @@ get "/profile/:id" do
end end
end end
# Profile user for logged in user
get "/profile" do get "/profile" do
if is_logged_in then if is_logged_in then
redirect "/profile/#{session[:userid]}" redirect "/profile/#{session[:userid]}"
@ -25,8 +30,10 @@ get "/profile" do
end end
end end
# Reputation
USER_REP_LIMIT ||= Hash.new(Hash.new(0)) USER_REP_LIMIT ||= Hash.new(Hash.new(0))
# Add or remove users reputation score
# @param [Integer] id User id
# @param [String] type Either "plus" or "minus"
get "/user/rep/:id" do get "/user/rep/:id" do
if !is_logged_in then if !is_logged_in then
session[:ret] = request.fullpath session[:ret] = request.fullpath
@ -59,11 +66,16 @@ get "/user/rep/:id" do
end end
end end
# User stuff # Logged in users settings
get "/settings" do get "/settings" do
serve :"user/settings" serve :"user/settings"
end end
# Register user
# @param [String] email
# @param [String] name
# @param [String] password
# @param [String] password_confirm
post "/register" do post "/register" do
email = params[:email] email = params[:email]
name = params[:name] name = params[:name]
@ -81,6 +93,9 @@ post "/register" do
end end
end end
# Login user
# @param [String] email
# @param [String] password
post "/login" do post "/login" do
email = params[:email].strip email = params[:email].strip
password = params[:password].strip password = params[:password].strip
@ -95,12 +110,17 @@ post "/login" do
end end
end end
# Logout current user
get "/logout" do get "/logout" do
session.clear session.clear
flash[:success] = "Successfully logged out!" flash[:success] = "Successfully logged out!"
redirect "/" redirect "/"
end end
# Update user credentials
# @param [Integer] id (Only applied if logged in user is admin), otherwise it defaults to current session user
# @param [String] displayname New user name
# @param [String] bio_text New bio text
post "/user/update" do post "/user/update" do
id = (get_current_user.admin? and params[:id]) ? params[:id].to_i : session[:userid] id = (get_current_user.admin? and params[:id]) ? params[:id].to_i : session[:userid]

Loading…
Cancel
Save