Skip to content
This repository has been archived by the owner on Feb 6, 2024. It is now read-only.

Commit

Permalink
i waited far too long to commit this...
Browse files Browse the repository at this point in the history
  • Loading branch information
Shpigford committed Jan 9, 2024
1 parent 5b93e9e commit 2d8b412
Show file tree
Hide file tree
Showing 29 changed files with 3,020 additions and 186 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@
/app/assets/builds/*
!/app/assets/builds/.keep
*NOTES*
lib/data/.DS_Store
9 changes: 9 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ gem "bootsnap", require: false
gem "image_processing", "~> 1.2"
gem "aws-sdk-s3", require: false

gem 'pagy'

# Authentication
gem 'devise', github: 'heartcombo/devise'
gem 'omniauth'
Expand All @@ -58,6 +60,13 @@ gem 'omniauth-github'
# Background jobs
gem 'good_job'

# Data
gem 'faraday'
gem 'geocoder'
gem 'timezone'
gem 'geo_names'


group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem "debug", platforms: %i[ mri windows ]
Expand Down
23 changes: 23 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ GEM
debug (1.9.1)
irb (~> 1.10)
reline (>= 0.3.8)
domain_name (0.6.20231109)
dotenv (2.8.1)
dotenv-rails (2.8.1)
dotenv (= 2.8.1)
Expand All @@ -177,6 +178,9 @@ GEM
fugit (1.9.0)
et-orbi (~> 1, >= 1.2.7)
raabro (~> 1.4)
geo_names (1.0.2)
rest-client (~> 2)
geocoder (1.8.2)
globalid (1.2.1)
activesupport (>= 6.1)
good_job (3.22.0)
Expand All @@ -191,6 +195,9 @@ GEM
actioncable (>= 6.0.0)
listen (>= 3.0.0)
railties (>= 6.0.0)
http-accept (1.7.0)
http-cookie (1.0.5)
domain_name (~> 0.5)
i18n (1.14.1)
concurrent-ruby (~> 1.0)
image_processing (1.12.2)
Expand Down Expand Up @@ -228,6 +235,9 @@ GEM
net-smtp
marcel (1.0.2)
matrix (0.4.2)
mime-types (3.5.2)
mime-types-data (~> 3.2015)
mime-types-data (3.2023.1205)
mini_magick (4.12.0)
mini_mime (1.1.5)
minitest (5.20.0)
Expand All @@ -242,6 +252,7 @@ GEM
timeout
net-smtp (0.4.0.1)
net-protocol
netrc (0.11.0)
nio4r (2.7.0)
nokogiri (1.16.0-aarch64-linux)
racc (~> 1.4)
Expand Down Expand Up @@ -275,6 +286,7 @@ GEM
actionpack (>= 4.2)
omniauth (~> 2.0)
orm_adapter (0.5.0)
pagy (6.2.0)
parallel (1.24.0)
parser (3.3.0.0)
ast (~> 2.4.1)
Expand Down Expand Up @@ -321,6 +333,11 @@ GEM
responders (3.1.1)
actionpack (>= 5.2)
railties (>= 5.2)
rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
rexml (3.2.6)
rubocop (1.59.0)
json (~> 2.3)
Expand Down Expand Up @@ -381,6 +398,7 @@ GEM
railties (>= 6.0.0)
thor (1.3.0)
timeout (0.4.1)
timezone (1.3.24)
turbo-rails (1.5.0)
actionpack (>= 6.0.0)
activejob (>= 6.0.0)
Expand Down Expand Up @@ -420,6 +438,9 @@ DEPENDENCIES
devise!
dotenv-rails
error_highlight (>= 0.4.0)
faraday
geo_names
geocoder
good_job
hotwire-livereload
image_processing (~> 1.2)
Expand All @@ -430,6 +451,7 @@ DEPENDENCIES
omniauth-github
omniauth-google-oauth2
omniauth-rails_csrf_protection
pagy
pg (~> 1.1)
puma (>= 5.0)
rails!
Expand All @@ -439,6 +461,7 @@ DEPENDENCIES
sprockets-rails
stimulus-rails
tailwindcss-rails
timezone
turbo-rails
tzinfo-data
web-console
Expand Down
18 changes: 18 additions & 0 deletions app/controllers/api/exchanges_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class Api::ExchangesController < ApiController

def index
exchanges = Exchange.order(:name)
@pagy, @exchanges = pagy(exchanges, items: 2)
@pagy_metadata = pagy_metadata(@pagy)

api_user.charge_credits(1, nil, 'Exchange index')
end

def show
@exchange = Exchange.find_by('lower(acronym) = ? OR lower(mic_code) = ?', params[:id].downcase, params[:id].downcase)

api_user.charge_credits(1, @exchange)

raise ActiveRecord::RecordNotFound if @exchange.nil?
end
end
9 changes: 9 additions & 0 deletions app/controllers/api/users_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class Api::UsersController < ApplicationController
include ApiAuthentication
skip_before_action :verify_authenticity_token

def show
@user = api_user
render json: { id: @user.id, email: @user.email, name: @user.name, balance: @user.balance }
end
end
17 changes: 17 additions & 0 deletions app/controllers/api_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class ApiController < ApplicationController
include Pagy::Backend
include ApiAuthentication
skip_before_action :verify_authenticity_token
before_action :set_default_response_format
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found

private

def set_default_response_format
request.format = :json
end

def record_not_found
render json: { error: 'Record not found' }, status: :not_found
end
end
26 changes: 26 additions & 0 deletions app/controllers/concerns/ApiAuthentication.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module ApiAuthentication
extend ActiveSupport::Concern
included do
before_action :authenticate
end

def api_user
@api_key.user if @api_key
end

private

def authenticate
authenticate_token || unauthenticated
end

def authenticate_token
authenticate_with_http_token do |token|
@api_key = ApiKey.find_by(key: token)
end
end

def unauthenticated
render json: { error: 'Invalid API key' }, status: :unauthorized
end
end
2 changes: 2 additions & 0 deletions app/helpers/api/exchanges_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module Api::ExchangesHelper
end
2 changes: 2 additions & 0 deletions app/helpers/api/users_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module Api::UsersHelper
end
24 changes: 17 additions & 7 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,24 @@ def self.from_omniauth(auth, referral = nil)
end
end

def charge_credits(amount, transactable)
def charge_credits(amount, transactable = nil, notes = nil)
if self.balance >= amount
Transaction.create!(
user: self,
amount: -amount,
transaction_timestamp: Time.now,
transactable: transactable
)

if transactable.present?
Transaction.create!(
user: self,
amount: -amount,
transaction_timestamp: Time.now,
transactable: transactable
)
else
Transaction.create!(
user: self,
amount: -amount,
description: notes,
transaction_timestamp: Time.now
)
end
true
else
false
Expand Down
9 changes: 9 additions & 0 deletions app/views/api/exchanges/_exchange.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
json.id exchange.id
json.name exchange.name
json.acronym exchange.acronym
json.mic_code exchange.mic_code
json.city exchange.city
json.country_code exchange.country_code
json.timezone exchange.timezone
json.currency exchange.currency
json.links exchange.links
15 changes: 15 additions & 0 deletions app/views/api/exchanges/index.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
json.data do
json.partial! 'exchange', collection: @exchanges, as: :exchange
end
json.paging do
json.prev @pagy_metadata[:prev_url]
json.next @pagy_metadata[:next_url]
json.total_records @pagy_metadata[:count]
json.current_page @pagy_metadata[:page]
json.per_page @pagy_metadata[:items]
json.total_pages @pagy_metadata[:pages]
end
json.meta do
json.credits_used 1
json.credits_remaining @api_key.user.balance
end
7 changes: 7 additions & 0 deletions app/views/api/exchanges/show.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
json.data do
json.partial! 'exchange', locals: {exchange: @exchange}
end
json.meta do
json.credits_used 1
json.credits_remaining @api_key.user.balance
end
1 change: 1 addition & 0 deletions config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,5 @@

# Set host for accessing via ngrok
config.hosts << "sabotage.ngrok.dev"
config.hosts << "api.synth.ngrok.dev"
end
4 changes: 4 additions & 0 deletions config/initializers/geocoder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Geocoder.configure(
# geocoding service request timeout, in seconds (default 3):
timeout: 5
)
3 changes: 3 additions & 0 deletions config/initializers/geonames.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
GeoNames.configure do |config|
config.username = ENV['GEONAMES_USERNAME']
end
3 changes: 3 additions & 0 deletions config/initializers/pagy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
require 'pagy/extras/metadata'
require 'pagy/extras/overflow'
Pagy::DEFAULT[:overflow] = :empty_page
3 changes: 3 additions & 0 deletions config/initializers/timezone.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Timezone::Lookup.config(:geonames) do |c|
c.username = ENV['GEONAMES_USERNAME']
end
13 changes: 6 additions & 7 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@

devise_for :users, skip: [:registrations, :passwords, :confirmations], controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }

# devise_scope :user do
# #get 'sign_in', to: 'devise/sessions#new', as: :new_user_session
# get 'sign_up', to: redirect('/users/sign_in'), as: :new_user_registration
# get 'password/new', to: redirect('/users/sign_in'), as: :new_user_password
# get 'confirmation/new', to: redirect('/users/sign_in'), as: :new_user_confirmation
# end
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
constraints subdomain: /.*api.*/ do
namespace :api, path: nil do
resources :exchanges, only: [:index, :show]
resource :user, only: [:show]
end
end

# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
# Can be used by load balancers and uptime monitors to verify that the app is live.
Expand Down
15 changes: 15 additions & 0 deletions db/migrate/20240108191730_add_context_to_exchanges.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class AddContextToExchanges < ActiveRecord::Migration[7.2]
def change
add_column :exchanges, :operating_mic_code, :string
add_column :exchanges, :kind, :string, default: "operating" # "operating" or "segment"
add_column :exchanges, :legal_name, :string
add_column :exchanges, :lei, :string
add_column :exchanges, :mic_category, :string
add_column :exchanges, :acronym, :string
add_column :exchanges, :country_code, :string # ISO 3166-1 alpha-2
add_column :exchanges, :city, :string
add_column :exchanges, :active, :boolean, default: true
add_column :exchanges, :notes, :text
add_column :exchanges, :primary, :boolean, default: false
end
end
6 changes: 6 additions & 0 deletions db/migrate/20240108201443_add_lat_lng_to_exchanges.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class AddLatLngToExchanges < ActiveRecord::Migration[7.2]
def change
add_column :exchanges, :lat, :decimal, precision: 10, scale: 6
add_column :exchanges, :lng, :decimal, precision: 10, scale: 6
end
end
15 changes: 14 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 2d8b412

Please sign in to comment.