mobile_workflow 0.1.0 → 0.5.1

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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/mobile_workflow/param_parser.rb +17 -0
  3. data/app/controllers/concerns/mobile_workflow/s3_storable.rb +2 -2
  4. data/app/controllers/mobile_workflow/sns_notifications_controller.rb +4 -0
  5. data/app/models/concerns/mobile_workflow/displayable.rb +95 -0
  6. data/bin/mwf +34 -0
  7. data/config/routes.rb +1 -0
  8. data/db/migrate/20200823174210_create_users.rb +11 -0
  9. data/lib/generators/mobile_workflow/controller_generator.rb +0 -4
  10. data/lib/generators/mobile_workflow/install/install_generator.rb +51 -10
  11. data/lib/generators/mobile_workflow/install/templates/Gemfile.erb +50 -0
  12. data/lib/generators/mobile_workflow/install/templates/Procfile +2 -0
  13. data/lib/generators/mobile_workflow/install/templates/Procfile.dev +1 -0
  14. data/lib/generators/mobile_workflow/install/templates/README.md.erb +22 -0
  15. data/lib/generators/mobile_workflow/install/templates/ability.rb +7 -0
  16. data/lib/generators/mobile_workflow/install/templates/api_controller.rb.erb +19 -0
  17. data/lib/generators/mobile_workflow/install/templates/seeds.rb.erb +3 -0
  18. data/lib/generators/mobile_workflow/install/templates/sessions_controller.rb.erb +20 -0
  19. data/lib/generators/mobile_workflow/install/templates/storage.s3.yml +14 -0
  20. data/lib/generators/mobile_workflow/install/templates/user.rb.erb +4 -0
  21. data/lib/generators/mobile_workflow/templates/controller.rb.erb +5 -7
  22. data/lib/generators/mobile_workflow/templates/controller_spec.rb.erb +2 -2
  23. data/lib/mobile_workflow/cli.rb +9 -0
  24. data/lib/mobile_workflow/cli/app_builder.rb +84 -0
  25. data/lib/mobile_workflow/cli/app_server_cleaner.rb +24 -0
  26. data/lib/mobile_workflow/cli/app_server_generator.rb +98 -0
  27. data/lib/mobile_workflow/cli/aws_backend.rb +80 -0
  28. data/lib/mobile_workflow/cli/dokku_backend.rb +57 -0
  29. data/lib/mobile_workflow/cli/heroku_backend.rb +47 -0
  30. data/lib/mobile_workflow/version.rb +3 -1
  31. data/lib/templates/active_record/model/model.rb.erb +3 -35
  32. metadata +59 -18
  33. data/app/models/mobile_workflow/application_record.rb +0 -5
  34. data/lib/tasks/mobile_workflow_tasks.rake +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '068f070743f72d5743182cd41021c33b89579ecef7182a5747c799393a1d4208'
4
- data.tar.gz: 41aef887eb318cf98736112ce4aad51835af98f1d20e0d75f7810c9014f4c5e4
3
+ metadata.gz: a1d55314927070ee5d1b4498b99b760952214839e146ae0e271bc2ff49a1fce9
4
+ data.tar.gz: e666ed9c786f10335e1d30505a4f62059636034821d3e4e2d17d532929bfee93
5
5
  SHA512:
6
- metadata.gz: 90ad8d639c45ff2c757a933199022a1fad59d649c815211425366c45d72a9596e516fe382835b7ffca76f1dc7bdbc85b14d35b65b723dcd751750ff10195803d
7
- data.tar.gz: 8adcf9c22591e5644b484c0216a9f8d157222078f8ed37cebcdc9333560c30294f018e06cdfc26c8d3a27bfe9f7016346658ff4fe83a215d162f2a0946dbcaa6
6
+ metadata.gz: 80da58aa822183db3273fd34e89b9563040349bc17b60f8817f467f59561e2d7e1684ecaa48b85f88e3993ac7819538fb0515b0aeaddf513727f3f033117b5be
7
+ data.tar.gz: 6ad8369700ca16b92de687238fabad59f9bd695c9b8941d85beae13edd38d338a658edc5e5085439c3944d63f855f5ae3078ed4cd17467283dd121b7d4b8e848
@@ -0,0 +1,17 @@
1
+ module MobileWorkflow
2
+ module ParamParser
3
+ def mw_rewrite_payload_properties(model:, properties:)
4
+ properties.each {|property| mw_rewrite_payload_property(model: model, model_property: property, params_property: property)}
5
+ end
6
+
7
+ def mw_rewrite_payload_property(model:, model_property:, params_property:)
8
+ params[model][model_property] = params.dig(:payload, params_property, :answer)
9
+ end
10
+
11
+ def mw_rewrite_payload_array(model:, model_property:, params_property:)
12
+ answer = params.dig(:payload, params_property, :answer)
13
+ params[model][model_property] = answer[0] if answer
14
+ end
15
+ end
16
+ end
17
+
@@ -7,11 +7,11 @@ module MobileWorkflow
7
7
  return unless params["binaries"]
