Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ gem 'pg', '~> 1.1'
gem 'puma', '~> 5.6'
gem 'rack-cors'
gem 'rails', '~> 7.0.0'
gem 'sentry-rails', '~> 5.5.0'
gem 'sprockets-rails'
gem 'stimulus-rails'
gem 'turbo-rails'
Expand Down
6 changes: 6 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,11 @@ GEM
rubocop (~> 1.19)
ruby-progressbar (1.11.0)
ruby2_keywords (0.0.5)
sentry-rails (5.5.0)
railties (>= 5.0)
sentry-ruby (~> 5.5.0)
sentry-ruby (5.5.0)
concurrent-ruby (~> 1.0, >= 1.0.2)
shoulda-matchers (5.0.0)
activesupport (>= 5.2.0)
simplecov (0.21.2)
Expand Down Expand Up @@ -308,6 +313,7 @@ DEPENDENCIES
rubocop
rubocop-rails
rubocop-rspec
sentry-rails (~> 5.5.0)
shoulda-matchers (~> 5.0)
simplecov
sprockets-rails
Expand Down
23 changes: 16 additions & 7 deletions app/concepts/project/operation/create.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
# frozen_string_literal: true

require 'operation_response'

class Project
module Operation
class Create
require 'operation_response'

DEFAULT_COMPONENT = { name: 'main', extension: 'py', default: true, index: 0 }.freeze
DEFAULT_PROJECT = { type: 'python', name: 'Untitled project', components: [DEFAULT_COMPONENT],
image_list: [] }.freeze
DEFAULT_COMPONENT = {
name: 'main',
extension: 'py',
default: true,
index: 0
}.freeze
DEFAULT_PROJECT = {
type: 'python',
name: 'Untitled project',
components: [DEFAULT_COMPONENT],
image_list: []
}.freeze

class << self
def call(user_id:, params:)
Expand All @@ -26,8 +35,8 @@ def call(user_id:, params:)
response[:project] = new_project
response[:project].save!
response
rescue StandardError
# TODO: log error
rescue StandardError => e
Sentry.capture_exception(e)
response[:error] = 'Error creating project'
response
end
Expand Down
15 changes: 9 additions & 6 deletions app/concepts/project/operation/create_remix.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
# frozen_string_literal: true

require 'operation_response'

class Project
module Operation
class CreateRemix
require 'operation_response'

class << self
def call(params:, user_id:, original_project:)
response = OperationResponse.new

validate_params(response, params, user_id, original_project)
remix_project(response, params, user_id, original_project)
remix_project(response, params, user_id, original_project) if response.success?
response
rescue StandardError => e
Sentry.capture_exception(e)
response[:error] = I18n.t('errors.project.remixing.cannot_save')
response
end

Expand All @@ -22,11 +26,9 @@ def validate_params(response, params, user_id, original_project)
end

def remix_project(response, params, user_id, original_project)
return if response[:error]

response[:project] = create_remix(original_project, params, user_id)

response[:error] = I18n.t('errors.project.remixing.cannot_save') unless response[:project].save
response[:project].save!
response
end

Expand All @@ -43,6 +45,7 @@ def create_remix(original_project, params, user_id)
params[:components].each do |x|
remix.components.build(x.slice(:name, :extension, :content, :index))
end

remix
end
end
Expand Down
36 changes: 18 additions & 18 deletions app/concepts/project/operation/update.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
# frozen_string_literal: true

require 'operation_response'

class Project
module Operation
class Update
require 'operation_response'

def self.call(params:, project:)
response = setup_response(project)

setup_deletions(response, params)
update_project_attributes(response, params)
update_component_attributes(response, params)
persist_changes(response)
class << self
def call(params:, project:)
response = setup_response(project)

response
end
setup_deletions(response, params)
update_project_attributes(response, params)
update_component_attributes(response, params)
persist_changes(response)
response
rescue StandardError => e
Sentry.capture_exception(e)
response[:error] ||= 'Error persisting changes'
response
end

class << self
private

def setup_response(project)
Expand All @@ -41,13 +44,13 @@ def validate_deletions(response)
end

def update_project_attributes(response, params)
return if response[:error]
return if response.failure?

response[:project].assign_attributes(params.slice(:name))
end

def update_component_attributes(response, params)
return if response[:error]
return if response.failure?

params[:components].each do |component_params|
if component_params[:id].present?
Expand All @@ -60,14 +63,11 @@ def update_component_attributes(response, params)
end

def persist_changes(response)
return if response[:error]
return if response.failure?

ActiveRecord::Base.transaction do
response[:project].save!
response[:project].components.where(id: response[:component_ids_to_delete]).destroy_all
rescue StandardError
# TODO: log error?
response[:error] = 'Error persisting changes'
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion config/initializers/auth.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# frozen_string_literal: true

BYPASS_AUTH = ENV['BYPASS_AUTH'] == 'true'
AUTH_USER_ID = ENV['AUTH_USER_ID'] if BYPASS_AUTH
AUTH_USER_ID = ENV.fetch('AUTH_USER_ID', nil) if BYPASS_AUTH
9 changes: 9 additions & 0 deletions config/initializers/sentry.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

