Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
a9b1485
started EventsController
williampj Nov 10, 2020
a4da75c
latest controller change
williampj Nov 10, 2020
26ebd02
Merge branch 'master' of https://github.com/angeljruiz/BridgeAPI.rb i…
williampj Nov 10, 2020
60b7e77
Merge branch 'master' of https://github.com/angeljruiz/BridgeAPI.rb i…
williampj Nov 10, 2020
c93f543
.
williampj Nov 10, 2020
5b92135
fast forwarded
williampj Nov 10, 2020
2bc0290
.
williampj Nov 10, 2020
47d2906
updated user model
williampj Nov 10, 2020
112c694
.
williampj Nov 10, 2020
3b35da6
.
williampj Nov 10, 2020
14dbaa0
updated db schema
williampj Nov 10, 2020
88463d1
fixed type
williampj Nov 10, 2020
5bf7e3b
binary to jsonb
williampj Nov 11, 2020
250f782
.
williampj Nov 11, 2020
4f8920e
progressing
williampj Nov 11, 2020
95f2735
Merge branch 'master' of https://github.com/angeljruiz/BridgeAPI.rb i…
williampj Nov 11, 2020
45e38b8
removed null constraint from status_code attribute
williampj Nov 11, 2020
efc0d24
http request functionality in sidekiq
williampj Nov 12, 2020
e2de02f
latest
williampj Nov 12, 2020
f83a65f
finished draft for index, create and show eventscontroller actions
williampj Nov 12, 2020
cc00730
.
williampj Nov 12, 2020
8c135cd
.
williampj Nov 12, 2020
216b7e0
added destroy action
williampj Nov 12, 2020
0649385
updating retry and delay logic
williampj Nov 13, 2020
2912f95
updated create action and event_worker to work with delays, retries a…
williampj Nov 14, 2020
ca94904
cleaned up actions
williampj Nov 14, 2020
cc6d0ea
fast forwarded master
williampj Nov 16, 2020
7bbc6ad
updated event_worker
williampj Nov 17, 2020
4049037
updated seed db
williampj Nov 17, 2020
b70bbc3
DRY events_controller
williampj Nov 17, 2020
29e4b20
finished events_controller and event worker
williampj Nov 18, 2020
d72afe5
created event_spec test file
williampj Nov 18, 2020
3d348ca
addressed rubocop complaints
williampj Nov 18, 2020
d8f61de
editet data formatting and added sidekiq retry middleware
williampj Nov 19, 2020
918d0c1
added dynamic delay to event_worker
williampj Nov 19, 2020
17dfdf4
Syntax Parser
AndiLavera Nov 19, 2020
81cf04b
Skeleton classes
AndiLavera Nov 19, 2020
ae590ef
Fix Zeitwerk::NameError
AndiLavera Nov 19, 2020
257af7e
small cleanup
williampj Nov 19, 2020
a918cc2
Merge branch 'syntax-parser' of github.com:angeljruiz/BridgeAPI.rb in…
AndiLavera Nov 20, 2020
a2bb448
Broke parser into smaller classes, rubocop seeds
AndiLavera Nov 20, 2020
f694933
Broken EventWorker into smaller classes
AndiLavera Nov 20, 2020
583cbdf
Deconstructor is working
AndiLavera Nov 20, 2020
94d90e3
Remove downcasing headers, better deconstructing for non-downcased he…
AndiLavera Nov 20, 2020
be8ed1e
Support DI for Deconstructor
AndiLavera Nov 20, 2020
7b6f2ea
Integrating SyntaxParser into RequestHandler
AndiLavera Nov 20, 2020
0d2c608
Merge branch 'master' of github.com:angeljruiz/BridgeAPI.rb into brid…
AndiLavera Nov 20, 2020
f203db1
It works! Header & payload parsing works, deconstructing & saving wor…
AndiLavera Nov 20, 2020
57cfc62
Documentation & Clean up
AndiLavera Nov 21, 2020
c72d000
Rubocop
AndiLavera Nov 21, 2020
7e499f8
Fix broken event model specs
AndiLavera Nov 21, 2020
9632eee
Fix database.yml & add pending spec
AndiLavera Nov 21, 2020
726aee4
Handler => RequestHandler, setting up tests
AndiLavera Nov 21, 2020
9c88964
Added webmock & factory bot for testing, created factories, created m…
AndiLavera Nov 21, 2020
f4fe1fc
Formatter spec
AndiLavera Nov 21, 2020
a450457
Deconstructor spec
AndiLavera Nov 21, 2020
5ea08a2
PayloadParser: Add support for deeply nested hashes or arrays
AndiLavera Nov 21, 2020
bb9f38c
Update payload parser spec
AndiLavera Nov 21, 2020
1c71f80
Add better docs for payload parser
AndiLavera Nov 21, 2020
1eaa0f5
request_handler_spec
AndiLavera Nov 21, 2020
a553ff1
Couple rubocop errors
AndiLavera Nov 21, 2020
481d61a
Builder spec
AndiLavera Nov 21, 2020
45783c1
Remove unused event helper
AndiLavera Nov 21, 2020
445154e
Fix EventsController
AndiLavera Nov 21, 2020
969b40d
Event Specs
AndiLavera Nov 22, 2020
3128a6b
Merge branch 'master' of github.com:angeljruiz/BridgeAPI.rb into brid…
AndiLavera Nov 23, 2020
a629012
Fast forward fixes
AndiLavera Nov 23, 2020
d6d2d4b
EventController#create spec
AndiLavera Nov 23, 2020
05ce897
Remove test env in http builder as it wasn't needed
AndiLavera Nov 23, 2020
2c79927
DI for EventWorker
AndiLavera Nov 23, 2020
9d7dbc1
Pending event_worker_specs
AndiLavera Nov 23, 2020
719abfc
Remove retry arg for EventWorker
AndiLavera Nov 23, 2020
ca98882
Small doc in EventWorker
AndiLavera Nov 23, 2020
865b58e
Rubocop
AndiLavera Nov 24, 2020
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
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ AllCops:
- "db/*/*"
Metrics/BlockLength:
Exclude:
- "spec/*/*"
- "spec/**/*"
4 changes: 3 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ gem 'puma', '~> 4.1'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.7'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
gem 'redis', '~> 4.0'
# Use Active Model has_secure_password
gem 'bcrypt', '~> 3.1.7'
gem 'jwt'
Expand Down Expand Up @@ -46,8 +46,10 @@ group :development do
end

