diff --git a/Gemfile b/Gemfile index 200cfb4..2639237 100644 --- a/Gemfile +++ b/Gemfile @@ -26,6 +26,9 @@ gem 'rack', '~> 3.1' # Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible gem 'rack-cors' +# Used for uploading files to Digital Ocean Spaces +gem 'aws-sdk-s3' + # Used for our import of the card data. gem 'activerecord-import' diff --git a/Gemfile.lock b/Gemfile.lock index 304ae8a..f104be5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -91,6 +91,25 @@ GEM kramdown railties ast (2.4.3) + aws-eventstream (1.4.0) + aws-partitions (1.1246.0) + aws-sdk-core (3.246.0) + aws-eventstream (~> 1, >= 1.3.0) + aws-partitions (~> 1, >= 1.992.0) + aws-sigv4 (~> 1.9) + base64 + bigdecimal + jmespath (~> 1, >= 1.6.1) + logger + aws-sdk-kms (1.124.0) + aws-sdk-core (~> 3, >= 3.244.0) + aws-sigv4 (~> 1.5) + aws-sdk-s3 (1.221.0) + aws-sdk-core (~> 3, >= 3.244.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.5) + aws-sigv4 (1.12.1) + aws-eventstream (~> 1, >= 1.0.2) base64 (0.3.0) bigdecimal (4.1.2) bootsnap (1.24.0) @@ -172,6 +191,7 @@ GEM prism (>= 1.3.0) rdoc (>= 4.0.0) reline (>= 0.4.2) + jmespath (1.6.2) json (2.19.4) jsonapi-renderer (0.2.2) jsonapi-serializable (0.3.1) @@ -597,6 +617,7 @@ PLATFORMS DEPENDENCIES activerecord-import apitome + aws-sdk-s3 bootsnap brakeman bullet @@ -655,6 +676,12 @@ CHECKSUMS activesupport (8.1.3) sha256=21a5e0dfbd4c3ddd9e1317ec6a4d782fa226e7867dc70b0743acda81a1dca20e apitome (0.3.1) sha256=7698009c4bf363b22c70d137244ecd785ac97b8537562cb1d0f30a62e06ac318 ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383 + aws-eventstream (1.4.0) sha256=116bf85c436200d1060811e6f5d2d40c88f65448f2125bc77ffce5121e6e183b + aws-partitions (1.1246.0) sha256=809cd7d38b7ba4ea651c9879248ecf9fd0f8289412e76f26478d2b37064faa1d + aws-sdk-core (3.246.0) sha256=393864ec8948560e69fcccc2e4d256b40c7028eb98930608dd295279e3c4ddcc + aws-sdk-kms (1.124.0) sha256=40d00ab706d7e49fd620270bd0dcb546f266295abdd49b54fec2611e2a41f37c + aws-sdk-s3 (1.221.0) sha256=a05488eab2083a1e90b02e18479d8f65e401081d671b2d138992a2c5fef85491 + aws-sigv4 (1.12.1) sha256=6973ff95cb0fd0dc58ba26e90e9510a2219525d07620c8babeb70ef831826c00 base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd bootsnap (1.24.0) sha256=34e6dea61ff4895101aa9c10894ce30186bec73fe2279e0eb52040d8d4cec297 @@ -690,6 +717,7 @@ CHECKSUMS i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5 io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3 + jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1 json (2.19.4) sha256=670a7d333fb3b18ca5b29cb255eb7bef099e40d88c02c80bd42a3f30fe5239ac jsonapi-renderer (0.2.2) sha256=b5c44b033d61b4abdb6500fa4ab84807ca0b36ea0e59e47a2c3ca7095a6e447b jsonapi-serializable (0.3.1) sha256=221e657677659d798e268a33ec97a83ec5ea0e4233f931358db84e88056552e9 diff --git a/lib/tasks/sqlite.rake b/lib/tasks/sqlite.rake index 2ca4562..1d8d90b 100644 --- a/lib/tasks/sqlite.rake +++ b/lib/tasks/sqlite.rake @@ -2,10 +2,29 @@ namespace :sqlite do desc 'Create a sqlite3 database for configured tables.' - task create: :environment do + task :create, [:upload] => :environment do |_, args| require 'sqlite3' require 'json' require 'zlib' + require 'aws-sdk-s3' + + upload = ['true', true].include?(args[:upload]) + + if upload + missing_vars = [] + %w[DO_SPACES_KEY DO_SPACES_SECRET DO_SPACES_ENDPOINT DO_SPACES_REGION DO_SPACES_BUCKET + DO_SPACES_FOLDER].each do |var| + missing_vars << var if ENV[var].nil? || ENV[var].strip.empty? + end + + if missing_vars.any? + missing_vars.each do |var| + puts "Missing required environment variable for upload: #{var}" + end + puts 'Upload requested but required environment variables are missing. Exiting.' + exit 1 + end + end target_models = [ Card, @@ -122,7 +141,9 @@ namespace :sqlite do end end - compress_db(db_file) + gzip_path = compress_db(db_file) + + upload_to_spaces(gzip_path) if upload puts 'Done.' end @@ -246,5 +267,32 @@ namespace :sqlite do end end puts "Database compressed to #{gzip_path}" + gzip_path + end + + def upload_to_spaces(file_path) + puts "Uploading #{file_path} to Digital Ocean Spaces..." + s3_client = Aws::S3::Client.new( + access_key_id: ENV.fetch('DO_SPACES_KEY'), + secret_access_key: ENV.fetch('DO_SPACES_SECRET'), + endpoint: ENV.fetch('DO_SPACES_ENDPOINT'), + region: ENV.fetch('DO_SPACES_REGION') + ) + + bucket = ENV.fetch('DO_SPACES_BUCKET') + folder = ENV.fetch('DO_SPACES_FOLDER') + filename = File.basename(file_path) + key = folder ? File.join(folder, filename) : filename + + File.open(file_path, 'rb') do |file| + s3_client.put_object( + bucket: bucket, + key: key, + body: file, + acl: 'public-read', + content_type: 'application/gzip' + ) + end + puts "Successfully #{file_path} uploaded to spaces: #{bucket}/#{key}" end end