ixtlan 0.2.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 (65) hide show
  1. data/Manifest.txt +64 -0
  2. data/README.txt +86 -0
  3. data/Rakefile +38 -0
  4. data/generators/ixtlan_datamapper_model/ixtlan_datamapper_model_generator.rb +20 -0
  5. data/generators/ixtlan_datamapper_model/templates/model.rb +17 -0
  6. data/generators/ixtlan_datamapper_rspec_model/ixtlan_datamapper_rspec_model_generator.rb +20 -0
  7. data/generators/ixtlan_datamapper_rspec_model/templates/model_spec.rb +58 -0
  8. data/generators/ixtlan_datamapper_rspec_scaffold/ixtlan_datamapper_rspec_scaffold_generator.rb +37 -0
  9. data/generators/ixtlan_datamapper_rspec_scaffold/templates/controller.rb +99 -0
  10. data/generators/ixtlan_datamapper_rspec_scaffold/templates/controller_spec.rb +206 -0
  11. data/generators/ixtlan_datamapper_rspec_scaffold/templates/guard.rb +8 -0
  12. data/generators/ixtlan_datamapper_rspec_scaffold/templates/i18n.rb +11 -0
  13. data/lib/dm-serializer/common.rb +28 -0
  14. data/lib/dm-serializer/to_xml.rb +99 -0
  15. data/lib/dm-serializer/xml_serializers/libxml.rb +42 -0
  16. data/lib/dm-serializer/xml_serializers/nokogiri.rb +36 -0
  17. data/lib/dm-serializer/xml_serializers/rexml.rb +30 -0
  18. data/lib/dm-serializer/xml_serializers.rb +17 -0
  19. data/lib/dm-serializer.rb +1 -0
  20. data/lib/ixtlan/audit_config.rb +35 -0
  21. data/lib/ixtlan/cms_script.rb +29 -0
  22. data/lib/ixtlan/controllers/texts_controller.rb +65 -0
  23. data/lib/ixtlan/digest.rb +15 -0
  24. data/lib/ixtlan/error_notifier/error_notification.rhtml +1 -0
  25. data/lib/ixtlan/guard.rb +125 -0
  26. data/lib/ixtlan/logger_config.rb +65 -0
  27. data/lib/ixtlan/models/authentication.rb +30 -0
  28. data/lib/ixtlan/models/configuration.rb +74 -0
  29. data/lib/ixtlan/models/configuration_locale.rb +19 -0
  30. data/lib/ixtlan/models/group.rb +69 -0
  31. data/lib/ixtlan/models/group_locale_user.rb +22 -0
  32. data/lib/ixtlan/models/group_user.rb +39 -0
  33. data/lib/ixtlan/models/locale.rb +37 -0
  34. data/lib/ixtlan/models/permission.rb +29 -0
  35. data/lib/ixtlan/models/phrase.rb +71 -0
  36. data/lib/ixtlan/models/role.rb +35 -0
  37. data/lib/ixtlan/models/text.rb +140 -0
  38. data/lib/ixtlan/models/translation.rb +40 -0
  39. data/lib/ixtlan/models/user.rb +112 -0
  40. data/lib/ixtlan/models/word.rb +12 -0
  41. data/lib/ixtlan/models.rb +13 -0
  42. data/lib/ixtlan/modified_by.rb +80 -0
  43. data/lib/ixtlan/monkey_patches.rb +38 -0
  44. data/lib/ixtlan/optimistic_persistence.rb +20 -0
  45. data/lib/ixtlan/optimistic_persistence_module.rb +22 -0
  46. data/lib/ixtlan/optimistic_persistence_validation.rb +21 -0
  47. data/lib/ixtlan/passwords.rb +19 -0
  48. data/lib/ixtlan/rails/audit.rb +22 -0
  49. data/lib/ixtlan/rails/error_handling.rb +130 -0
  50. data/lib/ixtlan/rails/guard.rb +11 -0
  51. data/lib/ixtlan/rails/session_timeout.rb +93 -0
  52. data/lib/ixtlan/rails/timestamps_modified_by_filter.rb +33 -0
  53. data/lib/ixtlan/rails/unrestful_authentication.rb +137 -0
  54. data/lib/ixtlan/rolling_file.rb +61 -0
  55. data/lib/ixtlan/session.rb +18 -0
  56. data/lib/ixtlan/user_logger.rb +49 -0
  57. data/lib/ixtlan/version.rb +3 -0
  58. data/lib/ixtlan.rb +2 -0
  59. data/lib/models.rb +14 -0
  60. data/spec/authentication_spec.rb +30 -0
  61. data/spec/guard_spec.rb +125 -0
  62. data/spec/guards/samples.rb +12 -0
  63. data/spec/spec.opts +1 -0
  64. data/spec/spec_helper.rb +170 -0
  65. metadata +210 -0
