dbhero 1.0.0

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 (73) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +21 -0
  4. data/app/assets/javascripts/dbhero/application.js +45 -0
  5. data/app/assets/javascripts/dbhero/dataclips.js +42 -0
  6. data/app/assets/stylesheets/dbhero/application.css.scss +88 -0
  7. data/app/controllers/dbhero/application_controller.rb +30 -0
  8. data/app/controllers/dbhero/dataclips_controller.rb +84 -0
  9. data/app/helpers/dbhero/application_helper.rb +4 -0
  10. data/app/helpers/dbhero/dataclips_helper.rb +4 -0
  11. data/app/models/dbhero/dataclip.rb +50 -0
  12. data/app/views/dbhero/dataclips/_clip_table.html.slim +38 -0
  13. data/app/views/dbhero/dataclips/_form.html.slim +32 -0
  14. data/app/views/dbhero/dataclips/edit.html.slim +6 -0
  15. data/app/views/dbhero/dataclips/index.html.slim +25 -0
  16. data/app/views/dbhero/dataclips/new.html.slim +2 -0
  17. data/app/views/dbhero/dataclips/show.html.slim +18 -0
  18. data/app/views/layouts/dbhero/application.html.slim +24 -0
  19. data/config/routes.rb +6 -0
  20. data/lib/dbhero.rb +7 -0
  21. data/lib/dbhero/configuration.rb +39 -0
  22. data/lib/dbhero/engine.rb +9 -0
  23. data/lib/dbhero/gdrive_exporter.rb +56 -0
  24. data/lib/dbhero/router_constraint.rb +43 -0
  25. data/lib/dbhero/version.rb +3 -0
  26. data/lib/generators/dbhero/install/install_generator.rb +29 -0
  27. data/lib/generators/dbhero/install/templates/dbhero.rb +26 -0
  28. data/lib/generators/dbhero/install/templates/migrations/create_dbhero_dataclips.rb +17 -0
  29. data/lib/tasks/dbhero_tasks.rake +4 -0
  30. data/spec/controllers/dbhero/dataclips_controller_spec.rb +293 -0
  31. data/spec/dummy/README.rdoc +28 -0
  32. data/spec/dummy/Rakefile +6 -0
  33. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  34. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  35. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  36. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  37. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  38. data/spec/dummy/bin/bundle +3 -0
  39. data/spec/dummy/bin/rails +4 -0
  40. data/spec/dummy/bin/rake +4 -0
  41. data/spec/dummy/config.ru +4 -0
  42. data/spec/dummy/config/application.rb +27 -0
  43. data/spec/dummy/config/boot.rb +5 -0
  44. data/spec/dummy/config/database.yml +85 -0
  45. data/spec/dummy/config/environment.rb +5 -0
  46. data/spec/dummy/config/environments/development.rb +37 -0
  47. data/spec/dummy/config/environments/production.rb +78 -0
  48. data/spec/dummy/config/environments/test.rb +39 -0
  49. data/spec/dummy/config/initializers/assets.rb +8 -0
  50. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  51. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  52. data/spec/dummy/config/initializers/dbhero.rb +26 -0
  53. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  54. data/spec/dummy/config/initializers/inflections.rb +16 -0
  55. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  56. data/spec/dummy/config/initializers/session_store.rb +3 -0
  57. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  58. data/spec/dummy/config/locales/en.yml +23 -0
  59. data/spec/dummy/config/routes.rb +4 -0
  60. data/spec/dummy/config/secrets.yml +22 -0
  61. data/spec/dummy/db/migrate/20150323172444_create_dbhero_dataclips.rb +17 -0
  62. data/spec/dummy/db/schema.rb +32 -0
  63. data/spec/dummy/log/development.log +27 -0
  64. data/spec/dummy/log/test.log +3758 -0
  65. data/spec/dummy/public/404.html +67 -0
  66. data/spec/dummy/public/422.html +67 -0
  67. data/spec/dummy/public/500.html +66 -0
  68. data/spec/dummy/public/favicon.ico +0 -0
  69. data/spec/factories.rb +8 -0
  70. data/spec/models/dbhero/dataclip_spec.rb +119 -0
  71. data/spec/rails_helper.rb +57 -0
  72. data/spec/spec_helper.rb +90 -0
  73. metadata +312 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 04ea97a58981185948410f15d73215eb9caa4c7e
