Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f7dadc1
Merge pull request #14 from CreatekIO/rails-6-0-compatibility
rjpaskin May 13, 2024
7efed83
Upgrade actions in CodeQL workflow to latest versions
rjpaskin May 22, 2024
388e435
Add workflow to sync Dependabot alerts to Jira
rjpaskin May 22, 2024
82b83aa
Merge pull request #16 from CreatekIO/technical/REW-733-upgrade-codeq…
rjpaskin May 22, 2024
f903de6
Merge pull request #15 from CreatekIO/rails-6-1-compatibility
rjpaskin Jul 9, 2024
c30c747
Update Ruby & MySQL versions to 'current'
rjpaskin Feb 5, 2025
d8033fe
Fix error in spec_helper
rjpaskin Feb 5, 2025
abbb8b3
Add GH workflow for CI
rjpaskin Feb 5, 2025
8fbd168
Remove Buildkite files
rjpaskin Feb 5, 2025
9453597
Remove no-longer-needed development gem
rjpaskin Feb 5, 2025
0667089
Remove obsolete reference to CircleCI
rjpaskin Feb 5, 2025
4347a94
Merge pull request #17 from CreatekIO/technical/REW-687-ci-on-github-…
rjpaskin Mar 3, 2025
65e4b21
Update rails constraints to 7.0
Albion31 Apr 9, 2025
98af8a5
Merge pull request #18 from CreatekIO/rails-7.0-compatibility
rjpaskin Apr 9, 2025
37dcbaa
Fix autoloading for Rails 7.0
farisalamin Apr 9, 2025
7ab7863
Merge pull request #19 from CreatekIO/rails-7.0-compatibility
rjpaskin Apr 9, 2025
b334cb9
REW-2045 - implement storage adapters for active storage and dragonfly
reissjohnson May 15, 2025
257e5fa
REW-2045 - requires AS and Dragonfly adapters in spec helper
reissjohnson May 15, 2025
b411e87
REW-2045 - Basic upload of a file processor now in place
reissjohnson May 16, 2025
60ce0ca
REW-2045 - return str and not nil if string is UTF8 already ( was cau…
reissjohnson May 19, 2025
4a1a655
REW-2045 - always encode strings in csv2db/import.rb
reissjohnson May 20, 2025
c2ba05c
REW-2045 - adds back in base check of file extension
reissjohnson May 20, 2025
d1fd922
REW-2045 - use File.open(file) instead of file.tempfile as was causin…
reissjohnson May 21, 2025
8c7fe93
REW-2045 - adds local_storage_host config option to csv2db gem
reissjohnson May 22, 2025
9fe686f
REW-2045 - implement expiring link method and use on downloads table
reissjohnson May 22, 2025
dcb2076
REW-2045 - adds specs to gem base model
reissjohnson May 22, 2025
8a3fa9b
REW-2045 - update set_current_host method to include test environment
reissjohnson May 23, 2025
4a9a7ce
REW-2045 - fixes failing spec due to alias_method
reissjohnson May 23, 2025
045e4e2
REW-2045 - adds responds to missing method into csv2db gem
reissjohnson May 23, 2025
0b70347
REW-2045 - rename MAX_EXPIRY to LINK_MAX_EXPIRY
reissjohnson May 23, 2025
e403294
REW-2045 - adds private keyword to dragonfly adapter
reissjohnson May 23, 2025
6d94812
REW-2045 - switch round if statement logic
reissjohnson May 24, 2025
4d526e4
Merge pull request #20 from CreatekIO/REW-2045-file-upload-restrictio…
rjpaskin May 29, 2025
c170ac0
REW-2045 - rename expiring_link method to download_link (can then be …
reissjohnson Jun 6, 2025
70853e5
Merge pull request #21 from CreatekIO/REW-2045-file-upload-restrictio…
reissjohnson Jun 6, 2025
031fa7c
REW-2045 - adds download_link method for dragonfly adapter and use th…
reissjohnson Jun 10, 2025
37ba706
Merge pull request #22 from CreatekIO/REW-2045-file-upload-restrictio…
reissjohnson Jun 10, 2025
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
32 changes: 0 additions & 32 deletions .buildkite/pipeline.yml

This file was deleted.

26 changes: 0 additions & 26 deletions .buildkite/test.sh

This file was deleted.

51 changes: 51 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Test Suite

on:
push:
workflow_dispatch:

jobs:
spec:
name: RSpec
runs-on: ubuntu-latest

container:
image: ruby:2.7.8
credentials:
username: ${{ secrets.ORG_DOCKERHUB_USERNAME }}
password: ${{ secrets.ORG_DOCKERHUB_TOKEN }}
env:
DB_HOST: db
DB_USERNAME: root

services: # versions here should match those used in docker-compose.yml
db:
image: mysql:8.0.34
env:
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=3

steps:
- uses: actions/checkout@v4

- name: Run RSpec
shell: script -q -e -c "bash {0}" # force colour output - see https://github.com/actions/runner/issues/241
run: |
set -euo pipefail

./docker-entrypoint.sh

mkdir -p tmp
mkdir -p log

bin/rspec

- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: "test.log"
path: log/test.log
8 changes: 4 additions & 4 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
Expand All @@ -60,7 +60,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v3

# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
Expand All @@ -73,6 +73,6 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
22 changes: 22 additions & 0 deletions .github/workflows/github-security-jira.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: GitHub Security Alerts for Jira

on:
schedule:
- cron: '0 4 * * *'
workflow_dispatch:

jobs:
syncSecurityAlerts:
runs-on: ubuntu-latest
steps:
- name: "Sync security alerts to Jira issues"
uses: reload/github-security-jira@v1.5.0
env:
GH_SECURITY_TOKEN: ${{ secrets.ORG_GITHUBSECURITYTOKEN }}
JIRA_TOKEN: ${{ secrets.ORG_JIRA_TOKEN }}
JIRA_HOST: https://360insights.atlassian.net/
JIRA_USER: ${{secrets.ORG_JIRA_USERNAME}}
JIRA_PROJECT: SB
JIRA_ISSUE_TYPE: Security Code Analysis
JIRA_ISSUE_LABELS: MYREWARDS_SECURITY_ALERT
JIRA_RESTRICTED_COMMENT_ROLE: Developer
2 changes: 1 addition & 1 deletion app/controllers/concerns/csv2db/controller_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def enqueue_csv_import_and_redirect(klass, options = {}, &block)
end

def enqueue_csv_import(klass, options = {})
permitted_params = options.fetch(:params) do
permitted_params = options.fetch(:params) do
params.require(klass.model_name.param_key).permit(
:file,
*options[:extra_params]
Expand Down
67 changes: 67 additions & 0 deletions app/models/concerns/csv2db/active_storage_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
module Csv2db::ActiveStorageAdapter
require 'active_support/all'

extend ActiveSupport::Concern
FILE_TYPE = 'text/csv'.freeze
LINK_MAX_EXPIRY = 7.days.to_s.freeze

included do
has_one_attached Csv2db.config.file_attachment_name

validate :check_file_extension

alias_method :file_attachment, Csv2db.config.file_attachment_name
end

def file=(file)
# Override Dragonfly setter method
return unless file.present?

filename = file.original_filename

file_attachment.attach(
io: File.open(file),
filename: filename,
content_type: file.content_type
)

self.file_name = filename
end

def download_link
return unless file_attachment.present? && file_attachment.attached?

set_current_host

file_attachment.service_url(
expires_in: LINK_MAX_EXPIRY.to_i,
disposition: 'attachment'
)
end

private

def set_current_host
return unless %i[test local].include?(Rails.application.config.active_storage.service)

ActiveStorage::Current.host = Csv2db.config.local_storage_host
end

def check_file_extension
# very basic check of file extension
errors.add(:file, I18n.t('shared.file_processor.incorrect_file_type')) unless file_attachment.blob.content_type == FILE_TYPE
end

def file_data
return @file_data if @file_data.present?

file_attachment.blob.open do |blob|
@file_data = str_to_utf8(blob.read)
end

byte_order_mark = Csv2db::Import::BYTE_ORDER_MARK
@file_data.sub!(byte_order_mark, '') if @file_data.starts_with?(byte_order_mark)

@file_data
end
end
31 changes: 31 additions & 0 deletions app/models/concerns/csv2db/dragonfly_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module Csv2db::DragonflyAdapter
extend ActiveSupport::Concern
require 'dragonfly'

included do
extend Dragonfly::Model

dragonfly_accessor :file

validates :file, presence: true
validate :check_file_extension
end

def download_link
file.url
end

private

def check_file_extension
# very basic check of file extension
errors.add(:file, I18n.t('shared.file_processor.incorrect_file_type')) unless file.ext == 'csv'
end

def file_data
file_data = str_to_utf8(file.data)
byte_order_mark = Csv2db::Import::BYTE_ORDER_MARK
file_data.sub!(byte_order_mark, '') if file_data.starts_with?(byte_order_mark)
file_data
end
end
32 changes: 13 additions & 19 deletions app/models/concerns/csv2db/import.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,9 @@ def around_process(*args, &block)
end

included do
extend Dragonfly::Model
include Module.const_get("Csv2db::#{Csv2db.config.storage_adapter.camelize.constantize}Adapter")

validates :file, presence: true
validate :required_params_are_present
validate :check_file_extension

dragonfly_accessor :file

after_initialize :set_default_values, :set_required_params

Expand Down Expand Up @@ -128,10 +124,14 @@ def method_missing(method, *args, &block)
end
end

def respond_to_missing?(method, include_private = false)
method.to_s.start_with?('param_') || super
end

private

def check_file_contains_data
error(I18n.t('shared.file_processor.insufficient_rows')) unless file.data.present? && csv.count > 0
error(I18n.t('shared.file_processor.insufficient_rows')) unless csv.headers.present? && csv.count.positive?
stop if errors?
end

Expand Down Expand Up @@ -165,12 +165,6 @@ def csv
@csv ||= CSV.parse(file_data, headers: true)
end

def file_data
file_data = str_to_utf_8(file.data)
file_data.sub!(BYTE_ORDER_MARK, '') if file_data.starts_with?(BYTE_ORDER_MARK)
file_data
end

def required_params_are_present
return if @required_params.empty?

Expand All @@ -183,7 +177,7 @@ def required_params_are_present
end

def log(message, level = :info)
log_messages << { message: str_to_utf_8(message), level: level, time: Time.now }
log_messages << { message: str_to_utf8(message), level: level, time: Time.now }
end

def error(message)
Expand All @@ -203,16 +197,16 @@ def set_default_values
self.status ||= Status::PENDING
end

def str_to_utf_8(str)
CharlockHolmes::Converter.convert(str, str.detect_encoding[:encoding], 'UTF-8')
def str_to_utf8(str)
CharlockHolmes::Converter.convert(str, str_encoding(str), 'UTF-8')
end

def set_required_params
@required_params = []
def str_encoding(str)
str.detect_encoding[:encoding]
end

def check_file_extension
errors.add(:file, I18n.t('shared.file_processor.incorrect_file_type')) unless file.ext == 'csv'
def set_required_params
@required_params = []
end
end
end
2 changes: 1 addition & 1 deletion app/views/csv2db/_csv_import_table.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
%tr
%td= import.id
%td= import.created_at
%td= link_to import.file.name, import.file.url, target: '_blank'
%td= link_to(import.file_name, import.download_link)
%td
.badge{ class: "badge-upload-#{import.status}" }= import.status
%td
Expand Down
7 changes: 3 additions & 4 deletions csv2db.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,16 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ['lib']

spec.add_dependency 'activerecord', '>= 4.2', '< 6.2'
spec.add_dependency 'activesupport', '>= 4.2', '< 6.2'
spec.add_dependency 'activerecord', '>= 4.2', '< 7.1'
spec.add_dependency 'activesupport', '>= 4.2', '< 7.1'
spec.add_dependency 'charlock_holmes', '~> 0.7.3'
spec.add_dependency 'dragonfly', '~> 1'
spec.add_dependency 'railties', '>= 4.2', '< 6.2'
spec.add_dependency 'railties', '>= 4.2', '< 7.1'
spec.add_dependency 'sidekiq', '>= 3'

spec.add_development_dependency 'bundler', '>= 2.2.18', '< 3'
spec.add_development_dependency 'byebug'
spec.add_development_dependency 'mysql2', '~> 0.5.3'
spec.add_development_dependency 'rake', '~> 12.3.3'
spec.add_development_dependency 'rspec', '~> 3.0'
spec.add_development_dependency 'rspec_junit_formatter', '~> 0.4'
end
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: '3'
services:
app:
image: ruby:${RUBY_VERSION:-2.6.10}
image: ruby:${RUBY_VERSION:-2.7.8}
working_dir: /app
command: >
bash -eu -c '
Expand All @@ -18,7 +18,7 @@ services:
- .:/app:cached

db:
image: mysql:5.7
image: mysql:8.0.34
environment:
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
expose:
Expand Down
Loading
Loading