@@ -0,0 +1,61 @@
1
+ require 'logging'
2
+
3
+ module Ixtlan
4
+
5
+ class RollingFile < ::Logging::Appenders::RollingFile
6
+
7
+ def current_logfile
8
+ "#{@filename_base}_#{Time.now.strftime(@date_pattern)}.#{@extension}"
9
+ end
10
+
11
+ def initialize( name, opts = {} )
12
+ @date_pattern = opts.getopt(:date_pattern, '%Y-%m-%d')
13
+ @extension = opts.getopt(:filename_extension, 'log')
14
+ @filename_base = opts.getopt(:filename_base, 'log')
15
+ opts.delete(:age)
16
+ opts[:truncate] = false
17
+ opts[:filename] = current_logfile
18
+ super(name, opts)
19
+ roll_files
20
+ end
21
+
22
+ def roll_required?( str = nil )
23
+ not ::File.exist?(current_logfile)
24
+ end
25
+
26
+ def roll_files
27
+ @fn = current_logfile
28
+ files = Dir.glob("#{@filename_base}_*.#{@extension}").sort
29
+ if (files.size > @keep)
30
+ files[0..(files.size - 1 - @keep)].each do |file|
31
+ ::File.delete file
32
+ end
33
+ end
34
+ end
35
+
36
+ def write( event )
37
+ str = event.instance_of?(::Logging::LogEvent) ?
38
+ @layout.format(event) : event.to_s
39
+ return if str.empty?
40
+
41
+ check_logfile
42
+
43
+ if roll_required?(str)
44
+ return roll unless @lockfile
45
+
46
+ begin
47
+ @lockfile.lock {
48
+ check_logfile
49
+ roll if roll_required?
50
+ }
51
+ rescue
52
+ # just do it without lock !!
53
+ check_logfile
54
+ roll if roll_required?
55
+ end
56
+ end
57
+ super(str)
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,18 @@
1
+ require 'rack_datamapper/session/abstract/store'
2
+ module Ixtlan
3
+ class Session < DataMapper::Session::Abstract::Session
4
+
5
+ def data=(data)
6
+ d = {}
7
+ data.each{|k,v| d[k.to_sym] = v}
8
+ @user = d.delete(:user)
9
+ @flash = d.delete(:flash)
10
+ @expires_at = d.delete(:expires_at)
11
+ attribute_set(:data, ::Base64.encode64(Marshal.dump(d)))
12
+ end
13
+
14
+ def data
15
+ Marshal.load(::Base64.decode64(attribute_get(:data))).merge({:user => @user, :flash => @flash, :expires_at => @expires_at})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,49 @@
1
+ require 'slf4r'
2
+ module Ixtlan
3
+
4
+ class UserLogger
5
+
6
+ def initialize(arg)
7
+ @logger = Slf4r::LoggerFacade.new(arg)
8
+ end
9
+
10
+ private
11
+
12
+ def login_from(controller)
13
+ user = controller.respond_to?(:current_user) ? controller.send(:current_user) : nil
14
+ user.nil? ? nil: user.login
15
+ end
16
+
17
+ public
18
+
19
+ def log(controller, message = nil, &block)
20
+ log_user(login_from(controller), message, &block)
21
+ end
22
+
23
+ def log_action(controller, message = nil)
24
+ log_user(login_from(controller)) do
25
+ as_xml = controller.response.content_type == 'application/xml' ? " - xml" : ""
26
+ if controller.params[:controller]
27
+ audits = controller.instance_variable_get("@#{controller.params[:controller].to_sym}")
28
+ if(audits)
29
+ "#{controller.params[:controller]}##{controller.params[:action]} #{audits.model.to_s.plural}[#{audits.size}]#{as_xml}#{message}"
30
+ else
31
+ audit = controller.instance_variable_get("@#{controller.params[:controller].singular.to_sym}")
32
+ if(audit)
33
+ "#{controller.params[:controller]}##{controller.params[:action]} #{audit.model}(#{audit.key})#{as_xml}#{message}"
34
+ else
35
+ "#{controller.params[:controller]}##{controller.params[:action]}#{as_xml}#{message}"
36
+ end
37
+ end
38
+ else
39
+ "params=#{controller.params.inspect}"
40
+ end
41
+ end
42
+ end
43
+
44
+ def log_user(user, message = nil, &block)
45
+ user = "???" unless user
46
+ @logger.info {"[#{user}] #{message}#{block.call if block}" }
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ class Ixtlan
2
+ VERSION = '0.2.0'
3
+ end
data/lib/ixtlan.rb ADDED
@@ -0,0 +1,2 @@
1
+ module Ixtlan
2
+ end
data/lib/models.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'dm-core'
2
+ require 'dm-timestamps'
3
+ require 'dm-validations'
4
+ require 'dm-serializer'
5
+ require 'ixtlan/models'
6
+ load 'ixtlan/models/user.rb'
7
+ load 'ixtlan/models/group_locale_user.rb'
8
+ load 'ixtlan/models/group.rb'
9
+ load 'ixtlan/models/group_user.rb'
10
+ load 'ixtlan/models/locale.rb'
11
+ load 'ixtlan/models/permission.rb'
12
+ load 'ixtlan/models/role.rb'
13
+ load 'ixtlan/models/configuration.rb'
14
+ load 'ixtlan/models/configuration_locale.rb'
@@ -0,0 +1,30 @@
1
+
2
+ require 'pathname'
3
+ require Pathname(__FILE__).dirname + 'spec_helper.rb'
4
+
5
+
6
+ require 'ixtlan' / 'models' / 'authentication'
7
+
8
+ describe Ixtlan::Models::Authentication do
9
+
10
+ before :each do
11
+ #Ixtlan::Models::Group.all.destroy!
12
+ #Ixtlan::Models::User.all.destroy!
13
+ user = Ixtlan::Models::User.new(:login => "marvin2", :name => 'marvin the robot', :email=> "marvin@universe.example.com", :language => "xx", :id => 1356, :created_at => DateTime.now, :updated_at => DateTime.now)
14
+ user.created_by_id = 1356
15
+ user.updated_by_id = 1356
16
+ user.save!
17
+ group = Ixtlan::Models::Group.create(:id => 1356, :name => 'marvin2_root', :current_user => user)
18
+ user.groups << group
19
+ group.save
20
+ group.locales << Ixtlan::Models::Locale.default
21
+ group.locales << Ixtlan::Models::Locale.first_or_create(:code => "en")
22
+ @authentication = Ixtlan::Models::Authentication.create(:login => user.login, :user => user)
23
+ end
24
+
25
+ it "should" do
26
+ xml = @authentication.to_xml
27
+ xml.gsub!(/[0-9-]{10}T[0-9+-:]{14}/, "").gsub!(/ type='[^']+'/, '').gsub!(/<created_at><\/created_at>/, "<created_at/>").should == "<authentication><login>marvin2</login><user><id>1356</id><login>marvin2</login><name>marvin the robot</name><email>marvin@universe.example.com</email><language>xx</language><created_at/><updated_at></updated_at><created_by_id>1356</created_by_id><updated_by_id>1356</updated_by_id><groups><group><id>1356</id><name>marvin2_root</name><created_at/><created_by_id>1356</created_by_id><updated_by_id>1356</updated_by_id><locales><locale><code>DEFAULT</code><created_at/></locale><locale><code>en</code><created_at/></locale></locales></group></groups></user></authentication>"
28
+ end
29
+
30
+ end
@@ -0,0 +1,125 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname + 'spec_helper.rb'
3
+
4
+ module ActionView
5
+ module Base
6
+ end
7
+ end
8
+ module Erector
9
+ class Widget
10
+
11
+ attr_writer :controller
12
+
13
+ class Helpers
14
+ attr_accessor :controller
15
+ end
16
+
17
+ def helpers
18
+ @helpers ||= Helpers.new
19
+ @helpers.controller = @controller
20
+ @helpers
21
+ end
22
+ end
23
+ end
24
+
25
+ require 'ixtlan/rails/guard'
26
+
27
+ describe Ixtlan::Models::Permission do
28
+
29
+ before :each do
30
+ @role = Ixtlan::Models::Role.new :name => 'root'
31
+ @permission = Ixtlan::Models::Permission.new :resource => "permissions", :action => "index"
32
+ @permission.roles << @role
33
+ end
34
+
35
+ it "should produce xml" do
36
+ @permission.to_xml.should == "<permission><resource>permissions</resource><action>index</action><roles type='array'><role><name>root</name></role></roles></permission>"
37
+ end
38
+
39
+ end
40
+
41
+ class Controller
42
+ include ActionController::Base
43
+ end
44
+
45
+ describe Ixtlan::Guard do
46
+
47
+ before :each do
48
+ Ixtlan::Guard.load( Slf4r::LoggerFacade.new(:root), :root, (Pathname(__FILE__).dirname + 'guards').expand_path )
49
+
50
+ @controller = Controller.new
51
+ @widget = Erector::Widget.new
52
+ @widget.controller = @controller
53
+ end
54
+
55
+ it 'should export permissions' do
56
+ Ixtlan::Guard.export_xml.should == "<permissions type='array'><permission><resource>configurations</resource><action>edit</action><roles type='array'><role><name>root</name></role></roles></permission><permission><resource>configurations</resource><action>show</action><roles type='array'><role><name>root</name></role><role><name>admin</name></role></roles></permission><permission><resource>configurations</resource><action>update</action><roles type='array'><role><name>root</name></role></roles></permission><permission><resource>permissions</resource><action>destroy</action><roles type='array'><role><name>root</name></role></roles></permission><permission><resource>permissions</resource><action>edit</action><roles type='array'><role><name>root</name></role><role><name>admin</name></role></roles></permission><permission><resource>permissions</resource><action>show</action><roles type='array'><role><name>root</name></role><role><name>guest</name></role></roles></permission><permission><resource>permissions</resource><action>update</action><roles type='array'><role><name>root</name></role><role><name>admin</name></role></roles></permission></permissions>"
57
+ end
58
+
59
+ it 'should allow' do
60
+ Ixtlan::Guard.check(@controller, :permissions, :update).should be_true
61
+ end
62
+
63
+ it 'should disallow' do
64
+ Ixtlan::Guard.check(@controller, :configurations, :update).should be_false
65
+ end
66
+
67
+ it 'should allow with locale' do
68
+ Ixtlan::Guard.check(@controller, :permissions, :update, Ixtlan::Models::Locale.first_or_create(:code => "en")).should be_true
69
+ end
70
+
71
+ it 'should disallow with locale' do
72
+ Ixtlan::Guard.check(@controller, :configurations, :update, Ixtlan::Models::Locale.first_or_create(:code => "en")).should be_false
73
+ end
74
+
75
+ it 'should raise GuardException on unknown controller' do
76
+ lambda { Ixtlan::Guard.check(@controller, :unknown_resources, :update) }.should raise_error(Ixtlan::GuardException)
77
+ end
78
+
79
+ it 'should raise GuardException on unknown action' do
80
+ lambda { Ixtlan::Guard.check(@controller, :permissions, :unknown_action) }.should raise_error(Ixtlan::GuardException)
81
+ end
82
+
83
+ it 'should pass' do
84
+ @controller.params[:action] = :update
85
+ @controller.params[:controller] = :permissions
86
+
87
+ @controller.send(:guard).should be_true
88
+ end
89
+
90
+ it 'should deny permission' do
91
+ @controller.params[:action] = :update
92
+ @controller.params[:controller] = :configurations
93
+
94
+ lambda {@controller.send(:guard)}.should raise_error( Ixtlan::PermissionDenied)
95
+ end
96
+
97
+ it 'should pass with locale' do
98
+ @controller.params[:action] = :update
99
+ @controller.params[:controller] = :permissions
100
+
101
+ @controller.send(:guard, Ixtlan::Models::Locale.first_or_create(:code => "en")).should be_true
102
+ end
103
+
104
+ it 'should deny permission with right locale' do
105
+ @controller.params[:action] = :update
106
+ @controller.params[:controller] = :configurations
107
+
108
+ lambda {@controller.send(:guard, Ixtlan::Models::Locale.first_or_create(:code => "en"))}.should raise_error( Ixtlan::PermissionDenied)
109
+ end
110
+
111
+ it 'should deny permission with wrong locale' do
112
+ @controller.params[:action] = :update
113
+ @controller.params[:controller] = :permissions
114
+
115
+ lambda {@controller.send(:guard, Ixtlan::Models::Locale.first_or_create(:code => "de"))}.should raise_error( Ixtlan::PermissionDenied)
116
+ end
117
+
118
+ it 'should allow with locale' do
119
+ @widget.send(:allowed, :permissions, :update, Ixtlan::Models::Locale.first_or_create(:code => "en")).should be_true
120
+ end
121
+
122
+ it 'should deny permission with locale' do
123
+ @widget.send(:allowed, :configurations, :update, Ixtlan::Models::Locale.first_or_create(:code => "en")).should be_false
124
+ end
125
+ end
@@ -0,0 +1,12 @@
1
+ Ixtlan::Guard.initialize(:permissions,
2
+ { :show => [:guest],
3
+ :edit => [:root, :admin],
4
+ :update => [:root, :admin],
5
+ :destroy => [:root] }
6
+ )
7
+
8
+ Ixtlan::Guard.initialize(:configurations,
9
+ { :show => [:admin],
10
+ :edit => [:root],
11
+ :update => [:root] }
12
+ )
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,170 @@
1
+ require 'rubygems'
2
+ lib_path = (Pathname(__FILE__).dirname.parent.expand_path + 'lib').to_s
3
+ $LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
4
+
5
+ require 'dm-core'
6
+ require 'dm-validations'
7
+ require 'dm-serializer'
8
+ require 'dm-timestamps'
9
+
10
+ require 'slf4r'
11
+
12
+ require 'ixtlan' / 'models'
13
+ require 'ixtlan' / 'user_logger'
14
+ require 'ixtlan' / 'modified_by'
15
+ require 'ixtlan' / 'models' / 'user'
16
+ require 'ixtlan' / 'models' / 'locale'
17
+ require 'ixtlan' / 'models' / 'group'
18
+ require 'ixtlan' / 'models' / 'configuration'
19
+ require 'ixtlan' / 'models' / 'group_user'
20
+ require 'ixtlan' / 'models' / 'group_locale_user'
21
+ require 'ixtlan' / 'models' / 'permission'
22
+ require 'ixtlan' / 'models' / 'role'
23
+ require 'ixtlan' / 'models' / 'text'
24
+ require 'ixtlan' / 'passwords'
25
+ require 'ixtlan' / 'digest'
26
+
27
+ #hide log output
28
+ Slf4r::LoggerFacade4RubyLogger.file = StringIO.new
29
+
30
+ module ActiveSupport
31
+ class SecureRandom
32
+ def self.random_number(max)
33
+ rand(max)
34
+ end
35
+ end
36
+ end
37
+
38
+ module ActionController
39
+ module Base
40
+
41
+ def self.prepend_before_filter(*args)
42
+ end
43
+
44
+ def self.before_filter(filter)
45
+ @filters ||= []
46
+ @filters << filter
47
+ end
48
+
49
+ def self.filters
50
+ @filters
51
+ end
52
+ end
53
+ end
54
+ class Request
55
+ attr_accessor :headers, :method, :content_type
56
+ def initialize
57
+ @headers = {}
58
+ @method = :get
59
+ @content_type = 'text/html'
60
+ end
61
+ end
62
+ class Controller
63
+ include ActionController::Base
64
+ def initialize
65
+ @params = {}
66
+ u = Ixtlan::Models::User.first(:login => :marvin)
67
+ if u.nil?
68
+ u = Ixtlan::Models::User.new(:login => :marvin, :name => 'marvin the robot', :email=> "marvin@universe.example.com", :language => "xx", :id => 1, :created_at => DateTime.now, :updated_at => DateTime.now)
69
+ if(u.respond_to? :created_by_id)
70
+ u.created_by_id = 1
71
+ u.updated_by_id = 1
72
+ end
73
+ u.save!
74
+ end
75
+ @password = u.reset_password
76
+ u.save!
77
+ g = Ixtlan::Models::Group.first(:name => :admin) || Ixtlan::Models::Group.create(:name => :admin, :current_user => u)
78
+ #p g.errors
79
+ #gg = Ixtlan::Models::Group.new(:name => :admin2, :current_user => u)
80
+ #gg.save
81
+ #p gg.errors
82
+ # clear up old relations
83
+ Ixtlan::Models::GroupUser.all.destroy!
84
+ Ixtlan::Models::GroupLocaleUser.all.destroy!
85
+ u.groups << g
86
+ g.locales << Ixtlan::Models::Locale.default
87
+ g.locales << Ixtlan::Models::Locale.first_or_create(:code => "en")
88
+ g.save
89
+ @user = u
90
+ end
91
+
92
+ attr_reader :params, :password, :user, :rendered
93
+
94
+ def current_user
95
+ @user
96
+ end
97
+
98
+ def render_session_timeout
99
+ @rendered = true
100
+ end
101
+
102
+ def session_timeout
103
+ a = Object.new
104
+ def a.minutes
105
+ b = Object.new
106
+ def b.from_now
107
+ DateTime.now
108
+ end
109
+ b
110
+ end
111
+ a
112
+ end
113
+
114
+ def session
115
+ @session ||= {}
116
+ end
117
+
118
+ def request
119
+ @request ||= Request.new
120
+ end
121
+ end
122
+
123
+ DataMapper.setup(:default, :adapter => :in_memory)
124
+
125
+ class String
126
+ def cleanup
127
+ gsub(/ type='[a-z:]*'/, '').gsub(/[0-9-]+T[0-9:]+\+[0-9:]+/, 'date')
128
+ end
129
+ end
130
+
131
+ if RUBY_PLATFORM =~ /java/
132
+ module DataMapper
133
+ module Validate
134
+ class NumericValidator
135
+
136
+ def validate_with_comparison(value, cmp, expected, error_message_name, errors, negated = false)
137
+ return if expected.nil?
138
+ if cmp == :=~
139
+ return value =~ expected
140
+ end
141
+ comparison = value.send(cmp, expected)
142
+ return if negated ? !comparison : comparison
143
+
144
+ errors << ValidationErrors.default_error_message(error_message_name, field_name, expected)
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ class DateTime
152
+
153
+ alias :to_s_old :to_s
154
+ def to_s(format = nil)
155
+ to_s_old
156
+ end
157
+
158
+ end
159
+
160
+ class Object
161
+ def self.full_const_get(clazz, ref = Object)
162
+ if clazz =~ /::/
163
+ clazz.sub!(/^::/, '')
164
+ ref = ref.const_get(clazz.sub(/::.*/, ''))
165
+ self.full_const_get(clazz.sub(/[^:]*::/, ''), ref)
166
+ else
167
+ ref.const_get(clazz)
168
+ end
169
+ end
170
+ end