group :test do
gem 'factory_bot_rails'
# Generate test coverage reports
gem 'simplecov', require: false
gem 'webmock'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
Expand Down
17 changes: 17 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ GEM
minitest (~> 5.1)
tzinfo (~> 1.1)
zeitwerk (~> 2.2, >= 2.2.2)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
ast (2.4.1)
bcrypt (3.1.16)
bootsnap (1.5.0)
Expand All @@ -65,13 +67,20 @@ GEM
coderay (1.1.3)
concurrent-ruby (1.1.7)
connection_pool (2.2.3)
crack (0.4.4)
crass (1.0.6)
diff-lcs (1.4.4)
docile (1.3.2)
erubi (1.9.0)
factory_bot (6.1.0)
activesupport (>= 5.0.0)
factory_bot_rails (6.1.0)
factory_bot (~> 6.1.0)
railties (>= 5.0.0)
ffi (1.13.1)
globalid (0.4.2)
activesupport (>= 4.2.0)
hashdiff (1.0.1)
i18n (1.8.5)
concurrent-ruby (~> 1.0)
jbuilder (2.10.1)
Expand Down Expand Up @@ -103,6 +112,7 @@ GEM
pry (0.13.1)
coderay (~> 1.1)
method_source (~> 1.0)
public_suffix (4.0.6)
puma (4.3.6)
nio4r (~> 2.0)
rack (2.2.3)
Expand Down Expand Up @@ -197,6 +207,10 @@ GEM
tzinfo (1.2.8)
thread_safe (~> 0.1)
unicode-display_width (1.7.0)
webmock (3.10.0)
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
websocket-driver (0.7.3)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
Expand All @@ -209,6 +223,7 @@ DEPENDENCIES
bcrypt (~> 3.1.7)
bootsnap (>= 1.5.0)
byebug
factory_bot_rails
jbuilder (~> 2.7)
jwt
listen (~> 3.2)
Expand All @@ -217,13 +232,15 @@ DEPENDENCIES
puma (~> 4.1)
rack-cors
rails (~> 6.0.3, >= 6.0.3.4)
redis (~> 4.0)
rspec-rails (~> 4.0.1)
rubocop
sidekiq
simplecov
spring
spring-watcher-listen (~> 2.0.0)
tzinfo-data
webmock