8
8
 
9
9
  params["binaries"].collect do |binary|
10
- property = binary["identifier"].split('/')[0] # i.e. image/jpg --> image, video/mp4 --> video
10
+ extension = binary["mimetype"].split('/')[1] # i.e. image/jpg --> image, video/mp4 --> video
11
11
 
12
12
  {
13
13
  "identifier" => binary["identifier"],
14
- "url" => presigned_url("#{object.class.name.underscore}/#{object.id}/#{property}"),
14
+ "url" => presigned_url("#{object.class.name.underscore}/#{object.id}/#{binary["identifier"]}.#{extension}"),
15
15
  "method" => "PUT"
16
16
  }
17
17
  end
@@ -46,6 +46,10 @@ module MobileWorkflow
46
46
  end
47
47
 
48
48
  def attribute_name
49
+ file_name.split(".")[0] # remove the extension
50
+ end
51
+
52
+ def file_name
49
53
  key_identifiers[2]
50
54
  end
51
55
 
@@ -0,0 +1,95 @@
1
+ module MobileWorkflow
2
+ module Displayable
3
+ extend ActiveSupport::Concern
4
+ include Rails.application.routes.url_helpers
5
+
6
+ ON_SUCCESS_OPTIONS = [:none, :reload, :backward, :forward]
7
+ BUTTON_STYLES = [:primary, :outline, :danger]
8
+
9
+ def mw_list_item(id: self.id, text:, detail_text: nil, sf_symbol_name: nil, image_attachment: nil)
10
+ mw_list_item = {id: id, text: text, detailText: detail_text, sfSymbolName: sf_symbol_name}
11
+ mw_list_item[:imageURL] = preview_url(image_attachment, height: 100, width: 100) if image_attachment
12
+ mw_list_item.compact
13
+ end
14
+
15
+ def mw_display_text(text:, label: nil)
16
+ {type: :text, label: label, text: text.to_s}.compact
17
+ end
18
+
19
+ def mw_display_image(attachment)
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}
30
+ end
31
+
32
+ def mw_display_video(attachment)
33
+ {type: :video, previewURL: preview_url(attachment, height: 600, width: 1200), url: attachment_url(attachment)}
34
+ end
35
+
36
+ def mw_display_button(label:, style: :primary, on_success: :forward)
37
+ validate_on_success!(on_success)
38
+ validate_button_style!(style)
39
+
40
+ {type: :button, label: label, style: style, onSuccess: on_success}
41
+ end
42
+
43
+ def mw_display_delete_button(url:, label: "Delete", method: :delete, style: :danger, on_success: :backward)
44
+ validate_on_success!(on_success)
45
+ validate_button_style!(style)
46
+
47
+ {type: :button, label: label, url: url, method: method, style: style, onSuccess: on_success}
48
+ end
49
+
50
+ def mw_display_button_for_url(label:, url:, method: :put, style: :primary, on_success: :reload)
51
+ validate_on_success!(on_success)
52
+ validate_button_style!(style)
53
+
54
+ {type: :button, label: label, url: url, method: method, style: style, onSuccess: on_success}
55
+ end
56
+
57
+ def mw_display_button_for_modal_workflow(label:, modal_workflow_name:, style: :primary, on_success: :none)
58
+ validate_on_success!(on_success)
59
+ validate_button_style!(style)
60
+
61
+ {type: :button, label: label, modalWorkflow: modal_workflow_name, style: style, onSuccess: on_success}
62
+ end
63
+
64
+ private
65
+ def validate_on_success!(on_success)
66
+ raise 'Unknown on_success action' unless ON_SUCCESS_OPTIONS.include?(on_success)
67
+ end
68
+
69
+ def validate_button_style!(style)
70
+ raise 'Unknown style' unless BUTTON_STYLES.include?(style)
71
+ end
72
+
73
+ def preview_url(attachment, height:, width:, options: { resize_to_fill: [height, width]} )
74
+ return nil unless attachment.attached?
75
+
76
+ if attachment.image?
77
+ Rails.application.routes.url_helpers.rails_representation_url(attachment.variant(combine_options: options), host: attachment_host)
78
+ elsif attachment.previewable?
79
+ Rails.application.routes.url_helpers.rails_representation_url(attachment.preview(options), host: attachment_host)
80
+ else
81
+ return nil
82
+ end
83
+ end
84
+
85
+ def attachment_url(attachment)
86
+ return nil unless attachment.attached?
87
+
88
+ Rails.application.routes.url_helpers.rails_blob_url(attachment, host: attachment_host)
89
+ end
90
+
91
+ def attachment_host
92
+ "https://#{ENV['HEROKU_APP_NAME']}.herokuapp.com"
93
+ end
94
+ end
95
+ end
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
+
@@ -1,2 +1,3 @@
1
1
  MobileWorkflow::Engine.routes.draw do
