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
@@ -0,0 +1,92 @@
1
+ module Typus
2
+
3
+ module Configuration
4
+
5
+ ##
6
+ # Default Typus options which can be overwritten from the initializer.
7
+ #
8
+ typus_options = { :app_name => 'Typus',
9
+ :config_folder => 'config/typus',
10
+ :email => 'admin@example.com',
11
+ :locales => [ [ "English", :en ] ],
12
+ :recover_password => false,
13
+ :root => 'admin',
14
+ :ssl => false,
15
+ :templates_folder => 'admin/templates',
16
+ :user_class_name => 'TypusUser',
17
+ :user_fk => 'typus_user_id' }
18
+
19
+ ##
20
+ # Default model options which can be overwritten from the initializer.
21
+ #
22
+ model_options = { :default_action_on_item => 'edit',
23
+ :end_year => nil,
24
+ :form_rows => 10,
25
+ :icon_on_boolean => true,
26
+ :index_after_save => false,
27
+ :minute_step => 5,
28
+ :nil => 'nil',
29
+ :per_page => 15,
30
+ :sidebar_selector => 5,
31
+ :start_year => nil,
32
+ :toggle => true }
33
+
34
+ @@options = typus_options.merge(model_options)
35
+
36
+ mattr_accessor :options
37
+
38
+ ##
39
+ # Read Typus Configuration files placed on <tt>config/typus/**/*.yml</tt>.
40
+ #
41
+ # Typus::Configuration.config! overwrites @@config
42
+ #
43
+ def self.config!
44
+
45
+ files = Dir["#{Rails.root}/#{options[:config_folder]}/**/*.yml"].sort
46
+ files = files.delete_if { |x| x.include?('_roles.yml') }
47
+
48
+ @@config = {}
49
+ files.each do |file|
50
+ data = YAML.load_file(file)
51
+ @@config = @@config.merge(data) if data
52
+ end
53
+
54
+ return @@config
55
+
56
+ end
57
+
58
+ mattr_accessor :config
59
+
60
+ ##
61
+ # Read Typus Roles from configuration files placed on <tt>config/typus/**/*_roles.yml</tt>.
62
+ #
63
+ # Typus::Configuration.roles! overwrites @@roles
64
+ #
65
+ def self.roles!
66
+
67
+ files = Dir["#{Rails.root}/#{options[:config_folder]}/**/*_roles.yml"].sort
68
+
69
+ @@roles = { options[:root] => {} }
70
+
71
+ files.each do |file|
72
+ data = YAML.load_file(file)
73
+ next unless data
74
+ data.each do |key, value|
75
+ next unless value
76
+ begin
77
+ @@roles[key] = @@roles[key].merge(value)
78
+ rescue
79
+ @@roles[key] = value
80
+ end
81
+ end
82
+ end
83
+
84
+ return @@roles.compact
85
+
86
+ end
87
+
88
+ mattr_accessor :roles
89
+
90
+ end
91
+
92
+ end
@@ -0,0 +1,56 @@
1
+ module Typus
2
+
3
+ module Format
4
+
5
+ protected
6
+
7
+ def generate_html
8
+
9
+ items_count = @resource[:class].count(:joins => @joins, :conditions => @conditions)
10
+ items_per_page = @resource[:class].typus_options_for(:per_page).to_i
11
+
12
+ @pager = ::Paginator.new(items_count, items_per_page) do |offset, per_page|
13
+ data(:limit => per_page, :offset => offset)
14
+ end
15
+
16
+ @items = @pager.page(params[:page])
17
+
18
+ select_template :index
19
+
20
+ end
21
+
22
+ def generate_csv
23
+
24
+ require 'fastercsv'
25
+
26
+ fields = @resource[:class].typus_fields_for(:csv).collect { |i| i.first }
27
+ csv_string = FasterCSV.generate do |csv|
28
+ csv << fields.map { |f| _(f.humanize) }
29
+ data.each do |item|
30
+ csv << fields.map { |f| item.send(f) }
31
+ end
32
+ end
33
+
34
+ filename = "#{Time.now.strftime("%Y%m%d%H%M%S")}_#{@resource[:self]}.csv"
35
+ send_data(csv_string,
36
+ :type => 'text/csv; charset=utf-8; header=present',
37
+ :filename => filename)
38
+
39
+ rescue LoadError
40
+ render :text => _("FasterCSV is not installed.")
41
+ end
42
+
43
+ def generate_xml
44
+ fields = @resource[:class].typus_fields_for(:xml).collect { |i| i.first }
45
+ render :xml => data.to_xml(:only => fields)
46
+ end
47
+
48
+ def data(*args)
49
+ options = { :joins => @joins, :conditions => @conditions, :order => @order }
50
+ options.merge!(args.extract_options!)
51
+ @resource[:class].find(:all, options)
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -0,0 +1,173 @@
1
+ module Typus
2
+
3
+ def self.generator
4
+
5
+ logger = Logger.new("#{Rails.root}/log/#{Rails.env}.log")
6
+
7
+ # Create app/controllers/admin if doesn't exist.
8
+ admin_controllers_folder = "#{Rails.root}/app/controllers/admin"
9
+ Dir.mkdir(admin_controllers_folder) unless File.directory?(admin_controllers_folder)
10
+
11
+ # Get a list of all available app/controllers/admin
12
+ admin_controllers = Dir["#{Rails.root}/vendor/plugins/*/app/controllers/admin/*.rb", "#{Rails.root}/app/controllers/admin/*.rb"]
13
+ admin_controllers = admin_controllers.map { |i| File.basename(i) }
14
+
15
+ # Create app/views/admin if doesn't exist.
16
+ admin_views_folder = "#{Rails.root}/app/views/admin"
17
+ Dir.mkdir(admin_views_folder) unless File.directory?(admin_views_folder)
18
+
19
+ # Create test/functional/admin if doesn't exist.
20
+ if File.directory?("#{Rails.root}/test")
21
+ admin_controller_tests_folder = "#{Rails.root}/test/functional/admin"
22
+ Dir.mkdir(admin_controller_tests_folder) unless File.directory?(admin_controller_tests_folder)
23
+ end
24
+
25
+ # Get a list of all available functional test for admin.
26
+ admin_controller_tests = Dir["#{Rails.root}/vendor/plugins/*/test/functional/admin/*.rb", "#{Rails.root}/test/functional/admin/*.rb"]
27
+ admin_controller_tests = admin_controller_tests.map { |i| File.basename(i) }
28
+
29
+ # Generate unexisting controllers for resources which are not tied to
30
+ # a model.
31
+ resources.each do |resource|
32
+
33
+ controller_filename = "#{resource.underscore}_controller.rb"
34
+ controller_location = "#{admin_controllers_folder}/#{controller_filename}"
35
+
36
+ if !admin_controllers.include?(controller_filename)
37
+ controller = File.open(controller_location, "w+")
38
+ content = <<-RAW
39
+ # Controller generated by Typus, use it to extend admin functionality.
40
+ class Admin::#{resource}Controller < TypusController
41
+
42
+ ##
43
+ # This controller was generated because you have defined a resource
44
+ # which is not tied to a model on your <tt>config/typus/XXXXXX_roles.yml</tt>
45
+ # configuration file.
46
+ #
47
+ # admin:
48
+ # #{resource}: index
49
+ #
50
+
51
+ def index
52
+ end
53
+
54
+ end
55
+ RAW
56
+
57
+ controller.puts(content)
58
+ controller.close
59
+ logger.info "=> [typus] Admin::#{resource}Controller successfully created."
60
+
61
+ end
62
+
63
+ # And now we create the view.
64
+ view_folder = "#{admin_views_folder}/#{resource.underscore}"
65
+ view_filename = "index.html.erb"
66
+
67
+ if !File.exists?("#{view_folder}/#{view_filename}")
68
+ Dir.mkdir(view_folder) unless File.directory?(view_folder)
69
+ view = File.open("#{view_folder}/#{view_filename}", "w+")
70
+ content = <<-RAW
71
+ <!-- Sidebar -->
72
+
73
+ <% content_for :sidebar do %>
74
+ <%= typus_block :location => 'dashboard', :partial => 'sidebar' %>
75
+ <% end %>
76
+
77
+ <!-- Content -->
78
+
79
+ <h2><%= link_to _('Dashboard'), admin_dashboard_path %> &rsaquo; #{resource.humanize}</h2>
80
+
81
+ <p>And here we do whatever we want to ...</p>
82
+
83
+ RAW
84
+ view.puts(content)
85
+ view.close
86
+ logger.info "=> [typus] app/views/admin/#{resource.underscore}/index.html.erb successfully created."
87
+ end
88
+
89
+ end
90
+
91
+ # Generate unexisting controllers for resources which are tied to a
92
+ # model.
93
+ models.each do |model|
94
+
95
+ # Controller app/controllers/admin/*
96
+ controller_filename = "#{model.tableize}_controller.rb"
97
+ controller_location = "#{admin_controllers_folder}/#{controller_filename}"
98
+
99
+ if !admin_controllers.include?(controller_filename)
100
+ controller = File.open(controller_location, "w+")
101
+
102
+ content = <<-RAW
103
+ # Controller generated by Typus, use it to extend admin functionality.
104
+ class Admin::#{model.pluralize}Controller < Admin::MasterController
105
+
106
+ =begin
107
+
108
+ ##
109
+ # You can overwrite any Admin::MasterController methods.
110
+ #
111
+ def index
112
+ end
113
+
114
+ =end
115
+
116
+ =begin
117
+
118
+ ##
119
+ # You can extend Admin::MasterController with your methods.
120
+ #
121
+ # This actions have to be defined in <tt>config/typus/application.yml</tt>.
122
+ #
123
+ # #{model}:
124
+ # actions:
125
+ # index: custom_action
126
+ # edit: custom_action_for_an_item
127
+ #
128
+ def custom_action
129
+ end
130
+
131
+ def custom_action_for_an_item
132
+ end
133
+
134
+ =end
135
+
136
+ end
137
+ RAW
138
+
139
+ controller.puts(content)
140
+ controller.close
141
+ logger.info "=> [typus] Admin::#{model.pluralize}Controller successfully created."
142
+ end
143
+
144
+ # Test test/functional/admin/*_test.rb
145
+ test_filename = "#{model.tableize}_controller_test.rb"
146
+ test_location = "#{admin_controller_tests_folder}/#{test_filename}"
147
+
148
+ if !admin_controller_tests.include?(test_filename) && File.directory?("#{Rails.root}/test")
149
+ test = File.open(test_location, "w+")
150
+
151
+ content = <<-RAW
152
+ require 'test_helper'
153
+
154
+ class Admin::#{model.pluralize}ControllerTest < ActionController::TestCase
155
+
156
+ # Replace this with your real tests.
157
+ test "the truth" do
158
+ assert true
159
+ end
160
+
161
+ end
162
+ RAW
163
+
164
+ test.puts(content)
165
+ test.close
166
+ logger.info "=> [typus] Admin::#{model.pluralize}ControllerTest successfully created."
167
+ end
168
+
169
+ end
170
+
171
+ end
172
+
173
+ end
data/lib/typus/hash.rb ADDED
@@ -0,0 +1,10 @@
1
+ class Hash
2
+
3
+ ##
4
+ # Remove nil and empty keys.
5
+ #
6
+ def compact
7
+ delete_if { |key, value| value.nil? || value.empty? }
8
+ end
9
+
10
+ end
@@ -0,0 +1,17 @@
1
+ module Typus
2
+
3
+ module Locale
4
+
5
+ def set_locale
6
+ if params[:locale]
7
+ I18n.locale = params[:locale]
8
+ session[:typus_locale] = params[:locale]
9
+ redirect_to :back
10
+ else
11
+ I18n.locale = session[:typus_locale] || Typus.default_locale
12
+ end
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,22 @@
1
+ class Object
2
+
3
+ ##
4
+ # Instead of having to translate strings and defining a default value:
5
+ #
6
+ # t('Hello World!', :default => 'Hello World!')
7
+ #
8
+ # We define this method to define the value only once:
9
+ #
10
+ # _('Hello World!')
11
+ #
12
+ # Note that interpolation still works ...
13
+ #
14
+ # _('Hello {{world}}!', :world => @world)
15
+ #
16
+ def _(msg, *args)
17
+ options = args.extract_options!
18
+ options[:default] = msg
19
+ I18n.t(msg, options)
20
+ end
21
+
22
+ end
@@ -0,0 +1,33 @@
1
+ module Typus
2
+
3
+ module QuickEdit
4
+
5
+ def quick_edit
6
+
7
+ render :text => '' and return unless session[:typus_user_id]
8
+
9
+ url = url_for :controller => "admin/#{params[:resource]}",
10
+ :action => 'edit',
11
+ :id => params[:id]
12
+
13
+ @content = <<-HTML
14
+ var links = '';
15
+ links += '<div id="quick_edit">';
16
+ links += '<a href=\"#{url}\">#{params[:message]}</a>';
17
+ links += '</div>';
18
+ links += '<style type="text/css">';
19
+ links += '<!--';
20
+ links += '#quick_edit { font-size: 11px; float: right; position: fixed; right: 0px; background: #{params[:color]}; margin: 5px; padding: 3px 5px; }';
21
+ links += '#quick_edit a { color: #FFF; font-weight: bold; }'
22
+ links += '-->';
23
+ links += '</style>';
24
+ document.write(links);
25
+ HTML
26
+
27
+ render :text => @content
28
+
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,17 @@
1
+ module Typus
2
+
3
+ module Reloader
4
+
5
+ ##
6
+ # Reload config and roles when app is running in development.
7
+ #
8
+ def reload_config_et_roles
9
+ return if Rails.env.production?
10
+ logger.info "=> [typus] Configuration files have been reloaded."
11
+ Typus::Configuration.roles!
12
+ Typus::Configuration.config!
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,11 @@
1
+ class String
2
+
3
+ def typus_actions_for(filter)
4
+ Typus::Configuration.config[self]['actions'][filter.to_s].split(', ') rescue []
5
+ end
6
+
7
+ def typus_defaults_for(filter)
8
+ Typus::Configuration.config[self][filter.to_s].split(', ') rescue []
9
+ end
10
+
11
+ end
data/lib/typus/user.rb ADDED
@@ -0,0 +1,137 @@
1
+ module Typus
2
+
3
+ module EnableAsTypusUser
4
+
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ def enable_as_typus_user
12
+
13
+ extend ClassMethodsMixin
14
+
15
+ attr_accessor :password
16
+
17
+ validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/
18
+ validates_presence_of :email
19
+ validates_uniqueness_of :email
20
+
21
+ validates_confirmation_of :password, :if => :password_required?
22
+ validates_length_of :password, :within => 8..40, :if => :password_required?
23
+ validates_presence_of :password, :if => :password_required?
24
+
25
+ validates_presence_of :role
26
+
27
+ before_save :initialize_salt, :encrypt_password, :initialize_token
28
+
29
+ include InstanceMethods
30
+
31
+ end
32
+
33
+ end
34
+
35
+ module ClassMethodsMixin
36
+
37
+ def role
38
+ Typus::Configuration.roles.keys.sort
39
+ end
40
+
41
+ def authenticate(email, password)
42
+ user = find_by_email_and_status(email, true)
43
+ user && user.authenticated?(password) ? user : nil
44
+ end
45
+
46
+ def generate(email, password, role = Typus::Configuration.options[:root], status = true)
47
+ new :email => email,
48
+ :password => password,
49
+ :password_confirmation => password,
50
+ :role => role,
51
+ :status => status
52
+ end
53
+
54
+ end
55
+
56
+ module InstanceMethods
57
+
58
+ def full_name(*args)
59
+ options = args.extract_options!
60
+ full_name = (!first_name.empty? && !last_name.empty?) ? "#{first_name} #{last_name}" : email
61
+ full_name << " (#{role})" if options[:display_role]
62
+ return full_name
63
+ end
64
+
65
+ def authenticated?(password)
66
+ crypted_password == encrypt(password)
67
+ end
68
+
69
+ def resources
70
+ Typus::Configuration.roles[role].compact
71
+ end
72
+
73
+ def can_perform?(resource, action, options = {})
74
+
75
+ if options[:special]
76
+ _action = action
77
+ else
78
+ _action = case action
79
+ when 'new', 'create': 'create'
80
+ when 'index', 'show': 'read'
81
+ when 'edit', 'update': 'update'
82
+ when 'position': 'update'
83
+ when 'toggle': 'update'
84
+ when 'relate', 'unrelate': 'update'
85
+ when 'destroy': 'delete'
86
+ else
87
+ action
88
+ end
89
+ end
90
+
91
+ # OPTIMIZE: We should not use a rescue.
92
+ resources[resource.to_s].split(', ').include?(_action) rescue false
93
+
94
+ end
95
+
96
+ def is_root?
97
+ role == Typus::Configuration.options[:root]
98
+ end
99
+
100
+ protected
101
+
102
+ def generate_hash(string)
103
+ Digest::SHA1.hexdigest(string)
104
+ end
105
+
106
+ def encrypt_password
107
+ return if password.blank?
108
+ self.crypted_password = encrypt(password)
109
+ end
110
+
111
+ def encrypt(string)
112
+ generate_hash("--#{salt}--#{string}")
113
+ end
114
+
115
+ def initialize_salt
116
+ self.salt = generate_hash("--#{Time.now.utc.to_s}--#{email}--") if new_record?
117
+ end
118
+
119
+ def initialize_token
120
+ generate_token if new_record?
121
+ end
122
+
123
+ def generate_token
124
+ self.token = encrypt("--#{Time.now.utc.to_s}--#{password}--").first(12)
125
+ end
126
+
127
+ def password_required?
128
+ crypted_password.blank? || !password.blank?
129
+ end
130
+
131
+ end
132
+
133
+ end
134
+
135
+ end
136
+
137
+ ActiveRecord::Base.send :include, Typus::EnableAsTypusUser