typus 0.9.17

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 +8 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +86 -0
  4. data/Rakefile +61 -0
  5. data/VERSION +1 -0
  6. data/app/controllers/admin/master_controller.rb +354 -0
  7. data/app/controllers/typus_controller.rb +128 -0
  8. data/app/helpers/admin/form_helper.rb +386 -0
  9. data/app/helpers/admin/master_helper.rb +104 -0
  10. data/app/helpers/admin/public_helper.rb +27 -0
  11. data/app/helpers/admin/sidebar_helper.rb +236 -0
  12. data/app/helpers/admin/table_helper.rb +227 -0
  13. data/app/helpers/typus_helper.rb +194 -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 +24 -0
  18. data/app/views/admin/resources/index.html.erb +23 -0
  19. data/app/views/admin/resources/new.html.erb +22 -0
  20. data/app/views/admin/resources/show.html.erb +18 -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 +73 -0
  24. data/app/views/layouts/typus.html.erb +29 -0
  25. data/app/views/typus/dashboard.html.erb +9 -0
  26. data/app/views/typus/recover_password.html.erb +7 -0
  27. data/app/views/typus/reset_password.html.erb +15 -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/typus/de.yml +109 -0
  32. data/config/locales/typus/es.yml +109 -0
  33. data/config/locales/typus/language.yml.template +113 -0
  34. data/config/locales/typus/pt-BR.yml +111 -0
  35. data/config/locales/typus/ru.yml +111 -0
  36. data/generators/typus/templates/config/initializers/typus.rb +33 -0
  37. data/generators/typus/templates/config/typus/README +51 -0
  38. data/generators/typus/templates/config/typus/application.yml +6 -0
  39. data/generators/typus/templates/config/typus/application_roles.yml +23 -0
  40. data/generators/typus/templates/config/typus/typus.yml +14 -0
  41. data/generators/typus/templates/config/typus/typus_roles.yml +2 -0
  42. data/generators/typus/templates/db/create_typus_users.rb +21 -0
  43. data/generators/typus/templates/public/images/admin/arrow_down.gif +0 -0
  44. data/generators/typus/templates/public/images/admin/arrow_up.gif +0 -0
  45. data/generators/typus/templates/public/images/admin/spinner.gif +0 -0
  46. data/generators/typus/templates/public/images/admin/status_false.gif +0 -0
  47. data/generators/typus/templates/public/images/admin/status_true.gif +0 -0
  48. data/generators/typus/templates/public/images/admin/trash.gif +0 -0
  49. data/generators/typus/templates/public/javascripts/admin/application.js +14 -0
  50. data/generators/typus/templates/public/stylesheets/admin/reset.css +68 -0
  51. data/generators/typus/templates/public/stylesheets/admin/screen.css +729 -0
  52. data/generators/typus/typus_generator.rb +122 -0
  53. data/generators/typus_update_schema_to_01/templates/config/typus.yml +14 -0
  54. data/generators/typus_update_schema_to_01/templates/migration.rb +11 -0
  55. data/generators/typus_update_schema_to_01/typus_update_schema_to_01_generator.rb +19 -0
  56. data/lib/typus.rb +122 -0
  57. data/lib/typus/active_record.rb +307 -0
  58. data/lib/typus/authentication.rb +142 -0
  59. data/lib/typus/configuration.rb +85 -0
  60. data/lib/typus/extensions/routes.rb +15 -0
  61. data/lib/typus/format.rb +55 -0
  62. data/lib/typus/generator.rb +81 -0
  63. data/lib/typus/hash.rb +8 -0
  64. data/lib/typus/locale.rb +17 -0
  65. data/lib/typus/object.rb +21 -0
  66. data/lib/typus/quick_edit.rb +40 -0
  67. data/lib/typus/reloader.rb +15 -0
  68. data/lib/typus/string.rb +11 -0
  69. data/lib/typus/templates/index.html.erb +11 -0
  70. data/lib/typus/templates/resource_controller.rb.erb +15 -0
  71. data/lib/typus/templates/resource_controller_test.rb.erb +10 -0
  72. data/lib/typus/templates/resources_controller.rb.erb +37 -0
  73. data/lib/typus/user.rb +134 -0
  74. data/lib/vendor/active_record.rb +15 -0
  75. data/lib/vendor/paginator.rb +143 -0
  76. data/rails/init.rb +3 -0
  77. data/tasks/typus_tasks.rake +32 -0
  78. data/test/config/broken/application.yml +68 -0
  79. data/test/config/broken/application_roles.yml +20 -0
  80. data/test/config/broken/empty.yml +0 -0
  81. data/test/config/broken/empty_roles.yml +0 -0
  82. data/test/config/broken/undefined.yml +3 -0
  83. data/test/config/broken/undefined_roles.yml +6 -0
  84. data/test/config/default/typus.yml +14 -0
  85. data/test/config/default/typus_roles.yml +2 -0
  86. data/test/config/empty/empty_01.yml +0 -0
  87. data/test/config/empty/empty_01_roles.yml +0 -0
  88. data/test/config/empty/empty_02.yml +0 -0
  89. data/test/config/empty/empty_02_roles.yml +0 -0
  90. data/test/config/locales/es.yml +10 -0
  91. data/test/config/ordered/001_roles.yml +2 -0
  92. data/test/config/ordered/002_roles.yml +2 -0
  93. data/test/config/unordered/app_one_roles.yml +2 -0
  94. data/test/config/unordered/app_two_roles.yml +2 -0
  95. data/test/config/working/application.yml +68 -0
  96. data/test/config/working/application_roles.yml +22 -0
  97. data/test/config/working/typus.yml +14 -0
  98. data/test/config/working/typus_roles.yml +2 -0
  99. data/test/fixtures/app/controllers/admin/assets_controller.rb +2 -0
  100. data/test/fixtures/app/controllers/admin/categories_controller.rb +2 -0
  101. data/test/fixtures/app/controllers/admin/comments_controller.rb +2 -0
  102. data/test/fixtures/app/controllers/admin/pages_controller.rb +2 -0
  103. data/test/fixtures/app/controllers/admin/posts_controller.rb +2 -0
  104. data/test/fixtures/app/controllers/admin/status_controller.rb +6 -0
  105. data/test/fixtures/app/controllers/admin/typus_users_controller.rb +2 -0
  106. data/test/fixtures/app/controllers/admin/watch_dog_controller.rb +6 -0
  107. data/test/fixtures/app/views/admin/comments/_edit.html.erb +1 -0
  108. data/test/fixtures/app/views/admin/comments/_index.html.erb +1 -0
  109. data/test/fixtures/app/views/admin/comments/_new.html.erb +1 -0
  110. data/test/fixtures/app/views/admin/comments/_show.html.erb +1 -0
  111. data/test/fixtures/app/views/admin/comments/_sidebar.html.erb +1 -0
  112. data/test/fixtures/app/views/admin/dashboard/_content.html.erb +1 -0
  113. data/test/fixtures/app/views/admin/dashboard/_sidebar.html.erb +1 -0
  114. data/test/fixtures/app/views/admin/resources/_sidebar.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 +120 -0
  127. data/test/functional/admin/master_controller_test.rb +5 -0
  128. data/test/functional/admin/posts_controller_test.rb +261 -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 +321 -0
  132. data/test/helper.rb +51 -0
  133. data/test/helpers/admin/form_helper_test.rb +337 -0
  134. data/test/helpers/admin/master_helper_test.rb +69 -0
  135. data/test/helpers/admin/public_helper_test.rb +26 -0
  136. data/test/helpers/admin/sidebar_helper_test.rb +335 -0
  137. data/test/helpers/admin/table_helper_test.rb +239 -0
  138. data/test/helpers/typus_helper_test.rb +117 -0
  139. data/test/lib/active_record_test.rb +382 -0
  140. data/test/lib/configuration_test.rb +94 -0
  141. data/test/lib/hash_test.rb +11 -0
  142. data/test/lib/routes_test.rb +71 -0
  143. data/test/lib/string_test.rb +25 -0
  144. data/test/lib/typus_test.rb +85 -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 +136 -0
  153. data/typus.gemspec +228 -0
  154. metadata +241 -0
