From 4b57b91cc148f23dab3153fcfa76def01801c1a6 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Fri, 13 Oct 2023 15:23:44 +0300 Subject: [PATCH 01/18] auction api for mobile app --- Gemfile | 3 +++ Gemfile.lock | 21 +++++++++++++++++++ app/controllers/auth/sessions_controller.rb | 3 +++ app/controllers/offers_controller.rb | 7 +++++++ app/models/user.rb | 3 ++- config/customization.yml.sample | 1 + config/initializers/devise.rb | 7 +++++++ db/migrate/20231013110924_add_jti_to_users.rb | 6 ++++++ db/structure.sql | 1 - 9 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20231013110924_add_jti_to_users.rb diff --git a/Gemfile b/Gemfile index 214045d3a..c46719db9 100644 --- a/Gemfile +++ b/Gemfile @@ -82,3 +82,6 @@ group :test do gem 'spy' gem 'webmock' end + +gem 'devise-jwt' +gem 'jsonapi-serializer' diff --git a/Gemfile.lock b/Gemfile.lock index 07ba13bed..913024a9f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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) @@ -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) @@ -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) @@ -552,6 +571,7 @@ DEPENDENCIES delayed_job (~> 4.1.0) delayed_job_active_record devise + devise-jwt directo! faker faraday @@ -561,6 +581,7 @@ DEPENDENCIES i18n-debug jbuilder (~> 2.11) jsbundling-rails + jsonapi-serializer jwt letter_opener (~> 1.8) letter_opener_web (~> 3.0) diff --git a/app/controllers/auth/sessions_controller.rb b/app/controllers/auth/sessions_controller.rb index 84e7577d1..23b900be3 100644 --- a/app/controllers/auth/sessions_controller.rb +++ b/app/controllers/auth/sessions_controller.rb @@ -2,6 +2,9 @@ module Auth class SessionsController < Devise::SessionsController include InvalidUserDataHelper after_action :set_invalid_data_flag_in_session, only: [:create] + + skip_before_action :verify_authenticity_token + respond_to :html, :json def create super diff --git a/app/controllers/offers_controller.rb b/app/controllers/offers_controller.rb index 415ba7711..2322fc831 100644 --- a/app/controllers/offers_controller.rb +++ b/app/controllers/offers_controller.rb @@ -6,6 +6,8 @@ class OffersController < ApplicationController before_action :set_offer, only: %i[show edit update destroy] before_action :authorize_offer_for_user, except: %i[new index create delete] + respond_to :html, :json + include RecaptchaValidatable recaptcha_action 'offer' @@ -46,6 +48,11 @@ def create def index offers = current_user.offers.search(params) @pagy, @offers = pagy(offers, items: params[:per_page] ||= 15) + + respond_to do |format| + format.html + format.json { render json: @offers.as_json(include: [:auction, :billing_profile]) } + end end # GET /offers/aa450f1a-45e2-4f22-b2c3-f5f46b5f906b diff --git a/app/models/user.rb b/app/models/user.rb index df47808f4..315de0254 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,6 +3,7 @@ class User < ApplicationRecord include Bannable include ReferenceNo + include Devise::JWT::RevocationStrategies::JTIMatcher PARTICIPANT_ROLE = 'participant'.freeze ADMINISTATOR_ROLE = 'administrator'.freeze @@ -12,7 +13,7 @@ class User < ApplicationRecord TARA_PROVIDER = 'tara'.freeze devise :database_authenticatable, :recoverable, :rememberable, :validatable, :confirmable, - :timeoutable + :timeoutable, :jwt_authenticatable, jwt_revocation_strategy: self alias_attribute :country_code, :alpha_two_country_code diff --git a/config/customization.yml.sample b/config/customization.yml.sample index 01ac5f519..8bf036ead 100644 --- a/config/customization.yml.sample +++ b/config/customization.yml.sample @@ -19,6 +19,7 @@ default: &default vapid_private: "2xl1lvaQARjFHRCKrPo2B-MbTAc1IZ3UrfugDh6cJiE=" mobile_sms_sent_time_limit_in_minutes: 1 + jwt_secret: '' mailer: # Host to which links from emails should redirect to diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index b00090533..7788ac1e9 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -29,6 +29,13 @@ def skip_format? config.navigational_formats = ['*/*', :html, :turbo_stream] +config.jwt do |jwt| + jwt.secret = AuctionCenter::Application.config.customization[:jwt_secret] + jwt.dispatch_requests = [ ['POST', %r{^/login$}] ] + jwt.revocation_requests = [ ['DELETE', %r{^/logout$}] ] + jwt.expiration_time = 30.minutes.to_i +end + config.warden do |manager| manager.failure_app = TurboFailureApp # manager.intercept_401 = false diff --git a/db/migrate/20231013110924_add_jti_to_users.rb b/db/migrate/20231013110924_add_jti_to_users.rb new file mode 100644 index 000000000..cf4d56a7b --- /dev/null +++ b/db/migrate/20231013110924_add_jti_to_users.rb @@ -0,0 +1,6 @@ +class AddJtiToUsers < ActiveRecord::Migration[7.0] + def change + add_column :users, :jti, :string + add_index :users, :jti, unique: true + end +end diff --git a/db/structure.sql b/db/structure.sql index f5c7d32b8..1a79afc58 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -3199,4 +3199,3 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240603120701'), ('20240604124707'); - From 06fc397e4c396ad206b262d251530f458e77edbd Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Mon, 27 Nov 2023 10:47:42 +0200 Subject: [PATCH 02/18] fixed websocket issue --- .../auctions/update_list_broadcast_service.rb | 2 ++ app/channels/auctions_api_channel.rb | 11 +++++++++++ app/controllers/api/stream_names_controller.rb | 12 ++++++++++++ config/routes.rb | 4 ++++ 4 files changed, 29 insertions(+) create mode 100644 app/channels/auctions_api_channel.rb create mode 100644 app/controllers/api/stream_names_controller.rb diff --git a/app/broadcasts/auctions/update_list_broadcast_service.rb b/app/broadcasts/auctions/update_list_broadcast_service.rb index 680658ff7..4dacd0293 100644 --- a/app/broadcasts/auctions/update_list_broadcast_service.rb +++ b/app/broadcasts/auctions/update_list_broadcast_service.rb @@ -25,6 +25,8 @@ def post_call locals: { auction:, user:, updated: participants.include?(user) } end + ActionCable.server.broadcast('auctions_api', { auction: }) + broadcast_later 'auctions', 'auctions/streams/updated_list', locals: { auction:, user: nil, updated: false } diff --git a/app/channels/auctions_api_channel.rb b/app/channels/auctions_api_channel.rb new file mode 100644 index 000000000..a292cde43 --- /dev/null +++ b/app/channels/auctions_api_channel.rb @@ -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 diff --git a/app/controllers/api/stream_names_controller.rb b/app/controllers/api/stream_names_controller.rb new file mode 100644 index 000000000..c7610dfbe --- /dev/null +++ b/app/controllers/api/stream_names_controller.rb @@ -0,0 +1,12 @@ +module Api + class StreamNamesController < ApplicationController + skip_before_action :verify_authenticity_token + + def show + stream_name = 'auctions' + signed_stream_name = ActionCable.server.pubsub.signed_stream_identifier(stream_name) + + render json: { signed_stream_name: } + end + end +end diff --git a/config/routes.rb b/config/routes.rb index 12b250650..4ce20364f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -6,6 +6,10 @@ end # mount ActionCable.server => '/cable' + namespace :api do + resource :stream_name, only: :show + end + get 'unsubscribe/unsubscribe' patch 'unsubscribe/update' root to: 'auctions#index' From ad0dddbf6d55c51c1990dc4de7ccb653a255bc38 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Mon, 4 Dec 2023 12:45:13 +0200 Subject: [PATCH 03/18] updated broadcast --- app/controllers/api/stream_names_controller.rb | 5 +++-- app/views/auctions/index.json.jbuilder | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/stream_names_controller.rb b/app/controllers/api/stream_names_controller.rb index c7610dfbe..ffb8ba531 100644 --- a/app/controllers/api/stream_names_controller.rb +++ b/app/controllers/api/stream_names_controller.rb @@ -3,8 +3,9 @@ class StreamNamesController < ApplicationController skip_before_action :verify_authenticity_token def show - stream_name = 'auctions' - signed_stream_name = ActionCable.server.pubsub.signed_stream_identifier(stream_name) + # stream_name = 'auctions' + # signed_stream_name = ActionCable.server.signed_stream_identifier(stream_name) + signed_stream_name = Turbo::StreamsChannel.signed_stream_name 'auctions' render json: { signed_stream_name: } end diff --git a/app/views/auctions/index.json.jbuilder b/app/views/auctions/index.json.jbuilder index 2c8ebbc4f..b846a1005 100644 --- a/app/views/auctions/index.json.jbuilder +++ b/app/views/auctions/index.json.jbuilder @@ -4,4 +4,7 @@ json.array! @auctions_list do |auction| json.ends_at auction.ends_at.utc json.auction_type auction&.platform json.id auction.uuid + json.highest_bid auction.currently_winning_offer&.price.to_f + json.highest_bidder auction.currently_winning_offer&.username + json.auction_type auction&.platform end From febca63dbeb371774c36cfe6e69813f13b13bbb3 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Mon, 11 Dec 2023 11:15:08 +0200 Subject: [PATCH 04/18] updated --- app/controllers/api/offers_controller.rb | 35 ++++++++++++++++++++ app/controllers/application_controller.rb | 1 + app/controllers/auth/sessions_controller.rb | 4 ++- app/controllers/concerns/rack_session_fix.rb | 15 +++++++++ app/controllers/english_offers_controller.rb | 2 ++ app/controllers/offers_controller.rb | 5 ++- config/application.rb | 17 ++++++++++ config/initializers/devise.rb | 4 +-- config/routes.rb | 1 + 9 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 app/controllers/api/offers_controller.rb create mode 100644 app/controllers/concerns/rack_session_fix.rb diff --git a/app/controllers/api/offers_controller.rb b/app/controllers/api/offers_controller.rb new file mode 100644 index 000000000..3eb5a8ded --- /dev/null +++ b/app/controllers/api/offers_controller.rb @@ -0,0 +1,35 @@ +module Api + class OffersController < ApplicationController + before_action :authenticate_user! + respond_to :json + + skip_before_action :verify_authenticity_token + + def create + # Offer offer = Offer( + # auctionId: widget.auction.uuid, + # cents: _bidAmount!.toInt(), + # userId: user.uuid, + # ); + + # offerBloc.add(AddOfferEvent(offer: offer, authToken: user.tempTokenStore!, auctionType: widget.auction.type!)); + # Navigator.of(context).pop(); + puts '=====' + puts params + puts '=====' + + auction = Auction.find_by(uuid: params[:auctionId]) + + offer = Offer.new + offer.price = params[:cents] + + puts '=====' + puts auction.inspect + puts offer.inspect + puts current_user.inspect + puts '=====' + + render json: { status: 'ok' }, status: :ok + end + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3ce1892bb..708433cbc 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -4,6 +4,7 @@ class ApplicationController < ActionController::Base helper_method :turbo_frame_request? protect_from_forgery with: :exception + before_action :set_locale, :clear_flash before_action :notifications_for_header diff --git a/app/controllers/auth/sessions_controller.rb b/app/controllers/auth/sessions_controller.rb index 23b900be3..d194186df 100644 --- a/app/controllers/auth/sessions_controller.rb +++ b/app/controllers/auth/sessions_controller.rb @@ -1,8 +1,10 @@ module Auth class SessionsController < Devise::SessionsController + include RackSessionFix include InvalidUserDataHelper + after_action :set_invalid_data_flag_in_session, only: [:create] - + skip_before_action :verify_authenticity_token respond_to :html, :json diff --git a/app/controllers/concerns/rack_session_fix.rb b/app/controllers/concerns/rack_session_fix.rb new file mode 100644 index 000000000..c062d6156 --- /dev/null +++ b/app/controllers/concerns/rack_session_fix.rb @@ -0,0 +1,15 @@ +module RackSessionFix + extend ActiveSupport::Concern + class FakeRackSession < Hash + def enabled? + false + end + end + included do + before_action :set_fake_rack_session_for_devise + private + def set_fake_rack_session_for_devise + request.env['rack.session'] ||= FakeRackSession.new + end + end +end diff --git a/app/controllers/english_offers_controller.rb b/app/controllers/english_offers_controller.rb index 1a20a0f1f..7195783cb 100644 --- a/app/controllers/english_offers_controller.rb +++ b/app/controllers/english_offers_controller.rb @@ -10,6 +10,8 @@ class EnglishOffersController < ApplicationController # order is important include EnglishOffers::Offerable + skip_before_action :verify_authenticity_token + include RecaptchaValidatable recaptcha_action 'english_offer' include OfferNotifable diff --git a/app/controllers/offers_controller.rb b/app/controllers/offers_controller.rb index 2322fc831..675abca12 100644 --- a/app/controllers/offers_controller.rb +++ b/app/controllers/offers_controller.rb @@ -4,7 +4,10 @@ class OffersController < ApplicationController include Offerable before_action :set_offer, only: %i[show edit update destroy] - before_action :authorize_offer_for_user, except: %i[new index create delete] + before_action :check_for_ban, only: :create + before_action :authorize_phone_confirmation + before_action :authorize_offer_for_user, except: %i[new index create] + skip_before_action :verify_authenticity_token respond_to :html, :json diff --git a/config/application.rb b/config/application.rb index 9493e9967..9ba156ce3 100644 --- a/config/application.rb +++ b/config/application.rb @@ -9,6 +9,22 @@ module AuctionCenter class Application < Rails::Application + + class RequestLoggerMiddleware + def initialize(app) + @app = app + end + + def call(env) + Rails.logger.info "Request: #{env['REQUEST_METHOD']} #{env['PATH_INFO']}" + Rails.logger.info "Headers: #{env.select { |k, v| k.start_with? 'HTTP_' }}" + Rails.logger.info "Body: #{env['rack.input'].read}" + env['rack.input'].rewind + + @app.call(env) + end + end + # Initialize configuration defaults for originally generated Rails version. config.load_defaults 7.0 # config.autoloader = :classic @@ -17,6 +33,7 @@ class Application < Rails::Application config.active_model.i18n_customize_full_message = true config.autoload_paths += %W(#{config.root}/app/models/concerns) + config.middleware.insert_before 0, RequestLoggerMiddleware # config.autoload_paths += Dir[Rails.root.join('app', 'presenters', '**/')] # config.autoload_paths += Dir[Rails.root.join('app', 'broadcasts', '**/')] diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 7788ac1e9..b2d8cc6fc 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -31,8 +31,8 @@ def skip_format? config.jwt do |jwt| jwt.secret = AuctionCenter::Application.config.customization[:jwt_secret] - jwt.dispatch_requests = [ ['POST', %r{^/login$}] ] - jwt.revocation_requests = [ ['DELETE', %r{^/logout$}] ] + jwt.dispatch_requests = [ ['POST', %r{^/sessions/sign_in$}] ] + jwt.revocation_requests = [ ['DELETE', %r{^/sessions/sign_out$}] ] jwt.expiration_time = 30.minutes.to_i end diff --git a/config/routes.rb b/config/routes.rb index 4ce20364f..3fbdc3f81 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -8,6 +8,7 @@ namespace :api do resource :stream_name, only: :show + resource :offers, only: :create end get 'unsubscribe/unsubscribe' From 00d8883ed067b557aab779138027960bb48d42b8 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Fri, 29 Dec 2023 10:10:29 +0200 Subject: [PATCH 05/18] updated websocket --- .../auctions/update_list_broadcast_service.rb | 13 +++++- app/controllers/api/offers_controller.rb | 40 +++++++++++-------- .../billing_profiles/index.json.jbuilder | 11 +++++ 3 files changed, 46 insertions(+), 18 deletions(-) create mode 100644 app/views/billing_profiles/index.json.jbuilder diff --git a/app/broadcasts/auctions/update_list_broadcast_service.rb b/app/broadcasts/auctions/update_list_broadcast_service.rb index 4dacd0293..0a871056e 100644 --- a/app/broadcasts/auctions/update_list_broadcast_service.rb +++ b/app/broadcasts/auctions/update_list_broadcast_service.rb @@ -25,7 +25,18 @@ def post_call locals: { auction:, user:, updated: participants.include?(user) } end - ActionCable.server.broadcast('auctions_api', { auction: }) + + 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, + auction_type: auction&.platform + } + + ActionCable.server.broadcast('auctions_api', { auction: auction_json }) broadcast_later 'auctions', 'auctions/streams/updated_list', diff --git a/app/controllers/api/offers_controller.rb b/app/controllers/api/offers_controller.rb index 3eb5a8ded..86af8e170 100644 --- a/app/controllers/api/offers_controller.rb +++ b/app/controllers/api/offers_controller.rb @@ -6,30 +6,36 @@ class OffersController < ApplicationController skip_before_action :verify_authenticity_token def create - # Offer offer = Offer( - # auctionId: widget.auction.uuid, - # cents: _bidAmount!.toInt(), - # userId: user.uuid, - # ); - - # offerBloc.add(AddOfferEvent(offer: offer, authToken: user.tempTokenStore!, auctionType: widget.auction.type!)); - # Navigator.of(context).pop(); puts '=====' puts params puts '=====' - auction = Auction.find_by(uuid: params[:auctionId]) + auction = Auction.find_by(uuid: params[:bid][:auction_id]) + return if auction.nil? + + offer = auction.offer_from_user(current_user.uuid) - offer = Offer.new - offer.price = params[:cents] + billing_profile = current_user.billing_profiles.find_by(uuid: params[:bid][:billing_profile_id]) + + if offer.nil? + offer = Offer.new( + auction: auction, + user: current_user, + cents: Money.from_amount(params[:bid][:price]).cents, + billing_profile: billing_profile, + username: Username::GenerateUsernameService.new.call + ) + else + offer.cents = Money.from_amount(params[:bid][:price]).cents + end - puts '=====' - puts auction.inspect - puts offer.inspect - puts current_user.inspect - puts '=====' + if offer.save + Auctions::UpdateListBroadcastService.call({ auction: auction }) - render json: { status: 'ok' }, status: :ok + render json: { status: 'ok' }, status: :ok + else + render json: { status: 'error' }, status: :unprocessable_entity + end end end end diff --git a/app/views/billing_profiles/index.json.jbuilder b/app/views/billing_profiles/index.json.jbuilder new file mode 100644 index 000000000..1414faf3d --- /dev/null +++ b/app/views/billing_profiles/index.json.jbuilder @@ -0,0 +1,11 @@ +json.array! @billing_profiles do |billing_profile| + json.id billing_profile.uuid + json.user_id billing_profile.user_id + json.name billing_profile.name + json.vat_code billing_profile.vat_code + json.street billing_profile.street + json.city billing_profile.city + json.state billing_profile.state + json.postal_code billing_profile.postal_code + json.alpha_two_country_code billing_profile.alpha_two_country_code +end From 11b4ef943e12ff37075aeaae1338d89dd85fc1c8 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Tue, 2 Jan 2024 10:44:43 +0200 Subject: [PATCH 06/18] changes route paths --- app/controllers/api/offers_controller.rb | 41 ------------------- .../api/stream_names_controller.rb | 13 ------ app/controllers/api/v1/auctions_controller.rb | 23 +++++++++++ .../api/v1/autobiders_controller.rb | 34 +++++++++++++++ app/controllers/api/v1/offers_controller.rb | 39 ++++++++++++++++++ .../api/v1/stream_names_controller.rb | 13 ++++++ config/routes.rb | 8 +++- 7 files changed, 115 insertions(+), 56 deletions(-) delete mode 100644 app/controllers/api/offers_controller.rb delete mode 100644 app/controllers/api/stream_names_controller.rb create mode 100644 app/controllers/api/v1/auctions_controller.rb create mode 100644 app/controllers/api/v1/autobiders_controller.rb create mode 100644 app/controllers/api/v1/offers_controller.rb create mode 100644 app/controllers/api/v1/stream_names_controller.rb diff --git a/app/controllers/api/offers_controller.rb b/app/controllers/api/offers_controller.rb deleted file mode 100644 index 86af8e170..000000000 --- a/app/controllers/api/offers_controller.rb +++ /dev/null @@ -1,41 +0,0 @@ -module Api - class OffersController < ApplicationController - before_action :authenticate_user! - respond_to :json - - skip_before_action :verify_authenticity_token - - def create - puts '=====' - puts params - puts '=====' - - auction = Auction.find_by(uuid: params[:bid][:auction_id]) - return if auction.nil? - - offer = auction.offer_from_user(current_user.uuid) - - billing_profile = current_user.billing_profiles.find_by(uuid: params[:bid][:billing_profile_id]) - - if offer.nil? - offer = Offer.new( - auction: auction, - user: current_user, - cents: Money.from_amount(params[:bid][:price]).cents, - billing_profile: billing_profile, - username: Username::GenerateUsernameService.new.call - ) - else - offer.cents = Money.from_amount(params[:bid][:price]).cents - end - - if offer.save - Auctions::UpdateListBroadcastService.call({ auction: auction }) - - render json: { status: 'ok' }, status: :ok - else - render json: { status: 'error' }, status: :unprocessable_entity - end - end - end -end diff --git a/app/controllers/api/stream_names_controller.rb b/app/controllers/api/stream_names_controller.rb deleted file mode 100644 index ffb8ba531..000000000 --- a/app/controllers/api/stream_names_controller.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Api - class StreamNamesController < ApplicationController - skip_before_action :verify_authenticity_token - - def show - # stream_name = 'auctions' - # signed_stream_name = ActionCable.server.signed_stream_identifier(stream_name) - signed_stream_name = Turbo::StreamsChannel.signed_stream_name 'auctions' - - render json: { signed_stream_name: } - end - end -end diff --git a/app/controllers/api/v1/auctions_controller.rb b/app/controllers/api/v1/auctions_controller.rb new file mode 100644 index 000000000..7a0201c6a --- /dev/null +++ b/app/controllers/api/v1/auctions_controller.rb @@ -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.english.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 diff --git a/app/controllers/api/v1/autobiders_controller.rb b/app/controllers/api/v1/autobiders_controller.rb new file mode 100644 index 000000000..10b6b8567 --- /dev/null +++ b/app/controllers/api/v1/autobiders_controller.rb @@ -0,0 +1,34 @@ +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, domain_name: strong_params[:domain_name]) + + print('---- autobider ---- ') + print(params) + print('---- autobider ---- ') + + if autobider.nil? + autobider = Autobider.new(strong_params.merge(user: current_user)) + else + autobider.price = strong_params[:price] + end + + if autobider.save + render json: { status: 'ok' }, status: :ok + else + render json: { status: 'error' }, status: :unprocessable_entity + end + end + + def strong_params + params.require(:autobider).permit(:domain_name, :price) + end + end + end +end diff --git a/app/controllers/api/v1/offers_controller.rb b/app/controllers/api/v1/offers_controller.rb new file mode 100644 index 000000000..bbcba123a --- /dev/null +++ b/app/controllers/api/v1/offers_controller.rb @@ -0,0 +1,39 @@ +module Api + module V1 + class OffersController < ApplicationController + before_action :authenticate_user! + respond_to :json + + skip_before_action :verify_authenticity_token + + def create + auction = Auction.find_by(uuid: params[:bid][:auction_id]) + return if auction.nil? + + offer = auction.offer_from_user(current_user.uuid) + + billing_profile = current_user.billing_profiles.find_by(uuid: params[:bid][:billing_profile_id]) + + if offer.nil? + offer = Offer.new( + auction: auction, + user: current_user, + cents: Money.from_amount(params[:bid][:price]).cents, + billing_profile: billing_profile, + username: Username::GenerateUsernameService.new.call + ) + else + offer.cents = Money.from_amount(params[:bid][:price]).cents + end + + if offer.save + Auctions::UpdateListBroadcastService.call({ auction: auction }) + + render json: { status: 'ok' }, status: :ok + else + render json: { status: 'error' }, status: :unprocessable_entity + end + end + end + end +end diff --git a/app/controllers/api/v1/stream_names_controller.rb b/app/controllers/api/v1/stream_names_controller.rb new file mode 100644 index 000000000..fcfa982f5 --- /dev/null +++ b/app/controllers/api/v1/stream_names_controller.rb @@ -0,0 +1,13 @@ +module Api + module V1 + class StreamNamesController < ApplicationController + skip_before_action :verify_authenticity_token + + def show + signed_stream_name = Turbo::StreamsChannel.signed_stream_name 'auctions' + + render json: { signed_stream_name: } + end + end + end +end diff --git a/config/routes.rb b/config/routes.rb index 3fbdc3f81..04ae3cdc5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -7,8 +7,12 @@ # mount ActionCable.server => '/cable' namespace :api do - resource :stream_name, only: :show - resource :offers, only: :create + namespace :v1 do + resource :stream_name, only: :show + resource :offers, only: :create + resource :autobiders, only: :create + resource :auctions, only: :show + end end get 'unsubscribe/unsubscribe' From ac6cc907e03499ba94d85b89df8aaecb09ac3e11 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Mon, 15 Jan 2024 09:29:46 +0200 Subject: [PATCH 07/18] updated response --- .../auctions/update_list_broadcast_service.rb | 1 + .../api/v1/autobiders_controller.rb | 30 ++++++++++++------- app/controllers/api/v1/offers_controller.rb | 5 ++++ app/views/auctions/index.json.jbuilder | 1 + 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/app/broadcasts/auctions/update_list_broadcast_service.rb b/app/broadcasts/auctions/update_list_broadcast_service.rb index 0a871056e..85f7f745d 100644 --- a/app/broadcasts/auctions/update_list_broadcast_service.rb +++ b/app/broadcasts/auctions/update_list_broadcast_service.rb @@ -33,6 +33,7 @@ def post_call 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 } diff --git a/app/controllers/api/v1/autobiders_controller.rb b/app/controllers/api/v1/autobiders_controller.rb index 10b6b8567..b9177df3d 100644 --- a/app/controllers/api/v1/autobiders_controller.rb +++ b/app/controllers/api/v1/autobiders_controller.rb @@ -7,27 +7,37 @@ class AutobidersController < ApplicationController skip_before_action :verify_authenticity_token def create - autobider = Autobider.find_by(user_id: current_user.id, domain_name: strong_params[:domain_name]) + @autobider = Autobider.find_by(user_id: current_user.id, id: strong_params[:id]) - print('---- autobider ---- ') - print(params) - print('---- autobider ---- ') - - if autobider.nil? - autobider = Autobider.new(strong_params.merge(user: current_user)) + if @autobider.nil? + @autobider = Autobider.new(strong_params.merge(user: current_user)) else - autobider.price = strong_params[:price] + @autobider.price = strong_params[:price] end - if autobider.save + 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(:domain_name, :price) + params.require(:autobider).permit(:id, :domain_name, :price) end end end diff --git a/app/controllers/api/v1/offers_controller.rb b/app/controllers/api/v1/offers_controller.rb index bbcba123a..065f66853 100644 --- a/app/controllers/api/v1/offers_controller.rb +++ b/app/controllers/api/v1/offers_controller.rb @@ -29,6 +29,11 @@ def create if offer.save Auctions::UpdateListBroadcastService.call({ auction: auction }) + auction.update_minimum_bid_step(params[:bid][:price].to_f) + + AutobiderService.autobid(auction) + auction.update_ends_at(offer) + render json: { status: 'ok' }, status: :ok else render json: { status: 'error' }, status: :unprocessable_entity diff --git a/app/views/auctions/index.json.jbuilder b/app/views/auctions/index.json.jbuilder index b846a1005..f31dea549 100644 --- a/app/views/auctions/index.json.jbuilder +++ b/app/views/auctions/index.json.jbuilder @@ -6,5 +6,6 @@ json.array! @auctions_list do |auction| json.id auction.uuid json.highest_bid auction.currently_winning_offer&.price.to_f json.highest_bidder auction.currently_winning_offer&.username + json.min_bids_step auction.min_bids_step.to_f json.auction_type auction&.platform end From 4fe8c7cb2657e31d0baddbdc62705f2c7398c7f5 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Mon, 22 Jan 2024 11:02:40 +0200 Subject: [PATCH 08/18] added new path --- app/controllers/api/v1/invoices_controller.rb | 31 +++++++++++++++++++ config/routes.rb | 1 + 2 files changed, 32 insertions(+) create mode 100644 app/controllers/api/v1/invoices_controller.rb diff --git a/app/controllers/api/v1/invoices_controller.rb b/app/controllers/api/v1/invoices_controller.rb new file mode 100644 index 000000000..130751761 --- /dev/null +++ b/app/controllers/api/v1/invoices_controller.rb @@ -0,0 +1,31 @@ +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 + + private + + def invoices_list_by_status(status) + Invoice.accessible_by(current_ability) + .where(user_id: current_user.id) + .where(status: status) + .order(due_date: :desc) + end + end + end +end diff --git a/config/routes.rb b/config/routes.rb index 04ae3cdc5..abb31ac4a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -12,6 +12,7 @@ resource :offers, only: :create resource :autobiders, only: :create resource :auctions, only: :show + resources :invoices, only: :index end end From 0c1e7574885fc4e6629e4ebca10d3fa060fac7de Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Thu, 25 Jan 2024 13:40:54 +0200 Subject: [PATCH 09/18] updated logs --- app/controllers/api/v1/auctions_controller.rb | 2 +- app/controllers/api/v1/offers_controller.rb | 37 ++++++++++++++----- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/app/controllers/api/v1/auctions_controller.rb b/app/controllers/api/v1/auctions_controller.rb index 7a0201c6a..c03d21651 100644 --- a/app/controllers/api/v1/auctions_controller.rb +++ b/app/controllers/api/v1/auctions_controller.rb @@ -7,7 +7,7 @@ class AuctionsController < ApplicationController skip_before_action :verify_authenticity_token def show - @auction = Auction.english.find_by!(uuid: params[:auction_id]) + @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) diff --git a/app/controllers/api/v1/offers_controller.rb b/app/controllers/api/v1/offers_controller.rb index 065f66853..2bd069019 100644 --- a/app/controllers/api/v1/offers_controller.rb +++ b/app/controllers/api/v1/offers_controller.rb @@ -6,36 +6,53 @@ class OffersController < ApplicationController skip_before_action :verify_authenticity_token + # rubocop:disable Metrics/AbcSize + # rubocop:disable Metrics/MethodLength def create + Rails.logger.info('----') + Rails.logger.info(params) + Rails.logger.info('----') + auction = Auction.find_by(uuid: params[:bid][:auction_id]) return if auction.nil? - + offer = auction.offer_from_user(current_user.uuid) - billing_profile = current_user.billing_profiles.find_by(uuid: params[:bid][:billing_profile_id]) - + billing_profile = current_user.billing_profiles.find_by(id: params[:bid][:billing_profile_id]) + + Rails.logger.info('----') + Rails.logger.info(billing_profile.inspect) + Rails.logger.info('----') + if offer.nil? offer = Offer.new( - auction: auction, + auction:, user: current_user, cents: Money.from_amount(params[:bid][:price]).cents, - billing_profile: billing_profile, - username: Username::GenerateUsernameService.new.call + billing_profile:, + username: auction.english? ? Username::GenerateUsernameService.new.call : nil ) else offer.cents = Money.from_amount(params[:bid][:price]).cents end if offer.save - Auctions::UpdateListBroadcastService.call({ auction: auction }) + if auction.english? + Auctions::UpdateListBroadcastService.call({ auction: }) - auction.update_minimum_bid_step(params[:bid][:price].to_f) + auction.update_minimum_bid_step(params[:bid][:price].to_f) - AutobiderService.autobid(auction) - auction.update_ends_at(offer) + 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 From a075a46486f4a4e4048aa66181a05fc9648b1248 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Wed, 31 Jan 2024 11:43:52 +0200 Subject: [PATCH 10/18] added profile controller --- .../auctions/update_list_broadcast_service.rb | 6 +++- .../api/v1/profiles/passwords_controller.rb | 32 +++++++++++++++++++ app/controllers/api/v1/profiles_controller.rb | 23 +++++++++++++ app/views/auctions/index.json.jbuilder | 2 ++ config/routes.rb | 5 +++ 5 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 app/controllers/api/v1/profiles/passwords_controller.rb create mode 100644 app/controllers/api/v1/profiles_controller.rb diff --git a/app/broadcasts/auctions/update_list_broadcast_service.rb b/app/broadcasts/auctions/update_list_broadcast_service.rb index 85f7f745d..c10113ce0 100644 --- a/app/broadcasts/auctions/update_list_broadcast_service.rb +++ b/app/broadcasts/auctions/update_list_broadcast_service.rb @@ -16,6 +16,8 @@ def call private + # rubocop:disable Metrics/AbcSize + # rubocop:disable Metrics/MethodLength def post_call participants = auction.offers.map(&:user) @@ -34,7 +36,9 @@ def post_call 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 + 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 }) diff --git a/app/controllers/api/v1/profiles/passwords_controller.rb b/app/controllers/api/v1/profiles/passwords_controller.rb new file mode 100644 index 000000000..0ce36489a --- /dev/null +++ b/app/controllers/api/v1/profiles/passwords_controller.rb @@ -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 diff --git a/app/controllers/api/v1/profiles_controller.rb b/app/controllers/api/v1/profiles_controller.rb new file mode 100644 index 000000000..48a5c6ee6 --- /dev/null +++ b/app/controllers/api/v1/profiles_controller.rb @@ -0,0 +1,23 @@ +module Api + module V1 + class ProfilesController < ApplicationController + before_action :authenticate_user! + respond_to :json + + skip_before_action :verify_authenticity_token + + def update + if current_user.update(params_for_update) + render json: current_user, status: :ok + else + Rails.logger.info @user.errors.inspect + render json: current_user.errors, status: :unprocessable_entity + end + end + + def params_for_update + params.require(:user).permit(:email, :country_code, :given_names, :surname, :mobile_phone) + end + end + end +end diff --git a/app/views/auctions/index.json.jbuilder b/app/views/auctions/index.json.jbuilder index f31dea549..0dfb4f330 100644 --- a/app/views/auctions/index.json.jbuilder +++ b/app/views/auctions/index.json.jbuilder @@ -8,4 +8,6 @@ json.array! @auctions_list do |auction| json.highest_bidder auction.currently_winning_offer&.username json.min_bids_step auction.min_bids_step.to_f json.auction_type auction&.platform + json.enable_deposit auction.enable_deposit + json.requirement_deposit_in_cents auction.requirement_deposit_in_cents end diff --git a/config/routes.rb b/config/routes.rb index abb31ac4a..cda8e0713 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -12,6 +12,11 @@ resource :offers, only: :create resource :autobiders, only: :create resource :auctions, only: :show + resource :profiles, only: :update do + scope module: :profiles do + resource :passwords, only: :update + end + end resources :invoices, only: :index end end From 79c14d46ea8d24b01c88874d13bdc735b3244207 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Thu, 8 Feb 2024 10:34:18 +0200 Subject: [PATCH 11/18] added billing profile controller for api --- .../api/v1/billing_profiles_controller.rb | 33 +++++++++++++++++++ config/routes.rb | 1 + 2 files changed, 34 insertions(+) create mode 100644 app/controllers/api/v1/billing_profiles_controller.rb diff --git a/app/controllers/api/v1/billing_profiles_controller.rb b/app/controllers/api/v1/billing_profiles_controller.rb new file mode 100644 index 000000000..4c10f1362 --- /dev/null +++ b/app/controllers/api/v1/billing_profiles_controller.rb @@ -0,0 +1,33 @@ +module Api + module V1 + class BillingProfilesController < ApplicationController + before_action :authenticate_user! + respond_to :json + + skip_before_action :verify_authenticity_token + + 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 + + private + + def billing_profile_params + params.require(:billing_profile).permit(:name, :vat_code, :street, :city, :state, :postal_code, + :alpha_two_country_code, :uuid) + end + end + end +end diff --git a/config/routes.rb b/config/routes.rb index cda8e0713..2a01bf6cb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,6 +18,7 @@ end end resources :invoices, only: :index + resources :billing_profiles, only: %i[index update create destroy] end end From 390a95504666937c9afe2472027a78ee1242fe24 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Fri, 16 Feb 2024 13:17:43 +0200 Subject: [PATCH 12/18] added endpoints for create user and billing profile --- .../api/v1/billing_profiles_controller.rb | 16 ++++++++++++ app/controllers/api/v1/profiles_controller.rb | 26 ++++++++++++++++++- config/routes.rb | 2 +- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/v1/billing_profiles_controller.rb b/app/controllers/api/v1/billing_profiles_controller.rb index 4c10f1362..5589437a8 100644 --- a/app/controllers/api/v1/billing_profiles_controller.rb +++ b/app/controllers/api/v1/billing_profiles_controller.rb @@ -6,6 +6,8 @@ class BillingProfilesController < ApplicationController skip_before_action :verify_authenticity_token + rescue_from ActiveRecord::RecordNotUnique, with: :handle_unique_violation + def index @billing_profiles = current_user.billing_profiles @@ -22,12 +24,26 @@ def update 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 diff --git a/app/controllers/api/v1/profiles_controller.rb b/app/controllers/api/v1/profiles_controller.rb index 48a5c6ee6..2ce8d985c 100644 --- a/app/controllers/api/v1/profiles_controller.rb +++ b/app/controllers/api/v1/profiles_controller.rb @@ -1,7 +1,7 @@ module Api module V1 class ProfilesController < ApplicationController - before_action :authenticate_user! + before_action :authenticate_user!, only: %i[update] respond_to :json skip_before_action :verify_authenticity_token @@ -15,6 +15,30 @@ def update end end + def create + puts '----' + puts params_for_create + puts '----' + + user = User.new(params_for_create) + + if user.save + sign_in(User, user) + render json: user, status: :created + else + Rails.logger.info user.errors.inspect + render json: user.errors, status: :unprocessable_entity + end + end + + private + + def params_for_create + params.require(:user).permit(:email, :password, :password_confirmation, :country_code, + :given_names, :surname, :mobile_phone, :accepts_terms_and_conditions, + :locale, :daily_summary, :identity_code) + end + def params_for_update params.require(:user).permit(:email, :country_code, :given_names, :surname, :mobile_phone) end diff --git a/config/routes.rb b/config/routes.rb index 2a01bf6cb..11f8f71fc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -12,7 +12,7 @@ resource :offers, only: :create resource :autobiders, only: :create resource :auctions, only: :show - resource :profiles, only: :update do + resource :profiles, only: %i[update create] do scope module: :profiles do resource :passwords, only: :update end From 4010021b5b1bc968c2c5f2b14ff27f130aea0422 Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Wed, 13 Mar 2024 13:56:13 +0200 Subject: [PATCH 13/18] added tara auth --- .../api/v1/tara_auth_sessions_controller.rb | 35 +++++++++++++++++++ config/customization.yml.sample | 1 + config/initializers/omniauth.rb | 13 +++---- config/routes.rb | 1 + 4 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 app/controllers/api/v1/tara_auth_sessions_controller.rb diff --git a/app/controllers/api/v1/tara_auth_sessions_controller.rb b/app/controllers/api/v1/tara_auth_sessions_controller.rb new file mode 100644 index 000000000..fa425c74e --- /dev/null +++ b/app/controllers/api/v1/tara_auth_sessions_controller.rb @@ -0,0 +1,35 @@ +module Api + module V1 + class TaraAuthSessionsController < ApplicationController + before_action :check_for_permission, only: %i[create] + + respond_to :json + + skip_before_action :verify_authenticity_token + + def create + identity = params[:identity_code] + first_name = params[:first_name] + last_name = params[:last_name] + country_code = params[:country_code] + + @user = User.find_by(identity_code: identity, country_code: country_code) + @user.update(given_names: first_name, surname: last_name) if @user.present? + + if @user.present? + sign_in(User, @user) + render json: { message: 'User signed in', user: @user }, status: :ok + else + render json: { error: 'User not found' }, status: :not_found + end + end + + private + + def check_for_permission + # TODO: + true + end + end + end +end diff --git a/config/customization.yml.sample b/config/customization.yml.sample index 8bf036ead..b1d3727db 100644 --- a/config/customization.yml.sample +++ b/config/customization.yml.sample @@ -92,6 +92,7 @@ default: &default identifier: 'identifier' secret: 'secret' redirect_uri: 'redirect_url' + tara_keys: '{"kty":"RSA","n":"iVKwG5cTHFx60wYLndRLlzlvH9m2XsVaWh0LQFcvQBCcUMXjCYQRJ22sLjAz6fvig83dWcoKQVanZfzNGAqG_I54LIVT6oUZxFgCA1cyFKELaCqnpzQa3m7CBOklQUV7Z6Dtj1bMJiMIaEv8lzhtKmqkC6o2xjTWIbVCBublwF0DH5SsVdeX-kC4aJtYCbhsuYuzrn4VpR33NuvLxOBPHDVCMYImxlYU337uf6DjmdZMV96ODqP7E9iMS3GWk_MJEzrgLU7_7JiO3OWtkBUNspZ7pgNdIc6OQ5ZASfWsUufS44kt1fNmPqowklHCRNqcnFOx0lc7ya_VlCdXV6Qfew","e":"AQAB"}' keys: kty: 'RSA' kid: 'public:xWbbVoYq9EwMqphp' diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 18c8c778f..300399263 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -9,7 +9,8 @@ # Block GET requests to avoid exposing self to CVE-2015-9284 OmniAuth.config.allowed_request_methods = [:post] -signing_keys = AuctionCenter::Application.config.customization.dig(:tara, :keys).to_json +# signing_keys = AuctionCenter::Application.config.customization.dig(:tara, :keys).to_json +signing_keys = AuctionCenter::Application.config.customization.dig(:tara, :tara_keys).to_json issuer = AuctionCenter::Application.config.customization.dig(:tara, :issuer) host = AuctionCenter::Application.config.customization.dig(:tara, :host) identifier = AuctionCenter::Application.config.customization.dig(:tara, :identifier) @@ -19,22 +20,22 @@ Rails.application.config.middleware.use OmniAuth::Builder do provider "tara", { name: 'tara', - scope: ['openid'], + scope: %w[openid idcard mid smartid], state: Proc.new{ SecureRandom.hex(10) }, client_signing_alg: :RS256, client_jwk_signing_key: signing_keys, send_scope_to_token_endpoint: false, send_nonce: true, issuer: issuer, - + discovery: true, client_options: { scheme: 'https', host: host, - authorization_endpoint: '/oidc/authorize', - token_endpoint: '/oidc/token', + authorization_endpoint: '/oauth2/auth', + token_endpoint: '/oauth2/token', userinfo_endpoint: nil, # Not implemented - jwks_uri: '/oidc/jwks', + jwks_uri: '/.well-known/jwks.json', # Auction identifier: identifier, diff --git a/config/routes.rb b/config/routes.rb index 11f8f71fc..49f5b3da6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -11,6 +11,7 @@ resource :stream_name, only: :show resource :offers, only: :create resource :autobiders, only: :create + resource :tara_auth_session, only: :create resource :auctions, only: :show resource :profiles, only: %i[update create] do scope module: :profiles do From d38139d0dd0dd910a740b8dc39d7f8d786197425 Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Mon, 25 Mar 2024 13:41:02 +0200 Subject: [PATCH 14/18] added callbakc for payment by mobile --- .gitignore | 1 + app/controllers/api/v1/offers_controller.rb | 9 +++++++-- .../api/v1/tara_auth_sessions_controller.rb | 6 +++++- app/controllers/mobile_payments_controller.rb | 11 +++++++++++ app/models/auction.rb | 3 +++ app/views/mobile_payments/index.html.erb | 1 + config/initializers/devise.rb | 2 +- config/routes.rb | 8 ++++---- 8 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 app/controllers/mobile_payments_controller.rb create mode 100644 app/views/mobile_payments/index.html.erb diff --git a/.gitignore b/.gitignore index 88cce482b..ce6a9cb98 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,4 @@ app/assets/builds/* !/app/assets/builds/.keep Dockerfile.dev + diff --git a/app/controllers/api/v1/offers_controller.rb b/app/controllers/api/v1/offers_controller.rb index 2bd069019..29246248d 100644 --- a/app/controllers/api/v1/offers_controller.rb +++ b/app/controllers/api/v1/offers_controller.rb @@ -13,15 +13,20 @@ def create Rails.logger.info(params) Rails.logger.info('----') + #{"bid"=>{"price"=>320.0, "auction_id"=>"2a893210-f1f1-4be8-9d78-b793f1fa0ec6", "billing_profile_id"=>"23"}, + #"controller"=>"api/v1/offers", "action"=>"create", "offer"=>{}} + auction = Auction.find_by(uuid: params[:bid][:auction_id]) return if auction.nil? - offer = auction.offer_from_user(current_user.uuid) - billing_profile = current_user.billing_profiles.find_by(id: params[:bid][:billing_profile_id]) + offer = auction.offer_from_user(current_user.id) + Rails.logger.info('----') + Rails.logger.info(current_user.inspect) Rails.logger.info(billing_profile.inspect) + Rails.logger.info(offer.inspect) Rails.logger.info('----') if offer.nil? diff --git a/app/controllers/api/v1/tara_auth_sessions_controller.rb b/app/controllers/api/v1/tara_auth_sessions_controller.rb index fa425c74e..d075bc672 100644 --- a/app/controllers/api/v1/tara_auth_sessions_controller.rb +++ b/app/controllers/api/v1/tara_auth_sessions_controller.rb @@ -18,7 +18,7 @@ def create if @user.present? sign_in(User, @user) - render json: { message: 'User signed in', user: @user }, status: :ok + render json: { message: 'User signed in', user: @user, token: current_token }, status: :ok else render json: { error: 'User not found' }, status: :not_found end @@ -30,6 +30,10 @@ def check_for_permission # TODO: true end + + def current_token + request.env['warden-jwt_auth.token'] + end end end end diff --git a/app/controllers/mobile_payments_controller.rb b/app/controllers/mobile_payments_controller.rb new file mode 100644 index 000000000..f67094cc5 --- /dev/null +++ b/app/controllers/mobile_payments_controller.rb @@ -0,0 +1,11 @@ +class MobilePaymentsController < ApplicationController + skip_before_action :verify_authenticity_token, only: %i[callback] + + def callback + EisBilling::SendCallbackService.call(reference_number: linkpay_params[:payment_reference]) + + redirect_to mobile_payments_path + end + + def index; end +end diff --git a/app/models/auction.rb b/app/models/auction.rb index 9c7b801c9..e3c104e80 100644 --- a/app/models/auction.rb +++ b/app/models/auction.rb @@ -31,10 +31,13 @@ class Auction < ApplicationRecord # rubocop:disable Metrics delegate :size, to: :offers, prefix: true def update_list_broadcast + return if blind? + Auctions::UpdateListBroadcastService.call({ auction: self }) end def update_offer_broadcast + return if blind? Auctions::UpdateOfferBroadcastService.call({ auction: self }) end diff --git a/app/views/mobile_payments/index.html.erb b/app/views/mobile_payments/index.html.erb new file mode 100644 index 000000000..da60662fa --- /dev/null +++ b/app/views/mobile_payments/index.html.erb @@ -0,0 +1 @@ +Payment was paid! you can close the window arrrggg!!! \ No newline at end of file diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index b2d8cc6fc..5145e89cc 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -31,7 +31,7 @@ def skip_format? config.jwt do |jwt| jwt.secret = AuctionCenter::Application.config.customization[:jwt_secret] - jwt.dispatch_requests = [ ['POST', %r{^/sessions/sign_in$}] ] + jwt.dispatch_requests = [ ['POST', %r{^/sessions/sign_in$}], ['POST', %r{^/api/v1/tara_auth_session}] ] jwt.revocation_requests = [ ['DELETE', %r{^/sessions/sign_out$}] ] jwt.expiration_time = 30.minutes.to_i end diff --git a/config/routes.rb b/config/routes.rb index 49f5b3da6..4ccca7835 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -94,6 +94,7 @@ match '/auth/tara/cancel', via: %i[get post delete], to: 'auth/tara#cancel', as: :tara_cancel match '/auth/tara/create', via: [:post], to: 'auth/tara#create', as: :tara_create + match '/api/v1/tara_auth_sessions', via: [:post], to: 'api/v1/tara_auth_sessions#create' end devise_for :users, path: 'sessions', @@ -133,10 +134,6 @@ resources :payment_orders, only: %i[new show create], shallow: true, param: :uuid do member do - # get 'return' - # put 'return' - # post 'return' - post 'callback' end end @@ -145,6 +142,9 @@ match '/linkpay_callback', via: %i[get], to: 'linkpay#callback', as: :linkpay_callback match '/linkpay_deposit_callback', via: %i[get], to: 'linkpay#deposit_callback', as: :deposit_callback + match '/mobile_payments_callback', via: %i[get], to: 'mobile_payments#callback', as: :mobile_payments_callback + get '/mobile_payments', to: 'mobile_payments#index', as: :mobile_payments + resource :locale, only: :update resources :offers, only: :index resources :results, only: :show, param: :uuid From cb977264bbdcc57d0e45ca68e638103b123b233d Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Wed, 27 Mar 2024 13:12:05 +0200 Subject: [PATCH 15/18] added hmac validation in tara controller --- app/controllers/api/v1/invoices_controller.rb | 19 +++++++++++++++++- .../api/v1/tara_auth_sessions_controller.rb | 20 +++++++++++++------ app/controllers/mobile_payments_controller.rb | 12 +++++++++++ config/customization.yml.sample | 2 ++ config/routes.rb | 3 +++ 5 files changed, 49 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/v1/invoices_controller.rb b/app/controllers/api/v1/invoices_controller.rb index 130751761..70b9f635d 100644 --- a/app/controllers/api/v1/invoices_controller.rb +++ b/app/controllers/api/v1/invoices_controller.rb @@ -18,12 +18,29 @@ def index 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: status) + .where(status:) .order(due_date: :desc) end end diff --git a/app/controllers/api/v1/tara_auth_sessions_controller.rb b/app/controllers/api/v1/tara_auth_sessions_controller.rb index d075bc672..529d58797 100644 --- a/app/controllers/api/v1/tara_auth_sessions_controller.rb +++ b/app/controllers/api/v1/tara_auth_sessions_controller.rb @@ -1,19 +1,25 @@ module Api module V1 class TaraAuthSessionsController < ApplicationController - before_action :check_for_permission, only: %i[create] - respond_to :json skip_before_action :verify_authenticity_token def create + received_hmac = params[:token] + message = Rails.configuration.customization[:mobile_secret_word] + + unless valid_hmac?(received_hmac, message) + render json: { error: 'Invalid HMAC' }, status: :unauthorized + return + end + identity = params[:identity_code] first_name = params[:first_name] last_name = params[:last_name] country_code = params[:country_code] - @user = User.find_by(identity_code: identity, country_code: country_code) + @user = User.find_by(identity_code: identity, country_code:) @user.update(given_names: first_name, surname: last_name) if @user.present? if @user.present? @@ -26,9 +32,11 @@ def create private - def check_for_permission - # TODO: - true + def valid_hmac?(received_hmac, message) + secret_key = Rails.configuration.customization[:mobile_secret_key] + digest = OpenSSL::Digest.new('sha256') + hmac = OpenSSL::HMAC.digest(digest, secret_key, message) + Base64.strict_encode64(hmac) == received_hmac end def current_token diff --git a/app/controllers/mobile_payments_controller.rb b/app/controllers/mobile_payments_controller.rb index f67094cc5..4e924bb84 100644 --- a/app/controllers/mobile_payments_controller.rb +++ b/app/controllers/mobile_payments_controller.rb @@ -7,5 +7,17 @@ def callback redirect_to mobile_payments_path end + def deposit_callback + EisBilling::SendCallbackService.call(reference_number: linkpay_params[:payment_reference]) + + redirect_to mobile_payments_path + end + def index; end + + private + + def linkpay_params + params.permit(:order_reference, :payment_reference) + end end diff --git a/config/customization.yml.sample b/config/customization.yml.sample index b1d3727db..ec157253e 100644 --- a/config/customization.yml.sample +++ b/config/customization.yml.sample @@ -20,6 +20,8 @@ default: &default mobile_sms_sent_time_limit_in_minutes: 1 jwt_secret: '' + mobile_secret_key: '' + mobile_secret_word: '' mailer: # Host to which links from emails should redirect to diff --git a/config/routes.rb b/config/routes.rb index 4ccca7835..89d2a4c30 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -19,6 +19,8 @@ end end resources :invoices, only: :index + post 'pay_deposit', to: 'invoices#pay_deposit' + resources :billing_profiles, only: %i[index update create destroy] end end @@ -143,6 +145,7 @@ match '/linkpay_deposit_callback', via: %i[get], to: 'linkpay#deposit_callback', as: :deposit_callback match '/mobile_payments_callback', via: %i[get], to: 'mobile_payments#callback', as: :mobile_payments_callback + match '/mobile_payments_deposit_callback', via: %i[get], to: 'mobile_payments#deposit_callback', as: :mobile_payments_deposit_callback get '/mobile_payments', to: 'mobile_payments#index', as: :mobile_payments resource :locale, only: :update From ae066deae671c7882ea27f198af13b74d30d5503 Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Wed, 27 Mar 2024 13:15:50 +0200 Subject: [PATCH 16/18] fixed customization ident --- config/customization.yml.sample | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/customization.yml.sample b/config/customization.yml.sample index ec157253e..d68f21e86 100644 --- a/config/customization.yml.sample +++ b/config/customization.yml.sample @@ -94,7 +94,7 @@ default: &default identifier: 'identifier' secret: 'secret' redirect_uri: 'redirect_url' - tara_keys: '{"kty":"RSA","n":"iVKwG5cTHFx60wYLndRLlzlvH9m2XsVaWh0LQFcvQBCcUMXjCYQRJ22sLjAz6fvig83dWcoKQVanZfzNGAqG_I54LIVT6oUZxFgCA1cyFKELaCqnpzQa3m7CBOklQUV7Z6Dtj1bMJiMIaEv8lzhtKmqkC6o2xjTWIbVCBublwF0DH5SsVdeX-kC4aJtYCbhsuYuzrn4VpR33NuvLxOBPHDVCMYImxlYU337uf6DjmdZMV96ODqP7E9iMS3GWk_MJEzrgLU7_7JiO3OWtkBUNspZ7pgNdIc6OQ5ZASfWsUufS44kt1fNmPqowklHCRNqcnFOx0lc7ya_VlCdXV6Qfew","e":"AQAB"}' + tara_keys: '{"kty":"RSA","n":"iVKwG5cTHFx60wYLndRLlzlvH9m2XsVaWh0LQFcvQBCcUMXjCYQRJ22sLjAz6fvig83dWcoKQVanZfzNGAqG_I54LIVT6oUZxFgCA1cyFKELaCqnpzQa3m7CBOklQUV7Z6Dtj1bMJiMIaEv8lzhtKmqkC6o2xjTWIbVCBublwF0DH5SsVdeX-kC4aJtYCbhsuYuzrn4VpR33NuvLxOBPHDVCMYImxlYU337uf6DjmdZMV96ODqP7E9iMS3GWk_MJEzrgLU7_7JiO3OWtkBUNspZ7pgNdIc6OQ5ZASfWsUufS44kt1fNmPqowklHCRNqcnFOx0lc7ya_VlCdXV6Qfew","e":"AQAB"}' keys: kty: 'RSA' kid: 'public:xWbbVoYq9EwMqphp' From a5879369235d1d9b083ff74d6d0ab55b1c0b2965 Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Fri, 12 Apr 2024 13:45:59 +0300 Subject: [PATCH 17/18] added offers endpoint --- app/controllers/api/v1/offers_controller.rb | 27 +++++++++++---------- config/routes.rb | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/app/controllers/api/v1/offers_controller.rb b/app/controllers/api/v1/offers_controller.rb index 29246248d..09092892a 100644 --- a/app/controllers/api/v1/offers_controller.rb +++ b/app/controllers/api/v1/offers_controller.rb @@ -6,16 +6,23 @@ class OffersController < ApplicationController skip_before_action :verify_authenticity_token + def index + offers = Offer.includes(:auction) + .includes(:result) + .where(user_id: current_user) + .order('auctions.ends_at DESC') + + Rails.logger.info '---- offers ----' + Rails.logger.info(offers.inspect) + Rails.logger.info '----' + + # price with tax + render json: offers.as_json(include: [:auction, :billing_profile]) + end + # rubocop:disable Metrics/AbcSize # rubocop:disable Metrics/MethodLength def create - Rails.logger.info('----') - Rails.logger.info(params) - Rails.logger.info('----') - - #{"bid"=>{"price"=>320.0, "auction_id"=>"2a893210-f1f1-4be8-9d78-b793f1fa0ec6", "billing_profile_id"=>"23"}, - #"controller"=>"api/v1/offers", "action"=>"create", "offer"=>{}} - auction = Auction.find_by(uuid: params[:bid][:auction_id]) return if auction.nil? @@ -23,12 +30,6 @@ def create offer = auction.offer_from_user(current_user.id) - Rails.logger.info('----') - Rails.logger.info(current_user.inspect) - Rails.logger.info(billing_profile.inspect) - Rails.logger.info(offer.inspect) - Rails.logger.info('----') - if offer.nil? offer = Offer.new( auction:, diff --git a/config/routes.rb b/config/routes.rb index 89d2a4c30..56a6ac334 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,7 +9,7 @@ namespace :api do namespace :v1 do resource :stream_name, only: :show - resource :offers, only: :create + resources :offers, only: [:create, :index] resource :autobiders, only: :create resource :tara_auth_session, only: :create resource :auctions, only: :show From 04943fea8b42d9732565fa0d2b492e7ad3a949dc Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Fri, 3 May 2024 13:28:30 +0300 Subject: [PATCH 18/18] remove uneccesary comments, updated json response for offers --- app/controllers/api/v1/offers_controller.rb | 15 ++++--- app/controllers/api/v1/profiles_controller.rb | 4 -- app/models/offer.rb | 41 ++++++++++++++++--- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/app/controllers/api/v1/offers_controller.rb b/app/controllers/api/v1/offers_controller.rb index 09092892a..6eb061cf0 100644 --- a/app/controllers/api/v1/offers_controller.rb +++ b/app/controllers/api/v1/offers_controller.rb @@ -8,16 +8,15 @@ class OffersController < ApplicationController def index offers = Offer.includes(:auction) - .includes(:result) - .where(user_id: current_user) - .order('auctions.ends_at DESC') - - Rails.logger.info '---- offers ----' - Rails.logger.info(offers.inspect) - Rails.logger.info '----' + .includes(:result) + .where(user_id: current_user) + .order('auctions.ends_at DESC') # price with tax - render json: offers.as_json(include: [:auction, :billing_profile]) + 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 diff --git a/app/controllers/api/v1/profiles_controller.rb b/app/controllers/api/v1/profiles_controller.rb index 2ce8d985c..4637d6796 100644 --- a/app/controllers/api/v1/profiles_controller.rb +++ b/app/controllers/api/v1/profiles_controller.rb @@ -16,10 +16,6 @@ def update end def create - puts '----' - puts params_for_create - puts '----' - user = User.new(params_for_create) if user.save diff --git a/app/models/offer.rb b/app/models/offer.rb index 335c8b7b9..01af80d84 100644 --- a/app/models/offer.rb +++ b/app/models/offer.rb @@ -105,12 +105,43 @@ def price=(value) def total return price * (DEFAULT_PRICE_VALUE + billing_profile.vat_rate) if billing_profile.present? - if user&.country_code == 'EE' || user&.country_code.nil? - default_vat = Setting.find_by(code: :estonian_vat_rate).retrieve - else - default_vat = Countries.vat_rate_from_alpha2_code(user.country_code) + default_vat = if user&.country_code == 'EE' || user&.country_code.nil? + Setting.find_by(code: :estonian_vat_rate).retrieve + else + Countries.vat_rate_from_alpha2_code(user.country_code) + end + + price * (DEFAULT_PRICE_VALUE + (Invoice.find_by(result:)&.vat_rate || default_vat)) + end + + def auction_status + return 'you_won' if auction.finished? && result + return 'you_lost' if auction.finished? && auction.result && !result + + if auction.english? + return 'you_are_winning' if auction.currently_winning_offer == self + + return 'you_are_loosing' end - price * (DEFAULT_PRICE_VALUE + (Invoice.find_by(result: result)&.vat_rate || default_vat)) + 'still_in_progress' + end + + def api_total + total.to_d + end + + def api_price + price.to_d + end + + def api_bidders + auction.offers.map do |offer| + { + username: offer.username, + price: offer.price.to_d, + updated_at: offer.updated_at + } + end end end