module Api module V1 class AudienceSegmentsController < ApiController DEFAULT_PER_PAGE = 30 MAX_USER_IDS = 10_000 USER_ATTRIBUTES_FOR_SERIALIZATION = %i[ id username name twitter_username github_username profile_image website_url location summary created_at ].freeze before_action :authenticate_with_api_key! before_action :require_admin before_action :restrict_user_ids, only: %i[add_users remove_users] def index page, per_page = pagination_params @segments = scope.including_user_counts.order(id: :desc).page(page).per(per_page) render json: @segments end def show @segment = scope.including_user_counts.find(params[:id]) render json: @segment end def create @segment = AudienceSegment.create!(type_of: "manual") render json: @segment, status: :created end def destroy @segment = scope.find(params[:id]) if Billboard.where(audience_segment_id: @segment.id).any? render json: { error: "Segments cannot be deleted while in use by any billboards" }, status: :conflict else @segment.segmented_users.in_batches.delete_all result = @segment.destroy render json: @segment, status: (result ? :ok : :conflict) end end def users @segment = scope.find(params[:id]) page, per_page = pagination_params @users = @segment.users.joins(:profile).select(USER_ATTRIBUTES_FOR_SERIALIZATION).page(page).per(per_page) end def add_users @segment = scope.find(params[:id]) render json: SegmentedUsers::BulkUpsert.call(@segment, user_ids: @user_ids) end def remove_users @segment = scope.find(params[:id]) render json: SegmentedUsers::BulkDelete.call(@segment, user_ids: @user_ids) end private def require_admin authorize AudienceSegment, :access?, policy_class: InternalPolicy end def restrict_user_ids @user_ids = params.permit(user_ids: []).require(:user_ids) return unless @user_ids.size > MAX_USER_IDS render json: { error: "Too many user IDs provided" }, status: :unprocessable_entity end def pagination_params per_page_param = params[:per_page] || DEFAULT_PER_PAGE max_per_page = ApplicationConfig["API_PER_PAGE_MAX"] || 1000 per_page = [per_page_param, max_per_page].map(&:to_i).min [params[:page].to_i, per_page] end def scope AudienceSegment.manual end end end end