prelands_rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +3 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +6 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile.lock +1456 -0
  9. data/LICENSE.txt +21 -0
  10. data/Makefile +4 -0
  11. data/README.md +4 -0
  12. data/Rakefile +6 -0
  13. data/bin/console +14 -0
  14. data/bin/setup +8 -0
  15. data/lib/prelands_rails/concerns/abstract_interactor.rb +48 -0
  16. data/lib/prelands_rails/concerns/base.rb +25 -0
  17. data/lib/prelands_rails/concerns/can_handle_errors.rb +31 -0
  18. data/lib/prelands_rails/concerns/hash.rb +11 -0
  19. data/lib/prelands_rails/concerns/my_aws_client.rb +123 -0
  20. data/lib/prelands_rails/create_simple_source/check_zip_files/detect_absent_files.rb +25 -0
  21. data/lib/prelands_rails/create_simple_source/check_zip_files/extract_files.rb +31 -0
  22. data/lib/prelands_rails/create_simple_source/check_zip_files.rb +79 -0
  23. data/lib/prelands_rails/create_simple_source/compile/html_compiler.rb +106 -0
  24. data/lib/prelands_rails/create_simple_source/compile.rb +44 -0
  25. data/lib/prelands_rails/create_simple_source/create_record.rb +44 -0
  26. data/lib/prelands_rails/create_simple_source/detect_incoming_locales.rb +35 -0
  27. data/lib/prelands_rails/create_simple_source/upload/uploader.rb +47 -0
  28. data/lib/prelands_rails/create_simple_source/upload.rb +83 -0
  29. data/lib/prelands_rails/create_simple_source/validate_zip_content/validate_html/html.rb +115 -0
  30. data/lib/prelands_rails/create_simple_source/validate_zip_content/validate_html.rb +40 -0
  31. data/lib/prelands_rails/create_simple_source/validate_zip_content/validate_js/js.rb +62 -0
  32. data/lib/prelands_rails/create_simple_source/validate_zip_content/validate_js.rb +32 -0
  33. data/lib/prelands_rails/create_simple_source/validate_zip_content.rb +26 -0
  34. data/lib/prelands_rails/create_simple_source.rb +48 -0
  35. data/lib/prelands_rails/update_simple_source/check_zip_files.rb +39 -0
  36. data/lib/prelands_rails/update_simple_source/compile.rb +38 -0
  37. data/lib/prelands_rails/update_simple_source/update_record.rb +41 -0
  38. data/lib/prelands_rails/update_simple_source/upload/delete_compiled_files.rb +30 -0
  39. data/lib/prelands_rails/update_simple_source/upload.rb +43 -0
  40. data/lib/prelands_rails/update_simple_source/validate_zip_content.rb +35 -0
  41. data/lib/prelands_rails/update_simple_source.rb +48 -0
  42. data/lib/prelands_rails/validate_simple_source.rb +26 -0
  43. data/lib/prelands_rails/version.rb +3 -0
  44. data/lib/prelands_rails.rb +41 -0
  45. data/prelands_rails.gemspec +48 -0
  46. metadata +314 -0
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 C80609A
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/Makefile ADDED
@@ -0,0 +1,4 @@
1
+ DIR = $(shell pwd)
2
+
3
+ setup_local_gem:
4
+ bundle config local.prelands_rails $(DIR)
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ # PrelandsRails (Rails based gem)
2
+
3
+ Код, занимающийся валидацией и публикацией прелендов V4.
4
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "prelands_rails"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrelandsRails
4
+ module AbstractInteractor
5
+ include ::Interactor
6
+ include ::Interactor::Contracts
7
+ include CanHandleErrors
8
+
9
+ delegate :fail!, :to => :context
10
+
11
+ def call
12
+ begin
13
+ act
14
+ rescue ::Interactor::Failure # bad promises
15
+ report_error 'Bad promises: %s' % context.errors, context.to_h
16
+ fail! errors: context.errors
17
+ rescue ::ActiveRecord::RecordNotFound => e
18
+ report_error e.message, context.to_h
19
+ fail! errors: 'not found'
20
+ rescue StandardError => e
21
+ error_handler e, context.to_h
22
+ fail! errors: e.message
23
+ custom_error_handler e
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def act
30
+ raise NotImplementedError, "The `act` method must be defined in #{self.class}"
31
+ end
32
+
33
+ def custom_error_handler(_e); end
34
+
35
+ protected
36
+
37
+ def bad_expects(breaches)
38
+ errors = build_errors_message breaches
39
+ fail! errors: errors
40
+ end
41
+
42
+ # [{0=>["fail1", "fail2"], 1=>["fail1", "fail3"]}] => "fail1 ; fail2 ; fail3"
43
+ def build_errors_message(breaches)
44
+ msgs = breaches.map(&:messages).inspect.scan /(?<=")[^"\]\[{}]+(?=")/
45
+ (msgs - [', ']).map { |m| [m,nil] }.to_h.keys.join('; ')
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrelandsRails
4
+ module Base
5
+
6
+ private
7
+
8
+ RX_HTML_FILE = /\.html/
9
+ NAME_RX = /index_(\w{2})\.html/
10
+
11
+ # извлекаем входящие html файлы из контекста
12
+ def incoming_html_files
13
+ context.files_content.select { |key| key =~ RX_HTML_FILE }
14
+ end
15
+
16
+ # извлекаем скомпилированные html файлы из контекста
17
+ def compiled_html_files
18
+ context.compiled_htmls.select { |key| key =~ RX_HTML_FILE }
19
+ end
20
+
21
+ def make_tmp_path
22
+ 'tmp/cache/%s' % SecureRandom.uuid
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ # # frozen_string_literal: true
2
+
3
+ module PrelandsRails
4
+ module CanHandleErrors
5
+ private
6
+
7
+ # Отправит ошибку в Sentry, выведет в лог красным название класса, текст ошибки и backtrace
8
+ def error_handler(error, extra = {})
9
+ error_text = ['[%s] ' % self.class, error.message].join
10
+ Rails.logger.warn "\n\t\e[31m\e[1m%s\e[0m" % error_text
11
+ Rails.logger.warn "\n\e[31m\t%s \e[0m\n" % (error.backtrace[0..9] * "\n\t")
12
+ Raven.capture_exception(error, extra: extra) if defined?(Raven)
13
+ end
14
+
15
+ # Отправит message в Sentry, в dev/test лог скинет pretty extra info
16
+ def report_error(error_message = context.errors, extra = {})
17
+ message = ['[%s] ' % self.class, error_message].join
18
+
19
+ if Rails.env.test? || Rails.env.development?
20
+ div = '-' * 120
21
+ Rails.logger.warn div
22
+ Rails.logger.warn "\e[31m\e[1m%s\e[0m\n" % message
23
+ # Rails.logger.ap extra
24
+ Rails.logger.warn div
25
+ else
26
+ Raven.capture_message(message, extra: extra) if defined?(Raven)
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,11 @@
1
+ class Hash
2
+ def to_struct
3
+ Struct.new(*keys).new(*values)
4
+ end
5
+
6
+ # Convert Hash to OpenStruct recursively
7
+ # https://coderwall.com/p/74rajw/convert-a-complex-nested-hash-to-an-object
8
+ def to_o
9
+ JSON.parse to_json, object_class: OpenStruct
10
+ end
11
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aws-sdk-s3'
4
+
5
+ module PrelandsRails
6
+ class MyAwsClient
7
+
8
+ ACL_PUBLIC_READ = 'public-read'
9
+
10
+ def initialize(access_key, secret_key, region)
11
+ @s3 = Aws::S3::Resource.new(region: region, access_key_id: access_key, secret_access_key: secret_key)
12
+ end
13
+
14
+ def bucket_objects_count(bucket_name)
15
+ bucket = @s3.bucket bucket_name
16
+ result = bucket.objects.count
17
+ log :bucket_objects_count, 'bucket_name=%s, result=%s' % [bucket_name, result]
18
+ result
19
+ rescue Aws::S3::Errors::NoSuchBucket
20
+ log :bucket_objects_count, ['No such bucket: ', bucket_name].join
21
+ end
22
+
23
+ # @return [struct Aws::S3::Types::ListBucketsOutput]
24
+ def list_buckets
25
+ result = @s3.client.list_buckets({})
26
+ log :list_buckets, result.buckets.map(&:name)
27
+ end
28
+
29
+ # @return [True]
30
+ def create_bucket_if_not_exists(bucket_name)
31
+ log :create_bucket_if_not_exists, 'bucket_name=%s' % bucket_name
32
+ @s3.create_bucket bucket: bucket_name
33
+ true
34
+ rescue Aws::S3::Errors::BucketAlreadyOwnedByYou
35
+ true
36
+ rescue StandardError => e
37
+ log :create_bucket_if_not_exists, e.message
38
+ false
39
+ end
40
+
41
+ def delete_bucket(bucket_name)
42
+ log :delete_bucket, 'bucket_name=%s' % bucket_name
43
+ @s3.client.delete_bucket bucket: bucket_name
44
+ rescue StandardError => e
45
+ log :delete_bucket, e.message
46
+ false
47
+ end
48
+
49
+ def list_objects(bucket_name)
50
+ log :list_objects, 'bucket_name=%s' % bucket_name
51
+ result = (@s3.client.list_objects bucket: bucket_name).contents.map(&:key)
52
+ log :list_objects, result
53
+ result
54
+ rescue StandardError => e
55
+ log :list_objects, e.message
56
+ false
57
+ end
58
+
59
+ def delete_objects(bucket_name, objects)
60
+ log :delete_objects, 'bucket_name=%s' % bucket_name
61
+ result = @s3.client.delete_objects({
62
+ bucket: bucket_name,
63
+ delete: {
64
+ objects: objects
65
+ }
66
+ })
67
+ log :delete_objects, result
68
+ rescue StandardError => e
69
+ log :delete_objects, e.message
70
+ false
71
+ end
72
+
73
+ # @param [String] path_to_file Абсолютный к файлу на хосте.
74
+ # @param [String] s3_file_name Под каким именем будет сохранён файл на AWS.
75
+ # @param [String] bucket_name Название bucket
76
+
77
+ def upload_file(path_to_file, s3_file_name, bucket_name)
78
+ begin
79
+ obj = @s3.bucket(bucket_name).object s3_file_name
80
+ begin
81
+ if obj.get
82
+ log :upload_file, [s3_file_name, ' exists, skipping..'].join('')
83
+ end
84
+ rescue Aws::S3::Errors::NoSuchKey => _e
85
+ obj.upload_file path_to_file, acl: ACL_PUBLIC_READ
86
+ log :upload_file, [s3_file_name, ' uploaded to "', bucket_name, '".'].join('')
87
+ end
88
+ rescue Aws::S3::Errors::NoSuchBucket => _e
89
+ log :upload_file, 'No such bucket, create bucket: \'%s\'] ' % bucket_name
90
+ create_bucket_if_not_exists bucket_name
91
+ retry
92
+ end
93
+ end
94
+
95
+ private
96
+
97
+ def log(method, output)
98
+ Rails.logger.info "\r\t\e[33m\e[1m<MyAwsClient.%s> %s\e[0m" % [method, output]
99
+ nil
100
+ end
101
+ end
102
+ end
103
+
104
+ # require 'my_aws_client'
105
+ # client = MyAwsClient.new ENV['AWS_ACCESS_KEY_ID'], ENV['AWS_SECRET_ACCESS_KEY'], ENV['AWS_S3_REGION']
106
+ #
107
+ # client.list_buckets
108
+ # => #<struct Aws::S3::Types::ListBucketsOutput
109
+ # buckets=
110
+ # #<struct Aws::S3::Types::Bucket name="psckeditor-dev", creation_date=2020-12-24 13:22:29 UTC>,
111
+ # owner=#<struct Aws::S3::Types::Owner display_name=nil, id="ca37dafdbd424d0f11ccb2c87a2152b6174bf3986ebbf22760d77eb306f608c2
112
+ #
113
+ # client.bucket_objects_count "psckeditor-dev"
114
+ # => 3
115
+ #
116
+ # client.bucket_objects_count "psckeditor-dev222222222"
117
+ # => nil
118
+ #
119
+ # client.create_bucket_if_not_exists 'psckeditor-dev2'
120
+ # => true
121
+ #
122
+ # MyAwsClient.create_bucket_if_not_exists 'psckeditor-dev2'
123
+ # => true
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrelandsRails
4
+ class CreateSimpleSource
5
+ class CheckZipFiles
6
+ #
7
+ # Вернёт массив вида ['index.js not found',..]
8
+ # или пустой массив, если все ожидаемые файлы присутствуют в архиве с исходниками преленда
9
+ #
10
+ module DetectAbsentFiles
11
+ def detect_absent_files(expected_files, incoming_files)
12
+ raise 'expected_files must be present' unless expected_files.present?
13
+
14
+ # опрашиваем по списку пришедший контент
15
+ expected_files.map do |efile|
16
+ sought = incoming_files&.find { |ifile| ifile.ftype == efile.ftype && ifile.name == efile.name }
17
+ if sought.nil?
18
+ '%s not found' % efile.name
19
+ end
20
+ end.compact
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrelandsRails
4
+ class CreateSimpleSource
5
+ class CheckZipFiles
6
+ module ExtractFiles
7
+
8
+ # @return [Hash] { file_name => file_content, ... }
9
+ def read_into_memory(expected_files, tempfile)
10
+ Zip::File.open(tempfile) do |zipfile|
11
+ zipfile.map do |entry|
12
+ next unless expected_files.find_index { |efile| efile.name == entry.name }.present?
13
+
14
+ # Extract
15
+ tmp_path = Rails.root.join make_tmp_path
16
+ entry.extract tmp_path
17
+
18
+ # Read into memory
19
+ content = entry.get_input_stream.read
20
+
21
+ # Remove tmp file
22
+ File.delete(tmp_path) if File.exist?(tmp_path)
23
+
24
+ [entry.name, content]
25
+ end.compact.to_h
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrelandsRails
4
+ class CreateSimpleSource
5
+ #
6
+ # Проверит наличие файлов и директорий в архиве с исходниками преленда:
7
+ #
8
+ # * должен быть файл index.js
9
+ # * должен быть файл index.css
10
+ # * должна быть директория images/
11
+ # * должны быть все языковые файлы index_<lang>.html, согласно локалям преленда
12
+ # * размер любого файла не должен превышать 8мб
13
+ #
14
+ class CheckZipFiles
15
+ include ::PrelandsRails::AbstractInteractor
16
+ include ::Interactor
17
+ include ::Interactor::Contracts
18
+ include ::PrelandsRails::Base
19
+ include DetectAbsentFiles
20
+ include ExtractFiles
21
+
22
+ expects do
23
+ required(:archive).filled # Rack::Test::UploadedFile | ActionDispatch::Http::UploadedFile
24
+ required(:expected_locales).value(type?: Array)
25
+ required(:incoming_locales).filled(type?: Array)
26
+ end
27
+
28
+ assures do
29
+ required(:files_content).value(type?: Hash) # js,html,css: { file_name => file_content, ... }
30
+ end
31
+
32
+ before do
33
+ @expected_files =
34
+ [
35
+ { ftype: :directory, name: 'images/' },
36
+ { ftype: :file, name: 'index.css' },
37
+ { ftype: :file, name: 'index.js' }
38
+ ]
39
+
40
+ # читаем в память [и компилируем] все входящие с исходником локали
41
+ (context.expected_locales + context.incoming_locales).uniq.each do |short_name|
42
+ @expected_files << { ftype: :file, name: 'index_%s.html' % short_name }
43
+ end
44
+
45
+ @expected_files = @expected_files.map(&:to_struct).freeze
46
+ end
47
+
48
+ def act
49
+ # если нет хотя бы одного файла - уходим с ошибкой
50
+ absents = detect_absent_files @expected_files, incoming_files
51
+ if absents.present?
52
+ fail! errors: absents.join('; ')
53
+ end
54
+
55
+ # считываем в память файлы, которые необходимо валидировать
56
+ rx1 = /\.(css|js|html)/
57
+ files = @expected_files.select { |file| file.ftype == :file && file.name =~ rx1 }
58
+ context.files_content, context.tmp_paths = read_into_memory files, context.archive.tempfile
59
+ end
60
+
61
+ def incoming_files
62
+ @incoming_files ||= Zip::File.open(context.archive.tempfile) do |zipfile|
63
+ zipfile.map do |file|
64
+ if file.size > MAX_SIZE
65
+ fail! errors: 'File too large when extracted (must be less than %s bytes)' % MAX_SIZE
66
+ end
67
+ { ftype: file.ftype, name: file.name }
68
+ end
69
+ end.map(&:to_struct).freeze
70
+ end
71
+
72
+ on_breach { |breaches| bad_expects breaches }
73
+
74
+ private
75
+
76
+ MAX_SIZE = 1024**2 * 8 # 8 MiB
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrelandsRails
4
+ class CreateSimpleSource
5
+ class Compile
6
+ #
7
+ # Компилирует html преленда.
8
+ #
9
+ class HtmlCompiler
10
+
11
+ attr_reader :compiled
12
+
13
+ # @param [String] string Исходное содержимое входящего html файла.
14
+ # @param [String] index_css Исходное содержимое файла index.css
15
+ # @param [String] index_js Исходное содержимое файла index.js
16
+ # @param [String] lang Локаль
17
+ #
18
+ def initialize(string, index_css, index_js, lang, static_js_path)
19
+ @string = string.gsub(/(\r\n?|\n)/, '') # убираем переносы, мешающие регуляркам
20
+ @index_css = index_css
21
+ @index_js = index_js
22
+ @lang = lang
23
+ @static_js_path = static_js_path
24
+ prepare
25
+ end
26
+
27
+ private
28
+
29
+ META = '<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">'
30
+ HTML = '<!DOCTYPE html><html lang="%{lang}">%{head}%{body}</html>'
31
+
32
+ attr_accessor :head, :body
33
+
34
+ def prepare
35
+ build_head
36
+ build_body
37
+ build_html
38
+ end
39
+
40
+ # Из входящего head выберем только то, что нужно,
41
+ # добавим meta,
42
+ # впишем авторский стиль из index.css,
43
+ # добавим наш скрипт
44
+
45
+ def build_head
46
+ # фиксируем head
47
+ head_rx = /(?<=<head).+(?=<\/head>)/
48
+ result = @string[head_rx]
49
+
50
+ # фиксируем title
51
+ title_rx = /<title[^>]*>[^<]+<\/title>/
52
+ title = @string[title_rx]
53
+
54
+ # из head выбираем подключаемые скрипты (js)
55
+ head_script_rx = /<script[^>]*>[^<]*<\/script>/
56
+ head_scripts = result.scan head_script_rx
57
+
58
+ # из head выбираем подключаемые линки (css), исключая `index.css`
59
+ head_link_rx = /<link[^>]+>/
60
+ head_links = result.scan head_link_rx
61
+ head_links = head_links.select { |string| !string['index.css'] }.compact
62
+
63
+ # собираем извлечённое в один массив
64
+ @head = head_scripts.concat(head_links)
65
+ @head.unshift title
66
+ @head.unshift META
67
+ @head << ('<style>%s</style>' % @index_css)
68
+ @head = '<head>%s</head>' % @head.join('')
69
+
70
+ end
71
+
72
+ def build_body
73
+ body_rx = /<body[^>]*>.+<\/body>/
74
+ result = @string[body_rx]
75
+ @body = result
76
+ @body += static_js
77
+ end
78
+
79
+ # собираем результат
80
+ def build_html
81
+ @compiled =
82
+ HTML % {
83
+ lang: @lang,
84
+ head: @head,
85
+ body: @body
86
+ }
87
+ end
88
+
89
+ def static_js
90
+ <<-JS
91
+ <script>
92
+ (function(d, s, id){
93
+ var js, fjs = d.getElementsByTagName(s)[0];
94
+ if (d.getElementById(id)) {return;}
95
+ js = d.createElement(s); js.id = id;
96
+ js.async = true;
97
+ js.src = "#{@static_js_path}?" + Math.random();
98
+ fjs.parentNode.insertBefore(js, fjs);
99
+ }(document, 'script', 'sdk'));
100
+ </script>
101
+ JS
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,44 @@
1
+ module PrelandsRails
2
+ class CreateSimpleSource
3
+ #
4
+ # Из валидных исходников соберёт преленд.
5
+ #
6
+ class Compile
7
+ include ::PrelandsRails::AbstractInteractor
8
+ include ::Interactor
9
+ include ::Interactor::Contracts
10
+ include ::PrelandsRails::Base
11
+
12
+ expects do
13
+ required(:files_content).value(type?: Hash) # { file_name[String] => file_content[String], ... }
14
+ required(:static_js_path).value(type?: String)
15
+ end
16
+
17
+ assures do
18
+ required(:compiled_htmls).value(type?: Hash) # { file_name[String] => compiled_content[String], ... }
19
+ end
20
+
21
+ def act
22
+ context[:compiled_htmls] =
23
+ incoming_html_files.map do |key, content|
24
+ if NAME_RX =~ key
25
+ compiled = HtmlCompiler.new(content, index_css, index_js, $1, context.static_js_path).compiled
26
+ [key, compiled]
27
+ end
28
+ end.to_h
29
+ end
30
+
31
+ on_breach { |breaches| bad_expects breaches }
32
+
33
+ private
34
+
35
+ def index_js
36
+ context.files_content['index.js']
37
+ end
38
+
39
+ def index_css
40
+ context.files_content['index.css']
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ module PrelandsRails
2
+ class CreateSimpleSource
3
+ #
4
+ # Создаст/обновит запись ::Preland::SimpleSource
5
+ #
6
+ class CreateRecord
7
+ include ::PrelandsRails::AbstractInteractor
8
+ include ::Interactor
9
+ include ::Interactor::Contracts
10
+ include ::PrelandsRails::Base
11
+
12
+ expects do
13
+ required(:archive).filled # Входящий архив с исходниками от фрилансера. Rack::Test::UploadedFile | ActionDispatch::Http::UploadedFile
14
+ required(:aws_prefix).value(type?: String) # имя директории в букете
15
+ required(:preland_id).filled
16
+ required(:preland_domain_ids).value(type?: Array)
17
+ required(:incoming_locales).filled(type?: Array)
18
+ required(:model_preland_simple_source).filled
19
+ end
20
+
21
+ assures do
22
+ required(:preland_simple_source).filled
23
+ end
24
+
25
+ before do
26
+
27
+ end
28
+
29
+ def act
30
+ params = {
31
+ aws_prefix: context.aws_prefix,
32
+ archive: context.archive,
33
+ preland_id: context.preland_id,
34
+ preland_domain_ids: context.preland_domain_ids,
35
+ locales: context.incoming_locales
36
+ }
37
+ context.preland_simple_source =
38
+ context.model_preland_simple_source.create! params
39
+ end
40
+
41
+ on_breach { |breaches| bad_expects breaches }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrelandsRails
4
+ class CreateSimpleSource
5
+ #
6
+ # запоминаем, какие локали пришли в исходнике
7
+ #
8
+ class DetectIncomingLocales
9
+ include ::PrelandsRails::AbstractInteractor
10
+ include ::Interactor
11
+ include ::Interactor::Contracts
12
+ include ::PrelandsRails::Base
13
+
14
+ expects do
15
+ required(:archive).filled # Входящий архив с исходниками от фрилансера. Rack::Test::UploadedFile | ActionDispatch::Http::UploadedFile
16
+ end
17
+
18
+ assures do
19
+ required(:incoming_locales).filled(type?: Array)
20
+ end
21
+
22
+ def act
23
+ context.incoming_locales =
24
+ Zip::File.open(context.archive.tempfile) do |zipfile|
25
+ zipfile.map do |file|
26
+ file.name[NAME_RX]
27
+ $1
28
+ end
29
+ end.compact
30
+ end
31
+
32
+ on_breach { |breaches| bad_expects breaches }
33
+ end
34
+ end
35
+ end