mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 17:21:38 -05:00
Implement creating imports from watched directory
This commit is contained in:
parent
74ec1d65f9
commit
d4e2e5006e
10 changed files with 2623 additions and 3 deletions
13
.gitignore
vendored
13
.gitignore
vendored
|
|
@ -24,16 +24,23 @@
|
|||
/tmp/storage/*
|
||||
!/tmp/storage/
|
||||
!/tmp/storage/.keep
|
||||
/tmp/imports/*
|
||||
!/tmp/imports/
|
||||
!/tmp/imports/watched/
|
||||
!/tmp/imports/watched/.keep
|
||||
!/tmp/imports/watched/put-your-files-here.txt
|
||||
|
||||
|
||||
/public/assets
|
||||
|
||||
# We need directories for import and export files, but not the files themselves.
|
||||
# Ignore all files under /public/exports except the .keep file
|
||||
/public/exports/*
|
||||
!/public/exports/.keep
|
||||
!/public/exports/
|
||||
|
||||
# Ignore all files under /public/imports, but keep .keep files and the watched directory
|
||||
/public/imports/*
|
||||
!/public/imports/.keep
|
||||
!/public/imports/watched/.keep
|
||||
!/public/imports/watched/put-your-files-here.txt
|
||||
|
||||
# Ignore master key for decrypting credentials and more.
|
||||
/config/master.key
|
||||
|
|
|
|||
9
app/jobs/import/watcher_job.rb
Normal file
9
app/jobs/import/watcher_job.rb
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Import::WatcherJob < ApplicationJob
|
||||
queue_as :imports
|
||||
|
||||
def perform
|
||||
Imports::Watcher.new.call
|
||||
end
|
||||
end
|
||||
66
app/services/imports/watcher.rb
Normal file
66
app/services/imports/watcher.rb
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Imports::Watcher
|
||||
class UnsupportedSourceError < StandardError; end
|
||||
|
||||
WATCHED_DIR_PATH = Rails.root.join('tmp/imports/watched')
|
||||
|
||||
def call
|
||||
%w[*.gpx *.json].each do |pattern|
|
||||
Dir[WATCHED_DIR_PATH.join(pattern)].each do |file_path|
|
||||
# valid file_path example: "email@dawarich.app_2024-01-01-2024-01-31.json"
|
||||
file_name = File.basename(file_path)
|
||||
|
||||
user = find_user(file_name)
|
||||
next unless user
|
||||
|
||||
import = find_or_initialize_import(user, file_name)
|
||||
|
||||
next if import.persisted?
|
||||
|
||||
import_id = set_import_attributes(import, file_path, file_name)
|
||||
|
||||
ImportJob.perform_later(user.id, import_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_user(file_name)
|
||||
email = file_name.split('_').first
|
||||
|
||||
User.find_by(email:)
|
||||
end
|
||||
|
||||
def find_or_initialize_import(user, file_name)
|
||||
import_name = file_name.split('_')[1..].join('_')
|
||||
|
||||
Import.find_or_initialize_by(user:, name: import_name)
|
||||
end
|
||||
|
||||
def set_import_attributes(import, file_path, file_name)
|
||||
source = source(file_name)
|
||||
|
||||
import.source = source
|
||||
import.raw_data = raw_data(file_path, source)
|
||||
|
||||
import.save!
|
||||
|
||||
import.id
|
||||
end
|
||||
|
||||
def source(file_name)
|
||||
case file_name.split('.').last
|
||||
when 'json' then :geojson
|
||||
when 'gpx' then :gpx
|
||||
else raise UnsupportedSourceError, 'Unsupported source '
|
||||
end
|
||||
end
|
||||
|
||||
def raw_data(file_path, source)
|
||||
file = File.read(file_path)
|
||||
|
||||
source == :gpx ? Hash.from_xml(file) : JSON.parse(file)
|
||||
end
|
||||
end
|
||||
1
spec/fixtures/files/watched/user@domain.com_export_same_points.json
vendored
Normal file
1
spec/fixtures/files/watched/user@domain.com_export_same_points.json
vendored
Normal file
File diff suppressed because one or more lines are too long
1239
spec/fixtures/files/watched/user@domain.com_gpx_track_single_segment.gpx
vendored
Normal file
1239
spec/fixtures/files/watched/user@domain.com_gpx_track_single_segment.gpx
vendored
Normal file
File diff suppressed because it is too large
Load diff
5
spec/jobs/import/watcher_job_spec.rb
Normal file
5
spec/jobs/import/watcher_job_spec.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Import::WatcherJob, type: :job do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
||||
49
spec/services/imports/watcher_spec.rb
Normal file
49
spec/services/imports/watcher_spec.rb
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Imports::Watcher do
|
||||
describe '#call' do
|
||||
subject(:service) { described_class.new.call }
|
||||
|
||||
let(:watched_dir_path) { Rails.root.join('spec/fixtures/files/watched') }
|
||||
let(:user) { create(:user, email: 'user@domain.com') }
|
||||
|
||||
before do
|
||||
stub_const('Imports::Watcher::WATCHED_DIR_PATH', watched_dir_path)
|
||||
end
|
||||
|
||||
context 'when there are no files in the watched directory' do
|
||||
it 'does not call ImportJob' do
|
||||
expect(ImportJob).not_to receive(:perform_later)
|
||||
|
||||
service
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are files in the watched directory' do
|
||||
Sidekiq::Testing.inline! do
|
||||
context 'when the file has a valid user email' do
|
||||
it 'creates an import for the user' do
|
||||
expect { service }.to change(user.imports, :count).by(2)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the file has an invalid user email' do
|
||||
it 'does not create an import' do
|
||||
expect { service }.not_to change(Import, :count)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the import already exists' do
|
||||
it 'does not create a new import' do
|
||||
create(:import, user:, name: 'export_same_points.json')
|
||||
create(:import, user:, name: 'gpx_track_single_segment.gpx')
|
||||
|
||||
expect { service }.not_to change(Import, :count)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
1239
tmp/imports/watched/aa@bb.com-gpx_track_single_segment.gpx
Normal file
1239
tmp/imports/watched/aa@bb.com-gpx_track_single_segment.gpx
Normal file
File diff suppressed because it is too large
Load diff
5
tmp/imports/watched/put-your-files-here.txt
Normal file
5
tmp/imports/watched/put-your-files-here.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
The /public/imporst/watched/ directory is watched by Dawarich. Any files you put in this directory will be imported into the database. The name of the file must start with an email of the user you want to import the file for. The email must be followed by an underscore symbol (_) and the name of the file.
|
||||
|
||||
For example, if you want to import a file for the user with the email address "email@dawarich.app", you would name the file "email@dawarich.app_2024-05-01_2024-05-31.gpx". The file will be imported into the database and the user will receive a notification in the app.
|
||||
|
||||
Both GeoJSON and GPX files are supported.
|
||||
Loading…
Reference in a new issue