2
+ resources :sns_notifications, only: :create
2
3
  end
@@ -0,0 +1,11 @@
1
+ class CreateUsers < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :users do |t|
4
+ t.string :email
5
+ t.string :password_digest
6
+
7
+ t.timestamps
8
+ end
9
+ add_index :users, :email
10
+ end
11
+ end
@@ -23,10 +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
- attributes_names.map {|name| "params[:#{singular_table_name}][:#{name}] = params[:payload][:#{name}][:answer]" }.join("\n\t\t")
29
- end
30
26
  end
31
27
  end
32
28
  end
@@ -3,22 +3,42 @@ require "rails/generators/base"
3
3
  module MobileWorkflow
4
4
  module Generators
5
5
  class InstallGenerator < Rails::Generators::Base
6
+
7
+ # Schemas to avoid generating models for (static items from MW)
8
+ SKIP_SCHEMAS = ["attachment", "ListItem", "DisplayItem", "DisplayText", "DisplayButton", "DisplayImage", "DisplayVideo"]
9
+
6
10
  source_root File.expand_path("../templates", __FILE__)
7
11
 
8
12
  class_option :open_api_spec_path, type: :string, default: "config/open_api_spec.json"
13
+ class_option :doorkeeper_oauth, type: :boolean, default: false
14
+ class_option :interactive, type: :boolean, default: false
9
15
 
10
16
  def create_api_controller
11
- template(
12
- "api_controller.rb.erb",
13
- "app/controllers/api_controller.rb",
14
- )
17
+ template("api_controller.rb.erb", "app/controllers/api_controller.rb")
18
+ end
19
+
20
+ def mount_engine
21
+ route "mount MobileWorkflow::Engine => '/'"
22
+ end
23
+
24
+ def generate_doorkeeper
25
+ return unless options[:doorkeeper_oauth]
26
+ say "Generating Doorkeeper OAuth"
27
+
28
+ generate 'doorkeeper:install'
29
+ gsub_file 'config/initializers/doorkeeper.rb', 'raise "Please configure doorkeeper resource_owner_authenticator block located in #{__FILE__}"', 'User.find_by_id(session[:user_id]) || redirect_to(new_session_url(return_to: request.fullpath))'
30
+ generate 'doorkeeper:migration'
31
+ generate 'doorkeeper:pkce'
32
+ template("user.rb.erb", "app/models/user.rb")
33
+ template("sessions_controller.rb.erb", "app/controllers/sessions_controller.rb")
34
+ route "resources :sessions, only: [:new, :create]"
15
35
  end
16
36
 
17
37
  def generate_models
18
38
  say "Generating models"
19
39
  @model_properties = {}
20
40
  open_api_spec[:components][:schemas].each_pair do |model_name, schema|
