ixtlan 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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