@@ -0,0 +1,122 @@
1
+ class TypusGenerator < Rails::Generator::Base
2
+
3
+ def manifest
4
+
5
+ record do |m|
6
+
7
+ # Default name for our application.
8
+ application = Rails.root.basename
9
+
10
+ # To create <tt>application.yml</tt> and <tt>application_roles.yml</tt>
11
+ # detect available AR models on the application.
12
+ models = Dir['app/models/*.rb'].collect { |x| File.basename(x).sub(/\.rb$/,'').camelize }
13
+ ar_models = []
14
+
15
+ models.each do |model|
16
+ begin
17
+ klass = model.constantize
18
+ active_record_model = klass.superclass.equal?(ActiveRecord::Base) && !klass.abstract_class?
19
+ active_record_model_with_sti = klass.superclass.superclass.equal?(ActiveRecord::Base)
20
+ ar_models << klass if active_record_model || active_record_model_with_sti
21
+ rescue Exception => error
22
+ puts "=> [typus] #{error.message} on '#{class_name}'."
23
+ end
24
+ end
25
+
26
+ # Configuration files
27
+ config_folder = Typus::Configuration.options[:config_folder]
28
+ Dir.mkdir(config_folder) unless File.directory?(config_folder)
29
+
30
+ configuration = { :base => '', :roles => '' }
31
+
32
+ ar_models.sort{ |x,y| x.class_name <=> y.class_name }.each do |model|
33
+
34
+ # Detect all relationships except polymorphic belongs_to using reflection.
35
+ relationships = [ :belongs_to, :has_and_belongs_to_many, :has_many, :has_one ].map do |relationship|
36
+ model.reflect_on_all_associations(relationship).reject { |i| i.options[:polymorphic] }.map { |i| i.name.to_s }
37
+ end.flatten.sort
38
+
39
+ # Remove foreign key and polymorphic type attributes
40
+ reject_columns = []
41
+ model.reflect_on_all_associations(:belongs_to).each do |i|
42
+ reject_columns << model.columns_hash[i.name.to_s + '_id']
43
+ reject_columns << model.columns_hash[i.name.to_s + '_type'] if i.options[:polymorphic]
44
+ end
45
+
46
+ model_columns = model.columns - reject_columns
47
+
48
+ # Don't show `text` fields and timestamps in lists.
49
+ list = model_columns.reject { |c| c.sql_type == 'text' || %w( created_at updated_at ).include?(c.name) }.map(&:name)
50
+ # Don't show timestamps in forms.
51
+ form = model_columns.reject { |c| %w( id created_at updated_at ).include?(c.name) }.map(&:name)
52
+ # Show all model columns in the show action.
53
+ show = model_columns.map(&:name)
54
+
55
+ # We want attributes of belongs_to relationships to be shown in our
56
+ # field collections if those are not polymorphic.
57
+ [ list, form, show ].each do |fields|
58
+ fields << model.reflect_on_all_associations(:belongs_to).reject { |i| i.options[:polymorphic] }.map { |i| i.name.to_s }
59
+ fields.flatten!
60
+ end
61
+
62
+ configuration[:base] << <<-RAW
63
+ #{model}:
64
+ fields:
65
+ list: #{list.join(', ')}
66
+ form: #{form.join(', ')}
67
+ show: #{show.join(', ')}
68
+ actions:
69
+ index:
70
+ edit:
71
+ order_by:
72
+ relationships: #{relationships.join(', ')}
73
+ filters:
74
+ search:
75
+ application: #{application}
76
+ description:
77
+
78
+ RAW
79
+
80
+ configuration[:roles] << <<-RAW
81
+ #{model}: create, read, update, delete
82
+ RAW
83
+
84
+ end
85
+
86
+ Dir["#{Typus.root}/generators/typus/templates/config/typus/*"].each do |f|
87
+ base = File.basename(f)
88
+ m.template "config/typus/#{base}", "#{config_folder}/#{base}",
89
+ :assigns => { :configuration => configuration }
90
+ end
91
+
92
+ # Initializer
93
+
94
+ [ 'config/initializers/typus.rb' ].each do |initializer|
95
+ m.template initializer, initializer, :assigns => { :application => application }
96
+ end
97
+
98
+ # Assets
99
+
100
+ [ 'public/stylesheets/admin',
101
+ 'public/javascripts/admin',
102
+ 'public/images/admin' ].each { |f| Dir.mkdir(f) unless File.directory?(f) }
103
+
104
+ [ 'public/stylesheets/admin/screen.css',
105
+ 'public/stylesheets/admin/reset.css',
106
+ 'public/javascripts/admin/application.js' ].each { |f| m.file f, f }
107
+
108
+ Dir["#{Typus.root}/generators/typus/templates/public/images/admin/*"].each do |f|
109
+ file = "public/images/admin/#{File.basename(f)}"
110
+ m.file file, file
111
+ end
112
+
113
+ # Migration file
114
+
115
+ m.migration_template 'db/create_typus_users.rb', 'db/migrate',
116
+ { :migration_file_name => 'create_typus_users' }
117
+
118
+ end
119
+
120
+ end
121
+
122
+ end
@@ -0,0 +1,14 @@
1
+ TypusUser:
2
+ fields:
3
+ list: email, role, status
4
+ form: first_name, last_name, role, email, password, password_confirmation
5
+ options:
6
+ selectors: role
7
+ booleans:
8
+ status: Active, Inactive
9
+ filters: status, role
10
+ search: first_name, last_name, email, role
11
+ application: Typus
12
+ description: System Users Administration
13
+ options:
14
+ icon_on_boolean: false
@@ -0,0 +1,11 @@
1
+ class UpdateTypusSchemaTo01 < ActiveRecord::Migration
2
+
3
+ def self.up
4
+ rename_column :typus_users, :roles, :role
5
+ end
6
+
7
+ def self.down
8
+ rename_column :typus_users, :role, :roles
9
+ end
10
+
11
+ end
@@ -0,0 +1,19 @@
1
+ class TypusUpdateSchemaTo01Generator < Rails::Generator::Base
2
+
3
+ def manifest
4
+
5
+ record do |m|
6
+
7
+ config_folder = Typus::Configuration.options[:config_folder]
8
+ Dir["#{Typus.root}/generators/typus_update_schema_to_01/templates/config/*"].each do |f|
9
+ base = File.basename(f)
10
+ m.template "config/#{base}", "#{config_folder}/#{base}"
11
+ end
12
+
13
+ m.migration_template 'migration.rb', 'db/migrate', { :migration_file_name => 'update_typus_schema_to_01' }
14
+
15
+ end
16
+
17
+ end
18
+
19
+ end
data/lib/typus.rb ADDED
@@ -0,0 +1,122 @@
1
+ module Typus
2
+
3
+ class << self
4
+
5
+ def version
6
+ @@version ||= File.read("#{root}/VERSION").strip
7
+ end
8
+
9
+ def root
10
+ File.dirname(__FILE__) + '/../'
11
+ end
12
+
13
+ def locales
14
+ Typus::Configuration.options[:locales]
15
+ end
16
+
17
+ def default_locale
18
+ locales.map(&:last).first
19
+ end
20
+
21
+ def applications
22
+ Typus::Configuration.config.collect { |i| i.last['application'] }.compact.uniq.sort
23
+ end
24
+
25
+ # List of the modules of an application.
26
+ def application(name)
27
+ Typus::Configuration.config.collect { |i| i.first if i.last['application'] == name }.compact.uniq.sort
28
+ end
29
+
30
+ def models
31
+ Typus::Configuration.config.map { |i| i.first }.sort
32
+ end
33
+
34
+ def models_on_header
35
+ models.collect { |m| m if m.constantize.typus_options_for(:on_header) }.compact
36
+ end
37
+
38
+ # List of resources, which are tableless models.
39
+ def resources(models = get_model_names)
40
+
41
+ all_resources = Typus::Configuration.roles.keys.map do |key|
42
+ Typus::Configuration.roles[key].keys
43
+ end.flatten.sort.uniq
44
+
45
+ all_resources.delete_if { |x| models.include?(x) || x == 'TypusUser' } rescue []
46
+
47
+ end
48
+
49
+ def get_model_names
50
+ Dir[ "#{Rails.root}/app/models/**/*.rb",
51
+ "#{Rails.root}/vendor/plugins/**/app/models/**/*.rb" ].collect { |m| File.basename(m).sub(/\.rb$/,'').camelize }
52
+ end
53
+
54
+ def user_class
55
+ Typus::Configuration.options[:user_class_name].constantize
56
+ end
57
+
58
+ def user_fk
59
+ Typus::Configuration.options[:user_fk]
60
+ end
61
+
62
+ def testing?
63
+ Rails.env.test? && Dir.pwd == "#{Rails.root}/vendor/plugins/typus"
64
+ end
65
+
66
+ def plugin?
67
+ File.exist?("#{Rails.root}/vendor/plugins/typus")
68
+ end
69
+
70
+ def boot!
71
+
72
+ # return unless File.exists?("#{Rails.root}/config/initializers/typus.rb") || testing?
73
+ return if %w( script/generate script/destroy ).include?($0)
74
+
75
+ if testing?
76
+ Typus::Configuration.options[:config_folder] = 'vendor/plugins/typus/test/config/working'
77
+ end
78
+
79
+ # Ruby Extensions
80
+ require 'typus/hash'
81
+ require 'typus/object'
82
+ require 'typus/string'
83
+
84
+ # Load configuration and roles.
85
+ Typus::Configuration.config!
86
+ Typus::Configuration.roles!
87
+
88
+ # Load translation files from the plugin or the gem.
89
+ if plugin?
90
+ I18n.load_path += Dir[File.join(root, 'config', 'locales', '**', '*.{rb,yml}')]
91
+ else
92
+ Gem.path.each { |g| I18n.load_path += Dir[File.join("#{g}/gems/*typus-#{version}/config/locales/**/*.{rb,yml}")] }
93
+ end
94
+
95
+ # Require the test/models on when testing.
96
+ require File.dirname(__FILE__) + '/../test/models' if testing?
97
+
98
+ # Rails Extensions.
99
+ require 'typus/active_record'
100
+ require 'typus/extensions/routes'
101
+
102
+ # Mixins.
103
+ require 'typus/authentication'
104
+ require 'typus/format'
105
+ require 'typus/generator'
106
+ require 'typus/locale'
107
+ require 'typus/reloader'
108
+ require 'typus/quick_edit'
109
+ require 'typus/user'
110
+
111
+ # Vendor.
112
+ require 'vendor/active_record'
113
+ require 'vendor/paginator'
114
+
115
+ # Run controllers generator ...
116
+ generator unless testing? || Rails.env.production?
117
+
118
+ end
119
+
120
+ end
121
+
122
+ end
@@ -0,0 +1,307 @@
1
+ module Typus
2
+
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+
9
+ # Return model fields as a OrderedHash
10
+ def model_fields
11
+ hash = ActiveSupport::OrderedHash.new
12
+ columns.map { |u| hash[u.name.to_sym] = u.type.to_sym }
13
+ return hash
14
+ end
15
+
16
+ def model_relationships
17
+ hash = ActiveSupport::OrderedHash.new
18
+ reflect_on_all_associations.map { |i| hash[i.name] = i.macro }
19
+ return hash
20
+ end
21
+
22
+ ##
23
+ # This method is used to change a Rails behavior.
24
+ #
25
+ # typus $ script/console
26
+ # Loading development environment (Rails 2.3.2)
27
+ # >> TypusUser.human_name
28
+ # => "Typususer"
29
+ # >> TypusUser.typus_human_name
30
+ # => "Typus user"
31
+ #
32
+ def typus_human_name
33
+ human_name(:default => self.name.underscore.humanize)
34
+ end
35
+
36
+ def typus_description
37
+ Typus::Configuration.config[self.name]['description']
38
+ end
39
+
40
+ # Form and list fields
41
+ def typus_fields_for(filter)
42
+
43
+ fields_with_type = ActiveSupport::OrderedHash.new
44
+
45
+ begin
46
+ fields = Typus::Configuration.config[name]['fields'][filter.to_s]
47
+ fields = fields.split(', ').collect { |f| f.to_sym }
48
+ rescue
49
+ return [] if filter == 'list'
50
+ filter = 'list'
51
+ retry
52
+ end
53
+
54
+ begin
55
+
56
+ fields.each do |field|
57
+
58
+ attribute_type = model_fields[field]
59
+
60
+ # Custom field_type depending on the attribute name.
61
+ case field.to_s
62
+ when 'parent_id' then attribute_type = :tree
63
+ when /file_name/ then attribute_type = :file
64
+ when /password/ then attribute_type = :password
65
+ when 'position' then attribute_type = :position
66
+ end
67
+
68
+ if reflect_on_association(field)
69
+ attribute_type = reflect_on_association(field).macro
70
+ end
71
+
72
+ if typus_field_options_for(:selectors).include?(field)
73
+ attribute_type = :selector
74
+ end
75
+
76
+ if typus_tiny_mce_fields.include?(field.to_s)
77
+ attribute_type = :tiny_mce
78
+ end
79
+
80
+ # And finally insert the field and the attribute_type
81
+ # into the fields_with_type ordered hash.
82
+ fields_with_type[field.to_s] = attribute_type
83
+
84
+ end
85
+
86
+ rescue
87
+ fields = Typus::Configuration.config[name]['fields']['list'].split(', ')
88
+ retry
89
+ end
90
+
91
+ return fields_with_type
92
+
93
+ end
94
+
95
+ # Return tiny_mce options of the model merged into the default options
96
+ def typus_tiny_mce_options
97
+ typus_options_for(:tiny_mce).merge(Typus::Configuration.config[name]['fields']['options']['tiny_mce']['options'].symbolize_keys.delete_if { |key,value| value == nil})
98
+ rescue
99
+ typus_options_for(:tiny_mce)
100
+ end
101
+
102
+ # Tiny_mce fields of the model
103
+ def typus_tiny_mce_fields
104
+ Typus::Configuration.config[name]['fields']['options']['tiny_mce']['fields'].split(', ')
105
+ rescue
106
+ []
107
+ end
108
+
109
+ # Typus sidebar filters.
110
+ def typus_filters
111
+
112
+ fields_with_type = ActiveSupport::OrderedHash.new
113
+
114
+ data = Typus::Configuration.config[name]['filters']
115
+ return [] unless data
116
+ fields = data.split(', ').collect { |i| i.to_sym }
117
+
118
+ fields.each do |field|
119
+ attribute_type = model_fields[field.to_sym]
120
+ if reflect_on_association(field.to_sym)
121
+ attribute_type = reflect_on_association(field.to_sym).macro
122
+ end
123
+ fields_with_type[field.to_s] = attribute_type
124
+ end
125
+
126
+ return fields_with_type
127
+
128
+ end
129
+
130
+ # Extended actions for this model on Typus.
131
+ def typus_actions_for(filter)
132
+ Typus::Configuration.config[name]['actions'][filter.to_s].split(', ')
133
+ rescue
134
+ []
135
+ end
136
+
137
+ # Used for +search+, +relationships+
138
+ def typus_defaults_for(filter)
139
+ data = Typus::Configuration.config[name][filter.to_s]
140
+ return (!data.nil?) ? data.split(', ') : []
141
+ end
142
+
143
+ def typus_field_options_for(filter)
144
+ Typus::Configuration.config[name]['fields']['options'][filter.to_s].split(', ').collect { |i| i.to_sym }
145
+ rescue
146
+ []
147
+ end
148
+
149
+ # We should be able to overwrite options by model.
150
+ def typus_options_for(filter)
151
+
152
+ data = Typus::Configuration.config[name]
153
+ unless data['options'].nil?
154
+ value = data['options'][filter.to_s] unless data['options'][filter.to_s].nil?
155
+ end
156
+
157
+ return (!value.nil?) ? value : Typus::Configuration.options[filter.to_sym]
158
+
159
+ end
160
+
161
+ def typus_export_formats
162
+ data = Typus::Configuration.config[name]
163
+ !data['export'].nil? ? data['export'].split(', ') : []
164
+ end
165
+
166
+ # Used for `order_by`.
167
+ def typus_order_by
168
+
169
+ fields = typus_defaults_for(:order_by)
170
+ return "#{table_name}.id ASC" if fields.empty?
171
+
172
+ order = fields.map do |field|
173
+ (field.include?('-')) ? "#{table_name}.#{field.delete('-')} DESC" : "#{table_name}.#{field} ASC"
174
+ end.join(', ')
175
+
176
+ return order
177
+
178
+ end
179
+
180
+ # We are able to define our own booleans.
181
+ def typus_boolean(attribute = :default)
182
+
183
+ boolean = Typus::Configuration.config[name]['fields']['options']['booleans'][attribute.to_s] rescue nil
184
+ boolean = 'true, false' if boolean.nil?
185
+
186
+ hash = ActiveSupport::OrderedHash.new
187
+
188
+ if boolean.kind_of?(Array)
189
+ hash[:true] = boolean.first.humanize
190
+ hash[:false] = boolean.last.humanize
191
+ else
192
+ hash[:true] = boolean.split(', ').first.humanize
193
+ hash[:false] = boolean.split(', ').last.humanize
194
+ end
195
+
196
+ return hash
197
+
198
+ end
199
+
200
+ # We are able to define how to display dates on Typus
201
+ def typus_date_format(attribute = :default)
202
+ date_format = Typus::Configuration.config[name]['fields']['options']['date_formats'][attribute.to_s].to_sym rescue nil
203
+ date_format = :db if date_format.nil?
204
+ return date_format
205
+ end
206
+
207
+ # We are able to define which template to use to render the attribute
208
+ # within the form
209
+ def typus_template(attribute)
210
+ Typus::Configuration.config[name]['fields']['options']['templates'][attribute.to_s]
211
+ rescue
212
+ nil
213
+ end
214
+
215
+ def build_conditions(params)
216
+
217
+ conditions, joins = merge_conditions, []
218
+
219
+ query_params = params.dup
220
+ %w( action controller ).each { |param| query_params.delete(param) }
221
+
222
+ # If a search is performed.
223
+ if query_params[:search]
224
+ search = typus_defaults_for(:search).map do |s|
225
+ ["LOWER(#{s}) LIKE '%#{ActiveRecord::Base.connection.quote_string(query_params[:search].downcase)}%'"]
226
+ end
227
+ conditions = merge_conditions(conditions, search.join(' OR '))
228
+ end
229
+
230
+ query_params.each do |key, value|
231
+
232
+ filter_type = model_fields[key.to_sym] || model_relationships[key.to_sym]
233
+
234
+ ##
235
+ # Sidebar filters:
236
+ #
237
+ # - Booleans: true, false
238
+ # - Datetime: today, past_7_days, this_month, this_year
239
+ # - Integer & String: *_id and "selectors" (p.ej. category_id)
240
+ #
241
+ case filter_type
242
+ when :boolean
243
+ condition = { key => (value == 'true') ? true : false }
244
+ conditions = merge_conditions(conditions, condition)
245
+ when :datetime
246
+ interval = case value
247
+ when 'today' then Time.new.midnight..Time.new.midnight.tomorrow
248
+ when 'past_7_days' then 6.days.ago.midnight..Time.new.midnight.tomorrow
249
+ when 'this_month' then Time.new.midnight.last_month..Time.new.midnight.tomorrow
250
+ when 'this_year' then Time.new.midnight.last_year..Time.new.midnight.tomorrow
251
+ end
252
+ condition = ["#{key} BETWEEN ? AND ?", interval.first.to_s(:db), interval.last.to_s(:db)]
253
+ conditions = merge_conditions(conditions, condition)
254
+ when :integer, :string
255
+ condition = { key => value }
256
+ conditions = merge_conditions(conditions, condition)
257
+ when :has_and_belongs_to_many
258
+ condition = { key => { :id => value } }
259
+ conditions = merge_conditions(conditions, condition)
260
+ joins << key.to_sym
261
+ end
262
+
263
+ end
264
+
265
+ return conditions, joins
266
+
267
+ end
268
+
269
+ end
270
+
271
+ module InstanceMethods
272
+
273
+ def previous_and_next(condition = {}, klass = self.class)
274
+
275
+ previous_conditions = "#{klass.primary_key} < #{id}"
276
+ next_conditions = "#{klass.primary_key} > #{id}"
277
+
278
+ if !condition.empty?
279
+ conditions, joins = klass.build_conditions(condition)
280
+ previous_conditions += " AND #{conditions}"
281
+ next_conditions += " AND #{conditions}"
282
+ end
283
+
284
+ previous_ = klass.find :first,
285
+ :select => [klass.primary_key],
286
+ :order => "#{klass.primary_key} DESC",
287
+ :conditions => previous_conditions
288
+
289
+ next_ = klass.find :first,
290
+ :select => [klass.primary_key],
291
+ :order => "#{klass.primary_key} ASC",
292
+ :conditions => next_conditions
293
+
294
+ return previous_, next_
295
+
296
+ end
297
+
298
+ def typus_name
299
+ respond_to?(:name) ? name : "#{self.class}##{id}"
300
+ end
301
+
302
+ end
303
+
304
+ end
305
+
306
+ ActiveRecord::Base.send :include, Typus
307
+ ActiveRecord::Base.send :include, Typus::InstanceMethods