21
- next if ["answer", "attachment"].include? model_name # Don't generate schemas for MW schemas
41
+ next if SKIP_SCHEMAS.include? model_name # Don't generate schemas for MW schemas
22
42
 
23
43
  model_name = model_name.underscore
24
44
  model_properties = model_properties(model_name, schema)
@@ -29,8 +49,6 @@ module MobileWorkflow
29
49
 
30
50
  def generate_controllers_and_routes
31
51
  say "Generating controllers"
32
- controller_names = open_api_spec[:paths].keys.collect{|url_path| url_path.split('/').last }
33
-
34
52
  route "root to: 'admin/#{controller_names.first}#index'"
35
53
 
36
54
  controller_names.each do |plural_controller_name|
@@ -40,29 +58,52 @@ module MobileWorkflow
40
58
  route "resources :#{plural_controller_name}, only: [:index, :show, :create]"
41
59
  end
42
60
  end
61
+
62
+ def generate_seeds
63
+ template("seeds.rb.erb", "db/seeds.rb", force: true)
64
+ end
43
65
 
44
66
  private
67
+ def controller_names
68
+ @controller_names ||= oai_spec_paths.collect{|url_path| url_path.split('/')[1] }.uniq
69
+ end
70
+
71
+ def oai_spec_paths
72
+ @oai_spec_paths ||= open_api_spec[:paths].keys
73
+ end
74
+
45
75
  def open_api_spec
46
76
  @open_api_spec ||= read_openapi_spec
47
77
  end
48
78
 
49
79
  def read_openapi_spec
50
80
  say "Loading OpenAPI Spec: #{open_api_spec_path}"
51
- return JSON.parse(File.read(open_api_spec_path)).with_indifferent_access
81
+ return JSON.parse(File.read(File.join(Rails.root, open_api_spec_path))).with_indifferent_access
52
82
  end
53
83
 
54
84
  def open_api_spec_path
55
85
  options[:open_api_spec_path]
56
86
  end
57
87
 
88
+ def interactive?
89
+ options[:interactive]
90
+ end
91
+
58
92
  def model_properties(name, schema)
59
- generated_properties_args = schema["properties"].keys.collect{|key| "#{key}:string" }.join(" ")
60
- if yes?("Use generated schema #{name}(#{generated_properties_args})[yn]?")
93
+ generated_properties_args = schema["properties"].keys.collect{|key| "#{key}:#{model_property_type(schema["properties"][key])}" }.join(" ")
94
+ if !interactive? || yes?("Use generated schema #{name}(#{generated_properties_args})[yn]?")
61
95
  generated_properties_args
62
96
  else
63
97
  ask "Specify schema for #{name}: (e.g. text:string image:attachment region:reference)"
64
98
  end
65
99
  end
100
+
101
+ def model_property_type(property)
102
+ return property["type"] unless property["type"].blank?
103
+ return 'attachment' if property['$ref'] == "#/components/schemas/attachment"
104
+
105
+ raise 'Unknown property type'
106
+ end
66
107
  end
67
108
  end
68
109
  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,2 @@
1
+ web: bundle exec rackup config.ru -p $PORT
2
+ release: bundle exec rake db:migrate
@@ -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
@@ -0,0 +1,7 @@
1
+ class Ability
2
+ include CanCan::Ability
3
+
4
+ def initialize(user)
5
+ can :manage, :all
6
+ end
7
+ end
@@ -1,5 +1,24 @@
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
+
7
+ <% if options[:doorkeeper_oauth] %>
8
+ before_action :doorkeeper_authorize!, unless: :anonymous_action?
9
+
10
+ def current_resource_owner
11
+ User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token&.accessible?
12
+ end
13
+ alias_method :current_user, :current_resource_owner
14
+
15
+ protected
16
+ def anonymous_action?
17
+ false
18
+ end
19
+ <% else %>
2
20
  def current_user
3
21
  nil
4
22
  end
23
+ <% end %>
5
24
  end
