Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

auction api for mobile app #1167

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,4 @@ app/assets/builds/*
!/app/assets/builds/.keep

Dockerfile.dev

3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,6 @@ group :test do
gem 'spy'
gem 'webmock'
end

gem 'devise-jwt'
gem 'jsonapi-serializer'
21 changes: 21 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,22 @@ GEM
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
devise-jwt (0.11.0)
devise (~> 4.0)
warden-jwt_auth (~> 0.8)
docile (1.4.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
erubi (1.13.0)
dry-auto_inject (1.0.1)
dry-core (~> 1.0)
zeitwerk (~> 2.6)
dry-configurable (1.1.0)
dry-core (~> 1.0, < 2)
zeitwerk (~> 2.6)
dry-core (1.0.1)
concurrent-ruby (~> 1.0)
zeitwerk (~> 2.6)
event_stream_parser (1.0.0)
faker (3.2.0)
i18n (>= 1.8.11, < 2)
Expand Down Expand Up @@ -234,6 +246,8 @@ GEM
bindata
faraday (~> 2.0)
faraday-follow_redirects
jsonapi-serializer (2.2.0)
activesupport (>= 4.2)
jwt (2.7.1)
language_server-protocol (3.17.0.3)
launchy (2.5.2)
Expand Down Expand Up @@ -507,6 +521,11 @@ GEM
method_source (~> 1.0)
warden (1.2.9)
rack (>= 2.0.9)
warden-jwt_auth (0.8.0)
dry-auto_inject (>= 0.8, < 2)
dry-configurable (>= 0.13, < 2)
jwt (~> 2.1)
warden (~> 1.2)
web-console (4.2.0)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
Expand Down Expand Up @@ -552,6 +571,7 @@ DEPENDENCIES
delayed_job (~> 4.1.0)
delayed_job_active_record
devise
devise-jwt
directo!
faker
faraday
Expand All @@ -561,6 +581,7 @@ DEPENDENCIES
i18n-debug
jbuilder (~> 2.11)
jsbundling-rails
jsonapi-serializer
jwt
letter_opener (~> 1.8)
letter_opener_web (~> 3.0)
Expand Down
18 changes: 18 additions & 0 deletions app/broadcasts/auctions/update_list_broadcast_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ def call

private

# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
def post_call
participants = auction.offers.map(&:user)

Expand All @@ -25,6 +27,22 @@ def post_call
locals: { auction:, user:, updated: participants.include?(user) }
end


auction_json = {
domain_name: auction.domain_name,
starts_at: auction.starts_at,
ends_at: auction.ends_at,
id: auction.uuid,
highest_bid: auction.currently_winning_offer&.price.to_f,
highest_bidder: auction.currently_winning_offer&.username,
min_bids_step: auction.min_bids_step,
auction_type: auction&.platform,
enable_deposit: auction.enable_deposit,
requirement_deposit_in_cents: auction.requirement_deposit_in_cents
}

ActionCable.server.broadcast('auctions_api', { auction: auction_json })

broadcast_later 'auctions',
'auctions/streams/updated_list',
locals: { auction:, user: nil, updated: false }
Expand Down
11 changes: 11 additions & 0 deletions app/channels/auctions_api_channel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class AuctionsApiChannel < ApplicationCable::Channel
def subscribed
Rails.logger.info 'Client subscribed to AuctionsChannel'
stream_from 'auctions_api'
end

def unsubscribed
Rails.logger.info 'Client unsubscribed from AuctionsChannel'
# Any cleanup needed when channel is unsubscribed
end
end
23 changes: 23 additions & 0 deletions app/controllers/api/v1/auctions_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Api
module V1
class AuctionsController < ApplicationController
before_action :authenticate_user!
respond_to :json

skip_before_action :verify_authenticity_token

def show
@auction = Auction.find_by!(uuid: params[:auction_id])
offer = @auction.offer_from_user(current_user.id)
autobider = current_user.autobiders.find_or_initialize_by(domain_name: @auction.domain_name)
billing_profiles = BillingProfile.accessible_by(current_ability).where(user_id: current_user.id)

render json: {
offer: offer,
autobider: autobider,
billing_profiles: billing_profiles
}, status: :ok
end
end
end
end
44 changes: 44 additions & 0 deletions app/controllers/api/v1/autobiders_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module Api
module V1
class AutobidersController < ApplicationController
before_action :authenticate_user!
respond_to :json

skip_before_action :verify_authenticity_token

def create
@autobider = Autobider.find_by(user_id: current_user.id, id: strong_params[:id])

if @autobider.nil?
@autobider = Autobider.new(strong_params.merge(user: current_user))
else
@autobider.price = strong_params[:price]
end

if @autobider.save
auction = Auction.where(domain_name: @autobider.domain_name).order(:created_at).last
AutobiderService.autobid(auction) unless skip_autobid(auction)

Auctions::UpdateListBroadcastService.call({ auction: })

render json: { status: 'ok' }, status: :ok
else
render json: { status: 'error' }, status: :unprocessable_entity
end
end

private

def skip_autobid(auction)
return false if auction.offers.empty?

offer = auction.offers.order(:updated_at).last
offer.user == @autobider.user
end

def strong_params
params.require(:autobider).permit(:id, :domain_name, :price)
end
end
end
end
49 changes: 49 additions & 0 deletions app/controllers/api/v1/billing_profiles_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
module Api
module V1
class BillingProfilesController < ApplicationController
before_action :authenticate_user!
respond_to :json

skip_before_action :verify_authenticity_token

rescue_from ActiveRecord::RecordNotUnique, with: :handle_unique_violation

def index
@billing_profiles = current_user.billing_profiles

render json: { billing_profiles: @billing_profiles }
end

def update
@billing_profile = current_user.billing_profiles.find(params[:id])

if @billing_profile.update(billing_profile_params)
render json: { billing_profile: @billing_profile }
else
render json: { errors: @billing_profile.errors }, status: 422
end
end

def create
@billing_profile = current_user.billing_profiles.new(billing_profile_params)

if @billing_profile.save
render json: { billing_profile: @billing_profile }
else
render json: { errors: @billing_profile.errors }, status: 422
end
end

private

def billing_profile_params
params.require(:billing_profile).permit(:name, :vat_code, :street, :city, :state, :postal_code,
:alpha_two_country_code, :uuid)
end

def handle_unique_violation
render json: { errors: 'A billing profile with the same VAT code for this user already exists.' }, status: 422
end
end
end
end
48 changes: 48 additions & 0 deletions app/controllers/api/v1/invoices_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
module Api
module V1
class InvoicesController < ApplicationController
before_action :authenticate_user!
respond_to :json

skip_before_action :verify_authenticity_token

# rubocop:disable Metrics/AbcSize
def index
@issued_invoices = invoices_list_by_status(Invoice.statuses[:issued])
@paid_invoices = invoices_list_by_status(Invoice.statuses[:paid])
@cancelled_payable_invoices = invoices_list_by_status(Invoice.statuses[:cancelled]).with_ban
@cancelled_expired_invoices = invoices_list_by_status(Invoice.statuses[:cancelled]).without_ban
@deposit_paid = current_user.domain_participate_auctions.order(created_at: :desc)

render json: { issued_invoices: @issued_invoices, paid_invoices: @paid_invoices,
cancelled_payable_invoices: @cancelled_payable_invoices, cancelled_expired_invoices: @cancelled_expired_invoices, deposit_paid: @deposit_paid }
end

def pay_deposit
auction = Auction.find_by(uuid: params[:id])

render json: { errors: 'Auction not found' } and return unless auction

description = "auction_deposit #{auction.domain_name}, user_uuid #{current_user.uuid}, " \
"user_email #{current_user.email}"

response = EisBilling::PayDepositService.call(amount: auction.deposit,
customer_url: mobile_payments_deposit_callback_url, description:)
if response.result?
render json: { oneoff_redirect_link: response.instance['oneoff_redirect_link'] }
else
render json: { errors: response.errors }
end
end

private

def invoices_list_by_status(status)
Invoice.accessible_by(current_ability)
.where(user_id: current_user.id)
.where(status:)
.order(due_date: :desc)
end
end
end
end
66 changes: 66 additions & 0 deletions app/controllers/api/v1/offers_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
module Api
module V1
class OffersController < ApplicationController
before_action :authenticate_user!
respond_to :json

skip_before_action :verify_authenticity_token

def index
offers = Offer.includes(:auction)
.includes(:result)
.where(user_id: current_user)
.order('auctions.ends_at DESC')

# price with tax
render json: offers.as_json(
include: %i[auction billing_profile],
methods: %i[auction_status api_price api_total api_bidders]
)
end

# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
def create
auction = Auction.find_by(uuid: params[:bid][:auction_id])
return if auction.nil?

billing_profile = current_user.billing_profiles.find_by(id: params[:bid][:billing_profile_id])

offer = auction.offer_from_user(current_user.id)

if offer.nil?
offer = Offer.new(
auction:,
user: current_user,
cents: Money.from_amount(params[:bid][:price]).cents,
billing_profile:,
username: auction.english? ? Username::GenerateUsernameService.new.call : nil
)
else
offer.cents = Money.from_amount(params[:bid][:price]).cents
end

if offer.save
if auction.english?
Auctions::UpdateListBroadcastService.call({ auction: })

auction.update_minimum_bid_step(params[:bid][:price].to_f)

AutobiderService.autobid(auction)
auction.update_ends_at(offer)
end

render json: { status: 'ok' }, status: :ok
else

Rails.logger.info('----')
Rails.logger.info(offer.errors.inspect)
Rails.logger.info('----')

render json: { status: 'error' }, status: :unprocessable_entity
end
end
end
end
end
32 changes: 32 additions & 0 deletions app/controllers/api/v1/profiles/passwords_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module Api
module V1
module Profiles
class PasswordsController < ApplicationController
before_action :authenticate_user!
respond_to :json

skip_before_action :verify_authenticity_token

def update
puts params_for_update

if current_user.valid_password?(params[:user][:current_password])
if current_user.update(params_for_update)
bypass_sign_in(current_user)
render json: current_user, status: :ok
else
Rails.logger.info current_user.errors.inspect
render json: current_user.errors, status: :unprocessable_entity
end
else
render json: { errors: [t('.incorrect_password')] }, status: :unprocessable_entity
end
end

def params_for_update
params.require(:user).permit(:password, :password_confirmation)
end
end
end
end
end
Loading
Loading