mission_kontrol_relay 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,72 @@
1
+ ![MissionKontrol Logo](MissionKontrol-logo-original.png)
2
+
3
+ # MissionKontrolRelay
4
+
5
+ [![Gem Version](http://img.shields.io/gem/v/mission_kontrol_relay.svg?style=flat-square)](https://rubygems.org/gems/mission_kontrol_relay)
6
+ [![License](http://img.shields.io/:license-gpl3-blue.svg?style=flat-square)](http://www.gnu.org/licenses/gpl-3.0.html)
7
+
8
+ ## Description
9
+
10
+ [MissionKontrol](https://missionkontrol.io) is a simple and effective admin interface for your applications or microservices. It is a self hosted application that is quick and easy to set up, even if you aren't a developer. MissionKontrol doesn't need to know anything about your application(s) in order to work, it just needs to connect to your database(s).
11
+
12
+ **MisisonKontrolRelay** is a gem that gives your version of MissionKontrol more power and better features by providing it with more information about your application (such as model associations and validations).
13
+
14
+ Don't worry though, with the access token generated on install, only your hosted version of MissionKontrol will get access to this information.
15
+
16
+ #### Do I have to be using MissionKontrol in order to use this gem?
17
+
18
+ No! Anyone can use this gem. To see how you can use this gem outside of MissionKontrol, please see the 'endpoints' section below.
19
+
20
+ ## Installation instructions
21
+
22
+ You can install **MissionKontrolRelay** into your Rails application by adding it into your gemfile:
23
+
24
+ ```ruby
25
+ gem 'mission_kontrol_relay'
26
+ ```
27
+
28
+ or you can install it manually:
29
+
30
+ ```bash
31
+ $ gem install 'mission_kontrol_relay'
32
+ ```
33
+
34
+ Once you have installed the gem you need to run the generator:
35
+
36
+ ```bash
37
+ $ rails generate mission_kontrol_relay:install
38
+ ```
39
+
40
+ The generator will generate your token and save it as an environment variable. You will need this to allow MissionKontrol to talk to your application, or if you want to access the provided endpoints.
41
+
42
+ To access your token run the following:
43
+
44
+ ```bash
45
+ $ printenv MISSION_KONTROL_TOKEN
46
+ ```
47
+
48
+ ## Contributing
49
+
50
+ Before contributing please read the code of conduct [here](https://github.com/Mission-Kontrol/MissionKontrol-rails/CODE_OF_CONDUCT.md)
51
+
52
+ Here is the contribution workflow:
53
+
54
+ 1. Fork the repo on GitHub
55
+ 2. Clone the project to your own machine
56
+ 3. Commit changes to your own branch
57
+ 4. Push your work back up to your fork
58
+ 5. Submit a Pull request so that we can review your changes
59
+
60
+ ### Getting set up
61
+
62
+ ```bash
63
+ $ bundle install
64
+ $ RAILS_ENV=test bundle exec rails db:setup
65
+ $ RAILS_ENV=test bundle exec rails db:migrate
66
+ ```
67
+
68
+ ### Running tests
69
+
70
+ ```bash
71
+ $ bundle exec rspec
72
+ ```
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ APP_RAKEFILE = File.expand_path('test/dummy/Rakefile', __dir__)
9
+ # load 'rails/tasks/engine.rake'
10
+
11
+ # load 'rails/tasks/statistics.rake'
12
+ load 'rails/tasks/engine.rake'
13
+
14
+ load 'rails/tasks/statistics.rake'
15
+
16
+ require 'bundler/gem_tasks'
17
+
18
+ Bundler::GemHelper.install_tasks
19
+
20
+ require 'rake/testtask'
21
+
22
+ Rake::TestTask.new(:test) do |t|
23
+ t.libs << 'test'
24
+ t.pattern = 'test/**/*_test.rb'
25
+ t.verbose = false
26
+ end
27
+
28
+ task default: :test
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,56 @@
1
+ body { background-color: #fff; color: #333; }
2
+
3
+ body, p, ol, ul, td {
4
+ font-family: verdana, arial, helvetica, sans-serif;
5
+ font-size: 13px;
6
+ line-height: 18px;
7
+ }
8
+
9
+ pre {
10
+ background-color: #eee;
11
+ padding: 10px;
12
+ font-size: 11px;
13
+ }
14
+
15
+ a { color: #000; }
16
+ a:visited { color: #666; }
17
+ a:hover { color: #fff; background-color:#000; }
18
+
19
+ div.field, div.actions {
20
+ margin-bottom: 10px;
21
+ }
22
+
23
+ #notice {
24
+ color: green;
25
+ }
26
+
27
+ .field_with_errors {
28
+ padding: 2px;
29
+ background-color: red;
30
+ display: table;
31
+ }
32
+
33
+ #error_explanation {
34
+ width: 450px;
35
+ border: 2px solid red;
36
+ padding: 7px;
37
+ padding-bottom: 0;
38
+ margin-bottom: 20px;
39
+ background-color: #f0f0f0;
40
+ }
41
+
42
+ #error_explanation h2 {
43
+ text-align: left;
44
+ font-weight: bold;
45
+ padding: 5px 5px 5px 15px;
46
+ font-size: 12px;
47
+ margin: -7px;
48
+ margin-bottom: 0px;
49
+ background-color: #c00;
50
+ color: #fff;
51
+ }
52
+
53
+ #error_explanation ul li {
54
+ font-size: 12px;
55
+ list-style: square;
56
+ }
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MissionKontrolRelay
4
+ class ApplicationController < ActionController::Base
5
+ def index; end
6
+ end
7
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MissionKontrolRelay
4
+ class ModelsController < ApplicationController
5
+ before_action :validate_token
6
+ before_action :available_models
7
+
8
+ def associations
9
+ call_association_service
10
+
11
+ render json: @associations
12
+ end
13
+
14
+ def validations
15
+ call_validation_service
16
+
17
+ render json: @model_validations
18
+ end
19
+
20
+ private
21
+
22
+ def permitted_params
23
+ params.permit(:token)
24
+ end
25
+
26
+ def validate_token
27
+ token_matches = permitted_params[:token] == ENV['MISSION_KONTROL_TOKEN']
28
+ message = if permitted_params[:token] && !token_matches
29
+ 'Invalid token'
30
+ elsif permitted_params[:token].nil?
31
+ 'Please provide a token'
32
+ end
33
+
34
+ return if token_matches
35
+
36
+ render json: { error: message }, status: :unauthorized
37
+ end
38
+
39
+ def available_models
40
+ @available_models ||= MissionKontrolRelay::ModelRetrievalService.call
41
+ end
42
+
43
+ def call_association_service
44
+ @associations = []
45
+
46
+ @available_models.each do |model|
47
+ association = MissionKontrolRelay::AssociationMappingService.new(model)
48
+ .build
49
+ @associations << association
50
+ end
51
+ end
52
+
53
+ def call_validation_service
54
+ @model_validations = []
55
+
56
+ @available_models.each do |model|
57
+ validation = MissionKontrolRelay::ValidationMappingService.new(model)
58
+ .build
59
+ @model_validations << validation
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MissionKontrolRelay
4
+ module ApplicationHelper
5
+ end
6
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MissionKontrolRelay
4
+ class AssociationMappingService
5
+ def initialize(model)
6
+ @model = model
7
+ end
8
+
9
+ def build
10
+ {
11
+ model: @model.name,
12
+ columns: model_columns,
13
+ associations: model_associations
14
+ }
15
+ end
16
+
17
+ private
18
+
19
+ def model_columns
20
+ columns = []
21
+
22
+ @model.columns.each do |column|
23
+ columns << {
24
+ column: column.name,
25
+ type: column.sql_type_metadata.type
26
+ }
27
+ end
28
+
29
+ columns
30
+ end
31
+
32
+ def model_associations
33
+ associations = []
34
+
35
+ @model.reflections.each do |association|
36
+ association = association.last
37
+ associations << {
38
+ associated_model: association.name,
39
+ type: association.macro,
40
+ options: association.try(:options)
41
+ }
42
+ end
43
+
44
+ associations
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MissionKontrolRelay
4
+ class ModelRetrievalService
5
+ class << self
6
+ def call
7
+ Rails.application.eager_load!
8
+ ActiveRecord::Base.descendants.collect do |table|
9
+ table if valid_table?(table)
10
+ end.compact
11
+ end
12
+
13
+ private
14
+
15
+ def valid_table?(table)
16
+ table.table_exists? && not_join_table?(table)
17
+ end
18
+
19
+ def not_join_table?(table)
20
+ table.to_s.split('::').last.split('_').first != 'HABTM'
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MissionKontrolRelay
4
+ class ValidationMappingService
5
+ def initialize(model)
6
+ @model = model
7
+ end
8
+
9
+ def build
10
+ {
11
+ model: @model.name,
12
+ validations: model_validations
13
+ }
14
+ end
15
+
16
+ private
17
+
18
+ def model_validations
19
+ validations = []
20
+
21
+ @model._validate_callbacks.to_a.each do |validation|
22
+ validations << validation_attributes(validation)
23
+ end
24
+
25
+ validations
26
+ end
27
+
28
+ def validation_attributes(validation)
29
+ {
30
+ key: remove_klass_from_key(validation),
31
+ type: validation.instance_variable_get(:@key).try(:kind),
32
+ kind: validation.kind,
33
+ name: validation.name,
34
+ attributes: validation.try(:filter).try(:attributes),
35
+ if: validation.instance_variable_get(:@if),
36
+ unless: validation.instance_variable_get(:@unless)
37
+ }
38
+ end
39
+
40
+ def remove_klass_from_key(validation)
41
+ key = validation.instance_variable_get(:@key)
42
+ if key.instance_variable_get(:@klass)
43
+ key.instance_variable_set(:@klass, nil)
44
+ end
45
+
46
+ key
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>MissionKontrolRelay</title>
5
+ <%= stylesheet_link_tag "mission_kontrol_relay/application", media: "all" %>
6
+ <%= javascript_include_tag "mission_kontrol_relay/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'mission_kontrol_relay'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
5
+
6
+ ENGINE_ROOT = File.expand_path('..', __dir__)
7
+ ENGINE_PATH = File.expand_path('../lib/mission_kontrol_relay/engine', __dir__)
8
+ APP_PATH = File.expand_path('../test/dummy/config/application', __dir__)
9
+
10
+ # Set up gems listed in the Gemfile.
11
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
12
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
13
+
14
+ require 'rails/all'
15
+ require 'rails/engine/commands'