app/controllers/api/v8/users_controller.rb
# frozen_string_literal: true
module Api
module V8
class UsersController < Api::V8::BaseController
include Swagger::Blocks
swagger_path '/api/v8/users/{user_id}' do
operation :get do
key :description, "Returns the user's username, email, and administrator status by user id"
key :operationId, 'findUsersBasicInfoById'
key :produces, [
'application/json'
]
key :tags, [
'user'
]
parameter '$ref': '#/parameters/path_user_id'
response 200 do
key :description, "User's username, email, and administrator status by id as json"
schema do
key :title, :user
key :required, [:user]
property :user do
key :'$ref', :UsersBasicInfo
end
end
end
response 403, '$ref': '#/responses/error'
response 404, '$ref': '#/responses/error'
end
end
swagger_path '/api/v8/users/current' do
operation :get do
key :description, "Returns the current user's username, email, and administrator status"
key :operationId, 'findUsersBasicInfo'
key :produces, [
'application/json'
]
key :tags, [
'user'
]
response 200 do
key :description, "User's username, email, and administrator status as json"
schema do
key :title, :user
key :required, [:user]
property :user do
key :'$ref', :UsersBasicInfo
end
end
end
response 403, '$ref': '#/responses/error'
response 404, '$ref': '#/responses/error'
end
end
def show
unauthorize_guest! if current_user.guest?
user = current_user
user = User.find_by!(id: params[:id]) unless params[:id] == 'current'
authorize! :read, user
data = {
id: user.id,
username: user.login,
email: user.email,
administrator: user.administrator
}
if params[:show_user_fields]
user_field = {}
UserField.all.select { |f| f.visible_to?(current_user) }.each do |field|
value_record = user.field_value_record(field)
value = value_record.ruby_value
user_field[field.name] = value
end
data[:user_field] = user_field
end
if params[:extra_fields]
extra_fields = {}
namespace = params[:extra_fields]
UserAppDatum.where(namespace: namespace, user: user).each do |datum|
extra_fields[datum.field_name] = datum.value
end
data[:extra_fields] = extra_fields
end
render json: data
end
def create
authorize! :create, User
@user = User.new
@user.login = SecureRandom.uuid
set_email
set_password
set_user_fields
set_extra_data
if BannedEmail.banned?(@user.email)
return render json: {
success: true,
message: 'User created.'
}
end
if @user.errors.empty? && @user.save
# TODO: Whitelist origins
UserMailer.email_confirmation(@user, params[:origin], params[:language]).deliver_now
render json: {
success: true,
message: 'User created.'
}
else
errors = @user.errors
errors[:username] = errors.delete(:login) if errors.key?(:login)
render json: {
success: false,
errors: @user.errors
}
end
end
def update
unauthorize_guest! if current_user.guest?
User.transaction do
@user = current_user
@user = User.find_by!(id: params[:id]) unless params[:id] == 'current'
@email_before = @user.email
authorize! :update, @user
set_user_fields
set_extra_data(true)
update_email
maybe_update_password
raise ActiveRecord::Rollback if !@user.errors.empty? || !@user.save
RecentlyChangedUserDetail.email_changed.create!(old_value: @email_before, new_value: @user.email, username: @user.login, user_id: @user.id) unless @email_before.casecmp(@user.email).zero?
return render json: {
message: 'User details updated.'
}
end
render json: {
errors: @user.errors
}, status: :bad_request
end
private
def set_email
user_params = params[:user]
return unless @user.new_record?
if user_params[:email].blank?
@user.errors.add(:email, 'needed')
else
@user.email = user_params[:email].strip
end
end
def update_email
user_params = params[:user]
return unless user_params[:email]
new_email = user_params[:email].strip
if new_email.blank?
@user.errors.add(:email, 'needed')
elsif @user.email.casecmp(new_email) != 0
@user.email = new_email
@user.email_verified = false
end
end
def set_password
user_params = params[:user]
if user_params[:password].blank?
@user.errors.add(:password, 'needed')
elsif user_params[:password].length > 1000
@user.errors.add(:password, 'cannot be over 1000 characters')
elsif user_params[:password] != user_params[:password_confirmation]
@user.errors.add(:password_confirmation, 'did not match')
else
@user.password = user_params[:password]
end
end
def maybe_update_password
if params[:old_password].present? && params[:password].present?
if !@user.has_password?(params[:old_password])
@user.errors.add(:old_password, 'incorrect')
elsif params[:password] != params[:password_repeat]
@user.errors.add(:password_repeat, 'did not match')
elsif params[:password].blank?
@user.errors.add(:password, 'cannot be empty')
elsif params[:password].length > 1000
@user.errors.add(:password, 'cannot be over 1000 characters')
else
@user.password = params[:password]
end
end
end
def set_user_fields
return if params[:user_field].nil?
changes = {}
UserField.all.select { |f| f.visible_to?(current_user) }.each do |field|
value_record = @user.field_value_record(field)
old_value = value_record.ruby_value
value_record.set_from_form(params[:user_field][field.name])
new_value = value_record.ruby_value
changes[field.name] = { from: old_value, to: new_value } unless new_value == old_value
end
changes
end
def set_extra_data(eager_save = false)
return unless params['user']
extra_fields = params['user']['extra_fields']
return if extra_fields.nil?
namespace = extra_fields['namespace']
raise 'Namespace not defined' unless namespace
extra_fields['data'].each do |key, value|
datum = @user.user_app_data.find_or_initialize_by(namespace: namespace, field_name: key)
datum.value = value
datum.save! if eager_save
end
end
end
end
end