fesplugas-typus 0.9.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 (154) hide show
  1. data/.gitignore +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +80 -0
  4. data/Rakefile +61 -0
  5. data/VERSION +1 -0
  6. data/app/controllers/admin/master_controller.rb +324 -0
  7. data/app/controllers/typus_controller.rb +127 -0
  8. data/app/helpers/admin/form_helper.rb +351 -0
  9. data/app/helpers/admin/master_helper.rb +99 -0
  10. data/app/helpers/admin/public_helper.rb +24 -0
  11. data/app/helpers/admin/sidebar_helper.rb +259 -0
  12. data/app/helpers/admin/table_helper.rb +227 -0
  13. data/app/helpers/typus_helper.rb +169 -0
  14. data/app/models/typus_mailer.rb +14 -0
  15. data/app/models/typus_user.rb +5 -0
  16. data/app/views/admin/dashboard/_sidebar.html.erb +9 -0
  17. data/app/views/admin/resources/edit.html.erb +29 -0
  18. data/app/views/admin/resources/index.html.erb +28 -0
  19. data/app/views/admin/resources/new.html.erb +27 -0
  20. data/app/views/admin/resources/show.html.erb +21 -0
  21. data/app/views/admin/shared/_footer.html.erb +1 -0
  22. data/app/views/admin/shared/_pagination.html.erb +28 -0
  23. data/app/views/layouts/admin.html.erb +72 -0
  24. data/app/views/layouts/typus.html.erb +29 -0
  25. data/app/views/typus/dashboard.html.erb +13 -0
  26. data/app/views/typus/recover_password.html.erb +7 -0
  27. data/app/views/typus/reset_password.html.erb +13 -0
  28. data/app/views/typus/sign_in.html.erb +9 -0
  29. data/app/views/typus/sign_up.html.erb +7 -0
  30. data/app/views/typus_mailer/reset_password_link.erb +11 -0
  31. data/config/locales/es.yml +106 -0
  32. data/config/locales/pt-BR.yml +108 -0
  33. data/config/locales/typus_hacks.yml +14 -0
  34. data/config/routes.rb +14 -0
  35. data/generators/typus/templates/config/initializers/typus.rb +27 -0
  36. data/generators/typus/templates/config/typus/application.yml +45 -0
  37. data/generators/typus/templates/config/typus/application_roles.yml +23 -0
  38. data/generators/typus/templates/config/typus/typus.yml +14 -0
  39. data/generators/typus/templates/config/typus/typus_roles.yml +2 -0
  40. data/generators/typus/templates/db/create_typus_users.rb +21 -0
  41. data/generators/typus/templates/public/images/admin/arrow_down.gif +0 -0
  42. data/generators/typus/templates/public/images/admin/arrow_up.gif +0 -0
  43. data/generators/typus/templates/public/images/admin/spinner.gif +0 -0
  44. data/generators/typus/templates/public/images/admin/status_false.gif +0 -0
  45. data/generators/typus/templates/public/images/admin/status_true.gif +0 -0
  46. data/generators/typus/templates/public/images/admin/trash.gif +0 -0
  47. data/generators/typus/templates/public/javascripts/admin/application.js +14 -0
  48. data/generators/typus/templates/public/stylesheets/admin/reset.css +68 -0
  49. data/generators/typus/templates/public/stylesheets/admin/screen.css +709 -0
  50. data/generators/typus/typus_generator.rb +141 -0
  51. data/generators/typus_update_schema_to_01/templates/config/typus.yml +14 -0
  52. data/generators/typus_update_schema_to_01/templates/migration.rb +11 -0
  53. data/generators/typus_update_schema_to_01/typus_update_schema_to_01_generator.rb +19 -0
  54. data/init.rb +19 -0
  55. data/lib/typus/active_record.rb +298 -0
  56. data/lib/typus/authentication.rb +155 -0
  57. data/lib/typus/configuration.rb +92 -0
  58. data/lib/typus/format.rb +56 -0
  59. data/lib/typus/generator.rb +173 -0
  60. data/lib/typus/hash.rb +10 -0
  61. data/lib/typus/locale.rb +17 -0
  62. data/lib/typus/object.rb +22 -0
  63. data/lib/typus/quick_edit.rb +33 -0
  64. data/lib/typus/reloader.rb +17 -0
  65. data/lib/typus/string.rb +11 -0
  66. data/lib/typus/user.rb +137 -0
  67. data/lib/typus.rb +133 -0
  68. data/lib/vendor/active_record.rb +15 -0
  69. data/lib/vendor/paginator.rb +143 -0
  70. data/tasks/typus_tasks.rake +26 -0
  71. data/test/config/broken/application.yml +68 -0
  72. data/test/config/broken/application_roles.yml +20 -0
  73. data/test/config/broken/empty.yml +0 -0
  74. data/test/config/broken/empty_roles.yml +0 -0
  75. data/test/config/broken/undefined.yml +3 -0
  76. data/test/config/broken/undefined_roles.yml +6 -0
  77. data/test/config/default/typus.yml +14 -0
  78. data/test/config/default/typus_roles.yml +2 -0
  79. data/test/config/empty/empty_01.yml +0 -0
  80. data/test/config/empty/empty_01_roles.yml +0 -0
  81. data/test/config/empty/empty_02.yml +0 -0
  82. data/test/config/empty/empty_02_roles.yml +0 -0
  83. data/test/config/locales/es.yml +10 -0
  84. data/test/config/ordered/001_roles.yml +2 -0
  85. data/test/config/ordered/002_roles.yml +2 -0
  86. data/test/config/unordered/app_one_roles.yml +2 -0
  87. data/test/config/unordered/app_two_roles.yml +2 -0
  88. data/test/config/working/application.yml +67 -0
  89. data/test/config/working/application_roles.yml +22 -0
  90. data/test/config/working/typus.yml +14 -0
  91. data/test/config/working/typus_roles.yml +2 -0
  92. data/test/fixtures/app/controllers/admin/assets_controller.rb +2 -0
  93. data/test/fixtures/app/controllers/admin/categories_controller.rb +2 -0
  94. data/test/fixtures/app/controllers/admin/comments_controller.rb +2 -0
  95. data/test/fixtures/app/controllers/admin/pages_controller.rb +2 -0
  96. data/test/fixtures/app/controllers/admin/posts_controller.rb +2 -0
  97. data/test/fixtures/app/controllers/admin/status_controller.rb +6 -0
  98. data/test/fixtures/app/controllers/admin/typus_users_controller.rb +2 -0
  99. data/test/fixtures/app/controllers/admin/watch_dog_controller.rb +6 -0
  100. data/test/fixtures/app/views/admin/comments/_edit_bottom.html.erb +1 -0
  101. data/test/fixtures/app/views/admin/comments/_edit_sidebar.html.erb +1 -0
  102. data/test/fixtures/app/views/admin/comments/_edit_top.html.erb +1 -0
  103. data/test/fixtures/app/views/admin/comments/_index_bottom.html.erb +1 -0
  104. data/test/fixtures/app/views/admin/comments/_index_sidebar.html.erb +1 -0
  105. data/test/fixtures/app/views/admin/comments/_index_top.html.erb +1 -0
  106. data/test/fixtures/app/views/admin/comments/_new_bottom.html.erb +1 -0
  107. data/test/fixtures/app/views/admin/comments/_new_sidebar.html.erb +1 -0
  108. data/test/fixtures/app/views/admin/comments/_new_top.html.erb +1 -0
  109. data/test/fixtures/app/views/admin/comments/_show_bottom.html.erb +1 -0
  110. data/test/fixtures/app/views/admin/comments/_show_sidebar.html.erb +1 -0
  111. data/test/fixtures/app/views/admin/comments/_show_top.html.erb +1 -0
  112. data/test/fixtures/app/views/admin/dashboard/_bottom.html.erb +1 -0
  113. data/test/fixtures/app/views/admin/dashboard/_sidebar.html.erb +1 -0
  114. data/test/fixtures/app/views/admin/dashboard/_top.html.erb +1 -0
  115. data/test/fixtures/app/views/admin/shared/_footer.html.erb +1 -0
  116. data/test/fixtures/app/views/admin/status/index.html.erb +1 -0
  117. data/test/fixtures/app/views/admin/templates/_datepicker.html.erb +1 -0
  118. data/test/fixtures/assets.yml +11 -0
  119. data/test/fixtures/categories.yml +14 -0
  120. data/test/fixtures/comments.yml +27 -0
  121. data/test/fixtures/pages.yml +41 -0
  122. data/test/fixtures/posts.yml +37 -0
  123. data/test/fixtures/typus_users.yml +54 -0
  124. data/test/functional/admin/assets_controller_test.rb +57 -0
  125. data/test/functional/admin/categories_controller_test.rb +106 -0
  126. data/test/functional/admin/comments_controller_test.rb +121 -0
  127. data/test/functional/admin/master_controller_test.rb +5 -0
  128. data/test/functional/admin/posts_controller_test.rb +278 -0
  129. data/test/functional/admin/status_controller_test.rb +43 -0
  130. data/test/functional/admin/typus_users_controller_test.rb +239 -0
  131. data/test/functional/typus_controller_test.rb +315 -0
  132. data/test/helper.rb +51 -0
  133. data/test/helpers/admin/form_helper_test.rb +316 -0
  134. data/test/helpers/admin/master_helper_test.rb +65 -0
  135. data/test/helpers/admin/public_helper_test.rb +22 -0
  136. data/test/helpers/admin/sidebar_helper_test.rb +351 -0
  137. data/test/helpers/admin/table_helper_test.rb +255 -0
  138. data/test/helpers/typus_helper_test.rb +106 -0
  139. data/test/lib/active_record_test.rb +372 -0
  140. data/test/lib/configuration_test.rb +91 -0
  141. data/test/lib/hash_test.rb +11 -0
  142. data/test/lib/routes_test.rb +82 -0
  143. data/test/lib/string_test.rb +25 -0
  144. data/test/lib/typus_test.rb +105 -0
  145. data/test/models.rb +51 -0
  146. data/test/schema.rb +64 -0
  147. data/test/unit/typus_mailer_test.rb +33 -0
  148. data/test/unit/typus_test.rb +17 -0
  149. data/test/unit/typus_user_roles_test.rb +90 -0
  150. data/test/unit/typus_user_test.rb +177 -0
  151. data/test/vendor/active_record_test.rb +18 -0
  152. data/test/vendor/paginator_test.rb +138 -0
  153. data/typus.gemspec +225 -0
  154. metadata +241 -0
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.db
2
+ *.log
3
+ _dashboard*
4
+ rdoc/*
5
+ *~
6
+ *.gem
7
+ SPECDOC
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007-2009 Francesc Esplugas Marti
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/README.rdoc ADDED
@@ -0,0 +1,80 @@
1
+ = Typus: Effortless admin interface for your Rails application
2
+
3
+ *Typus* is designed for a single activity:
4
+
5
+ Trusted users editing structured content.
6
+
7
+ *Typus* doesn't try to be all the things to all the people but it's
8
+ extensible enough to match lots of use cases.
9
+
10
+ - Project site and documentation http://intraducibles.com/projects/typus
11
+ - Screenshoots http://intraducibles.com/projects/typus/screenshots
12
+ - Plugin source http://github.com/fesplugas/typus/tree
13
+ - Google Group http://groups.google.es/group/typus
14
+
15
+ == For the impatients: Demo in 3 steps
16
+
17
+ Step 1. Create a Rails application using a template.
18
+
19
+ $ rails example.com -m http://intraducibles.com/projects/typus/demo.txt
20
+
21
+ Step 2. Start the server:
22
+
23
+ $ cd example.com && script/server
24
+
25
+ Step 3. Go to the admin area and enjoy it!
26
+
27
+ http://0.0.0.0:3000/admin
28
+
29
+ == Installing
30
+
31
+ Install from GitHub the latest version which it's compatible with
32
+ Rails 2.3.2.
33
+
34
+ $ script/plugin install git://github.com/fesplugas/typus.git
35
+
36
+ Once plugin is installed generate *Typus* files and migrate your
37
+ database (<tt>typus_users</tt> table is created)
38
+
39
+ $ script/generate typus
40
+ $ rake db:migrate
41
+
42
+ To create the first user, start the application server, go to
43
+ http://0.0.0.0:3000/admin and follow the instructions.
44
+
45
+ == Support Typus
46
+
47
+ *Typus* is licensed under the MIT license. As an experiment we
48
+ encourage you to support this project by donating[http://intraducibles.com/projects/typus/donate]
49
+ 90 euros if you are a developer or studio. Donations do allow us to spend more
50
+ time working and supporting the project. All contributions are much appreciated!
51
+
52
+ Hire us to work on your next project. We build large and small websites.
53
+
54
+ Contribute your patches to the community & support people on the
55
+ mailing list.
56
+
57
+ Tell everybody about Typus, tell your friends and colleagues about
58
+ Typus and blog about Typus.
59
+
60
+ == Contributors
61
+
62
+ - Laia Gargallo (Lover and tea provider) http://azotacalles.net
63
+ - Isaac Feliu (Codereview on first public release) http://www.vesne.com
64
+ - Lluis Folch (Icons, feedback & crazy ideas) http://wet-floor.com
65
+ - Sergio Espeja (Code) http://github.com/spejman
66
+ - Eadz (Code) http://github.com/eadz
67
+ - Anthony Underwood (Code) http://github.com/aunderwo
68
+ - Felipe Talavera (Code) http://github.com/flype
69
+ - Erik Tigerholm (Code) http://github.com/eriktigerholm
70
+ - George Guimarães (Translation pt-br and code) http://github.com/georgeguimaraes
71
+ - José Valim (Code) http://github.com/josevalim
72
+ - Luqman Amjad (Code) http://github.com/snake
73
+
74
+ == Acknowledgments
75
+
76
+ - *Typus* uses "Paginator" by Bruce Williams http://codefluency.com.
77
+ - *Typus* has been inspired by "Django Admin" http://www.djangoproject.com.
78
+
79
+ Copyright (c) 2007-2009 Francesc Esplugas Marti, released under the
80
+ MIT license
data/Rakefile ADDED
@@ -0,0 +1,61 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the typus plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the typus plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_files.add ['README.rdoc', 'MIT-LICENSE', 'lib/**/*.rb']
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'Typus documentation'
20
+ rdoc.main = 'README.rdoc'
21
+ rdoc.options << '--charset=UTF-8'
22
+ rdoc.options << '--inline-source'
23
+ rdoc.options << '--line-numbers'
24
+ end
25
+
26
+ desc 'Generate specdoc-style documentation from tests'
27
+ task :specs do
28
+
29
+ puts 'Started'
30
+ timer, count = Time.now, 0
31
+
32
+ File.open('SPECDOC', 'w') do |file|
33
+ Dir.glob('test/**/*_test.rb').each do |test|
34
+ test =~ /.*\/([^\/].*)_test.rb$/
35
+ file.puts "#{$1.gsub('_', ' ').capitalize} should:" if $1
36
+ File.read(test).map { |line| /test_(.*)$/.match line }.compact.each do |spec|
37
+ file.puts "- #{spec[1].gsub('_', ' ')}"
38
+ sleep 0.001; print '.'; $stdout.flush; count += 1
39
+ end
40
+ file.puts
41
+ end
42
+ end
43
+
44
+ puts "\nFinished in #{Time.now - timer} seconds.\n"
45
+ puts "#{count} specifications documented"
46
+
47
+ end
48
+
49
+ begin
50
+ require 'jeweler'
51
+ Jeweler::Tasks.new do |gemspec|
52
+ gemspec.name = "typus"
53
+ gemspec.summary = "Effortless backend interface for Ruby on Rails applications. (Admin scaffold generator.)"
54
+ gemspec.email = "francesc@intraducibles.com"
55
+ gemspec.homepage = "http://intraducibles.com/projects/typus"
56
+ gemspec.description = "Effortless backend interface for Ruby on Rails applications. (Admin scaffold generator.)"
57
+ gemspec.authors = ["Francesc Esplugas"]
58
+ end
59
+ rescue LoadError
60
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
61
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.9.0
@@ -0,0 +1,324 @@
1
+ class Admin::MasterController < ApplicationController
2
+
3
+ layout 'admin'
4
+
5
+ include Typus::Authentication
6
+ include Typus::Format
7
+ include Typus::Locale
8
+ include Typus::Reloader
9
+
10
+ if Typus::Configuration.options[:ssl]
11
+ include SslRequirement
12
+ ssl_required :index, :new, :create, :edit, :show, :update, :destroy, :toggle, :position, :relate, :unrelate
13
+ end
14
+
15
+ filter_parameter_logging :password
16
+
17
+ before_filter :reload_config_et_roles
18
+
19
+ before_filter :require_login
20
+
21
+ before_filter :set_locale
22
+
23
+ before_filter :set_resource
24
+ before_filter :find_item,
25
+ :only => [ :show, :edit, :update, :destroy, :toggle, :position, :relate, :unrelate ]
26
+
27
+ before_filter :check_ownership_of_item,
28
+ :only => [ :edit, :update, :destroy, :toggle, :position, :relate, :unrelate ]
29
+
30
+ before_filter :check_if_user_can_perform_action_on_user,
31
+ :only => [ :edit, :update, :toggle, :destroy ]
32
+ before_filter :check_if_user_can_perform_action_on_resource
33
+
34
+ before_filter :set_order,
35
+ :only => [ :index ]
36
+ before_filter :set_fields,
37
+ :only => [ :index, :new, :edit, :create, :update, :show ]
38
+
39
+ ##
40
+ # This is the main index of the model. With filters, conditions
41
+ # and more.
42
+ #
43
+ # By default application can respond_to html, csv and xml, but you
44
+ # can add your formats.
45
+ #
46
+ def index
47
+
48
+ @conditions, @joins = @resource[:class].build_conditions(params)
49
+
50
+ respond_to do |format|
51
+ format.html { generate_html }
52
+ @resource[:class].typus_export_formats.each do |f|
53
+ format.send(f) { send("generate_#{f}") }
54
+ end
55
+ end
56
+
57
+ rescue Exception => error
58
+ error_handler(error)
59
+ end
60
+
61
+ def new
62
+
63
+ item_params = params.dup
64
+ %w( controller action resource resource_id back_to selected ).each do |param|
65
+ item_params.delete(param)
66
+ end
67
+
68
+ @item = @resource[:class].new(item_params.symbolize_keys)
69
+
70
+ select_template :new
71
+
72
+ end
73
+
74
+ ##
75
+ # Create new items. There's an special case when we create an
76
+ # item from another item. In this case, after the item is
77
+ # created we also create the relationship between these items.
78
+ #
79
+ def create
80
+
81
+ @item = @resource[:class].new(params[:item])
82
+
83
+ if @item.attributes.include?(Typus.user_fk)
84
+ @item.attributes = { Typus.user_fk => session[:typus_user_id] }
85
+ end
86
+
87
+ if @item.valid?
88
+ create_with_back_to and return if params[:back_to]
89
+ @item.save
90
+ flash[:success] = _("{{model}} successfully created.", :model => @resource[:class].human_name)
91
+ if @resource[:class].typus_options_for(:index_after_save)
92
+ redirect_to :action => 'index'
93
+ else
94
+ redirect_to :action => @resource[:class].typus_options_for(:default_action_on_item), :id => @item.id
95
+ end
96
+ else
97
+ select_template :new
98
+ end
99
+
100
+ end
101
+
102
+ def edit
103
+ item_params = params.dup
104
+ %w( action controller model model_id back_to id resource resource_id ).each { |p| item_params.delete(p) }
105
+ # We assign the params passed trough the url
106
+ @item.attributes = item_params
107
+ @previous, @next = @item.previous_and_next(item_params)
108
+ select_template :edit
109
+ end
110
+
111
+ def show
112
+
113
+ @previous, @next = @item.previous_and_next
114
+
115
+ respond_to do |format|
116
+ format.html { select_template :show }
117
+ format.xml { render :xml => @item }
118
+ end
119
+
120
+ end
121
+
122
+ def update
123
+ if @item.update_attributes(params[:item])
124
+ flash[:success] = _("{{model}} successfully updated.", :model => @resource[:class].human_name)
125
+ path = if @resource[:class].typus_options_for(:index_after_save)
126
+ params[:back_to] ? "#{params[:back_to]}##{@resource[:self]}" : { :action => 'index' }
127
+ else
128
+ { :action => @resource[:class].typus_options_for(:default_action_on_item), :id => @item.id }
129
+ end
130
+ redirect_to path
131
+ else
132
+ @previous, @next = @item.previous_and_next
133
+ select_template :edit
134
+ end
135
+ end
136
+
137
+ def destroy
138
+ @item.destroy
139
+ flash[:success] = _("{{model}} successfully removed.", :model => @resource[:class].human_name)
140
+ redirect_to :back
141
+ rescue Exception => error
142
+ error_handler(error, params.merge(:action => 'index', :id => nil))
143
+ end
144
+
145
+ def toggle
146
+ if @resource[:class].typus_options_for(:toggle)
147
+ @item.toggle!(params[:field])
148
+ flash[:success] = _("{{model}} {{attribute}} changed.",
149
+ :model => @resource[:class].human_name,
150
+ :attribute => params[:field].humanize.downcase)
151
+ else
152
+ flash[:notice] = _("Toggle is disabled.")
153
+ end
154
+ redirect_to :back
155
+ end
156
+
157
+ ##
158
+ # Change item position. This only works if acts_as_list is
159
+ # installed. We can then move items:
160
+ #
161
+ # params[:go] = 'move_to_top'
162
+ #
163
+ # Available positions are move_to_top, move_higher, move_lower,
164
+ # move_to_bottom.
165
+ #
166
+ def position
167
+ @item.send(params[:go])
168
+ flash[:success] = _("Record moved {{to}}.", :to => params[:go].gsub(/move_/, '').humanize.downcase)
169
+ redirect_to :back
170
+ end
171
+
172
+ ##
173
+ # Relate a model object to another, this action is used only by the
174
+ # has_and_belongs_to_many relationships.
175
+ #
176
+ def relate
177
+
178
+ resource_class = params[:related][:model].constantize
179
+ resource_tableized = params[:related][:model].tableize
180
+
181
+ @item.send(resource_tableized) << resource_class.find(params[:related][:id])
182
+
183
+ flash[:success] = _("{{model_a}} related to {{model_b}}.",
184
+ :model_a => resource_class.human_name,
185
+ :model_b => @resource[:class].human_name)
186
+
187
+ redirect_to :action => @resource[:class].typus_options_for(:default_action_on_item),
188
+ :id => @item.id,
189
+ :anchor => resource_tableized
190
+
191
+ end
192
+
193
+ ##
194
+ # Remove relationship between models.
195
+ #
196
+ def unrelate
197
+
198
+ resource_class = params[:resource].classify.constantize
199
+ resource = resource_class.find(params[:resource_id])
200
+
201
+ case params[:association]
202
+ when 'has_and_belongs_to_many'
203
+ @item.send(resource_class.table_name).delete(resource)
204
+ message = "{{model_a}} unrelated from {{model_b}}."
205
+ when 'has_many', 'has_one'
206
+ resource.destroy
207
+ message = "{{model_a}} removed from {{model_b}}."
208
+ end
209
+
210
+ flash[:success] = _(message, :model_a => resource_class.human_name, :model_b => @resource[:class].human_name)
211
+
212
+ redirect_to :controller => @resource[:self],
213
+ :action => @resource[:class].typus_options_for(:default_action_on_item),
214
+ :id => @item.id,
215
+ :anchor => resource_class.table_name
216
+
217
+ end
218
+
219
+ private
220
+
221
+ def set_resource
222
+ resource = params[:controller].split('/').last
223
+ @resource = { :self => resource, :class => resource.classify.constantize }
224
+ rescue Exception => error
225
+ error_handler(error)
226
+ end
227
+
228
+ ##
229
+ # Find model when performing an edit, update, destroy, relate,
230
+ # unrelate ...
231
+ #
232
+ def find_item
233
+ @item = @resource[:class].find(params[:id])
234
+ end
235
+
236
+ ##
237
+ # If item is owned by another user, we only can perform a
238
+ # show action on the item. Updated item is also blocked.
239
+ #
240
+ # before_filter :check_ownership_of_item, :only => [ :edit, :update, :destroy ]
241
+ #
242
+ def check_ownership_of_item
243
+
244
+ # If current_user is a root user, by-pass.
245
+ return if @current_user.is_root?
246
+
247
+ # If the current model doesn't include a key which relates it with the
248
+ # current_user, by-pass.
249
+ return unless @item.respond_to?(Typus.user_fk)
250
+
251
+ # If item is owned by the user ...
252
+ unless @item.send(Typus.user_fk) == session[:typus_user_id]
253
+ flash[:notice] = _("Record owned by another user.")
254
+ redirect_to :action => 'show', :id => @item.id
255
+ end
256
+
257
+ end
258
+
259
+ def set_fields
260
+ @fields = case params[:action]
261
+ when 'index'
262
+ @resource[:class].typus_fields_for(:list)
263
+ when 'new', 'edit', 'create', 'update'
264
+ @resource[:class].typus_fields_for(:form)
265
+ else
266
+ @resource[:class].typus_fields_for(params[:action])
267
+ end
268
+ end
269
+
270
+ def set_order
271
+ params[:sort_order] ||= 'desc'
272
+ @order = params[:order_by] ? "#{@resource[:class].table_name}.#{params[:order_by]} #{params[:sort_order]}" : @resource[:class].typus_order_by
273
+ end
274
+
275
+ def select_template(template, resource = @resource[:self])
276
+ folder = (File.exists?("app/views/admin/#{resource}/#{template}.html.erb")) ? resource : 'resources'
277
+ render :template => "admin/#{folder}/#{template}"
278
+ end
279
+
280
+ ##
281
+ # When <tt>params[:back_to]</tt> is defined this action is used.
282
+ #
283
+ # - <tt>has_and_belongs_to_many</tt> relationships.
284
+ # - <tt>has_many</tt> relationships (polymorphic ones).
285
+ #
286
+ def create_with_back_to
287
+
288
+ if params[:resource] && params[:resource_id]
289
+ resource_class = params[:resource].classify.constantize
290
+ resource_id = params[:resource_id]
291
+ resource = resource_class.find(resource_id)
292
+ association = @resource[:class].reflect_on_association(params[:resource].to_sym).macro rescue :polymorphic
293
+ else
294
+ association = :has_many
295
+ end
296
+
297
+ case association
298
+ when :belongs_to
299
+ @item.save
300
+ when :has_and_belongs_to_many
301
+ @item.save
302
+ @item.send(params[:resource]) << resource
303
+ when :has_many
304
+ @item.save
305
+ message = _("{{model}} successfully created.", :model => @resource[:class].human_name)
306
+ path = "#{params[:back_to]}?#{params[:selected]}=#{@item.id}"
307
+ when :polymorphic
308
+ resource.send(@item.class.name.tableize).create(params[:item])
309
+ end
310
+
311
+ flash[:success] = message || _("{{model_a}} successfully assigned to {{model_b}}.",
312
+ :model_a => @item.class,
313
+ :model_b => resource_class.name)
314
+ redirect_to path || "#{params[:back_to]}##{@resource[:self]}"
315
+
316
+ end
317
+
318
+ def error_handler(error, path = admin_dashboard_path)
319
+ raise error unless Rails.env.production?
320
+ flash[:error] = "#{error.message} (#{@resource[:class]})"
321
+ redirect_to path
322
+ end
323
+
324
+ end
@@ -0,0 +1,127 @@
1
+ class TypusController < ApplicationController
2
+
3
+ layout :select_layout
4
+
5
+ include Typus::Authentication
6
+ include Typus::Locale
7
+ include Typus::QuickEdit
8
+ include Typus::Reloader
9
+
10
+ if Typus::Configuration.options[:ssl]
11
+ include SslRequirement
12
+ ssl_required :sign_in, :sign_out,
13
+ :dashboard,
14
+ :recover_password, :reset_password
15
+ end
16
+
17
+ filter_parameter_logging :password
18
+
19
+ before_filter :set_locale
20
+
21
+ before_filter :reload_config_et_roles
22
+ before_filter :require_login,
23
+ :except => [ :sign_up, :sign_in, :sign_out,
24
+ :recover_password, :reset_password,
25
+ :quick_edit ]
26
+
27
+ before_filter :check_if_user_can_perform_action_on_resource_without_model,
28
+ :except => [ :sign_up, :sign_in, :sign_out,
29
+ :dashboard,
30
+ :recover_password, :reset_password,
31
+ :quick_edit, :set_locale ]
32
+
33
+ before_filter :recover_password_disabled?,
34
+ :only => [ :recover_password, :reset_password ]
35
+
36
+ def dashboard
37
+ flash[:notice] = _("There are not defined applications in config/typus/*.yml.") if Typus.applications.empty?
38
+ end
39
+
40
+ def sign_in
41
+
42
+ redirect_to admin_sign_up_path and return if Typus.user_class.count.zero?
43
+
44
+ if request.post?
45
+ if user = Typus.user_class.authenticate(params[:user][:email], params[:user][:password])
46
+ session[:typus_user_id] = user.id
47
+ redirect_to params[:back_to] || admin_dashboard_path
48
+ else
49
+ flash[:error] = _("The email and/or password you entered is invalid.")
50
+ redirect_to admin_sign_in_path
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ def sign_out
57
+ session[:typus_user_id] = nil
58
+ redirect_to admin_sign_in_path
59
+ end
60
+
61
+ def recover_password
62
+ if request.post?
63
+ if user = Typus.user_class.find_by_email(params[:user][:email])
64
+ ActionMailer::Base.default_url_options[:host] = request.host_with_port
65
+ TypusMailer.deliver_reset_password_link(user)
66
+ flash[:success] = _("Password recovery link sent to your email.")
67
+ redirect_to admin_sign_in_path
68
+ else
69
+ redirect_to admin_recover_password_path
70
+ end
71
+ end
72
+ end
73
+
74
+ ##
75
+ # Available if Typus::Configuration.options[:recover_password] is enabled.
76
+ #
77
+ def reset_password
78
+ @user = Typus.user_class.find_by_token!(params[:token])
79
+ if request.post?
80
+ @user.password = params[:user][:password]
81
+ @user.password_confirmation = params[:user][:password_confirmation]
82
+ if @user.save
83
+ flash[:success] = _("You can login with your new password.")
84
+ redirect_to admin_sign_in_path
85
+ else
86
+ flash[:error] = _("Passwords don't match.")
87
+ redirect_to admin_reset_password_path(:token => params[:token])
88
+ end
89
+ end
90
+ end
91
+
92
+ def sign_up
93
+
94
+ redirect_to admin_sign_in_path and return unless Typus.user_class.count.zero?
95
+
96
+ if request.post?
97
+
98
+ email, password = params[:user][:email], 'columbia'
99
+ user = Typus.user_class.generate(email, password)
100
+
101
+ if user.save
102
+ session[:typus_user_id] = user.id
103
+ flash[:notice] = _("Password set to \"{{password}}\".", :password => password)
104
+ redirect_to admin_dashboard_path
105
+ else
106
+ flash[:error] = _("That doesn't seem like a valid email address.")
107
+ end
108
+
109
+ else
110
+
111
+ flash[:notice] = _("Enter your email below to create the first user.")
112
+
113
+ end
114
+
115
+ end
116
+
117
+ private
118
+
119
+ def recover_password_disabled?
120
+ redirect_to admin_sign_in_path unless Typus::Configuration.options[:recover_password]
121
+ end
122
+
123
+ def select_layout
124
+ [ 'sign_up', 'sign_in', 'sign_out', 'recover_password', 'reset_password' ].include?(action_name) ? 'typus' : 'admin'
125
+ end
126
+
127
+ end