LifePex/src/systems/user.rb

163 lines
4.9 KiB
Ruby

require "yaml"
require_relative "./auth.rb"
require_relative "./csrf.rb"
class LifePex::Systems::UserSystem < LifePex::Systems::AuthSystem
include LifePex::Systems::CrlfHelper
DEFAULT_PEXS_FOR_NEW_USERS = YAML.load_file "config/default_pexs_for_new_users.yaml"
get "/login" do
slim :login
end
def login(params)
user = LifePex::User.where(username: params["username"]).first
if user && BCrypt::Password.new(user[:hashed_password]) == params["password"]
setup_user_cookie!(user[:id])
user
else
nil
end
end
post "/login", provides: 'html' do
if user = login(params)
redirect "/"
else
slim :login, locals: { flash: { danger: "Failed to login" } }
end
end
get "/register" do
slim :register
end
def register(params)
user = LifePex::User.where(username: params["username"]).first
if !user
hashed_password = BCrypt::Password.create params["password"]
user = LifePex::User.new(username: params["username"], hashed_password: hashed_password).save
cookies["auth"] = JWT.encode({ "user_id" => user.id }, LifePex::SECRET)
DEFAULT_PEXS_FOR_NEW_USERS.each do |pex|
LifePex::Pex.new(**pex, user_id: user.id).save
end
user.id
else
nil
end
end
post "/register", provides: 'html' do
if user_id = register(params)
redirect "/"
else
slim :register, locals: { flash: { danger: "Failed to register as #{params['username']}" } }
end
end
post "/logout", auth: [] do
cookies.delete "auth"
slim :logout, locals: { flash: { success: "Logged out" } }
end
get "/password", auth: [] do
slim :password
end
def change_password(params)
hashed_password = BCrypt::Password.create params["password"]
LifePex::User.where(id: current_user_id).update(hashed_password: hashed_password)
end
post "/password", auth: [], provides: 'html' do
if params["password"] != params["password_confirmation"]
slim :password, locals: { flash: { warning: "Password don't match" } }
else
change_password(params)
slim :password, locals: { flash: { success: "Password updated" } }
end
end
get "/about" do
slim :about
end
get "/preferences" do
show_preferences
end
UserPreferenceCookie = Struct.new(:cookie, :allow_blank, :convert, :html, :description)
USER_PREFERENCES = {
"inputRecapDays" => UserPreferenceCookie.new("recap_days", false, :to_i, { type: "text" }, "Amount of days to show in the recap"),
"inputLateDayOffset" => UserPreferenceCookie.new("late_day_offset", false, :to_f, { type: "number", min: "0", max: "24", step: "0.1" }, "Offset for today (so a few hours after midnight is still today)"),
"inputShowFullDate" => UserPreferenceCookie.new("show_full_date", true, :to_s, { type: "checkbox" }, "Show or hide the date of the current tab"),
}
post "/preferences" do
USER_PREFERENCES.each do |param_name, upc|
current_param = params[param_name]
next if !upc.allow_blank && current_param.blank?
cookies[upc.cookie] =
case upc.convert
when Symbol
current_param.send(upc.convert)
when Proc
upc.convert.call(current_param)
else
current_param
end
end
show_preferences
end
def show_preferences
slim :preferences
end
extend DocMyRoutes::Annotatable
register Sinatra::Namespace
namespace '/api/user/v1' do
summary 'Generate a authentication cookie for a registrated account'
notes ''
produces 'application/json'
status_codes [200]
parameter :username, required: true, type: 'string', in: 'body'
parameter :password, required: true, type: 'string', in: 'body'
post "/login", provides: 'json' do
if user = login(json_params)
{ message: 'Logged in' }.to_json
else
halt 400, { message: 'Invalid credentials' }.to_json
end
end
summary 'Register a new account if the username does not exists already'
notes ''
produces 'application/json'
status_codes [200]
parameter :username, required: true, type: 'string', in: 'body'
parameter :password, required: true, type: 'string', in: 'body'
post "/register", provides: 'json' do
if user_id = register(json_params)
{ message: "Registered as user_id=#{user_id}", user: { id: user_id, username: json_params["username"] } }.to_json
else
halt 400, { message: "Failed to register as #{json_params['username']}" }.to_json
end
end
summary 'Change the authentication password of the account'
produces 'application/json'
status_codes [200]
parameter :password, required: true, type: 'string', in: 'body'
parameter :auth, required: true, type: 'string', in: 'cookies'
post "/password", auth: [], provides: 'html' do
change_password(json_params)
{ message: 'password changed' }.to_json
end
end
include LifePex::Systems::ApiList
end