# frozen_string_literal: true module YiffRest class ApikeysController < ApplicationController include ::ApplicationController::ReadonlyMethods before_action :validate_discord, except: %i[logout] before_action :handle_ratelimit, except: %i[index logout] before_action :prepare_user, except: %i[logout] before_action :load_apikey, except: %i[index new create logout] before_action :manager_only, only: %i[disable] before_action :admin_only, only: %i[edit] before_action :check_can_create_apikeys, only: %i[new create] before_action -> { check_apikey_access(:can_edit?) }, only: %i[update] before_action -> { check_apikey_access(:can_delete?) }, only: %i[destroy] before_action -> { check_apikey_access(:can_disable?) }, only: %i[disable enable] before_action -> { check_apikey_access(:can_deactivate?) }, only: %i[deactivate reactivate] before_action -> { check_apikey_access(:can_regenerate?) }, only: %i[regenerate] protect_from_forgery with: :exception def index @apikeys = APIKey.all @apikeys = @apikeys.where(owner_id: CurrentUser.id) unless CurrentUser.is_manager? @apikeys = @apikeys.search(search_params) end def new @apikey = APIKey.new(owner_id: CurrentUser.id) end def edit end def create allowed_params = apikey_params allowed_params[:owner_id] ||= CurrentUser.id apiuser = APIUser.find_by(id: allowed_params[:owner_id]) APIUser.create!(id: allowed_params[:owner_id], name: "User#{allowed_params[:owner_id]}") if apiuser.nil? @apikey = APIKey.create(allowed_params) if @apikey.errors.any? redirect_back(fallback_location: new_yiff_rest_apikey_path, notice: @apikey.errors.full_messages.join("; ")) else redirect_to(yiff_rest_apikeys_path, notice: "API Key created. You can view the documentation via the link in the top bar. Click \"View\" to see your apikey.") end end def update @apikey.update(apikey_params) return redirect_back(fallback_location: edit_yiff_rest_apikey_path(@apikey), notice: @apikey.errors.full_messages.join("; ")) if @apikey.errors.any? redirect_to(yiff_rest_apikeys_path, notice: "API Key Updated.") end def destroy @apikey.destroy redirect_back(fallback_location: yiff_rest_apikeys_path) end def disable @apikey.update(disabled: true, disabled_reason: disable_params[:disabled_reason]) redirect_back(fallback_location: yiff_rest_apikeys_path, notice: @apikey.errors.any? ? @apikey.errors.full_messages : "API Key disabled.") end def enable @apikey.update(disabled: false, disabled_reason: nil) redirect_back(fallback_location: yiff_rest_apikeys_path, notice: @apikey.errors.any? ? @apikey.errors.full_messages : "API Key enabled.") end def deactivate @apikey.update(active: false) redirect_back(fallback_location: yiff_rest_apikeys_path, notice: @apikey.errors.any? ? @apikey.errors.full_messages : "API Key deactivated.") end def reactivate @apikey.update(active: true) redirect_back(fallback_location: yiff_rest_apikeys_path, notice: @apikey.errors.any? ? @apikey.errors.full_messages : "API Key reactivated.") end def regenerate @apikey.regenerate! redirect_back(fallback_location: yiff_rest_apikeys_path, notice: @apikey.errors.any? ? @apikey.errors.full_messages : "API Key regenerated.") end def logout session.delete("discord_user") CurrentUser.user = nil redirect_to(yiff_rest_root_path, notice: "You have been logged out.") end private def site_domain YiffRestRoutes::DOMAIN end def site_title "YiffyAPI - API Keys" end def assets_path YiffMediaRoutes::DOMAIN end def validate_discord redirect_to(Websites.config.yiffyapi_discord_redirect("apikey"), allow_other_host: true) if session[:discord_user].blank? end def apikey_params permitted_params = %i[application_name usage] permitted_params += %i[super unlimited bulk_limit limit_long limit_short window_long window_short flags_images flags_thumbs flags_shortener flags_images_bulk owner_id] if CurrentUser.is_admin? params.require(:api_key).permit(permitted_params) end def disable_params params.require(:api_key).permit(:disabled_reason) end def search_params permitted_params = %i[] permitted_params += %i[owner_id application_name usage active disabled disabled_reason] if CurrentUser.is_manager? permit_search_params(permitted_params) end def handle_ratelimit info, body, rlheaders = RateLimiter.process(request, ignore_auth: true) headers.merge!(rlheaders) return if info.nil? # noinspection RubyCaseWithoutElseBlockInspection case info when :RATELIMIT_SHORT render_error(YiffyAPIErrorCodes::RATELIMIT_ROUTE, error: "Request Limit Exceeded", info: body) when :RATELIMIT_LONG render_error(YiffyAPIErrorCodes::RATELIMIT_GLOBAL, error: "Request Limit Exceeded", info: body) end end def prepare_user name = session.dig("discord_user", "global_name") || "#{session.dig('discord_user', 'username')}#{@session.dig('discord_user', 'discriminator')}" CurrentUser.user = APIUser.find_or_create_by(id: session.dig("discord_user", "id")) CurrentUser.update!(name: name, discord_data: session["discord_user"]) CurrentUser.update_avatar(session.dig("discord_user", "avatar")) end def load_apikey @apikey = APIKey.find(params[:id]) end def check_apikey_access(method) return if @apikey.nil? access_denied(message: "You don't have access to that.") unless @apikey.send(method, CurrentUser) end def check_can_create_apikeys return if CurrentUser.is_admin? access_denied(message: "You already have the maximum amount of apikeys.") unless CurrentUser.can_create_apikey? end end end