@@ -0,0 +1,3 @@
1
+ <%- if options[:doorkeeper_oauth] %>
2
+ Doorkeeper::Application.create! name: 'Main App', redirect_uri: 'mww://callback', scopes: 'public'
3
+ <%- end %>
@@ -0,0 +1,20 @@
1
+ class SessionsController < ApplicationController
2
+ def new
3
+ end
4
+
5
+ def create
6
+ @user = User.find_by(email: params[:email])
7
+ if @user && @user.authenticate(params[:password])
8
+ session[:user_id] = @user.id
9
+ redirect_to params[:return_to] || root_url, notice: "Logged in!"
10
+ else
11
+ flash[:warning] = "You have entered incorrect email and/or password."
12
+ render :new
13
+ end
14
+ end
15
+
16
+ def destroy
17
+ session.delete(:user_id)
18
+ redirect_to root_path
19
+ end
20
+ end
@@ -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'] %>
@@ -0,0 +1,4 @@
1
+ class User < ApplicationRecord
2
+ has_secure_password
3
+ validates :email, presence: true
4
+ end
@@ -1,5 +1,6 @@
1
1
  <% module_namespacing do -%>
2
2
  class <%= controller_class_name %>Controller < ApiController
3
+ # include MobileWorkflow::S3Storable
3
4
  before_action :rewrite_payload, only: :create
4
5
 
5
6
  load_and_authorize_resource
@@ -23,19 +24,16 @@ class <%= controller_class_name %>Controller < ApiController
23
24
  private
24
25
  def rewrite_payload
25
26
  # Use this method to make any changes to params to make them compatible with ActiveRecord
26
-
27
- # 1. Example to get properties from question
28
- # params[:payload][:name] = params.dig(:payload, :name, :answer)
29
-
30
- # 2. Example to get selected id from a list
27
+
28
+ # 1. Example to get selected id from a list
31
29
  # passport_id = params.dig(:payload, :choose_passport, :selected, :id)
32
30
 
33
31
  Rails.logger.debug "Pre-rewrite params: #{params}"
34
- <%= rewrite_params %>
32
+ # Do your rewriting here
35
33
  end
36
34
 
37
35
  def <%= singular_table_name.underscore %>_params
38
- params.require(:<%= singular_table_name %>).permit(<%= permitted_params %>)
36
+ params.require(:payload).permit(<%= permitted_params %>)
39
37
  end
40
38
  end
