mission_kontrol_relay 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +60 -0
- data/.rspec +3 -0
- data/.rubocop.yml +25 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +185 -0
- data/LICENSE +674 -0
- data/MissionKontrol-logo-original.png +0 -0
- data/README.md +72 -0
- data/Rakefile +28 -0
- data/app/assets/images/mission_kontrol_relay/.keep +0 -0
- data/app/assets/javascripts/mission_kontrol_relay/application.js +13 -0
- data/app/assets/stylesheets/mission_kontrol_relay/application.css +15 -0
- data/app/assets/stylesheets/scaffold.css +56 -0
- data/app/controllers/mission_kontrol_relay/application_controller.rb +7 -0
- data/app/controllers/mission_kontrol_relay/models_controller.rb +63 -0
- data/app/helpers/mission_kontrol_relay/application_helper.rb +6 -0
- data/app/services/mission_kontrol_relay/association_mapping_service.rb +47 -0
- data/app/services/mission_kontrol_relay/model_retrieval_service.rb +24 -0
- data/app/services/mission_kontrol_relay/validation_mapping_service.rb +49 -0
- data/app/views/layouts/mission_kontrol_relay/application.html.erb +14 -0
- data/bin/console +15 -0
- data/bin/rails +15 -0
- data/bin/setup +8 -0
- data/config/routes.rb +10 -0
- data/lib/generators/mission_kontrol_relay/mission_kontrol_relay_generator.rb +14 -0
- data/lib/mission_kontrol_relay.rb +6 -0
- data/lib/mission_kontrol_relay/engine.rb +7 -0
- data/lib/mission_kontrol_relay/version.rb +5 -0
- data/mission_kontrol_relay.gemspec +31 -0
- metadata +133 -0
Binary file
|
data/README.md
ADDED
@@ -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
|
+
```
|
data/Rakefile
ADDED
@@ -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
|
File without changes
|
@@ -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,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,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>
|
data/bin/console
ADDED
@@ -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__)
|
data/bin/rails
ADDED
@@ -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'
|