# frozen_string_literal: true # A code that can be redeemed for a Gold account. Codes are pre-generated and # one time use only. Upgrade codes are sold in the Danbooru store. class UpgradeCode < ApplicationRecord class InvalidCodeError < StandardError; end class RedeemedCodeError < StandardError; end class AlreadyUpgradedError < StandardError; end UPGRADE_CODE_LENGTH = 8 attribute :code, default: -> { UpgradeCode.generate_code } attribute :status, default: :unsold belongs_to :creator, class_name: "User" belongs_to :redeemer, class_name: "User", optional: true belongs_to :user_upgrade, optional: true enum status: { unsold: 0, unredeemed: 100, redeemed: 200, } def self.visible(user) if user.is_owner? all elsif user.is_anonymous? none else where(redeemer: user).or(where(creator: user)) end end def self.search(params, current_user) q = search_attributes(params, [:id, :created_at, :updated_at, :code, :status, :creator, :redeemer, :user_upgrade], current_user: current_user) q.apply_default_order(params) end def self.generate_code SecureRandom.send(:choose, [*"0".."9", *"A".."Z", *"a".."z"], UPGRADE_CODE_LENGTH) # base62 end def self.redeem!(code:, redeemer:) upgrade_code = UpgradeCode.find_by(code: code) raise InvalidCodeError, "This upgrade code is invalid" if upgrade_code.nil? upgrade_code.redeem!(redeemer) end def redeem!(redeemer) transaction do raise RedeemedCodeError, "This upgrade code has already been used" if redeemed? raise AlreadyUpgradedError, "Your account is already Gold or higher" if redeemer.is_gold? user_upgrade = UserUpgrade.create!(recipient: redeemer, purchaser: redeemer, status: "processing", upgrade_type: "gold", payment_processor: "upgrade_code") user_upgrade.process_upgrade!("paid") update!(status: :redeemed, redeemer: redeemer, user_upgrade: user_upgrade) self end end end