41
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 %>) { <%= controller_class_name.singularize %>.create }
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 %>) { <%= controller_class_name.singularize %>.create }
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,84 @@
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 ability_generator
21
+ copy_file 'ability.rb', 'app/models/ability.rb'
22
+ end
23
+
24
+ def active_storage
25
+ rails_command 'active_storage:install'
26
+ copy_file 'storage.s3.yml', 'config/storage.yml'
27
+ gsub_file 'config/environments/production.rb', 'config.active_storage.service = :local', 'config.active_storage.service = :amazon'
28
+ end
29
+
30
+ def mobile_workflow_generator(open_api_spec_path)
31
+ copy_file open_api_spec_path, 'config/open_api_spec.json'
32
+ gen_opts = ""
33
+ gen_opts += "--doorkeeper_oauth" if options[:doorkeeper_oauth]
34
+ generate "mobile_workflow:install #{gen_opts}"
35
+
36
+ # Copy user migrations if needed
37
+ rails_command 'mobile_workflow:install:migrations' if options[:doorkeeper_oauth]
38
+ end
39
+
40
+ def s3_backend(region)
41
+ @region = region
42
+ aws_backend.create
43
+ aws_backend.write_env
44
+
45
+ if options[:heroku]
46
+ heroku_backend.sync_dotenv
47
+ sleep 10 # Wait for the server to restart
48
+ aws_backend.create_topic_subscription(heroku_backend.notifications_endpoint)
49
+ elsif options[:dokku]
50
+ dokku_backend.sync_dotenv
51
+ aws_backend.create_topic_subscription(dokku_backend.notifications_endpoint)
52
+ end
53
+
54
+ end
55
+
56
+ def heroku
57
+ heroku_backend.create
58
+ heroku_backend.configure_activestorage if options[:s3_storage]
59
+ heroku_backend.deploy
60
+ heroku_backend.sync_dotenv
61
+ end
62
+
63
+ def dokku(dokku_host)
64
+ @dokku_host = dokku_host
65
+ dokku_backend.create
66
+ dokku_backend.configure_activestorage if options[:s3_storage]
67
+ dokku_backend.deploy
68
+ dokku_backend.sync_dotenv
69
+ end
70
+
71
+ private
72
+ def aws_backend
73
+ @aws_backend ||= AwsBackend.new(app_name: app_name, region: @region)
74
+ end
75
+
76
+ def dokku_backend
77
+ @dokku_backend ||= DokkuBackend.new(app_name: app_name, dokku_host: @dokku_host)
78
+ end
79
+
80
+ def heroku_backend
81
+ @heroku_backend ||= HerokuBackend.new(app_name: app_name)
82
+ end
83
+ end
84
+ 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,98 @@
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
+ generate_administrate
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 generate_administrate
61
+ generate 'administrate:install'
62
+ file 'app/assets/config/manifest.js', <<-CODE
63
+ //= link administrate/application.css
64
+ //= link administrate/application.js
65
+ CODE
66
+
67
+ file 'app/controllers/admin/application_controller.rb', <<-CODE
68
+ module Admin
69
+ class ApplicationController < Administrate::ApplicationController
70
+ http_basic_authenticate_with(name: ENV["ADMIN_USER"], password: ENV["ADMIN_PASSWORD"])
71
+ end
72
+ end
73
+ CODE
74
+ generate 'administrate:routes'
75
+ end
76
+
77
+ def setup_db
78
+ rails_command "db:drop"
79
+ rails_command "db:create"
80
+ rails_command "db:migrate"
81
+ end
82
+
83
+ def initial_git_commit
84
+ git add: "."
85
+ git commit: %Q{ -m 'Initial commit' }
86
+ end
87
+
88
+ def generate_dot_env
89
+ admin_user = 'admin'
90
+ admin_password = SecureRandom.base64(12)
91
+
92
+ file '.env', <<-CODE
93
+ ADMIN_USER=#{admin_user}
94
+ ADMIN_PASSWORD=#{admin_password}
95
+ CODE
96
+ end
97
+ end
98
+ 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
@@ -1,3 +1,5 @@
1
1
  module MobileWorkflow
2
- VERSION = '0.1.0'
2
+ VERSION = '0.5.1'
3
+ RUBY_VERSION = '2.5.5'
4
+ RAILS_VERSION = '6.1.0'
3
5
  end
@@ -1,7 +1,6 @@
1
1
  <% module_namespacing do -%>
2
2
  class <%= class_name %> < <%= parent_class_name.classify %>
3
- # Enable if you need to generate attachment URLs
4
- # include Rails.application.routes.url_helpers
3
+ include MobileWorkflow::Displayable
5
4
 
6
5
  <% attributes.select(&:reference?).each do |attribute| -%>
7
6
  belongs_to :<%= attribute.name %><%= ', polymorphic: true' if attribute.polymorphic? %>
@@ -14,43 +13,12 @@ class <%= class_name %> < <%= parent_class_name.classify %>
14
13
  <% end -%>
15
14
 
16
15
  def list_item_as_json
17
- {
18
- id: id,
19
- text: text,
20
- # detailText: nil,
21
- # sfSymbolName: nil,
22
- # imageURL: preview_url(image, height: 100, width: 100)
23
- }
16
+ mw_list_item(text: text)
24
17
  end
25
18
 
26
19
  def display_as_json
27
- [
28
- {label: "ID", text: text, mimeType: 'text/plain'},
29
- {label: "Text", text: text, mimeType: 'text/plain'}
30
- ]
20
+ [mw_display_text(label: 'ID', text: id.to_s)]
31
21
  end
32
-
33
- # private
34
- # include Rails.application.routes.url_helpers # for attachment URLs
35
- # def preview_url(attachment, height:, width:, options: { resize_to_fill: [height, width]} )
36
- # return nil unless attachment.attached?
37
- #
38
- # if attachment.image?
39
- # Rails.application.routes.url_helpers.rails_representation_url(attachment.variant(combine_options: options), host: attachment_host)
40
- # elsif attachment.previewable?
41
- # Rails.application.routes.url_helpers.rails_representation_url(attachment.preview(options), host: attachment_host)
42
- # else
43
- # return nil
44
- # end
45
- # end
46
- #
47
- # def attachment_url(attachment)
48
- # Rails.application.routes.url_helpers.rails_blob_url(attachment, host: attachment_host)
49
- # end
50
- #
51
- # def attachment_host
52
- # "https://#{ENV['HEROKU_APP_NAME']}.herokuapp.com"
53
- # end
54
22
 
