tennpipes-su 3.6.6

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 (192) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.rdoc +70 -0
  4. data/Rakefile +22 -0
  5. data/lib/tennpipes-su.rb +35 -0
  6. data/lib/tennpipes-su/access_control.rb +191 -0
  7. data/lib/tennpipes-su/bootstrap-less/alerts.less +67 -0
  8. data/lib/tennpipes-su/bootstrap-less/badges.less +55 -0
  9. data/lib/tennpipes-su/bootstrap-less/bootstrap.less +49 -0
  10. data/lib/tennpipes-su/bootstrap-less/breadcrumbs.less +26 -0
  11. data/lib/tennpipes-su/bootstrap-less/button-groups.less +226 -0
  12. data/lib/tennpipes-su/bootstrap-less/buttons.less +155 -0
  13. data/lib/tennpipes-su/bootstrap-less/carousel.less +232 -0
  14. data/lib/tennpipes-su/bootstrap-less/close.less +33 -0
  15. data/lib/tennpipes-su/bootstrap-less/code.less +63 -0
  16. data/lib/tennpipes-su/bootstrap-less/component-animations.less +29 -0
  17. data/lib/tennpipes-su/bootstrap-less/dropdowns.less +213 -0
  18. data/lib/tennpipes-su/bootstrap-less/font-awesome/bordered-pulled.less +16 -0
  19. data/lib/tennpipes-su/bootstrap-less/font-awesome/core.less +12 -0
  20. data/lib/tennpipes-su/bootstrap-less/font-awesome/fixed-width.less +6 -0
  21. data/lib/tennpipes-su/bootstrap-less/font-awesome/font-awesome.less +17 -0
  22. data/lib/tennpipes-su/bootstrap-less/font-awesome/icons.less +412 -0
  23. data/lib/tennpipes-su/bootstrap-less/font-awesome/larger.less +13 -0
  24. data/lib/tennpipes-su/bootstrap-less/font-awesome/list.less +19 -0
  25. data/lib/tennpipes-su/bootstrap-less/font-awesome/mixins.less +20 -0
  26. data/lib/tennpipes-su/bootstrap-less/font-awesome/path.less +14 -0
  27. data/lib/tennpipes-su/bootstrap-less/font-awesome/rotated-flipped.less +9 -0
  28. data/lib/tennpipes-su/bootstrap-less/font-awesome/spinning.less +30 -0
  29. data/lib/tennpipes-su/bootstrap-less/font-awesome/stacked.less +20 -0
  30. data/lib/tennpipes-su/bootstrap-less/font-awesome/variables.less +381 -0
  31. data/lib/tennpipes-su/bootstrap-less/forms.less +419 -0
  32. data/lib/tennpipes-su/bootstrap-less/glyphicons.less +233 -0
  33. data/lib/tennpipes-su/bootstrap-less/grid.less +100 -0
  34. data/lib/tennpipes-su/bootstrap-less/input-groups.less +157 -0
  35. data/lib/tennpipes-su/bootstrap-less/jumbotron.less +44 -0
  36. data/lib/tennpipes-su/bootstrap-less/labels.less +64 -0
  37. data/lib/tennpipes-su/bootstrap-less/list-group.less +110 -0
  38. data/lib/tennpipes-su/bootstrap-less/media.less +56 -0
  39. data/lib/tennpipes-su/bootstrap-less/mixins.less +926 -0
  40. data/lib/tennpipes-su/bootstrap-less/modals.less +138 -0
  41. data/lib/tennpipes-su/bootstrap-less/navbar.less +616 -0
  42. data/lib/tennpipes-su/bootstrap-less/navs.less +242 -0
  43. data/lib/tennpipes-su/bootstrap-less/normalize.less +423 -0
  44. data/lib/tennpipes-su/bootstrap-less/pager.less +55 -0
  45. data/lib/tennpipes-su/bootstrap-less/pagination.less +88 -0
  46. data/lib/tennpipes-su/bootstrap-less/panels.less +230 -0
  47. data/lib/tennpipes-su/bootstrap-less/popovers.less +133 -0
  48. data/lib/tennpipes-su/bootstrap-less/print.less +101 -0
  49. data/lib/tennpipes-su/bootstrap-less/progress-bars.less +80 -0
  50. data/lib/tennpipes-su/bootstrap-less/responsive-utilities.less +93 -0
  51. data/lib/tennpipes-su/bootstrap-less/scaffolding.less +134 -0
  52. data/lib/tennpipes-su/bootstrap-less/tables.less +233 -0
  53. data/lib/tennpipes-su/bootstrap-less/tennpipes-su.less +18 -0
  54. data/lib/tennpipes-su/bootstrap-less/theme.less +247 -0
  55. data/lib/tennpipes-su/bootstrap-less/thumbnails.less +36 -0
  56. data/lib/tennpipes-su/bootstrap-less/tooltip.less +95 -0
  57. data/lib/tennpipes-su/bootstrap-less/type.less +296 -0
  58. data/lib/tennpipes-su/bootstrap-less/utilities.less +56 -0
  59. data/lib/tennpipes-su/bootstrap-less/variables.less +827 -0
  60. data/lib/tennpipes-su/bootstrap-less/wells.less +29 -0
  61. data/lib/tennpipes-su/generators/actions.rb +78 -0
  62. data/lib/tennpipes-su/generators/admin_app.rb +169 -0
  63. data/lib/tennpipes-su/generators/admin_page.rb +68 -0
  64. data/lib/tennpipes-su/generators/orm.rb +172 -0
  65. data/lib/tennpipes-su/generators/templates/account/activerecord.rb.tt +41 -0
  66. data/lib/tennpipes-su/generators/templates/account/couchrest.rb.tt +67 -0
  67. data/lib/tennpipes-su/generators/templates/account/datamapper.rb.tt +56 -0
  68. data/lib/tennpipes-su/generators/templates/account/dynamoid.rb.tt +55 -0
  69. data/lib/tennpipes-su/generators/templates/account/minirecord.rb.tt +44 -0
  70. data/lib/tennpipes-su/generators/templates/account/mongoid.rb.tt +54 -0
  71. data/lib/tennpipes-su/generators/templates/account/mongomapper.rb.tt +47 -0
  72. data/lib/tennpipes-su/generators/templates/account/ohm.rb.tt +70 -0
  73. data/lib/tennpipes-su/generators/templates/account/seeds.rb.tt +29 -0
  74. data/lib/tennpipes-su/generators/templates/account/sequel.rb.tt +53 -0
  75. data/lib/tennpipes-su/generators/templates/app.rb.tt +42 -0
  76. data/lib/tennpipes-su/generators/templates/app/controllers/base.rb.tt +5 -0
  77. data/lib/tennpipes-su/generators/templates/app/controllers/sessions.rb.tt +29 -0
  78. data/lib/tennpipes-su/generators/templates/assets/images/favicon.ico +0 -0
  79. data/lib/tennpipes-su/generators/templates/assets/images/font/FontAwesome.otf +0 -0
  80. data/lib/tennpipes-su/generators/templates/assets/images/font/fontawesome-webfont.eot +0 -0
  81. data/lib/tennpipes-su/generators/templates/assets/images/font/fontawesome-webfont.svg +414 -0
  82. data/lib/tennpipes-su/generators/templates/assets/images/font/fontawesome-webfont.ttf +0 -0
  83. data/lib/tennpipes-su/generators/templates/assets/images/font/fontawesome-webfont.woff +0 -0
  84. data/lib/tennpipes-su/generators/templates/assets/images/logo.png +0 -0
  85. data/lib/tennpipes-su/generators/templates/assets/javascripts/application.js +118 -0
  86. data/lib/tennpipes-su/generators/templates/assets/javascripts/bootstrap/affix.js +137 -0
  87. data/lib/tennpipes-su/generators/templates/assets/javascripts/bootstrap/alert.js +88 -0
  88. data/lib/tennpipes-su/generators/templates/assets/javascripts/bootstrap/bootstrap.min.js +6 -0
  89. data/lib/tennpipes-su/generators/templates/assets/javascripts/bootstrap/button.js +107 -0
  90. data/lib/tennpipes-su/generators/templates/assets/javascripts/bootstrap/carousel.js +205 -0
  91. data/lib/tennpipes-su/generators/templates/assets/javascripts/bootstrap/collapse.js +170 -0
  92. data/lib/tennpipes-su/generators/templates/assets/javascripts/bootstrap/dropdown.js +147 -0
  93. data/lib/tennpipes-su/generators/templates/assets/javascripts/bootstrap/modal.js +243 -0
  94. data/lib/tennpipes-su/generators/templates/assets/javascripts/bootstrap/popover.js +110 -0
  95. data/lib/tennpipes-su/generators/templates/assets/javascripts/bootstrap/scrollspy.js +153 -0
  96. data/lib/tennpipes-su/generators/templates/assets/javascripts/bootstrap/tab.js +125 -0
  97. data/lib/tennpipes-su/generators/templates/assets/javascripts/bootstrap/tooltip.js +399 -0
  98. data/lib/tennpipes-su/generators/templates/assets/javascripts/bootstrap/transition.js +48 -0
  99. data/lib/tennpipes-su/generators/templates/assets/javascripts/jquery-1.11.0.min.js +4 -0
  100. data/lib/tennpipes-su/generators/templates/assets/stylesheets/application.css +353 -0
  101. data/lib/tennpipes-su/generators/templates/assets/stylesheets/bootstrap.css +4 -0
  102. data/lib/tennpipes-su/generators/templates/assets/stylesheets/fonts/FontAwesome.otf +0 -0
  103. data/lib/tennpipes-su/generators/templates/assets/stylesheets/fonts/fontawesome-webfont.eot +0 -0
  104. data/lib/tennpipes-su/generators/templates/assets/stylesheets/fonts/fontawesome-webfont.svg +414 -0
  105. data/lib/tennpipes-su/generators/templates/assets/stylesheets/fonts/fontawesome-webfont.ttf +0 -0
  106. data/lib/tennpipes-su/generators/templates/assets/stylesheets/fonts/fontawesome-webfont.woff +0 -0
  107. data/lib/tennpipes-su/generators/templates/erb/app/base/index.erb.tt +15 -0
  108. data/lib/tennpipes-su/generators/templates/erb/app/errors/403.erb.tt +3 -0
  109. data/lib/tennpipes-su/generators/templates/erb/app/errors/404.erb.tt +3 -0
  110. data/lib/tennpipes-su/generators/templates/erb/app/errors/500.erb.tt +3 -0
  111. data/lib/tennpipes-su/generators/templates/erb/app/layouts/application.erb.tt +64 -0
  112. data/lib/tennpipes-su/generators/templates/erb/app/layouts/error.erb.tt +23 -0
  113. data/lib/tennpipes-su/generators/templates/erb/app/sessions/new.erb.tt +44 -0
  114. data/lib/tennpipes-su/generators/templates/erb/page/_form.erb.tt +18 -0
  115. data/lib/tennpipes-su/generators/templates/erb/page/edit.erb.tt +10 -0
  116. data/lib/tennpipes-su/generators/templates/erb/page/index.erb.tt +81 -0
  117. data/lib/tennpipes-su/generators/templates/erb/page/new.erb.tt +9 -0
  118. data/lib/tennpipes-su/generators/templates/haml/app/base/index.haml.tt +12 -0
  119. data/lib/tennpipes-su/generators/templates/haml/app/errors/403.haml.tt +3 -0
  120. data/lib/tennpipes-su/generators/templates/haml/app/errors/404.haml.tt +3 -0
  121. data/lib/tennpipes-su/generators/templates/haml/app/errors/500.haml.tt +3 -0
  122. data/lib/tennpipes-su/generators/templates/haml/app/layouts/application.haml.tt +49 -0
  123. data/lib/tennpipes-su/generators/templates/haml/app/layouts/error.haml.tt +18 -0
  124. data/lib/tennpipes-su/generators/templates/haml/app/sessions/new.haml.tt +38 -0
  125. data/lib/tennpipes-su/generators/templates/haml/page/_form.haml.tt +16 -0
  126. data/lib/tennpipes-su/generators/templates/haml/page/edit.haml.tt +8 -0
  127. data/lib/tennpipes-su/generators/templates/haml/page/index.haml.tt +58 -0
  128. data/lib/tennpipes-su/generators/templates/haml/page/new.haml.tt +7 -0
  129. data/lib/tennpipes-su/generators/templates/page/controller.rb.tt +92 -0
  130. data/lib/tennpipes-su/generators/templates/slim/app/base/index.slim.tt +12 -0
  131. data/lib/tennpipes-su/generators/templates/slim/app/errors/403.slim.tt +3 -0
  132. data/lib/tennpipes-su/generators/templates/slim/app/errors/404.slim.tt +3 -0
  133. data/lib/tennpipes-su/generators/templates/slim/app/errors/500.slim.tt +3 -0
  134. data/lib/tennpipes-su/generators/templates/slim/app/layouts/application.slim.tt +48 -0
  135. data/lib/tennpipes-su/generators/templates/slim/app/layouts/error.slim.tt +19 -0
  136. data/lib/tennpipes-su/generators/templates/slim/app/sessions/new.slim.tt +37 -0
  137. data/lib/tennpipes-su/generators/templates/slim/page/_form.slim.tt +16 -0
  138. data/lib/tennpipes-su/generators/templates/slim/page/edit.slim.tt +8 -0
  139. data/lib/tennpipes-su/generators/templates/slim/page/index.slim.tt +56 -0
  140. data/lib/tennpipes-su/generators/templates/slim/page/new.slim.tt +7 -0
  141. data/lib/tennpipes-su/helpers/authentication_helpers.rb +108 -0
  142. data/lib/tennpipes-su/helpers/view_helpers.rb +87 -0
  143. data/lib/tennpipes-su/locale/admin/cs.yml +56 -0
  144. data/lib/tennpipes-su/locale/admin/da.yml +56 -0
  145. data/lib/tennpipes-su/locale/admin/de.yml +56 -0
  146. data/lib/tennpipes-su/locale/admin/en.yml +56 -0
  147. data/lib/tennpipes-su/locale/admin/es.yml +56 -0
  148. data/lib/tennpipes-su/locale/admin/fr.yml +56 -0
  149. data/lib/tennpipes-su/locale/admin/hu.yml +56 -0
  150. data/lib/tennpipes-su/locale/admin/it.yml +56 -0
  151. data/lib/tennpipes-su/locale/admin/ja.yml +57 -0
  152. data/lib/tennpipes-su/locale/admin/lv.yml +56 -0
  153. data/lib/tennpipes-su/locale/admin/nl.yml +56 -0
  154. data/lib/tennpipes-su/locale/admin/no.yml +56 -0
  155. data/lib/tennpipes-su/locale/admin/pl.yml +56 -0
  156. data/lib/tennpipes-su/locale/admin/pt_br.yml +56 -0
  157. data/lib/tennpipes-su/locale/admin/ro.yml +56 -0
  158. data/lib/tennpipes-su/locale/admin/ru.yml +57 -0
  159. data/lib/tennpipes-su/locale/admin/sv.yml +56 -0
  160. data/lib/tennpipes-su/locale/admin/tr.yml +56 -0
  161. data/lib/tennpipes-su/locale/admin/uk.yml +56 -0
  162. data/lib/tennpipes-su/locale/admin/zh_cn.yml +56 -0
  163. data/lib/tennpipes-su/locale/admin/zh_tw.yml +56 -0
  164. data/lib/tennpipes-su/locale/orm/cs.yml +12 -0
  165. data/lib/tennpipes-su/locale/orm/da.yml +12 -0
  166. data/lib/tennpipes-su/locale/orm/de.yml +12 -0
  167. data/lib/tennpipes-su/locale/orm/en.yml +12 -0
  168. data/lib/tennpipes-su/locale/orm/es.yml +12 -0
  169. data/lib/tennpipes-su/locale/orm/fr.yml +12 -0
  170. data/lib/tennpipes-su/locale/orm/hu.yml +12 -0
  171. data/lib/tennpipes-su/locale/orm/it.yml +12 -0
  172. data/lib/tennpipes-su/locale/orm/ja.yml +12 -0
  173. data/lib/tennpipes-su/locale/orm/lv.yml +12 -0
  174. data/lib/tennpipes-su/locale/orm/nl.yml +12 -0
  175. data/lib/tennpipes-su/locale/orm/no.yml +12 -0
  176. data/lib/tennpipes-su/locale/orm/pl.yml +38 -0
  177. data/lib/tennpipes-su/locale/orm/pt_br.yml +12 -0
  178. data/lib/tennpipes-su/locale/orm/ro.yml +12 -0
  179. data/lib/tennpipes-su/locale/orm/ru.yml +12 -0
  180. data/lib/tennpipes-su/locale/orm/sv.yml +12 -0
  181. data/lib/tennpipes-su/locale/orm/tr.yml +12 -0
  182. data/lib/tennpipes-su/locale/orm/uk.yml +12 -0
  183. data/lib/tennpipes-su/locale/orm/zh_cn.yml +12 -0
  184. data/lib/tennpipes-su/locale/orm/zh_tw.yml +12 -0
  185. data/test/fixtures/sequel.rb +72 -0
  186. data/test/generators/test_account_model_generator.rb +108 -0
  187. data/test/generators/test_admin_app_generator.rb +218 -0
  188. data/test/generators/test_admin_page_generator.rb +140 -0
  189. data/test/helper.rb +47 -0
  190. data/test/test_admin_application.rb +271 -0
  191. data/test/test_locale.rb +25 -0
  192. metadata +298 -0
