# frozen_string_literal: true module YiffRocks class HomeController < ApplicationController include ::ApplicationController::ReadonlyMethods before_action :handle_ratelimit, only: %i[create update destroy] before_action :validate_api_key_required, only: %i[create update destroy] before_action :validate_shortener_access, only: %i[create update destroy] before_action :load_shorturl, only: %i[update destroy] before_action :ensure_edit_access, only: %i[update destroy] before_action -> { track_usage("shortener") }, except: %i[index] wrap_parameters format: :json, name: "short_url" def index end def show code = params[:code] preview = code.ends_with?("+") code = code[..-2] if preview if params[:format] == "json" return if handle_ratelimit && performed? return if validate_api_key_required && performed? return if validate_shortener_access && performed? @short = ShortUrl.find_by(code: code) return render_error(YiffyAPIErrorCodes::SHORTENER_NOT_FOUND, error: "A short url with that code was not found.") if @short.nil? return render(json: { success: true, data: @short, }) end @short = ShortUrl.find_by(code: code) return render(plain: "Unknown short url code.", status: 404) if @short.nil? return render("preview") if preview redirect_to(@short.url, allow_other_host: true) end def create @short_url = ShortUrl.create(creator_ua: request.headers["User-Agent"], **short_url_params(:create)) handle_errors return if performed? render(json: @short_url) end def update @short_url.update(short_url_params(:update)) handle_errors return if performed? return render_error(YiffyAPIErrorCodes::SHORTENER_NO_CHANGES, message: "No changes were detected.") unless @short_url.saved_change_to_url? || @short_url.saved_change_to_creator_name? render(json: @short_url) end def destroy @short_url.destroy end private def short_url_params(context = nil) permitted_params = %i[url credit creator_name] permitted_params += %i[code] if context == :create params.require(:short_url).permit(permitted_params) end def handle_errors if @short_url.errors.any? @short_url.errors.full_messages.each do |error| return render_error(YiffyAPIErrorCodes::SHORTENER_CODE_TOO_LONG, message: error, errors: @short_url.errors.full_messages) if error.to_s =~ /Code is too long/ return render_error(YiffyAPIErrorCodes::SHORTENER_INVALID_CODE, message: error, errors: @short_url.errors.full_messages) if error.to_s =~ /Code is invalid/ return render_error(YiffyAPIErrorCodes::SHORTENER_INVALID_URL, message: error, errors: @short_url.errors.full_messages) if error.to_s =~ /Url is invalid/ return render_error(YiffyAPIErrorCodes::SHORTENER_URL_TOO_LONG, message: error, errors: @short_url.errors.full_messages) if error.to_s =~ /Url is too long/ return render_error(YiffyAPIErrorCodes::SHORTENER_CREDIT_TOO_LONG, message: error, errors: @short_url.errors.full_messages) if error.to_s =~ /Creator name is too long/ return render_error(YiffyAPIErrorCodes::SHORTENER_CODE_IN_USE, message: error, errors: @short_url.errors.full_messages) if error.to_s =~ /Code has already been taken/ @short_url.save! # Make further failed validations raise end end end def load_shorturl @short_url = ShortUrl.find_by(code: params[:code]) render_error(YiffyAPIErrorCodes::SHORTENER_NOT_FOUND, message: "A short url with that code was not found.") if @short_url.nil? end def ensure_edit_access management_code = params.fetch(:short_url, {}).permit(:managementCode)[:managementCode] params[:short_url].delete(:managementCode) if management_code.present? if CurrentUser.user.id != @short_url.creator_id return render_error(YiffyAPIErrorCodes::SHORTENER_NO_MANAGEMENT_CODE, message: "That short url cannot be edited by you.") if @short_url.management_code.blank? || management_code.blank? render_error(YiffyAPIErrorCodes::SHORTENER_MANAGEMENT_CODE_MISMATCH, message: "That management code does not match this short url.") if management_code != @short_url.management_code end end end end