4
+ data.tar.gz: fb418837a8c175fec3dcd489427203da481b3a18
5
+ SHA512:
6
+ metadata.gz: 25d1e1f03d9fbf3af2457c4f2cf3d22e829737804703f010d9f2ca145f38266beea804810e8faf4c39b29ea9cba7ece97eef915c531e125d6fb1676436b76b58
7
+ data.tar.gz: 4d959ad723d1be89cd081f37a3ade030e80685f408afcc26b29680f9ffbbf611d6a809709350df240c0975325ae7522f032e5d5ed6c22ac80d97062b61630aa6
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
9
+
10
+ load 'rails/tasks/engine.rake'
11
+
12
+ Bundler::GemHelper.install_tasks
13
+
14
+ Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
15
+
16
+ require 'rspec/core'
17
+ require 'rspec/core/rake_task'
18
+
19
+ desc "Run all specs in spec directory (excluding plugin specs)"
20
+ RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
21
+ task :default => :spec
@@ -0,0 +1,45 @@
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 vendor/assets/javascripts of plugins, if any, 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/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require jquery
14
+ //= require_tree .
15
+
16
+ $(function(){
17
+
18
+ $('.dropdown-button').dropdown({
19
+ inDuration: 300,
20
+ outDuration: 225,
21
+ constrain_width: false, // Does not change width of dropdown to that of the activator
22
+ hover: false, // Activate on click
23
+ alignment: 'left', // Aligns dropdown to left or right edge (works with constrain_width)
24
+ gutter: 0, // Spacing from edge
25
+ belowOrigin: false // Displays dropdown below the button
26
+ }
27
+ );
28
+
29
+ try {
30
+ var $table = $('table#clip_table')
31
+
32
+ $table.dataTable({
33
+ scrollX: true,
34
+ searching: false,
35
+ lengthChange: false,
36
+ pagingType: 'simple'
37
+ });
38
+
39
+ //$table.floatThead({
40
+ // scrollingTop: 'pageTop',
41
+ //});
42
+ } catch(e) {
43
+ console.log(e);
44
+ }
45
+ });
@@ -0,0 +1,42 @@
1
+ $(function(){
2
+
3
+ startAce = function() {
4
+ var textarea = $('textarea#dataclip_raw_query');
5
+ console.log(textarea.width());
6
+ console.log(textarea.height());
7
+
8
+ var editDiv = $('<div>', {
9
+ id: "ace_editor",
10
+ position: 'absolute',
11
+ width: textarea.width(),
12
+ height: textarea.height(),
13
+ 'class': textarea.attr('class')
14
+ }).insertBefore(textarea);
15
+
16
+ textarea.css('display', 'none');
17
+
18
+ var editor = ace.edit(editDiv[0]);
19
+ editor.renderer.setShowGutter(true);
20
+
21
+ editor.getSession().setUseWrapMode(true);
22
+ editor.getSession().setValue(textarea.val());
23
+ editor.getSession().setTabSize(2);
24
+ editor.getSession().setUseSoftTabs(true);
25
+ editor.getSession().setMode("ace/mode/pgsql");
26
+
27
+ textarea.closest('form').submit(function () {
28
+ textarea.val(editor.getSession().getValue());
29
+ });
30
+
31
+ $('.ace_editor').css({'padding':'0'});
32
+
33
+ editor.setTheme("ace/theme/xcode");
34
+ $(editDiv).css({ 'font-size': '15px' })
35
+ }
36
+
37
+ if($('textarea#dataclip_raw_query').length > 0){
38
+ startAce();
39
+ }
40
+
41
+ });
42
+
@@ -0,0 +1,88 @@
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 vendor/assets/stylesheets of plugins, if any, 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
+ */
16
+ .editor-style {
17
+ height: 300px;
18
+ border-radius: 1px;
19
+ }
20
+
21
+ header {
22
+ border-bottom: 1px solid #cfd8dc;
23
+ .row {
24
+ margin-bottom: 0;
25
+ }
26
+ }
27
+ .dataTables_scrollBody {
28
+ overflow-y: hidden !important;
29
+ }
30
+
31
+ .bottom-bord {
32
+ border-bottom: 1px solid #cfd8dc;
33
+ }
34
+ .clip-title {
35
+ p {
36
+ margin-bottom: 5px;
37
+ }
38
+ }
39
+
40
+ .end {
41
+ margin-bottom: 0 !important;
42
+ }
43
+ header .btn-group {
44
+ margin-top: 15px;
45
+ }
46
+
47
+ header h1 {
48
+ font-size: 22px;
49
+ margin: 0;
50
+ color: #455a64;
51
+ }
52
+
53
+ .style-text-field {
54
+ /* label color */
55
+ .input-field label {
56
+ color: #455a64;
57
+ font-size: 22px;
58
+ }
59
+ /* label focus color */
60
+ .input-field input[type=text]:focus + label,
61
+ .input-field textarea:focus + label,
62
+ {
63
+ color: #90a4ae;
64
+ font-size: 18px;
65
+ }
66
+ /* label underline focus color */
67
+ .input-field input[type=text]:focus,
68
+ .input-field textarea:focus {
69
+ border-bottom: 1px solid #455a64;
70
+ box-shadow: 0 1px 0 0 #455a64;
71
+ }
72
+ /* valid color */
73
+ .input-field input[type=text].valid,
74
+ .input-field textarea.valid {
75
+ border-bottom: 1px solid #455a64;
76
+ box-shadow: 0 1px 0 0 #455a64;
77
+ }
78
+ /* invalid color */
79
+ .input-field input[type=text].invalid,
80
+ .input-field textarea.invalid {
81
+ border-bottom: 1px solid #455a64;
82
+ box-shadow: 0 1px 0 0 #455a64;
83
+ }
84
+ /* icon prefix focus color */
85
+ .input-field .prefix.active {
86
+ color: #455a64;
87
+ }
88
+ }
@@ -0,0 +1,30 @@
1
+ module Dbhero
2
+ class ApplicationController < ActionController::Base
3
+ def check_auth
4
+ if Dbhero.authenticate
5
+ unless _current_user && call_custom_auth
6
+ raise ActionController::RoutingError.new('Forbidden')
7
+ end
8
+ end
9
+ end
10
+
11
+ def user_representation
12
+ _current_user.send(Dbhero.user_representation) if _current_user
13
+ end
14
+
15
+ def _current_user
16
+ if Dbhero.current_user_method.present?
17
+ send(Dbhero.current_user_method)
18
+ end
19
+ end
20
+
21
+ def call_custom_auth
22
+ cond = Dbhero.custom_user_auth_condition
23
+ if cond.present? && cond.is_a?(Proc)
24
+ cond.call(_current_user)
25
+ else
26
+ true
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,84 @@
1
+ require_dependency "dbhero/application_controller"
2
+ require_dependency "responders"
3
+ require_dependency "google/api_client"
4
+ require_dependency "google_drive"
5
+
6
+ module Dbhero
7
+ class DataclipsController < ApplicationController
8
+ before_action :check_auth, except: [:show]
9
+ before_action :set_dataclip, only: [:show, :edit, :update, :destroy]
10
+ has_scope :search
11
+ respond_to :html, :csv
12
+
13
+ def index
14
+ @dataclips = apply_scopes(Dataclip.ordered)
15
+ end
16
+
17
+ def drive
18
+ token = session.delete(:clip_token)
19
+
20
+ google_client.fetch_access_token!(params[:code])
21
+ google_client.options[:import_data_url] = dataclip_url(id: token, format: 'csv')
22
+ google_client.export_clip_by_token token
23
+
24
+ redirect_to dataclip_path(google_client.dataclip, gdrive_file_url: google_client.exported_file_url)
25
+ end
26
+
27
+ def show
28
+ check_auth if @dataclip.private?
29
+
30
+ @dataclip.query_result
31
+
32
+ respond_to do |format|
33
+ format.html do
34
+ if params[:export_gdrive]
35
+ session[:clip_token] = @dataclip.token
36
+ redirect_to google_client.auth.authorization_uri.to_s
37
+ end
38
+ end
39
+
40
+ format.csv do
41
+ send_data @dataclip.csv_string, type: Mime::CSV, disposition: "attachment; filename=#{@dataclip.token}.csv"
42
+ end
43
+ end
44
+ end
45
+
46
+ def new
47
+ @dataclip = Dataclip.new
48
+ end
49
+
50
+ def edit
51
+ @dataclip.query_result
52
+ end
53
+
54
+ def create
55
+ @dataclip = Dataclip.create(dataclip_params.merge(user: user_representation))
56
+ respond_with @dataclip, location: edit_dataclip_path(@dataclip),notice: 'Dataclip was successfully created.'
57
+ end
58
+
59
+ def update
60
+ @dataclip.update(dataclip_params)
61
+ respond_with @dataclip, location: edit_dataclip_path(@dataclip), notice: 'Dataclip was successfully updated.'
62
+ end
63
+
64
+ def destroy
65
+ @dataclip.destroy
66
+ redirect_to dataclips_url, notice: 'Dataclip was successfully destroyed.'
67
+ end
68
+
69
+ private
70
+ # Use callbacks to share common setup or constraints between actions.
71
+ def set_dataclip
72
+ @dataclip = Dataclip.find_by_token(params[:id])
73
+ end
74
+
75
+ # Only allow a trusted parameter "white list" through.
76
+ def dataclip_params
77
+ params.require(:dataclip).permit(:description, :raw_query, :private)
78
+ end
79
+
80
+ def google_client
81
+ @g_client ||= Dbhero::GdriveExporter.new(redirect_uri: drive_dataclips_url)
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,4 @@
1
+ module Dbhero
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Dbhero
2
+ module DataclipsHelper
3
+ end
4
+ end
@@ -0,0 +1,50 @@
1
+ module Dbhero
2
+ class Dataclip < ActiveRecord::Base
3
+ before_create :set_token
4
+
5
+ scope :ordered, -> { order(updated_at: :desc) }
6
+ scope :search, ->(term) { where(arel_table[:description].matches("%#{term}%")) }
7
+
8
+ validates :description, :raw_query, presence: true
9
+ attr_reader :q_result
10
+
11
+ def set_token
12
+ self.token = SecureRandom.uuid unless self.token
13
+ end
14
+
15
+ def to_param
16
+ self.token
17
+ end
18
+
19
+ def title
20
+ description.split("\n")[0]
21
+ end
22
+
23
+ def description_without_title
24
+ description.split("\n")[1..-1].join("\n")
25
+ end
26
+
27
+ def total_rows
28
+ @total_rows ||= @q_result.rows.length
29
+ end
30
+
31
+ def query_result
32
+ Dataclip.transaction do
33
+ begin
34
+ @q_result ||= ActiveRecord::Base.connection.select_all(self.raw_query)
35
+ rescue => e
36
+ self.errors.add(:base, e.message)
37
+ end
38
+ raise ActiveRecord::Rollback
39
+ end
40
+ end
41
+
42
+ def csv_string
43
+ query_result
44
+ csv = ''
45
+ csv << "#{@q_result.columns.join(',')}\n"
46
+ @q_result.rows.each { |row| csv << "#{row.join(',')}\n" }
47
+ csv
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,38 @@
1
+ = stylesheet_link_tag "//cdn.datatables.net/1.10.5/css/jquery.dataTables.min.css"
2
+ = javascript_include_tag "//cdn.datatables.net/1.10.5/js/jquery.dataTables.min.js"
3
+ = javascript_include_tag "//cdnjs.cloudflare.com/ajax/libs/floatthead/1.2.10/jquery.floatThead.min.js"
4
+
5
+ - show_public_link = defined?(show_public_link) ? show_public_link : false
6
+ .section
7
+ .row
8
+ .col.s6.style-text-field
9
+ - if show_public_link
10
+ .input-field
11
+ i.tiny.mdi-social-share.prefix
12
+ input#icon_prefix.validate type="text" value=dataclip_url(@dataclip)
13
+ label for="icon_prefix"
14
+ strong PUBLIC URL
15
+ - else
16
+ p style="margin-top: 40px; margin-bottom: 0;"
17
+ | total rows returned&nbsp;
18
+ strong= @dataclip.total_rows
19
+ .col.s6.right-align style="margin-top: 25px;"
20
+ a class='dropdown-button btn' href='#' data-activates='export-drop' Export
21
+
22
+ ul id='export-drop' class='dropdown-content'
23
+ li
24
+ = link_to 'csv', dataclip_path(@dataclip, format: 'csv')
25
+ li
26
+ = link_to 'google drive', dataclip_path(@dataclip, export_gdrive: true)
27
+
28
+ .col.s12 style="overflow: auto;"
29
+ table#clip_table.cell-border.striped data-page-length='300'
30
+ thead.grey.lighten-2
31
+ tr
32
+ - @dataclip.q_result.columns.each do |column|
33
+ th= column
34
+ tbody
35
+ - @dataclip.q_result.rows.each do |row|
36
+ tr
37
+ - row.each do |value|
38
+ td style="min-width: 200px;"= value