55
23
  end
56
24
  <% 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.1.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Brooke-Smith
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-30 00:00:00.000000000 Z
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.3.2
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.3.2
26
+ version: 6.1.0
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: sqlite3
35
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,10 +52,39 @@ dependencies:
58
52
  - - ">="
59
53
  - !ruby/object:Gem::Version
60
54
  version: '0'
61
- description:
55
+ - !ruby/object:Gem::Dependency
56
+ name: generator_spec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: byebug
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description:
62
84
  email:
63
85
  - matt@futureworkshops.com
64
- executables: []
86
+ executables:
87
+ - mwf
65
88
  extensions: []
66
89
  extra_rdoc_files: []
67
90
  files:
@@ -70,29 +93,47 @@ files:
70
93
  - Rakefile
71
94
  - app/assets/config/mobile_workflow_manifest.js
72
95
  - app/assets/stylesheets/mobile_workflow/application.css
96
+ - app/controllers/concerns/mobile_workflow/param_parser.rb
73
97
  - app/controllers/concerns/mobile_workflow/s3_storable.rb
74
98
  - app/controllers/mobile_workflow/sns_notifications_controller.rb
75
99
  - app/helpers/mobile_workflow/application_helper.rb
76
100
  - app/jobs/mobile_workflow/application_job.rb
77
101
  - app/mailers/mobile_workflow/application_mailer.rb
78
- - app/models/mobile_workflow/application_record.rb
102
+ - app/models/concerns/mobile_workflow/displayable.rb
79
103
  - app/views/layouts/mobile_workflow/application.html.erb
104
+ - bin/mwf
80
105
  - config/routes.rb
106
+ - db/migrate/20200823174210_create_users.rb
81
107
  - lib/generators/mobile_workflow/controller_generator.rb
82
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
83
114
  - lib/generators/mobile_workflow/install/templates/api_controller.rb.erb
115
+ - lib/generators/mobile_workflow/install/templates/seeds.rb.erb
116
+ - lib/generators/mobile_workflow/install/templates/sessions_controller.rb.erb
117
+ - lib/generators/mobile_workflow/install/templates/storage.s3.yml
118
+ - lib/generators/mobile_workflow/install/templates/user.rb.erb
84
119
  - lib/generators/mobile_workflow/templates/controller.rb.erb
85
120
  - lib/generators/mobile_workflow/templates/controller_spec.rb.erb
86
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
87
129
  - lib/mobile_workflow/engine.rb
88
130
  - lib/mobile_workflow/version.rb
89
- - lib/tasks/mobile_workflow_tasks.rake
90
131
  - lib/templates/active_record/model/model.rb.erb
91
132
  homepage: https://github.com/futureworkshops/mobile_workflow
92
133
  licenses:
93
134
  - MIT
94
135
  metadata: {}
95
- post_install_message:
136
+ post_install_message:
96
137
  rdoc_options: []
97
138
  require_paths:
98
139
  - lib
@@ -100,7 +141,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
100
141
  requirements:
101
142
  - - ">="
102
143
  - !ruby/object:Gem::Version
103
- version: '0'
144
+ version: 2.5.5
104
145
  required_rubygems_version: !ruby/object:Gem::Requirement
105
146
  requirements:
106
147
  - - ">="
@@ -108,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
149
  version: '0'
109
150
  requirements: []
110
151
  rubygems_version: 3.0.8
111
- signing_key:
152
+ signing_key:
112
153
  specification_version: 4
113
154
  summary: A Rails engine to provide API support for Mobile Workflow Apps.
114
155
  test_files: []
@@ -1,5 +0,0 @@
1
- module MobileWorkflow
2
- class ApplicationRecord < ActiveRecord::Base
3
- self.abstract_class = true
4
- end
5
- end
@@ -1,4 +0,0 @@
1
- # desc "Explaining what the task does"
2
- # task :mobile_workflow do
3
- # # Task goes here
4
- # end