diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..6df3e31 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,73 @@ +name: Test + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-18.04 + strategy: + matrix: + ruby: [ 2.5, 3.0, jruby-head ] + neo4j: [ 3.5.26, 4.0.11 ] + driver: [ ffi ] + include: + - ruby: jruby-head + neo4j: 4.0.11 + driver: java + - ruby: 2.5 + neo4j: 3.4.18 + driver: ffi + java-version: 8 + active-model-version: 5.2.3 + env: + NEO4J_EDITION_FLAG: -e + NEO4J_VERSION: ${{ matrix.neo4j }} + driver: ${{ matrix.driver }} + ACTIVE_MODEL_VERSION: ${{ matrix.active-model-version }} + JRUBY_OPTS: --debug -J-Xmx1280m -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF + steps: + - uses: actions/checkout@v2 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.8.x' + - uses: BSFishy/pip-action@v1 + with: + packages: git+https://github.com/klobuczek/boltkit@1.3#egg=boltkit + + - name: Set up Java + uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java-version || 11 }} + + - name: Setup Neo4j + run: | + neoctrl-install $NEO4J_EDITION_FLAG $NEO4J_VERSION servers + if [ -n "$NEO4J_EDITION_FLAG" ]; then NEO4J_EDITION=enterprise; else NEO4J_EDITION=community; fi + NEO4J_DIR=servers/neo4j-$NEO4J_EDITION-$NEO4J_VERSION + neoctrl-configure $NEO4J_DIR dbms.memory.pagecache.size=600m dbms.memory.heap.max_size=600m dbms.memory.heap.initial_size=600m dbms.directories.import= dbms.connectors.default_listen_address=:: dbms.security.auth_enabled=false + neoctrl-start $NEO4J_DIR + + - name: Setup Seabolt + if: matrix.driver != 'java' + run: | + wget https://github.com/neo4j-drivers/seabolt/releases/download/v1.7.4/seabolt-1.7.4-Linux-ubuntu-18.04.deb + sudo dpkg -i seabolt-1.7.4-Linux-ubuntu-18.04.deb + + - name: Install dependencies + run: bundle update + - name: Run tests + run: bundle exec rspec diff --git a/README.md b/README.md index 77def9d..e2a2e9b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## CarrierWave for Neo4j +## CarrierWave for ActiveGraph This gem adds support for Neo4j 3.0+ (neo4j.rb 9.6.0+) to CarrierWave 2.1.0+, see the CarrierWave documentation for more detailed usage instructions. @@ -7,10 +7,10 @@ This gem adds support for Neo4j 3.0+ (neo4j.rb 9.6.0+) to CarrierWave 2.1.0+, se Add to your Gemfile: ```ruby -gem 'carrierwave-neo4j', '~> 3.0', require: 'carrierwave/neo4j' +gem 'carrierwave-neo4j', '~> 3.0', require: 'carrierwave/active_graph' ``` -You can see example usage in `spec/neo4j_realistic_spec.rb` but in brief, you can use it like this: +You can see example usage in `spec/active_graph_realistic_spec.rb` but in brief, you can use it like this: ```ruby class AttachmentUploader < CarrierWave::Uploader::Base @@ -22,7 +22,7 @@ class AttachmentUploader < CarrierWave::Uploader::Base end class Asset - include Neo4j::ActiveNode + include ActiveGraph::Node property :attachment, type: String mount_uploader :attachment, AttachmentUploader @@ -47,7 +47,7 @@ brew install imagemagick ```sh bundle install -rake neo4j:install[community-latest,test] +rake neo4j:install[community-4.0.11,test] rake neo4j:start[test] rake spec ``` diff --git a/carrierwave-neo4j.gemspec b/carrierwave-neo4j.gemspec index 2c3a310..c52c41a 100644 --- a/carrierwave-neo4j.gemspec +++ b/carrierwave-neo4j.gemspec @@ -1,10 +1,10 @@ # -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) -require "carrierwave/neo4j/version" +require "carrierwave/active_graph/version" Gem::Specification.new do |s| - s.name = "carrierwave-neo4j" - s.version = CarrierWave::Neo4j::VERSION + s.name = "carrierwave-activegraph" + s.version = CarrierWave::ActiveGraph::VERSION s.authors = ["Rodrigo Navarro"] s.email = ["navarro@manapot.com.br"] s.homepage = "https://github.com/neo4jrb/carrierwave-neo4j" @@ -17,8 +17,9 @@ Gem::Specification.new do |s| s.require_paths = ["lib"] s.add_dependency("activesupport", ">= 6.0" ) - s.add_dependency("neo4j", "~> 9.6.0") + s.add_dependency("activegraph", ">= 10.0.0") s.add_dependency("carrierwave", ">= 2.1") + s.add_development_dependency("neo4j-#{ENV['driver'] == 'java' ? 'java' : 'ruby'}-driver", '~> 1.7.4') s.add_development_dependency("rspec", "~> 3.0") s.add_development_dependency("rspec-its") s.add_development_dependency("webmock") diff --git a/lib/carrierwave/neo4j.rb b/lib/carrierwave/active_graph.rb similarity index 94% rename from lib/carrierwave/neo4j.rb rename to lib/carrierwave/active_graph.rb index a82b7ff..c20c518 100644 --- a/lib/carrierwave/neo4j.rb +++ b/lib/carrierwave/active_graph.rb @@ -1,8 +1,8 @@ -require "carrierwave/neo4j/version" -require "neo4j" +require "carrierwave/active_graph/version" +require "active_graph" require "carrierwave" require "carrierwave/validations/active_model" -require "carrierwave/neo4j/uploader_converter" +require "carrierwave/active_graph/uploader_converter" require "active_support/concern" ###### @@ -14,7 +14,7 @@ # ...which is mixed into Model classes. ###### module CarrierWave - module Neo4j + module ActiveGraph # this class methods junk is necessary because ActiveNode is implemented as # a model instead of a class for god-knows-what-reason. @@ -85,7 +85,8 @@ def mount_base(column, uploader=nil, options={}, &block) # but at init time, the value of the column is not yet available # so after init, the empty @uploaders cache must be invalidated # it will reinitialized with the processed column value on first access - after_initialize :_set_uploaders_nil + # TODO: This currently break things when initializing a model with #new and parameters. Do we need it? + #after_initialize :_set_uploaders_nil before_save :"write_#{column}_identifier" after_save :"store_#{column}!" @@ -159,7 +160,7 @@ def _force_uploaders_reload # okay, this actually works: def force_retrieve_#{column} - send(:#{column}).send(:retrieve_from_store!, #{column}_identifier) + send(:#{column}).send(:retrieve_from_store!, #{column}_identifier) if #{column}_identifier end # these produce an infinite loop, so... don't reintroduce them: @@ -208,4 +209,4 @@ def store_previous_changes_for_#{column} end end -Neo4j::ActiveNode.include CarrierWave::Neo4j +ActiveGraph::Node.include CarrierWave::ActiveGraph diff --git a/lib/carrierwave/neo4j/uploader_converter.rb b/lib/carrierwave/active_graph/uploader_converter.rb similarity index 66% rename from lib/carrierwave/neo4j/uploader_converter.rb rename to lib/carrierwave/active_graph/uploader_converter.rb index 7a8f305..308a004 100644 --- a/lib/carrierwave/neo4j/uploader_converter.rb +++ b/lib/carrierwave/active_graph/uploader_converter.rb @@ -1,4 +1,4 @@ -module CarrierWave::Neo4j +module CarrierWave::ActiveGraph module TypeConverters class UploaderConverter class << self @@ -23,14 +23,14 @@ def to_ruby(value) end def register_converter(mod) - mod::TypeConverters.send :include, CarrierWave::Neo4j::TypeConverters + mod::TypeConverters.send :include, CarrierWave::ActiveGraph::TypeConverters end -major = Neo4j::VERSION.split('.').first.to_i +major = ActiveGraph::VERSION.split('.').first.to_i case major when 1..2 then fail('Unsupported version of Neo4j gem. Please update it.') when 3 then register_converter(Neo4j) when 4 then register_converter(Neo4j::Shared) - when 5..Float::INFINITY then Neo4j::Shared::TypeConverters.register_converter(CarrierWave::Neo4j::TypeConverters::UploaderConverter) + when 5..Float::INFINITY then ActiveGraph::Shared::TypeConverters.register_converter(CarrierWave::ActiveGraph::TypeConverters::UploaderConverter) end diff --git a/lib/carrierwave/neo4j/version.rb b/lib/carrierwave/active_graph/version.rb similarity index 70% rename from lib/carrierwave/neo4j/version.rb rename to lib/carrierwave/active_graph/version.rb index 1ea95be..19db7b4 100644 --- a/lib/carrierwave/neo4j/version.rb +++ b/lib/carrierwave/active_graph/version.rb @@ -1,5 +1,5 @@ module CarrierWave - module Neo4j + module ActiveGraph VERSION = '3.0.0' end end diff --git a/spec/neo4j_realistic_spec.rb b/spec/active_graph_realistic_spec.rb similarity index 96% rename from spec/neo4j_realistic_spec.rb rename to spec/active_graph_realistic_spec.rb index 7df275b..70964f6 100644 --- a/spec/neo4j_realistic_spec.rb +++ b/spec/active_graph_realistic_spec.rb @@ -13,18 +13,18 @@ def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end - def extension_whitelist + def extension_allowlist %w(jpg jpeg gif png) end end class Book - include Neo4j::ActiveNode + include ActiveGraph::Node property :cover, type: String mount_uploader :cover, RealisticUploader end -describe CarrierWave::Neo4j do +describe CarrierWave::ActiveGraph do after do Book.destroy_all end diff --git a/spec/neo4j_sanity_spec.rb b/spec/active_graph_sanity_spec.rb similarity index 70% rename from spec/neo4j_sanity_spec.rb rename to spec/active_graph_sanity_spec.rb index 7e51aff..e3b5da4 100644 --- a/spec/neo4j_sanity_spec.rb +++ b/spec/active_graph_sanity_spec.rb @@ -12,14 +12,14 @@ def reset_class Object.send(:remove_const, "User") rescue nil Object.const_set("User", Class.new()) User.class_eval do - include Neo4j::ActiveNode + include ActiveGraph::Node property :image, type: String mount_uploader :image, DefaultUploader end User end -describe CarrierWave::Neo4j do +describe CarrierWave::ActiveGraph do before do reset_class @user = User.new @@ -68,6 +68,18 @@ def reset_class end describe "#image" do + it "should return blank uploader when nothing has been assigned" do + expect(@user.image).to be_blank + end + + it "should return blank uploader when an blank uploader has been assigned" do + @user[:image] = DefaultUploader.new + @user.save! + @user.reload + other = User.find(@user.id) + expect(@user.image).to be_blank + expect(other.image).to be_blank + end end describe "#save" do @@ -85,6 +97,30 @@ def reset_class expect(@user[:image].identifier).to eq('ong.jpg') expect(@user.image_identifier).to eq('ong.jpg') end + + it "should assign the filename to the database even if uploader was previous nil" do + expect(@user.save).to be_truthy + expect(@user.image).to be_blank + image = File.open(file_path("ong.jpg")) + expect(@user.update(image: image)).to be_truthy + @user.reload + expect(@user[:image]).not_to eq('ong.jpg') + expect(@user[:image].identifier).to eq('ong.jpg') + expect(@user.image_identifier).to eq('ong.jpg') + end + + it "should assign the filename to the database when using #new even if uploader was previous nil" do + expect(@user.save).to be_truthy + expect(@user.image).to be_blank + image = File.open(file_path("ong.jpg")) + user = User.new(image: image) + expect(user.save).to be_truthy + user.reload + expect(user[:image]).not_to eq('ong.jpg') + expect(user[:image].identifier).to eq('ong.jpg') + expect(user.image_identifier).to eq('ong.jpg') + end + end describe "#update" do @@ -101,16 +137,15 @@ def reset_class expect(@user.reload.image).to be_blank end - it "does not respect `update_column`" do + it "does respect `update_column` only after find" do @user.image = File.open(file_path("ong.jpg")) @user.save! # ActiveRecord would respect `update_column` User.find(@user.id).update_column(:image, nil) - expect(@user.reload.image).to be_present other = User.find(@user.id) - expect(other.image).to be_present + expect(other.image).to be_blank end end @@ -119,6 +154,8 @@ def reset_class describe "#remote_image_url=" do before do + allow_any_instance_of(CarrierWave::Downloader::Base).to receive(:skip_ssrf_protection?). + and_return(true) stub_request(:get, "www.example.com/test.jpg").to_return(body: File.read(file_path("ong.jpg"))) end diff --git a/spec/neo4j_spec.rb b/spec/active_graph_spec.rb similarity index 98% rename from spec/neo4j_spec.rb rename to spec/active_graph_spec.rb index c85046f..a827fd9 100644 --- a/spec/neo4j_spec.rb +++ b/spec/active_graph_spec.rb @@ -8,14 +8,14 @@ def reset_class(uploader = DefaultUploader) end class User - include Neo4j::ActiveNode + include ActiveGraph::Node property :image, type: String end class DefaultUploader < CarrierWave::Uploader::Base ; end class PngUploader < CarrierWave::Uploader::Base - def extension_whitelist + def extension_allowlist %w(png) end end @@ -34,7 +34,7 @@ def download!(file, headers = {}) end end -describe CarrierWave::Neo4j do +describe CarrierWave::ActiveGraph do let(:user_class) { reset_class } let(:user_class_png) { reset_class(PngUploader) } let(:user_class_error) { reset_class(ProcessingErrorUploader) } diff --git a/spec/helpers/database_cleaner.rb b/spec/helpers/database_cleaner.rb index 4bbb441..ae46884 100644 --- a/spec/helpers/database_cleaner.rb +++ b/spec/helpers/database_cleaner.rb @@ -1,8 +1,8 @@ -require "neo4j" +require "active_graph" class DatabaseCleaner - include Neo4j::Migrations::Helpers + include ActiveGraph::Migrations::Helpers def self.clean DatabaseCleaner.new.clean_db @@ -11,9 +11,9 @@ def self.clean def self.avoid_validation # migrations and db cleanup have to happen outside of validations # or they never succeed - Neo4j::Migrations.currently_running_migrations = true + ActiveGraph::Migrations.currently_running_migrations = true yield - Neo4j::Migrations.currently_running_migrations = false + ActiveGraph::Migrations.currently_running_migrations = false end def clean_db diff --git a/spec/helpers/fake_book_migration.rb b/spec/helpers/fake_book_migration.rb index c4105b0..9bcac84 100644 --- a/spec/helpers/fake_book_migration.rb +++ b/spec/helpers/fake_book_migration.rb @@ -1,7 +1,7 @@ -require "neo4j" +require "active_graph" -class FakeBookMigration < Neo4j::Migrations::Base +class FakeBookMigration < ActiveGraph::Migrations::Base def self.create FakeBookMigration.new(:fake_book_migration) diff --git a/spec/helpers/fake_schema_migration.rb b/spec/helpers/fake_schema_migration.rb index f242fe1..2e0da7d 100644 --- a/spec/helpers/fake_schema_migration.rb +++ b/spec/helpers/fake_schema_migration.rb @@ -1,13 +1,13 @@ -require "neo4j" +require "active_graph" -class FakeSchemaMigration < Neo4j::Migrations::Base +class FakeSchemaMigration < ActiveGraph::Migrations::Base def self.create FakeSchemaMigration.new(:fake_schema_migration) end def up - add_constraint :"Neo4j::Migrations::SchemaMigration", :migration_id, force: true + add_constraint :"ActiveGraph::Migrations::SchemaMigration", :migration_id, force: true end end diff --git a/spec/helpers/fake_user_migration.rb b/spec/helpers/fake_user_migration.rb index 5ecd69a..1b41332 100644 --- a/spec/helpers/fake_user_migration.rb +++ b/spec/helpers/fake_user_migration.rb @@ -1,7 +1,7 @@ -require "neo4j" +require "active_graph" -class FakeUserMigration < Neo4j::Migrations::Base +class FakeUserMigration < ActiveGraph::Migrations::Base def self.create FakeUserMigration.new(:fake_user_migration) diff --git a/spec/helpers/filesystem_cleaner.rb b/spec/helpers/filesystem_cleaner.rb index 51bfed3..ee6d50a 100644 --- a/spec/helpers/filesystem_cleaner.rb +++ b/spec/helpers/filesystem_cleaner.rb @@ -1,5 +1,5 @@ -require "neo4j" +require "active_graph" class FilesystemCleaner def self.clean diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 736ce00..2e8f430 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,14 +5,13 @@ require "rspec/its" require "webmock/rspec" -require "neo4j" -require "neo4j/core/cypher_session/adaptors/bolt" +require "active_graph" require "helpers/database_cleaner" require "helpers/filesystem_cleaner" require "helpers/fake_migrations" require "carrierwave" -require "carrierwave/neo4j" +require "carrierwave/active_graph" def file_path(*paths) File.expand_path(File.join(File.dirname(__FILE__), "fixtures", *paths)) @@ -29,8 +28,9 @@ def tmp_path( *paths ) CarrierWave.root = public_path # DatabaseCleaner[:neo4j, connection: {type: :bolt, path: 'bolt://localhost:7006'}].strategy = :transaction -neo4j_adaptor = Neo4j::Core::CypherSession::Adaptors::Bolt.new('bolt://localhost:7472', {ssl: false}) -Neo4j::ActiveBase.on_establish_session { Neo4j::Core::CypherSession.new(neo4j_adaptor) } +server_url = ENV['NEO4J_URL'] || 'bolt://localhost:7687' +ActiveGraph::Base.driver = + Neo4j::Driver::GraphDatabase.driver(server_url, Neo4j::Driver::AuthTokens.none, encryption: false) RSpec.configure do |config| config.before(:each) do