mobile_workflow 0.3.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/models/concerns/mobile_workflow/displayable.rb +13 -4
- data/bin/mwf +34 -0
- data/lib/generators/mobile_workflow/controller_generator.rb +0 -8
- data/lib/generators/mobile_workflow/install/install_generator.rb +13 -12
- data/lib/generators/mobile_workflow/install/templates/Gemfile.erb +50 -0
- data/lib/generators/mobile_workflow/install/templates/Procfile +2 -0
- data/lib/generators/mobile_workflow/install/templates/Procfile.dev +1 -0
- data/lib/generators/mobile_workflow/install/templates/README.md.erb +22 -0
- data/lib/generators/mobile_workflow/install/templates/ability.rb +7 -0
- data/lib/generators/mobile_workflow/install/templates/api_controller.rb.erb +6 -1
- data/lib/generators/mobile_workflow/install/templates/storage.s3.yml +14 -0
- data/lib/generators/mobile_workflow/templates/controller.rb.erb +4 -7
- data/lib/generators/mobile_workflow/templates/controller_spec.rb.erb +2 -2
- data/lib/mobile_workflow/cli.rb +9 -0
- data/lib/mobile_workflow/cli/app_builder.rb +104 -0
- data/lib/mobile_workflow/cli/app_server_cleaner.rb +24 -0
- data/lib/mobile_workflow/cli/app_server_generator.rb +81 -0
- data/lib/mobile_workflow/cli/aws_backend.rb +80 -0
- data/lib/mobile_workflow/cli/dokku_backend.rb +57 -0
- data/lib/mobile_workflow/cli/heroku_backend.rb +47 -0
- data/lib/mobile_workflow/version.rb +3 -1
- metadata +21 -13
- data/lib/tasks/mobile_workflow_tasks.rake +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfdd780bae1700eef4c227697f5d75b953bfb70c4a553f2ac9dc3fa6b1a92d28
|
4
|
+
data.tar.gz: ad16f3eb17f23f6e92fea8c56d50d5deb06c2faa9b1ee62d5774ddb26f38c62f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d826dd850a09030b3f54666ffa37abb05fcdf39b0bc45e348d7988aebe03244a7bbddb38eea54a8ee482e4442256548d5fbd85d6c74d95dd365f2215b9930e0a
|
7
|
+
data.tar.gz: a8e597024e8ffa0eca83ec1958d6d90f02ff2e68722fd498bb8e96dcde216e46420f7f822e229507920f3d65ed291e7023c22dcefb484466309981a8de86d91a
|
@@ -17,11 +17,20 @@ module MobileWorkflow
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def mw_display_image(attachment)
|
20
|
-
{type: :image, previewURL: preview_url(attachment, height:
|
20
|
+
{type: :image, previewURL: preview_url(attachment, height: 600, width: 1200), url: attachment_url(attachment)}
|
21
|
+
end
|
22
|
+
|
23
|
+
def mw_display_unsplash_image(image_url)
|
24
|
+
if image_url.start_with? "https://unsplash.com/photos"
|
25
|
+
unsplash_id = image_url.split('/').last
|
26
|
+
image_url = "https://source.unsplash.com/#{unsplash_id}/800x600"
|
27
|
+
end
|
28
|
+
|
29
|
+
{type: :image, previewURL: image_url, url: image_url}
|
21
30
|
end
|
22
31
|
|
23
32
|
def mw_display_video(attachment)
|
24
|
-
{type: :video, previewURL: preview_url(attachment, height:
|
33
|
+
{type: :video, previewURL: preview_url(attachment, height: 600, width: 1200), url: attachment_url(attachment)}
|
25
34
|
end
|
26
35
|
|
27
36
|
def mw_display_button(label:, style: :primary, on_success: :forward)
|
@@ -45,11 +54,11 @@ module MobileWorkflow
|
|
45
54
|
{type: :button, label: label, url: url, method: method, style: style, onSuccess: on_success}
|
46
55
|
end
|
47
56
|
|
48
|
-
def mw_display_button_for_modal_workflow(label:,
|
57
|
+
def mw_display_button_for_modal_workflow(label:, modal_workflow_name:, style: :primary, on_success: :none)
|
49
58
|
validate_on_success!(on_success)
|
50
59
|
validate_button_style!(style)
|
51
60
|
|
52
|
-
{type: :button, label: label, modalWorkflow:
|
61
|
+
{type: :button, label: label, modalWorkflow: modal_workflow_name, style: style, onSuccess: on_success}
|
53
62
|
end
|
54
63
|
|
55
64
|
private
|
data/bin/mwf
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require_relative '../lib/mobile_workflow/cli'
|
3
|
+
|
4
|
+
# Byebug for dev
|
5
|
+
begin
|
6
|
+
require 'byebug'
|
7
|
+
rescue LoadError
|
8
|
+
end
|
9
|
+
|
10
|
+
if ARGV.empty?
|
11
|
+
puts "USAGE: mwf <platform> <command> [options]"
|
12
|
+
puts "Example: mwf rails create:app_server --help"
|
13
|
+
puts "Example: mwf rails destroy:app_server --help"
|
14
|
+
exit 0
|
15
|
+
elsif ['-v', '--version'].include? ARGV[0]
|
16
|
+
puts MobileWorkflow::VERSION
|
17
|
+
exit 0
|
18
|
+
elsif 'rails' == ARGV[0] && 'create:app_server' == ARGV[1]
|
19
|
+
ARGV.shift
|
20
|
+
ARGV.shift
|
21
|
+
|
22
|
+
templates_root = File.expand_path(File.join("..", "lib", "generators", "mobile_workflow", "install", "templates"), File.dirname(__FILE__))
|
23
|
+
MobileWorkflow::Cli::AppServerGenerator.source_root templates_root
|
24
|
+
MobileWorkflow::Cli::AppServerGenerator.source_paths << Rails::Generators::AppGenerator.source_root << templates_root
|
25
|
+
MobileWorkflow::Cli::AppServerGenerator.start
|
26
|
+
elsif 'rails' == ARGV[0] && 'destroy:app_server' == ARGV[1]
|
27
|
+
ARGV.shift
|
28
|
+
ARGV.shift
|
29
|
+
|
30
|
+
ARGV.unshift(MobileWorkflow::Cli::AppServerCleaner.default_task) unless ARGV[0] == '--help'
|
31
|
+
MobileWorkflow::Cli::AppServerCleaner.start(ARGV)
|
32
|
+
end
|
33
|
+
|
34
|
+
|
@@ -23,14 +23,6 @@ module MobileWorkflow
|
|
23
23
|
params = attributes_names.map{ |name| ":#{name}" }
|
24
24
|
params.join(", ")
|
25
25
|
end
|
26
|
-
|
27
|
-
def rewrite_params
|
28
|
-
if attributes_names
|
29
|
-
init_params = "\n\t\tparams[:#{singular_table_name}] = {}\n"
|
30
|
-
rewrite_params = attributes_names.map {|name| "params[:#{singular_table_name}][:#{name}] = params.dig(:payload, :#{name}, :answer)" }.join("\n\t\t")
|
31
|
-
init_params + rewrite_params
|
32
|
-
end
|
33
|
-
end
|
34
26
|
end
|
35
27
|
end
|
36
28
|
end
|
@@ -5,12 +5,13 @@ module MobileWorkflow
|
|
5
5
|
class InstallGenerator < Rails::Generators::Base
|
6
6
|
|
7
7
|
# Schemas to avoid generating models for (static items from MW)
|
8
|
-
SKIP_SCHEMAS = ["
|
8
|
+
SKIP_SCHEMAS = ["attachment", "ListItem", "DisplayItem", "DisplayText", "DisplayButton", "DisplayImage", "DisplayVideo"]
|
9
9
|
|
10
10
|
source_root File.expand_path("../templates", __FILE__)
|
11
11
|
|
12
12
|
class_option :open_api_spec_path, type: :string, default: "config/open_api_spec.json"
|
13
13
|
class_option :doorkeeper_oauth, type: :boolean, default: false
|
14
|
+
class_option :interactive, type: :boolean, default: false
|
14
15
|
|
15
16
|
def create_api_controller
|
16
17
|
template("api_controller.rb.erb", "app/controllers/api_controller.rb")
|
@@ -59,7 +60,7 @@ module MobileWorkflow
|
|
59
60
|
end
|
60
61
|
|
61
62
|
def generate_seeds
|
62
|
-
template("seeds.rb.erb", "db/seeds.rb")
|
63
|
+
template("seeds.rb.erb", "db/seeds.rb", force: true)
|
63
64
|
end
|
64
65
|
|
65
66
|
private
|
@@ -77,16 +78,20 @@ module MobileWorkflow
|
|
77
78
|
|
78
79
|
def read_openapi_spec
|
79
80
|
say "Loading OpenAPI Spec: #{open_api_spec_path}"
|
80
|
-
return JSON.parse(File.read(
|
81
|
+
return JSON.parse(File.read(open_api_spec_path)).with_indifferent_access
|
81
82
|
end
|
82
83
|
|
83
84
|
def open_api_spec_path
|
84
85
|
options[:open_api_spec_path]
|
85
86
|
end
|
86
87
|
|
88
|
+
def interactive?
|
89
|
+
options[:interactive]
|
90
|
+
end
|
91
|
+
|
87
92
|
def model_properties(name, schema)
|
88
93
|
generated_properties_args = schema["properties"].keys.collect{|key| "#{key}:#{model_property_type(schema["properties"][key])}" }.join(" ")
|
89
|
-
if yes?("Use generated schema #{name}(#{generated_properties_args})[yn]?")
|
94
|
+
if !interactive? || yes?("Use generated schema #{name}(#{generated_properties_args})[yn]?")
|
90
95
|
generated_properties_args
|
91
96
|
else
|
92
97
|
ask "Specify schema for #{name}: (e.g. text:string image:attachment region:reference)"
|
@@ -94,14 +99,10 @@ module MobileWorkflow
|
|
94
99
|
end
|
95
100
|
|
96
101
|
def model_property_type(property)
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
'attachment'
|
102
|
-
else
|
103
|
-
'string'
|
104
|
-
end
|
102
|
+
return property["type"] unless property["type"].blank?
|
103
|
+
return 'attachment' if property['$ref'] == "#/components/schemas/attachment"
|
104
|
+
|
105
|
+
raise 'Unknown property type'
|
105
106
|
end
|
106
107
|
end
|
107
108
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
3
|
+
|
4
|
+
ruby '2.6.6'
|
5
|
+
|
6
|
+
# Core Gems
|
7
|
+
gem 'rails', '~> 6.1.0'
|
8
|
+
gem 'puma', '~> 5.0'
|
9
|
+
gem 'sass-rails', '>= 6'
|
10
|
+
gem 'turbolinks', '~> 5'
|
11
|
+
|
12
|
+
# Mobile Workflow
|
13
|
+
#gem 'mobile_workflow', path: '../mobile_workflow'
|
14
|
+
gem 'mobile_workflow', github: 'FutureWorkshops/mobile_workflow'
|
15
|
+
|
16
|
+
# Authorisation / Authentication
|
17
|
+
<%- if options[:doorkeeper_oauth] %>
|
18
|
+
gem 'doorkeeper'
|
19
|
+
gem 'bcrypt-ruby'
|
20
|
+
<%- end %>
|
21
|
+
gem 'cancancan', '~> 3.1'
|
22
|
+
|
23
|
+
# Admin console
|
24
|
+
gem 'administrate', '~> 0.13.0'
|
25
|
+
gem 'administrate-field-active_storage'
|
26
|
+
gem 'administrate-field-enum'
|
27
|
+
|
28
|
+
<%- if options[:s3_storage] %>
|
29
|
+
# Backend storage for S3
|
30
|
+
gem "image_processing"
|
31
|
+
gem 'aws-sdk-s3', '~> 1.60', '>= 1.60.1'
|
32
|
+
gem 'aws-sdk-sns', '~> 1.23'
|
33
|
+
<%- end %>
|
34
|
+
|
35
|
+
group :development do
|
36
|
+
gem 'web-console', '>= 3.3.0'
|
37
|
+
gem 'listen', '>= 3.0.5', '< 3.2'
|
38
|
+
end
|
39
|
+
|
40
|
+
group :development, :test do
|
41
|
+
gem 'sqlite3'
|
42
|
+
gem 'rspec-rails', '~> 4.0.0'
|
43
|
+
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
|
44
|
+
gem 'dotenv-rails'
|
45
|
+
gem 'factory_bot_rails'
|
46
|
+
end
|
47
|
+
|
48
|
+
group :production do
|
49
|
+
gem 'pg', '>= 0.18', '< 2.0'
|
50
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
web: bundle exec rackup config.ru -p $PORT
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# <%= app_name.humanize %>
|
2
|
+
|
3
|
+
## Prereqs
|
4
|
+
* Ruby >= 2.5.5
|
5
|
+
* Rails >= 6.0.0
|
6
|
+
|
7
|
+
Optional
|
8
|
+
* Heroku toolbelt
|
9
|
+
* Heroku account
|
10
|
+
|
11
|
+
## Getting Started
|
12
|
+
|
13
|
+
After you have cloned this repo, run this setup script to set up your machine
|
14
|
+
with the necessary dependencies to run and test this app:
|
15
|
+
|
16
|
+
% ./bin/setup
|
17
|
+
|
18
|
+
After setting up, you can run the application using [Heroku Local]:
|
19
|
+
|
20
|
+
% heroku local
|
21
|
+
|
22
|
+
[Heroku Local]: https://devcenter.heroku.com/articles/heroku-local
|
@@ -1,9 +1,14 @@
|
|
1
1
|
class ApiController < ActionController::API
|
2
|
+
rescue_from CanCan::AccessDenied do |exception|
|
3
|
+
Rails.logger.debug "Access denied on #{exception.action} #{exception.subject.inspect}"
|
4
|
+
head :forbidden
|
5
|
+
end
|
6
|
+
|
2
7
|
<% if options[:doorkeeper_oauth] %>
|
3
8
|
before_action :doorkeeper_authorize!, unless: :anonymous_action?
|
4
9
|
|
5
10
|
def current_resource_owner
|
6
|
-
User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
|
11
|
+
User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token&.accessible?
|
7
12
|
end
|
8
13
|
alias_method :current_user, :current_resource_owner
|
9
14
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
test:
|
2
|
+
service: Disk
|
3
|
+
root: <%= Rails.root.join("tmp/storage") %>
|
4
|
+
|
5
|
+
local:
|
6
|
+
service: Disk
|
7
|
+
root: <%= Rails.root.join("storage") %>
|
8
|
+
|
9
|
+
amazon:
|
10
|
+
service: S3
|
11
|
+
access_key_id: <%= ENV['AWS_ACCESS_ID'] %>
|
12
|
+
secret_access_key: <%= ENV['AWS_SECRET_KEY'] %>
|
13
|
+
region: <%= ENV['AWS_REGION'] %>
|
14
|
+
bucket: <%= ENV['AWS_BUCKET_NAME'] %>
|
@@ -24,19 +24,16 @@ class <%= controller_class_name %>Controller < ApiController
|
|
24
24
|
private
|
25
25
|
def rewrite_payload
|
26
26
|
# Use this method to make any changes to params to make them compatible with ActiveRecord
|
27
|
-
|
28
|
-
# 1. Example to get
|
29
|
-
# params[:payload][:name] = params.dig(:payload, :name, :answer)
|
30
|
-
|
31
|
-
# 2. Example to get selected id from a list
|
27
|
+
|
28
|
+
# 1. Example to get selected id from a list
|
32
29
|
# passport_id = params.dig(:payload, :choose_passport, :selected, :id)
|
33
30
|
|
34
31
|
Rails.logger.debug "Pre-rewrite params: #{params}"
|
35
|
-
|
32
|
+
# Do your rewriting here
|
36
33
|
end
|
37
34
|
|
38
35
|
def <%= singular_table_name.underscore %>_params
|
39
|
-
params.require(
|
36
|
+
params.require(:payload).permit(<%= permitted_params %>)
|
40
37
|
end
|
41
38
|
end
|
42
39
|
<% end %>
|
@@ -8,7 +8,7 @@ RSpec.describe <%= controller_class_name %>Controller do
|
|
8
8
|
let(:json_response) { JSON.parse(response.body, symbolize_names: true) }
|
9
9
|
|
10
10
|
describe 'GET #index' do
|
11
|
-
let!(:<%= controller_class_name.singularize.underscore %>) {
|
11
|
+
let!(:<%= controller_class_name.singularize.underscore %>) { create(:<%= controller_class_name.singularize.underscore %>) }
|
12
12
|
before(:each) { get :index, params: params }
|
13
13
|
|
14
14
|
context 'ok' do
|
@@ -18,7 +18,7 @@ RSpec.describe <%= controller_class_name %>Controller do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
describe 'GET #show' do
|
21
|
-
let(:<%= controller_class_name.singularize.underscore %>) {
|
21
|
+
let(:<%= controller_class_name.singularize.underscore %>) { create(:<%= controller_class_name.singularize.underscore %>) }
|
22
22
|
let(:params) { { id: <%= controller_class_name.singularize.underscore %>.id } }
|
23
23
|
before(:each) { get :show, params: params }
|
24
24
|
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require "mobile_workflow/version"
|
2
|
+
|
3
|
+
require "mobile_workflow/cli/app_server_generator"
|
4
|
+
require "mobile_workflow/cli/app_builder"
|
5
|
+
require "mobile_workflow/cli/app_server_cleaner"
|
6
|
+
|
7
|
+
require "mobile_workflow/cli/aws_backend"
|
8
|
+
require "mobile_workflow/cli/heroku_backend"
|
9
|
+
require "mobile_workflow/cli/dokku_backend"
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module MobileWorkflow::Cli
|
2
|
+
class AppBuilder < Rails::AppBuilder
|
3
|
+
def readme
|
4
|
+
template 'README.md.erb', 'README.md'
|
5
|
+
end
|
6
|
+
|
7
|
+
def gemfile
|
8
|
+
template 'Gemfile.erb', 'Gemfile'
|
9
|
+
end
|
10
|
+
|
11
|
+
def procfiles
|
12
|
+
copy_file 'Procfile', 'Procfile'
|
13
|
+
copy_file 'Procfile.dev', 'Procfile.dev'
|
14
|
+
end
|
15
|
+
|
16
|
+
def rspec_generator
|
17
|
+
generate 'rspec:install'
|
18
|
+
end
|
19
|
+
|
20
|
+
def administrate_generator
|
21
|
+
Bundler.with_clean_env { generate 'administrate:install' }
|
22
|
+
|
23
|
+
#rails_command 'generate administrate:install'
|
24
|
+
file 'app/assets/config/manifest.js', <<-CODE
|
25
|
+
//= link administrate/application.css
|
26
|
+
//= link administrate/application.js
|
27
|
+
CODE
|
28
|
+
|
29
|
+
file 'app/controllers/admin/application_controller.rb', <<-CODE
|
30
|
+
module Admin
|
31
|
+
class ApplicationController < Administrate::ApplicationController
|
32
|
+
http_basic_authenticate_with(name: ENV["ADMIN_USER"], password: ENV["ADMIN_PASSWORD"])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
CODE
|
36
|
+
|
37
|
+
Bundler.with_clean_env { generate 'administrate:routes' }
|
38
|
+
end
|
39
|
+
|
40
|
+
def ability_generator
|
41
|
+
copy_file 'ability.rb', 'app/models/ability.rb'
|
42
|
+
end
|
43
|
+
|
44
|
+
def active_storage
|
45
|
+
rails_command 'active_storage:install'
|
46
|
+
copy_file 'storage.s3.yml', 'config/storage.yml'
|
47
|
+
gsub_file 'config/environments/production.rb', 'config.active_storage.service = :local', 'config.active_storage.service = :amazon'
|
48
|
+
end
|
49
|
+
|
50
|
+
def mobile_workflow_generator(open_api_spec_path)
|
51
|
+
copy_file open_api_spec_path, 'config/open_api_spec.json'
|
52
|
+
gen_opts = ""
|
53
|
+
gen_opts += "--doorkeeper_oauth" if options[:doorkeeper_oauth]
|
54
|
+
generate "mobile_workflow:install #{gen_opts}"
|
55
|
+
|
56
|
+
# Copy user migrations if needed
|
57
|
+
rails_command 'mobile_workflow:install:migrations' if options[:doorkeeper_oauth]
|
58
|
+
end
|
59
|
+
|
60
|
+
def s3_backend(region)
|
61
|
+
@region = region
|
62
|
+
aws_backend.create
|
63
|
+
aws_backend.write_env
|
64
|
+
|
65
|
+
if options[:heroku]
|
66
|
+
heroku_backend.sync_dotenv
|
67
|
+
sleep 10 # Wait for the server to restart
|
68
|
+
aws_backend.create_topic_subscription(heroku_backend.notifications_endpoint)
|
69
|
+
elsif options[:dokku]
|
70
|
+
dokku_backend.sync_dotenv
|
71
|
+
aws_backend.create_topic_subscription(dokku_backend.notifications_endpoint)
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
def heroku
|
77
|
+
heroku_backend.create
|
78
|
+
heroku_backend.configure_activestorage if options[:s3_storage]
|
79
|
+
heroku_backend.deploy
|
80
|
+
heroku_backend.sync_dotenv
|
81
|
+
end
|
82
|
+
|
83
|
+
def dokku(dokku_host)
|
84
|
+
@dokku_host = dokku_host
|
85
|
+
dokku_backend.create
|
86
|
+
dokku_backend.configure_activestorage if options[:s3_storage]
|
87
|
+
dokku_backend.deploy
|
88
|
+
dokku_backend.sync_dotenv
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
def aws_backend
|
93
|
+
@aws_backend ||= AwsBackend.new(app_name: app_name, region: @region)
|
94
|
+
end
|
95
|
+
|
96
|
+
def dokku_backend
|
97
|
+
@dokku_backend ||= DokkuBackend.new(app_name: app_name, dokku_host: @dokku_host)
|
98
|
+
end
|
99
|
+
|
100
|
+
def heroku_backend
|
101
|
+
@heroku_backend ||= HerokuBackend.new(app_name: app_name)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/rails/app/app_generator'
|
3
|
+
require 'json'
|
4
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
5
|
+
|
6
|
+
module MobileWorkflow::Cli
|
7
|
+
class AppServerCleaner < Thor
|
8
|
+
class_option :version, type: :boolean, aliases: "-v", desc: "Show version number and quit"
|
9
|
+
class_option :help, type: :boolean, aliases: '-h', desc: "Show this help message and quit"
|
10
|
+
|
11
|
+
class_option :heroku, type: :boolean, default: false, desc: "Clean Heroku app"
|
12
|
+
class_option :s3_storage, type: :boolean, default: false, desc: "Clean an s3 backend for attachment upload and storage"
|
13
|
+
class_option :aws_region, type: :string, default: 'us-east-1', desc: "Specify a region to create AWS resources in"
|
14
|
+
|
15
|
+
default_task :clean
|
16
|
+
|
17
|
+
desc "rails destroy:app_server APP_NAME", "Destroy App server"
|
18
|
+
def clean(app_name)
|
19
|
+
`rm -rf #{app_name}`
|
20
|
+
AwsBackend.new(app_name: app_name, region: options[:aws_region]).destroy if options[:s3_storage]
|
21
|
+
HerokuBackend.new(app_name: app_name).destroy if options[:heroku]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/rails/app/app_generator'
|
3
|
+
require 'json'
|
4
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
5
|
+
|
6
|
+
module MobileWorkflow::Cli
|
7
|
+
class AppServerGenerator < Rails::Generators::AppGenerator
|
8
|
+
hide!
|
9
|
+
class_option :skip_test, type: :boolean, default: true, desc: "Skip Test Unit"
|
10
|
+
class_option :force, type: :boolean, default: true, desc: "Force overwrite"
|
11
|
+
class_option :skip_webpack_install, type: :boolean, default: true, desc: "Skip webpacker installation"
|
12
|
+
class_option :skip_bootsnap, type: :boolean, default: true, desc: "Skip Bootsnap"
|
13
|
+
|
14
|
+
class_option :version, type: :boolean, aliases: "-v", desc: "Show version number and quit"
|
15
|
+
class_option :help, type: :boolean, aliases: '-h', desc: "Show this help message and quit"
|
16
|
+
|
17
|
+
class_option :heroku, type: :boolean, default: false, desc: "Create Heroku app"
|
18
|
+
|
19
|
+
class_option :dokku, type: :boolean, default: false, desc: "Create Dokku app"
|
20
|
+
class_option :dokku_host, type: :string, desc: "Specify the Dokku host machine e.g. 18.131.127.164"
|
21
|
+
|
22
|
+
class_option :s3_storage, type: :boolean, default: false, desc: "Create an s3 backend for attachment upload and storage"
|
23
|
+
class_option :aws_region, type: :string, default: 'us-east-1', desc: "Specify a region to create AWS resources in"
|
24
|
+
|
25
|
+
class_option :doorkeeper_oauth, type: :boolean, default: false, desc: "Use Doorkeeper gem for OAuth login"
|
26
|
+
|
27
|
+
def self.banner
|
28
|
+
"mwf rails create:app_server <directory> <OpenAPI Spec file path> [options]"
|
29
|
+
end
|
30
|
+
|
31
|
+
def finish_template
|
32
|
+
super
|
33
|
+
after_bundle do
|
34
|
+
build :procfiles
|
35
|
+
build :rspec_generator
|
36
|
+
build :ability_generator
|
37
|
+
build :active_storage if options[:s3_storage]
|
38
|
+
build :mobile_workflow_generator, ARGV[1]
|
39
|
+
setup_db
|
40
|
+
build :administrate_generator
|
41
|
+
|
42
|
+
generate_dot_env
|
43
|
+
initial_git_commit
|
44
|
+
|
45
|
+
build :heroku if options[:heroku]
|
46
|
+
build :dokku, options[:dokku_host] if options[:dokku]
|
47
|
+
build :s3_backend, options[:aws_region] if options[:s3_storage]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def get_builder_class
|
54
|
+
MobileWorkflow::Cli::AppBuilder
|
55
|
+
end
|
56
|
+
|
57
|
+
# Todo: MBS - move these methods to the builder class
|
58
|
+
# Ideally override RailsBuilder methods
|
59
|
+
private
|
60
|
+
def setup_db
|
61
|
+
rails_command "db:drop"
|
62
|
+
rails_command "db:create"
|
63
|
+
rails_command "db:migrate"
|
64
|
+
end
|
65
|
+
|
66
|
+
def initial_git_commit
|
67
|
+
git add: "."
|
68
|
+
git commit: %Q{ -m 'Initial commit' }
|
69
|
+
end
|
70
|
+
|
71
|
+
def generate_dot_env
|
72
|
+
admin_user = 'admin'
|
73
|
+
admin_password = SecureRandom.base64(12)
|
74
|
+
|
75
|
+
file '.env', <<-CODE
|
76
|
+
ADMIN_USER=#{admin_user}
|
77
|
+
ADMIN_PASSWORD=#{admin_password}
|
78
|
+
CODE
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module MobileWorkflow::Cli
|
4
|
+
class AwsBackend
|
5
|
+
|
6
|
+
attr_accessor :access_id, :secret_key, :region, :bucket_name
|
7
|
+
|
8
|
+
def initialize(app_name:, region:)
|
9
|
+
@app_name = app_name
|
10
|
+
@aws_name = @app_name.gsub("_", "-")
|
11
|
+
@region = region
|
12
|
+
end
|
13
|
+
|
14
|
+
def bucket_name
|
15
|
+
@aws_name
|
16
|
+
end
|
17
|
+
|
18
|
+
def create
|
19
|
+
bucket_configuration = ''
|
20
|
+
bucket_configuration += "--create-bucket-configuration LocationConstraint=#{@region}" unless @region.eql? 'us-east-1'
|
21
|
+
aws_command "aws s3api create-bucket --bucket #{@aws_name} --acl private --region #{@region} #{bucket_configuration}"
|
22
|
+
@topic_arn = aws_command("aws sns create-topic --name #{@aws_name} --region #{@region}")["TopicArn"]
|
23
|
+
aws_command "aws iam create-user --user-name #{@aws_name}"
|
24
|
+
aws_command "aws iam put-user-policy --user-name #{@aws_name} --policy-name s3 --policy-document '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"s3:PutObject\",\"s3:PutObjectAcl\",\"s3:GetObject\", \"s3:DeleteObject\"],\"Resource\":[\"arn:aws:s3:::#{@aws_name}/*\"]}, {\"Effect\": \"Allow\", \"Action\": \"s3:ListBucket\", \"Resource\": \"arn:aws:s3:::#{@aws_name}\"}]}'"
|
25
|
+
aws_command "aws iam put-user-policy --user-name #{@aws_name} --policy-name sns --policy-document '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"sns:ConfirmSubscription\"],\"Resource\":[\"#{@topic_arn}\"]}]}'"
|
26
|
+
aws_command "aws sns set-topic-attributes --topic-arn #{@topic_arn} --region #{@region} --attribute-name Policy --attribute-value '{\"Version\": \"2012-10-17\", \"Id\": \"s3\", \"Statement\": [{\"Sid\": \"#{@aws_name}-s3-sid\", \"Effect\": \"Allow\", \"Principal\": {\"AWS\": \"*\"}, \"Action\": \"SNS:Publish\", \"Resource\": \"#{@topic_arn}\", \"Condition\": {\"ArnEquals\": {\"aws:SourceArn\": \"arn:aws:s3:::#{@aws_name}\"}}}]}'"
|
27
|
+
aws_command "aws s3api put-bucket-notification-configuration --bucket #{@aws_name} --notification-configuration '{\"TopicConfigurations\": [{\"TopicArn\": \"#{@topic_arn}\", \"Events\": [\"s3:ObjectCreated:*\"]}]}'"
|
28
|
+
aws_credentials_json = aws_command("aws iam create-access-key --user-name #{@aws_name}")["AccessKey"]
|
29
|
+
@access_id, @secret_key = aws_credentials_json["AccessKeyId"], aws_credentials_json["SecretAccessKey"]
|
30
|
+
return @access_id, @secret_key
|
31
|
+
end
|
32
|
+
|
33
|
+
def put_env
|
34
|
+
puts "AWS_ACCESS_ID=#{access_id}"
|
35
|
+
puts "AWS_SECRET_KEY=#{secret_key}"
|
36
|
+
puts "AWS_REGION=#{region}"
|
37
|
+
puts "AWS_BUCKET_NAME=#{bucket_name}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def write_env
|
41
|
+
open('.env', 'a') { |f|
|
42
|
+
f.puts "AWS_ACCESS_ID=#{access_id}"
|
43
|
+
f.puts "AWS_SECRET_KEY=#{secret_key}"
|
44
|
+
f.puts "AWS_REGION=#{region}"
|
45
|
+
f.puts "AWS_BUCKET_NAME=#{bucket_name}"
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_topic_subscription(endpoint)
|
50
|
+
aws_command "aws sns subscribe --topic-arn #{@topic_arn} --region #{@region} --protocol https --notification-endpoint #{endpoint}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def destroy
|
54
|
+
aws_command "aws s3api delete-bucket --bucket #{@aws_name} --region #{@region}"
|
55
|
+
|
56
|
+
aws_command("aws sns list-topics")["Topics"].each do |topic|
|
57
|
+
topic_arn = topic["TopicArn"]
|
58
|
+
aws_command "aws sns delete-topic --topic-arn '#{topic_arn}'" if topic_arn.end_with?(@aws_name)
|
59
|
+
end
|
60
|
+
|
61
|
+
aws_command "aws iam delete-user-policy --user-name #{@aws_name} --policy-name s3"
|
62
|
+
aws_command "aws iam delete-user-policy --user-name #{@aws_name} --policy-name sns"
|
63
|
+
aws_command("aws iam list-access-keys --user-name #{@aws_name}")["AccessKeyMetadata"].each do |accessKeyMetadata|
|
64
|
+
aws_command "aws iam delete-access-key --user-name #{@aws_name} --access-key #{accessKeyMetadata["AccessKeyId"]}"
|
65
|
+
end
|
66
|
+
aws_command "aws iam delete-user --user-name #{@aws_name}"
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
def aws_command(command)
|
71
|
+
puts "Running: #{command}"
|
72
|
+
output = `#{command}`
|
73
|
+
return nil if output == nil || output.strip == ""
|
74
|
+
|
75
|
+
puts "Output: #{output}"
|
76
|
+
JSON.parse(output)
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module MobileWorkflow::Cli
|
2
|
+
class DokkuBackend
|
3
|
+
def initialize(dokku_host:, app_name:)
|
4
|
+
@dokku_host = dokku_host
|
5
|
+
@dokku_app_name = app_name.gsub("_", "-")
|
6
|
+
end
|
7
|
+
|
8
|
+
def create
|
9
|
+
remote_command "dokku apps:create #{@dokku_app_name}"
|
10
|
+
remote_command "dokku postgres:create #{@dokku_app_name}"
|
11
|
+
remote_command "dokku postgres:link #{@dokku_app_name} #{@dokku_app_name}"
|
12
|
+
remote_command "dokku domains:enable #{@dokku_app_name}"
|
13
|
+
remote_command "dokku letsencrypt #{@dokku_app_name}"
|
14
|
+
|
15
|
+
local_command "git remote add dokku dokku@#{@dokku_host}:#{@dokku_app_name}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def configure_activestorage
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
def deploy
|
23
|
+
local_command "git push dokku master"
|
24
|
+
end
|
25
|
+
|
26
|
+
def sync_dotenv
|
27
|
+
env = File.read(".env").split.join(" ")
|
28
|
+
puts "Setting env: #{env}"
|
29
|
+
local_command "dokku config:set #{env}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def destroy
|
33
|
+
remote_command "dokku apps:destroy #{@dokku_app_name}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def dokku_app_host
|
37
|
+
remote_command "dokku url #{@dokku_app_name}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def notifications_endpoint
|
41
|
+
"https://#{dokku_app_host}/sns_notifications"
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def remote_command(command)
|
46
|
+
command = "ssh -t ubuntu@#{@dokku_host} '#{command}'"
|
47
|
+
local_command(command)
|
48
|
+
end
|
49
|
+
|
50
|
+
def local_command(command)
|
51
|
+
puts "Running: #{command}"
|
52
|
+
output = `#{command}`
|
53
|
+
puts "Output: #{output}" unless output.blank?
|
54
|
+
return output
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module MobileWorkflow::Cli
|
2
|
+
class HerokuBackend
|
3
|
+
def initialize(app_name:)
|
4
|
+
@heroku_app_name = app_name.gsub("_", "-")
|
5
|
+
end
|
6
|
+
|
7
|
+
def create
|
8
|
+
heroku_command "heroku create #{@heroku_app_name}"
|
9
|
+
heroku_command "git push --set-upstream heroku master"
|
10
|
+
end
|
11
|
+
|
12
|
+
def configure_activestorage
|
13
|
+
heroku_command "heroku buildpacks:add -i 1 https://github.com/heroku/heroku-buildpack-activestorage-preview --app #{@heroku_app_name}"
|
14
|
+
heroku_command "heroku labs:enable runtime-dyno-metadata --app #{@heroku_app_name}" # Gives access to heroku variables which can be used to construct URLs
|
15
|
+
|
16
|
+
# Force recompile after buildpacks change
|
17
|
+
heroku_command "git commit --allow-empty -m 'empty commit'"
|
18
|
+
deploy
|
19
|
+
end
|
20
|
+
|
21
|
+
def deploy
|
22
|
+
heroku_command "git push"
|
23
|
+
end
|
24
|
+
|
25
|
+
def sync_dotenv
|
26
|
+
env = File.read(".env").split.join(" ")
|
27
|
+
puts "Setting env: #{env}"
|
28
|
+
heroku_command "heroku config:set #{env} --app #{@heroku_app_name}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def destroy
|
32
|
+
heroku_command "heroku destroy #{@heroku_app_name} --confirm #{@heroku_app_name}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def notifications_endpoint
|
36
|
+
"https://#{@heroku_app_name}.herokuapp.com/sns_notifications"
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def heroku_command(command)
|
41
|
+
puts "Running: #{command}"
|
42
|
+
output = `#{command}`
|
43
|
+
puts "Output: #{output}"
|
44
|
+
return output
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
metadata
CHANGED
@@ -1,35 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mobile_workflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3
|
4
|
+
version: 0.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Brooke-Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-12-
|
11
|
+
date: 2020-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 6.0.3
|
20
17
|
- - ">="
|
21
18
|
- !ruby/object:Gem::Version
|
22
|
-
version: 6.0
|
19
|
+
version: 6.1.0
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
|
-
- - "~>"
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 6.0.3
|
30
24
|
- - ">="
|
31
25
|
- !ruby/object:Gem::Version
|
32
|
-
version: 6.0
|
26
|
+
version: 6.1.0
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
28
|
name: sqlite3
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -89,7 +83,8 @@ dependencies:
|
|
89
83
|
description:
|
90
84
|
email:
|
91
85
|
- matt@futureworkshops.com
|
92
|
-
executables:
|
86
|
+
executables:
|
87
|
+
- mwf
|
93
88
|
extensions: []
|
94
89
|
extra_rdoc_files: []
|
95
90
|
files:
|
@@ -106,20 +101,33 @@ files:
|
|
106
101
|
- app/mailers/mobile_workflow/application_mailer.rb
|
107
102
|
- app/models/concerns/mobile_workflow/displayable.rb
|
108
103
|
- app/views/layouts/mobile_workflow/application.html.erb
|
104
|
+
- bin/mwf
|
109
105
|
- config/routes.rb
|
110
106
|
- db/migrate/20200823174210_create_users.rb
|
111
107
|
- lib/generators/mobile_workflow/controller_generator.rb
|
112
108
|
- lib/generators/mobile_workflow/install/install_generator.rb
|
109
|
+
- lib/generators/mobile_workflow/install/templates/Gemfile.erb
|
110
|
+
- lib/generators/mobile_workflow/install/templates/Procfile
|
111
|
+
- lib/generators/mobile_workflow/install/templates/Procfile.dev
|
112
|
+
- lib/generators/mobile_workflow/install/templates/README.md.erb
|
113
|
+
- lib/generators/mobile_workflow/install/templates/ability.rb
|
113
114
|
- lib/generators/mobile_workflow/install/templates/api_controller.rb.erb
|
114
115
|
- lib/generators/mobile_workflow/install/templates/seeds.rb.erb
|
115
116
|
- lib/generators/mobile_workflow/install/templates/sessions_controller.rb.erb
|
117
|
+
- lib/generators/mobile_workflow/install/templates/storage.s3.yml
|
116
118
|
- lib/generators/mobile_workflow/install/templates/user.rb.erb
|
117
119
|
- lib/generators/mobile_workflow/templates/controller.rb.erb
|
118
120
|
- lib/generators/mobile_workflow/templates/controller_spec.rb.erb
|
119
121
|
- lib/mobile_workflow.rb
|
122
|
+
- lib/mobile_workflow/cli.rb
|
123
|
+
- lib/mobile_workflow/cli/app_builder.rb
|
124
|
+
- lib/mobile_workflow/cli/app_server_cleaner.rb
|
125
|
+
- lib/mobile_workflow/cli/app_server_generator.rb
|
126
|
+
- lib/mobile_workflow/cli/aws_backend.rb
|
127
|
+
- lib/mobile_workflow/cli/dokku_backend.rb
|
128
|
+
- lib/mobile_workflow/cli/heroku_backend.rb
|
120
129
|
- lib/mobile_workflow/engine.rb
|
121
130
|
- lib/mobile_workflow/version.rb
|
122
|
-
- lib/tasks/mobile_workflow_tasks.rake
|
123
131
|
- lib/templates/active_record/model/model.rb.erb
|
124
132
|
homepage: https://github.com/futureworkshops/mobile_workflow
|
125
133
|
licenses:
|
@@ -133,7 +141,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
133
141
|
requirements:
|
134
142
|
- - ">="
|
135
143
|
- !ruby/object:Gem::Version
|
136
|
-
version:
|
144
|
+
version: 2.5.5
|
137
145
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
146
|
requirements:
|
139
147
|
- - ">="
|