RUBY VERSION
ruby 2.6.6p146
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/bridges_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def bridge_params
params.require(:bridge).permit(
:active,
:title,
:method,
:http_method,
:retries,
:delay,
:outbound_url,
Expand Down
116 changes: 68 additions & 48 deletions app/controllers/events_controller.rb
Original file line number Diff line number Diff line change
@@ -1,68 +1,88 @@
# frozen_string_literal: true

class EventsController < ApplicationController
before_action :authorize_request
before_action :set_user
# Needs to find all events based on bridge_id or event_id
# Needs to return id for each event as well
# def index
# events = @current_user.bridges
# events.map! do |event|
# updated_at = String(event.updated_at)
# date = date_format(updated_at.split(' ')[1])
# time = updated_at.split(' ')[0]
# { id: 1,
# time: time,
# date: date,
# status_code: event.status_code }
# end
# render json: { events: events }, status: 200 # OK
# end
before_action :authorize_request, except: :create
before_action :set_event, only: %i[show destroy]

def show; end
def index
if fetch_events.empty?
render json: { error: 'invalid parameters' }, status: 400 # Bad Request
else
render json: { events: @events }, status: 200
end
end

def show
if @event
render json: { event: @event }, status: 200
else
render json: { error: 'an event by that id was not found' }, status: 400
end
end

def destroy
return render json: {}, status: 204 if @event&.destroy

render json: { error: 'an event by that id was not found' }, status: 400
end

# receive bridge id + data
def create
bridge = Bridge.find(params[:id])
data = { inbound: request.body, outbounds: [] }
event = Event.new(data: data, bridge_id: bridge.id)
event = create_event(find_bridge)
if event.save
# EventWorker.perform(id of event just created)
status 201 # Created
EventWorker.perform_async(event.id)
render json: {}, status: 202 # Accepted
else
status 400 # Bad Request
render json: { error: 'Invalid parameters' }, status: 400 # Bad Request
end
rescue JSON::ParserError
render json: { error: 'Invalid request. Payload must be in JSON' }, status: 400 # Bad Request
end

private

def date_format(_date)
year = time.split('-')[0]
month = time.split('-')[1]
day = time.split('-')[2]
"#{year}-#{month}-#{day}"
def event_params
params.permit(:id, :bridge_id, :event_id, :test)
end

def set_user
# bridge_id or #event_id
# => User
def fetch_events
@events = if event_params[:bridge_id]
Event.where(bridge_id: event_params[:bridge_id]).order(completed_at: :desc).limit(100)
elsif event_params[:event_id]
Event.where(bridge_id: find_event&.bridge_id).order(completed_at: :desc).limit(100)
else
[] # Prevent nil
end
end
end

# Step 1
# Convert binary to jsonb
def data
{
'inbound' => {
'payload' => JSON.parse(request.body.read),
'dateTime' => DateTime.now.utc,
'ip' => request.ip,
'contentLength' => request.content_length
},
'outbound' => []
}
end

# Step 2
# payload:
{
test: 'user entered string from editor',
production: 'user entered string from editor'
}
def create_event(bridge)
Event.new(
data: data.to_json,
bridge_id: bridge&.id,
test: event_params[:test] || false
)
end

# Step 3
#
def set_event
@event = find_event
end

# NB: Need to run `bundle exec sidekiq` in separate terminal
# localhost:3000/sidekiq to monitor sidekiq while running
# after turning it on
# => mount Sidekiq::Web => '/sidekiq
def find_event
Event.find_by(id: event_params[:event_id])
end

def find_bridge
Bridge.find_by(id: event_params[:bridge_id])
end
end
8 changes: 8 additions & 0 deletions app/lib/bridge_api.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

require_relative './invalid_payload_key'
require_relative './invalid_environment_variable'
require_relative './sidekiq/large_status_code'

module BridgeApi
end
6 changes: 6 additions & 0 deletions app/lib/bridge_api/http.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

module BridgeApi
module Http
end
end
134 changes: 134 additions & 0 deletions app/lib/bridge_api/http/builder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# frozen_string_literal: true

module BridgeApi
module Http
# Handles building a HTTP Request object. Will parse user defined payloads
# and headers into expected values. Accepts custom parsers for extending.
#
# Example:
#
# ```ruby
# event = Event.find(1)
#
# handler = BridgeApi::Http::RequestHandler.new event
# builder = BridgeApi::Http::Builder.new handler, handler.payload_parser, handler.headers_parser
#
# builder.generate # => returns an Tuple containing Net::Http & Net::Http::{user_request_type} objects
# ```
class Builder
SCHEME = 'https://'

include Interfaces::Builder

# @param [BridgeApi::Http::Handler] request_handler - Used for delegation
# @param [BridgeApi::SyntaxParser::Interfaces::PayloadParser] payload_parser
# @param [BridgeApi::SyntaxParser::Interfaces::HeadersParser] headers_parser
def initialize(request_handler, payload_parser, headers_parser)
@request_handler = request_handler
@payload_parser = payload_parser
@headers_parser = headers_parser
end

# Generate & return `Net::HTTP`(net_http) & `Net::HTTP::{http_method}`(http_request) objects
#
# @return [Tuple(Net::HTTP, Net::HTTP::{http_method})]
def generate
[net_http, http_request]
end

private

delegate :bridge, to: :request_handler
delegate :event, to: :request_handler

attr_reader :request,
:request_handler,
:payload_parser,
:headers_parser

def net_http
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

http
end

def http_request
@request = net_http_request
parse_headers!
request.body = parsed_payload.to_json

request
end

# Convert user defined outbound_url into a valid URI
#
# @return [String]
def uri
@uri ||= URI(scheme)
end

# Sets the user defined headers into the `request` object
def parse_headers!
headers_parser.parse(headers) do |key, value|
request[key] = value
end
end

# Parse our custom syntax into the expected values
#
# @return [Hash(String, String)]
def parsed_payload
@parsed_payload ||= payload_parser.parse(
event.inbound_payload,
JSON.parse(unparsed_payload)
)
end

# Returns either payload or test_payload depending
# on the event environment
#
# @return [JSON]
def unparsed_payload
@unparsed_payload ||= data['payload']
end

# Ensures the scheme used is using TSL
#
# @return [String]
def scheme
return outbound_url if outbound_url.starts_with?('https')

"#{SCHEME}#{outbound_url.split('//').last}"
end

# Create a HTTP request object based on the user defined
# HTTP method.
#
# @return [Net::HTTP::{http_method}]
def net_http_request
"Net::HTTP::#{http_method}".constantize.new(uri, 'Content-Type' => 'application/json')
end

# @return [String]
def http_method
bridge.http_method.capitalize
end

# @return [Hash(String, JSON)]
def data
bridge.data
end

# @return [String]
def outbound_url
bridge.outbound_url
end

# @return [ActiveRecord::Relation(Header)]
def headers
@headers ||= bridge.headers
end
end
end
end
Loading