@@ -0,0 +1,29 @@
1
+ //
2
+ // Wells
3
+ // --------------------------------------------------
4
+
5
+
6
+ // Base class
7
+ .well {
8
+ min-height: 20px;
9
+ padding: 19px;
10
+ margin-bottom: 20px;
11
+ background-color: @well-bg;
12
+ border: 1px solid @well-border;
13
+ border-radius: @border-radius-base;
14
+ .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));
15
+ blockquote {
16
+ border-color: #ddd;
17
+ border-color: rgba(0,0,0,.15);
18
+ }
19
+ }
20
+
21
+ // Sizes
22
+ .well-lg {
23
+ padding: 24px;
24
+ border-radius: @border-radius-large;
25
+ }
26
+ .well-sm {
27
+ padding: 9px;
28
+ border-radius: @border-radius-small;
29
+ }
@@ -0,0 +1,78 @@
1
+ module Tennpipes
2
+ module Generators
3
+ ##
4
+ # Generator action definitions for the admin panel.
5
+ #
6
+ module Admin
7
+ ##
8
+ # Important tasks for setting up or configuring the admin application.
9
+ #
10
+ module Actions
11
+ ##
12
+ # Tell us which orm we are using.
13
+ #
14
+ def orm
15
+ fetch_component_choice(:orm).to_sym rescue :activerecord
16
+ end
17
+ alias :adapter :orm
18
+
19
+ ##
20
+ # Tell us which rendering engine you are using.
21
+ #
22
+ def ext
23
+ fetch_component_choice(:admin_renderer).to_sym rescue :haml
24
+ end
25
+
26
+ ##
27
+ # Tell us for now which orm we support
28
+ #
29
+ def supported_orm
30
+ [:minirecord, :datamapper, :activerecord, :mongomapper, :mongoid, :couchrest, :sequel, :ohm, :dynamoid]
31
+ end
32
+
33
+ ##
34
+ # Tell us for now which rendering engine we support.
35
+ #
36
+ def supported_ext
37
+ [:haml, :slim, :erb]
38
+ end
39
+
40
+ ##
41
+ # Add access_control permission in our app.rb.
42
+ #
43
+ def add_project_module(controller)
44
+ permission = " role.project_module :#{controller}, '/#{controller}'\n"
45
+ inject_into_file destination_root(@admin_path+'/app.rb'), permission, :after => "access_control.roles_for :admin do |role|\n"
46
+ end
47
+
48
+ ##
49
+ # Remove from access_control permissions.
50
+ #
51
+ def remove_project_module(controller)
52
+ path = destination_root(@admin_path+'/app.rb')
53
+ say_status :replace, @admin_path+'/app.rb', :red
54
+ content = File.binread(path)
55
+ content.gsub!(/^\s+role\.project_module :#{controller}, '\/#{controller}'\n/, '')
56
+ File.open(path, 'wb') { |f| f.write content }
57
+ end
58
+
59
+ ##
60
+ # Returns the app_name for the application at root.
61
+ #
62
+ # @param [String] app
63
+ # folder name of application.
64
+ #
65
+ # @return [String] module name for application.
66
+ #
67
+ # @example
68
+ # fetch_app_name('subapp')
69
+ #
70
+ # @api public
71
+ def fetch_app_name(app='app')
72
+ app_path = destination_root(app, 'app.rb')
73
+ @app_name ||= File.read(app_path).scan(/module\s(.*?)\n/).flatten[0]
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,169 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Tennpipes
3
+ module Generators
4
+ ##
5
+ # Defines the generator for creating a new admin app.
6
+ #
7
+ class AdminApp < Thor::Group
8
+
9
+ # Add this generator to our tennpipes-init
10
+ Tennpipes::Generators.add_generator(:admin, self)
11
+
12
+ # Define the source template root
13
+ def self.source_root; File.expand_path(File.dirname(__FILE__)); end
14
+ # Defines the "banner" text for the CLI.
15
+ def self.banner; "tennpipes-init admin"; end
16
+
17
+ # Include related modules.
18
+ include Thor::Actions
19
+ include Tennpipes::Generators::Actions
20
+ include Tennpipes::Generators::Admin::Actions
21
+
22
+ # Look for custom template files in a generators folder under the project root.
23
+ def source_paths
24
+ if File.exist? destination_root('generators', 'templates')
25
+ ["#{destination_root('generators')}", File.expand_path(File.dirname(__FILE__))]
26
+ else
27
+ [File.expand_path(File.dirname(__FILE__))]
28
+ end
29
+ end
30
+
31
+ desc "Description:\n\n\ttennpipes-init admin generates a new Tennpipes Admin application"
32
+
33
+ class_option :skip_migration, :aliases => "-s", :default => false, :type => :boolean
34
+ # class_option :models_path, :desc => 'The models destination path', :default => '.', :type => :string
35
+ class_option :root, :desc => "The root destination", :aliases => '-r', :default => ".", :type => :string
36
+ class_option :destroy, :aliases => '-d', :default => false, :type => :boolean
37
+ class_option :renderer, :aliases => '-e', :desc => "Rendering engine (erb, haml, slim)", :type => :string
38
+ class_option :admin_model, :aliases => '-m', :desc => "The name of model for access controlling", :default => 'Account', :type => :string
39
+ class_option :admin_name, :aliases => '-a', :desc => 'The admin application name and path', :default => 'admin', :type => :string
40
+
41
+ # Copies over the Tennpipes base admin application.
42
+ def create_admin
43
+ self.destination_root = options[:root]
44
+ if in_app_root?
45
+ unless supported_orm.include?(orm)
46
+ say "<= At the moment, Tennpipes only supports #{supported_orm.join(" or ")}. Sorry!", :yellow
47
+ raise SystemExit
48
+ end
49
+
50
+ tmp_ext = options[:renderer] || fetch_component_choice(:renderer)
51
+ unless supported_ext.include?(tmp_ext.to_sym)
52
+ say "<= Your are using '#{tmp_ext}' and for admin we only support '#{supported_ext.join(', ')}'. Please use -e haml or -e erb or -e slim", :yellow
53
+ raise SystemExit
54
+ end
55
+
56
+ # Get the app's namespace.
57
+ @app_name = fetch_app_name
58
+
59
+ # setup admin app name
60
+ @admin_name = options[:admin_name].classify
61
+ @admin_path = options[:admin_name].underscore
62
+
63
+ store_component_choice(:admin_renderer, tmp_ext)
64
+
65
+ self.behavior = :revoke if options[:destroy]
66
+
67
+ empty_directory destination_root(@admin_path)
68
+
69
+ # Setup Admin Model
70
+ @model_name = options[:admin_model].classify
71
+ @model_singular = @model_name.underscore
72
+ @model_plural = @model_singular.pluralize
73
+
74
+ directory "templates/app", destination_root(@admin_path)
75
+ directory "templates/assets", destination_root("public", @admin_path)
76
+ template "templates/app.rb.tt", destination_root(@admin_path + "/app.rb")
77
+ inject_into_file destination_root('config/apps.rb'), "\nTennpipes.mount(\"#{@app_name}::#{@admin_name}\", :app_file => Tennpipes.root('#{@admin_path}/app.rb')).to(\"/#{@admin_path}\")\n", :before => /^Tennpipes.mount.*\.to\('\/'\)$/
78
+ unless options[:destroy]
79
+ insert_middleware 'ActiveRecord::ConnectionAdapters::ConnectionManagement', @admin_path if [:minirecord, :activerecord].include?(orm)
80
+ end
81
+
82
+ params = [
83
+ @model_singular, "name:string", "surname:string", "email:string", "crypted_password:string", "role:string",
84
+ "-a=#{options[:models_path]}",
85
+ "-r=#{options[:root]}"
86
+ ]
87
+ params << "-s" if options[:skip_migration]
88
+ params << "-d" if options[:destroy]
89
+
90
+ Tennpipes::Generators::Model.start(params)
91
+ column = Struct.new(:name, :type)
92
+ columns = [:id, :name, :surname, :email].map { |col| column.new(col) }
93
+ column_fields = [
94
+ { :name => :name, :field_type => :text_field },
95
+ { :name => :surname, :field_type => :text_field },
96
+ { :name => :email, :field_type => :text_field },
97
+ { :name => :password, :field_type => :password_field },
98
+ { :name => :password_confirmation, :field_type => :password_field },
99
+ { :name => :role, :field_type => :text_field }
100
+ ]
101
+
102
+ unless options[:destroy]
103
+ admin_app = Tennpipes::Generators::AdminPage.new([@model_singular], :root => options[:root], :destroy => options[:destroy], :admin_model => @model_singular, :admin_name => @admin_name)
104
+ admin_app.default_orm = Tennpipes::Admin::Generators::Orm.new(@model_singular, orm, columns, column_fields)
105
+ admin_app.invoke_all
106
+ end
107
+
108
+ # TODO See this, there's something wrong it's not being applied properly or something because test_account_model_generator last test fails.
109
+ template "templates/account/#{orm}.rb.tt", destination_root("models", "#{@model_singular}.rb"), :force => true
110
+
111
+ if File.exist?(destination_root("db/seeds.rb"))
112
+ run "mv #{destination_root('db/seeds.rb')} #{destination_root('db/seeds.old')}"
113
+ end
114
+ template "templates/account/seeds.rb.tt", destination_root("db/seeds.rb")
115
+
116
+ empty_directory destination_root(@admin_path+"/controllers")
117
+ empty_directory destination_root(@admin_path+"/views")
118
+ empty_directory destination_root(@admin_path+"/views/base")
119
+ empty_directory destination_root(@admin_path+"/views/layouts")
120
+ empty_directory destination_root(@admin_path+"/views/sessions")
121
+ empty_directory destination_root(@admin_path+"/views/errors")
122
+
123
+ template "templates/#{ext}/app/base/index.#{ext}.tt", destination_root(@admin_path+"/views/base/index.#{ext}")
124
+ template "templates/#{ext}/app/layouts/application.#{ext}.tt", destination_root(@admin_path+"/views/layouts/application.#{ext}")
125
+ template "templates/#{ext}/app/layouts/error.#{ext}.tt", destination_root(@admin_path+"/views/layouts/error.#{ext}")
126
+ template "templates/#{ext}/app/sessions/new.#{ext}.tt", destination_root(@admin_path+"/views/sessions/new.#{ext}")
127
+ # Custom error.
128
+ template "templates/#{ext}/app/errors/403.#{ext}.tt", destination_root(@admin_path+"/views/errors/403.#{ext}")
129
+ template "templates/#{ext}/app/errors/404.#{ext}.tt", destination_root(@admin_path+"/views/errors/404.#{ext}")
130
+ template "templates/#{ext}/app/errors/500.#{ext}.tt", destination_root(@admin_path+"/views/errors/500.#{ext}")
131
+
132
+ unless options[:destroy]
133
+ add_project_module @model_plural
134
+ require_dependencies('bcrypt')
135
+ end
136
+
137
+ # A nicer select box.
138
+ # TODO FIXME This doesn't make much sense in here. Review.
139
+ # gsub_file destination_root("admin/views/#{@model_plural}/_form.#{ext}"), "f.text_field :role, :class => :text_field", "f.select :role, :options => access_control.roles"
140
+
141
+ # Destroy account only if not logged in.
142
+ gsub_file destination_root(@admin_path+"/controllers/#{@model_plural}.rb"), "if #{@model_singular}.destroy", "if #{@model_singular} != current_account && #{@model_singular}.destroy"
143
+ return if self.behavior == :revoke
144
+
145
+ instructions = []
146
+ instructions << "Run 'bundle'"
147
+ if [:activerecord, :datamapper, :sequel].include?(orm)
148
+ instructions << "Run 'bundle exec rake db:create' if you have not created a database yet"
149
+ instructions << "Run 'bundle exec rake db:migrate'"
150
+ end
151
+ instructions << "Now repeat after me... 'ohm mani padme hum', 'ohm mani padme hum'... :)" if orm == :ohm
152
+ instructions << "Run 'bundle exec rake db:seed'"
153
+ instructions << "Visit the admin panel in the browser at '/#{@admin_path}'"
154
+ instructions.map! { |i| " #{instructions.index(i)+1}) #{i}" }
155
+
156
+ say
157
+ say "="*65, :green
158
+ say "The admin panel has been mounted! Next, follow these steps:", :green
159
+ say "="*65, :green
160
+ say instructions.join("\n")
161
+ say "="*65, :green
162
+ say
163
+ else
164
+ say "You are not at the root of a Tennpipes application! (config/boot.rb not found)"
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,68 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Tennpipes
3
+ module Generators
4
+ ##
5
+ # Defines the generator for creating a new admin page.
6
+ #
7
+ class AdminPage < Thor::Group
8
+ attr_accessor :default_orm
9
+
10
+ # Add this generator to our tennpipes-init.
11
+ Tennpipes::Generators.add_generator(:admin_page, self)
12
+
13
+ # Define the source template root.
14
+ def self.source_root; File.expand_path(File.dirname(__FILE__)); end
15
+ # Defines the "banner" text for the CLI.
16
+ def self.banner; "tennpipes-init admin_page [model]"; end
17
+
18
+ # Include related modules.
19
+ include Thor::Actions
20
+ include Tennpipes::Generators::Actions
21
+ include Tennpipes::Generators::Admin::Actions
22
+
23
+ # Look for custom template files in a generators folder under the project root.
24
+ def source_paths
25
+ if File.exist? destination_root('generators')
26
+ ["#{destination_root('generators')}", File.expand_path(File.dirname(__FILE__))]
27
+ else
28
+ [File.expand_path(File.dirname(__FILE__))]
29
+ end
30
+ end
31
+
32
+ desc "Description:\n\n\ttennpipes-init admin_page model(s)"
33
+ argument :models, :desc => "The name(s) of your model(s)", :type => :array
34
+ class_option :skip_migration, :aliases => "-s", :default => false, :type => :boolean
35
+ class_option :root, :desc => "The root destination", :aliases => '-r', :type => :string
36
+ class_option :destroy, :aliases => '-d', :default => false, :type => :boolean
37
+ class_option :admin_name, :aliases => '-a', :desc => 'The admin application name and path', :default => 'admin', :type => :string
38
+ # Show help if no argv given.
39
+ require_arguments!
40
+
41
+ # Create controller for admin.
42
+ def create_controller
43
+ self.destination_root = options[:root]
44
+ if in_app_root?
45
+ @app_name = fetch_app_name
46
+ @admin_name = options[:admin_name].classify
47
+ @admin_path = options[:admin_name].underscore
48
+ @admin_model = options[:admin_model]
49
+ models.each do |model|
50
+ @orm = default_orm || Tennpipes::Admin::Generators::Orm.new(model, adapter)
51
+ self.behavior = :revoke if options[:destroy]
52
+ empty_directory destination_root(@admin_path+"/views/#{@orm.name_plural}")
53
+
54
+ template "templates/page/controller.rb.tt", destination_root(@admin_path+"/controllers/#{@orm.name_plural}.rb")
55
+ template "templates/#{ext}/page/_form.#{ext}.tt", destination_root(@admin_path+"/views/#{@orm.name_plural}/_form.#{ext}")
56
+ template "templates/#{ext}/page/edit.#{ext}.tt", destination_root(@admin_path+"/views/#{@orm.name_plural}/edit.#{ext}")
57
+ template "templates/#{ext}/page/index.#{ext}.tt", destination_root(@admin_path+"/views/#{@orm.name_plural}/index.#{ext}")
58
+ template "templates/#{ext}/page/new.#{ext}.tt", destination_root(@admin_path+"/views/#{@orm.name_plural}/new.#{ext}")
59
+
60
+ options[:destroy] ? remove_project_module(@orm.name_plural) : add_project_module(@orm.name_plural)
61
+ end
62
+ else
63
+ say "You are not at the root of a Tennpipes application! (config/boot.rb not found)"
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,172 @@
1
+ module Tennpipes
2
+ module Admin
3
+ ##
4
+ # Contains all admin related generator functionality.
5
+ #
6
+ module Generators
7
+ # Defines a generic exception for the admin ORM handler.
8
+ class OrmError < StandardError; end
9
+
10
+ ##
11
+ # Defines the generic ORM management functions used to manipulate data for admin.
12
+ class Orm
13
+ attr_reader :klass_name, :klass, :name_plural, :name_singular, :orm, :name_param
14
+
15
+ def initialize(name, orm, columns=nil, column_fields=nil)
16
+ name = name.to_s
17
+ @klass_name = name.underscore.camelize
18
+ @klass = @klass_name.constantize rescue nil
19
+ @name_param = name.underscore.gsub(/\//, '_')
20
+ @name_singular = name.underscore.gsub(/^.*\//, '') # convert submodules i.e. FooBar::Jank.all # => jank
21
+ @name_plural = @name_singular.pluralize
22
+ @orm = orm.to_sym
23
+ @columns = columns
24
+ @column_fields = column_fields
25
+ raise OrmError, "Model '#{klass_name}' could not be found!\nPerhaps you would like to run 'bundle exec tennpipes g model #{klass_name}' to create it first?" if @columns.nil? && @klass.nil?
26
+ end
27
+
28
+ def activerecord?
29
+ case orm
30
+ when :activerecord, :minirecord then true
31
+ else false
32
+ end
33
+ end
34
+
35
+ def field_type(type)
36
+ type = :string if type.nil? # couchrest-Hack to avoid the next line to fail
37
+ type = type.to_s.demodulize.downcase.to_sym unless type.is_a?(Symbol)
38
+ case type
39
+ when :integer, :float, :decimal then :text_field
40
+ when :string then :text_field
41
+ when :text then :text_area
42
+ when :boolean then :check_box
43
+ else :text_field
44
+ end
45
+ end
46
+
47
+ Column = Struct.new(:name, :type) # for compatibility
48
+
49
+ def columns
50
+ @columns ||= case orm
51
+ when :activerecord then @klass.columns
52
+ when :minirecord then @klass.columns
53
+ when :datamapper then @klass.properties.map { |p| dm_column(p) }
54
+ when :couchrest then @klass.properties
55
+ when :mongoid then @klass.fields.values.reject { |col| %w[_id _type].include?(col.name) }
56
+ when :mongomapper then @klass.keys.values.reject { |key| key.name == "_id" } # On MongoMapper keys are an hash
57
+ when :sequel then @klass.db_schema.map { |k,v| v[:type] = :text if v[:db_type] =~ /^text/i; Column.new(k, v[:type]) }
58
+ when :ohm then @klass.attributes.map { |a| Column.new(a.to_s, :string) } # ohm has strings
59
+ when :dynamoid then @klass.attributes.map { |k,v| Column.new(k.to_s, v[:type]) }
60
+ else raise OrmError, "Adapter #{orm} is not yet supported!"
61
+ end
62
+ end
63
+
64
+ def dm_column(p)
65
+ case p
66
+ when DataMapper::Property::Text
67
+ Column.new(p.name, :text)
68
+ when DataMapper::Property::Boolean
69
+ Column.new(p.name, :boolean)
70
+ when DataMapper::Property::Integer
71
+ Column.new(p.name, :integer)
72
+ when DataMapper::Property::Decimal
73
+ Column.new(p.name, :decimal)
74
+ when DataMapper::Property::Float
75
+ Column.new(p.name, :float)
76
+ when DataMapper::Property::String
77
+ Column.new(p.name, :string)
78
+ else #if all fails, lets assume its stringish
79
+ Column.new(p.name, :string)
80
+ end
81
+ end
82
+
83
+ def column_fields
84
+ excluded_columns = %w[created_at updated_at]
85
+ case orm
86
+ when :mongoid then excluded_columns << '_id'
87
+ else excluded_columns << 'id'
88
+ end
89
+
90
+ column_fields = columns.dup
91
+ column_fields.reject! { |column| excluded_columns.include?(column.name.to_s) }
92
+ @column_fields ||= column_fields.map do |column|
93
+ { :name => column.name, :field_type => field_type(column.type) }
94
+ end
95
+ end
96
+
97
+ def all
98
+ "#{klass_name}.all"
99
+ end
100
+
101
+ def find(params=nil)
102
+ case orm
103
+ when :activerecord, :minirecord, :mongomapper, :mongoid, :dynamoid then "#{klass_name}.find(#{params})"
104
+ when :datamapper, :couchrest then "#{klass_name}.get(#{params})"
105
+ when :sequel, :ohm then "#{klass_name}[#{params}]"
106
+ else raise OrmError, "Adapter #{orm} is not yet supported!"
107
+ end
108
+ end
109
+
110
+ def build(params=nil)
111
+ if params
112
+ "#{klass_name}.new(#{params})"
113
+ else
114
+ "#{klass_name}.new"
115
+ end
116
+ end
117
+
118
+ def save
119
+ case orm
120
+ when :sequel then "(@#{name_singular}.save rescue false)"
121
+ else "@#{name_singular}.save"
122
+ end
123
+ end
124
+
125
+ def update_attributes(params=nil)
126
+ case orm
127
+ when :activerecord, :minirecord, :mongomapper, :mongoid, :couchrest, :dynamoid then "@#{name_singular}.update_attributes(#{params})"
128
+ when :datamapper, :ohm then "@#{name_singular}.update(#{params})"
129
+ when :sequel then "@#{name_singular}.modified! && @#{name_singular}.update(#{params})"
130
+ else raise OrmError, "Adapter #{orm} is not yet supported!"
131
+ end
132
+ end
133
+
134
+ def destroy
135
+ case orm
136
+ when :ohm then "#{name_singular}.delete"
137
+ else "#{name_singular}.destroy"
138
+ end
139
+ end
140
+
141
+ def find_by_ids(params=nil)
142
+ case orm
143
+ when :ohm then "#{klass_name}.fetch(#{params})"
144
+ when :datamapper then "#{klass_name}.all(:id => #{params})"
145
+ when :sequel then "#{klass_name}.where(:id => #{params})"
146
+ when :mongoid then "#{klass_name}.find(#{params})"
147
+ when :couchrest then "#{klass_name}.all(:keys => #{params})"
148
+ when :dynamoid then "#{klass_name}.find(#{params})"
149
+ else find(params)
150
+ end
151
+ end
152
+
153
+ def multiple_destroy(params=nil)
154
+ case orm
155
+ when :ohm then "#{params}.each(&:delete)"
156
+ when :sequel then "#{params}.destroy"
157
+ when :datamapper then "#{params}.destroy"
158
+ when :couchrest, :mongoid, :mongomapper, :dynamoid then "#{params}.each(&:destroy)"
159
+ else "#{klass_name}.destroy #{params}"
160
+ end
161
+ end
162
+
163
+ def has_error(field)
164
+ case orm
165
+ when :datamapper, :ohm, :sequel then "@#{name_singular}.errors.key?(:#{field}) && @#{name_singular}.errors[:#{field}].count > 0"
166
+ else "@#{name_singular}.errors.include?(:#{field})"
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end