Sentry.init do |config|
config.dsn = ENV.fetch('SENTRY_DSN', nil) if Rails.env.production?
config.breadcrumbs_logger = [:active_support_logger]
config.environment = ENV.fetch('SENTRY_CURRENT_ENV', nil) || ENV.fetch('RAILS_ENV', nil)

config.traces_sample_rate = 0.5
end
4 changes: 1 addition & 3 deletions lib/operation_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

class OperationResponse < Hash
def success?
return false unless self[:error].nil?

true
fetch(:error, nil).nil?
end

def failure?
Expand Down
8 changes: 4 additions & 4 deletions spec/concepts/project/operation/create_remix_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

it 'returns success' do
result = create_remix
expect(result.success?).to eq(true)
expect(result.success?).to be(true)
end

it 'creates new project' do
Expand Down Expand Up @@ -104,7 +104,7 @@

it 'returns failure' do
result = create_remix
expect(result.failure?).to eq(true)
expect(result.failure?).to be(true)
end

it 'returns error message' do
Expand All @@ -122,7 +122,7 @@

it 'returns failure' do
result = create_remix
expect(result.failure?).to eq(true)
expect(result.failure?).to be(true)
end

it 'returns error message' do
Expand All @@ -143,7 +143,7 @@
end

it 'returns failure' do
expect(create_remix.failure?).to eq(true)
expect(create_remix.failure?).to be(true)
end

it 'sets error message' do
Expand Down
12 changes: 9 additions & 3 deletions spec/concepts/project/operation/create_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

describe '.call' do
it 'returns success' do
expect(create_project.success?).to eq(true)
expect(create_project.success?).to be(true)
end

it 'creates a new project' do
Expand Down Expand Up @@ -57,7 +57,7 @@
end

it 'returns success' do
expect(create_project_with_content.success?).to eq(true)
expect(create_project_with_content.success?).to be(true)
end

it 'returns project with correct component content' do
Expand All @@ -71,15 +71,21 @@
mock_project = instance_double(Project)
allow(mock_project).to receive(:components).and_raise('Some error')
allow(Project).to receive(:new).and_return(mock_project)
allow(Sentry).to receive(:capture_exception)
end

it 'returns failure' do
expect(create_project.failure?).to eq(true)
expect(create_project.failure?).to be(true)
end

it 'returns error message' do
expect(create_project[:error]).to eq('Error creating project')
end

it 'sent the exception to Sentry' do
create_project
expect(Sentry).to have_received(:capture_exception).with(kind_of(StandardError))
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
end

it 'returns failure? true' do
expect(update.failure?).to eq(true)
expect(update.failure?).to be(true)
end

it 'returns error message' do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

it 'deletes the correct component' do
update
expect(Component.find_by(id: component_to_delete.id)).to eq(nil)
expect(Component.find_by(id: component_to_delete.id)).to be_nil
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/concepts/project/operation/update_invalid_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
describe '.call' do
context 'when updated project component is invalid' do
it 'returns failure? true' do
expect(update.failure?).to eq(true)
expect(update.failure?).to be(true)
end

it 'does not amend any project properties' do
Expand Down
4 changes: 2 additions & 2 deletions spec/concepts/project/operation/update_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
let(:component_params) { [default_component_params, edited_component_params] }

it 'returns success? true' do
expect(update.success?).to eq(true)
expect(update.success?).to be(true)
end

it 'updates project properties' do
Expand All @@ -54,7 +54,7 @@
it 'creates component with correct properties' do
update
created_component = project.components.find_by(**new_component_params)
expect(created_component).not_to eq(nil)
expect(created_component).not_to be_nil
end
end
end
Expand Down
8 changes: 4 additions & 4 deletions spec/lib/operation_response_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
context 'when :error not present' do
it 'returns true' do
response = described_class.new
expect(response.success?).to eq(true)
expect(response.success?).to be(true)
end
end

context 'when :error has been set' do
it 'returns false' do
response = described_class.new
response[:error] = 'An error'
expect(response.success?).to eq(false)
expect(response.success?).to be(false)
end
end
end
Expand All @@ -25,15 +25,15 @@
context 'when :error not present' do
it 'returns false' do
response = described_class.new
expect(response.failure?).to eq(false)
expect(response.failure?).to be(false)
end
end

context 'when :error has been set' do
it 'returns true' do
response = described_class.new
response[:error] = 'An error'
expect(response.failure?).to eq(true)
expect(response.failure?).to be(true)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions spec/models/component_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
describe 'validations' do
it 'returns valid? false when name changed' do
component.name = 'updated'
expect(component.valid?).to eq(false)
expect(component.valid?).to be(false)
end

it 'sets error message when name changed' do
Expand All @@ -29,7 +29,7 @@

it 'returns valid? false when extension changed' do
component.extension = 'txt'
expect(component.valid?).to eq(false)
expect(component.valid?).to be(false)
end

it 'sets error message when extension changed' do
Expand Down
2 changes: 1 addition & 1 deletion spec/request/projects/index_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
it 'returns users projects' do
get '/api/projects'
returned = JSON.parse(response.body)
expect(returned.all? { |proj| proj['user_id'] == user_id }).to eq(true)
expect(returned.all? { |proj| proj['user_id'] == user_id }).to be(true)
end
end

Expand Down