class API::MembersController < API::ApiController before_action :authenticate_user!, except: [:last_subscribed] before_action :set_member, only: [:update, :destroy, :merge] respond_to :json def index @requested_attributes = params[:requested_attributes] @query = policy_scope(User) unless params[:page].nil? and params[:size].nil? @query = @query.page(params[:page].to_i).per(params[:size].to_i) end # remove unmerged profiles from list @members = @query.to_a @members.delete_if(&:need_completion?) end def last_subscribed @query = User.active.with_role(:member).includes(profile: [:user_avatar]).where('is_allow_contact = true AND confirmed_at IS NOT NULL').order('created_at desc').limit(params[:last]) # remove unmerged profiles from list @members = @query.to_a @members.delete_if(&:need_completion?) @requested_attributes = ['profile'] render :index end def show @member = User.friendly.find(params[:id]) authorize @member end def create authorize User if !user_params[:password] and !user_params[:password_confirmation] generated_password = Devise.friendly_token.first(8) @member = User.new(user_params.merge(password: generated_password).permit!) else @member = User.new(user_params.permit!) end # if the user is created by an admin and the authentication is made through an SSO, generate a migration token if current_user.admin? and AuthProvider.active.providable_type != DatabaseProvider.name @member.generate_auth_migration_token end if @member.save @member.generate_subscription_invoice @member.send_confirmation_instructions if !user_params[:password] and !user_params[:password_confirmation] UsersMailer.delay.notify_user_account_created(@member, generated_password) else UsersMailer.delay.notify_user_account_created(@member, user_params[:password]) end render :show, status: :created, location: member_path(@member) else render json: @member.errors, status: :unprocessable_entity end end def update authorize @member members_service = MembersService.new(@member) if user_params[:group_id] && @member.group_id != user_params[:group_id].to_i && !@member.subscribed_plan.nil? # here a group change is requested but unprocessable, handle the exception @member.errors[:group_id] = t('members.unable_to_change_the_group_while_a_subscription_is_running') render json: @member.errors, status: :unprocessable_entity else # otherwise, run the user update if members_service.update(user_params) # Update password without logging out sign_in(@member, bypass: true) unless current_user.id != params[:id].to_i render :show, status: :ok, location: member_path(@member) else render json: @member.errors, status: :unprocessable_entity end end end def destroy authorize @member @member.soft_destroy sign_out(@member) head :no_content end # export subscriptions def export_subscriptions authorize :export export = Export.where(category:'users', export_type: 'subscriptions').where('created_at > ?', Subscription.maximum('updated_at')).last if export.nil? || !FileTest.exist?(export.file) @export = Export.new(category:'users', export_type: 'subscriptions', user: current_user) if @export.save render json: { export_id: @export.id }, status: :ok else render json: @export.errors, status: :unprocessable_entity end else send_file File.join(Rails.root, export.file), type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', disposition: 'attachment' end end # export reservations def export_reservations authorize :export export = Export.where(category:'users', export_type: 'reservations') .where('created_at > ?', Reservation.maximum('updated_at')) .last if export.nil? || !FileTest.exist?(export.file) @export = Export.new(category: 'users', export_type: 'reservations', user: current_user) if @export.save render json: { export_id: @export.id }, status: :ok else render json: @export.errors, status: :unprocessable_entity end else send_file File.join(Rails.root, export.file), type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', disposition: 'attachment' end end def export_members authorize :export export = Export.where(category:'users', export_type: 'members') .where('created_at > ?', User.with_role(:member).maximum('updated_at')) .last if export.nil? || !FileTest.exist?(export.file) @export = Export.new(category:'users', export_type: 'members', user: current_user) if @export.save render json: { export_id: @export.id }, status: :ok else render json: @export.errors, status: :unprocessable_entity end else send_file File.join(Rails.root, export.file), type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', disposition: 'attachment' end end def merge authorize @member # here the user query to be mapped to his already existing account token = params.require(:user).permit(:auth_token)[:auth_token] @account = User.find_by(auth_token: token) if @account members_service = MembersService.new(@account) begin if members_service.merge_from_sso(@member) @member = @account # finally, log on the real account sign_in(@member, bypass: true) render :show, status: :ok, location: member_path(@member) else render json: @member.errors, status: :unprocessable_entity end rescue DuplicateIndexError => error render json: { error: t('members.please_input_the_authentication_code_sent_to_the_address', EMAIL: error.message) }, status: :unprocessable_entity end else render json: { error: t('members.your_authentication_code_is_not_valid') }, status: :unprocessable_entity end end def list authorize User p = params.require(:query).permit(:search, :order_by, :page, :size) render json: {error: 'page must be an integer'}, status: :unprocessable_entity unless p[:page].is_a? Integer render json: {error: 'size must be an integer'}, status: :unprocessable_entity unless p[:size].is_a? Integer direction = (p[:order_by][0] == '-' ? 'DESC' : 'ASC') order_key = (p[:order_by][0] == '-' ? p[:order_by][1, p[:order_by].size] : p[:order_by]) order_key = case order_key when 'last_name' 'profiles.last_name' when 'first_name' 'profiles.first_name' when 'email' 'users.email' when 'phone' 'profiles.phone' when 'group' 'groups.name' when 'plan' 'plans.base_name' else 'users.id' end @query = User.includes(:profile, :group, :subscriptions) .joins(:profile, :group, :roles, 'LEFT JOIN "subscriptions" ON "subscriptions"."user_id" = "users"."id" LEFT JOIN "plans" ON "plans"."id" = "subscriptions"."plan_id"') .where("users.is_active = 'true' AND roles.name = 'member'") .order("#{order_key} #{direction}") .page(p[:page]) .per(p[:size]) # ILIKE => PostgreSQL case-insensitive LIKE @query = @query.where('profiles.first_name ILIKE :search OR profiles.last_name ILIKE :search OR profiles.phone ILIKE :search OR email ILIKE :search OR groups.name ILIKE :search OR plans.base_name ILIKE :search', search: "%#{p[:search]}%") if p[:search].size > 0 @members = @query.to_a end def search @members = User.includes(:profile) .joins(:profile, :roles, 'LEFT JOIN "subscriptions" ON "subscriptions"."user_id" = "users"."id"') .where("users.is_active = 'true' AND roles.name = 'member'") .where("lower(f_unaccent(profiles.first_name)) ~ regexp_replace(:search, E'\\\\s+', '|') OR lower(f_unaccent(profiles.last_name)) ~ regexp_replace(:search, E'\\\\s+', '|')", search: params[:query].downcase) if current_user.member? # non-admin can only retrieve users with "public profiles" @members = @members.where("users.is_allow_contact = 'true'") else # only admins have the ability to filter by subscription if params[:subscription] === 'true' @members = @members.where('subscriptions.id IS NOT NULL AND subscriptions.expired_at >= :now', now: Date.today.to_s) elsif params[:subscription] === 'false' @members = @members.where('subscriptions.id IS NULL OR subscriptions.expired_at < :now', now: Date.today.to_s) end end @members = @members.to_a end def mapping authorize User @members = User.includes(:profile) end private def set_member @member = User.find(params[:id]) end def user_params if current_user.id == params[:id].to_i params.require(:user).permit(:username, :email, :password, :password_confirmation, :group_id, :is_allow_contact, :is_allow_newsletter, profile_attributes: [:id, :first_name, :last_name, :gender, :birthday, :phone, :interest, :software_mastered, :website, :job, :facebook, :twitter, :google_plus, :viadeo, :linkedin, :instagram, :youtube, :vimeo, :dailymotion, :github, :echosciences, :pinterest, :lastfm, :flickr, user_avatar_attributes: %i[id attachment destroy], address_attributes: %i[id address], organization_attributes: [:id, :name, address_attributes: %i[id address]]]) elsif current_user.admin? params.require(:user).permit(:username, :email, :password, :password_confirmation, :is_allow_contact, :is_allow_newsletter, :group_id, training_ids: [], tag_ids: [], profile_attributes: [:id, :first_name, :last_name, :gender, :birthday, :phone, :interest, :software_mastered, :website, :job, :facebook, :twitter, :google_plus, :viadeo, :linkedin, :instagram, :youtube, :vimeo, :dailymotion, :github, :echosciences, :pinterest, :lastfm, :flickr, user_avatar_attributes: %i[id attachment destroy], address_attributes: %i[id address], organization_attributes: [:id, :name, address_attributes: %i[id address]]]) end end end