goz 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+
3
+ require 'goz/service'
4
+ require 'goz/logger'
5
+
6
+
7
+ module Goz # :nodoc:
8
+ class Service # :nodoc:
9
+
10
+ #
11
+ # = Goz::Service::Base - TODO
12
+ #
13
+ # == Usage
14
+ #
15
+ # TODO
16
+ #
17
+ # == Author
18
+ #
19
+ # blair christensen. <mailto:blair.christensen@gmail.com>
20
+ #
21
+ # == Homepage
22
+ #
23
+ # https://github.com/blairc/goz/
24
+ #
25
+ class Base
26
+
27
+ TAG = self.name
28
+
29
+ @@cf = {}
30
+
31
+
32
+ #
33
+ # Set configuration.
34
+ #
35
+ def self.configuration(configuration)
36
+ @@cf = configuration
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+ end
43
+
@@ -0,0 +1,81 @@
1
+ # encoding: utf-8
2
+
3
+ require 'goz/service/base'
4
+ require 'yaml'
5
+
6
+
7
+ module Goz # :nodoc:
8
+ class Service # :nodoc:
9
+
10
+ #
11
+ # = Goz::Service:FakeService - TODO
12
+ #
13
+ # == Usage
14
+ #
15
+ # TODO
16
+ #
17
+ # == Author
18
+ #
19
+ # blair christensen. <mailto:blair.christensen@gmail.com>
20
+ #
21
+ # == Homepage
22
+ #
23
+ # https://github.com/blairc/goz/
24
+ #
25
+ class FakeService < Goz::Service::Base
26
+
27
+ FN = 'fake_service_database.yaml'
28
+ TAG = self.name
29
+
30
+ @@registry = nil
31
+
32
+
33
+ # XXX ALL UGLY HACKS!
34
+ def self.create(g)
35
+ Goz::Logger.debug TAG, "create( group.name=#{g.name} )"
36
+ load_registry
37
+ if @@registry.key? g.name
38
+ Goz::Logger.info TAG, "create( group.name=#{g.name} ) - group exists"
39
+ return true
40
+ end
41
+ Goz::Logger.info TAG, "create( group.name=#{g.name} ) - creating group"
42
+ @@registry[ g.name ] = { :group => g.to_hash }
43
+ save_registry
44
+ end
45
+
46
+ def self.load_registry
47
+ return @@registry unless @@registry.nil?
48
+ @@registry = File.exist?(FN) ? YAML.load_file(FN) : {}
49
+ end
50
+
51
+ def self.save_registry
52
+ File.open(FN, 'w') { |fh| fh.write YAML.dump(@@registry) }
53
+ end
54
+
55
+ def self.destroy(g)
56
+ Goz::Logger.debug TAG, "destroy( group.name=#{g.name} )"
57
+ load_registry
58
+ unless @@registry.key? g.name
59
+ Goz::Logger.info TAG, "destroy( group.name=#{g.name} ) - does not exist"
60
+ return true
61
+ end
62
+ Goz::Logger.info TAG, "destroy( group.name=#{g.name} ) - deleting group"
63
+ @@registry.delete g.name
64
+ save_registry
65
+ end
66
+
67
+ def self.sync_group(g, s)
68
+ Goz::Logger.debug TAG, "sync_group( group.name=#{g.name}, service.name=#{s.name} )"
69
+ load_registry
70
+ create(g) unless @@registry.key? g.name
71
+ @@registry[ g.name ][ :admins ] = {}
72
+ @@registry[ g.name ][ :members ] = {}
73
+ g.admins.each { |u| @@registry[ g.name ][:admins][ u.login ] = u.to_hash }
74
+ g.members.each { |u| @@registry[ g.name ][:members][ u.login ] = u.to_hash }
75
+ save_registry
76
+ end
77
+
78
+ end
79
+ end
80
+ end
81
+
data/lib/goz/test_case.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
+ require 'digest/sha1'
3
4
  require 'goz/database'
4
5
  require 'test/unit'
5
6
 
@@ -26,23 +27,34 @@ module Goz # :nodoc:
26
27
  [ :groups, :services, :users ].each { |t| db[t].delete }
27
28
  end
28
29
 
29
- @groups = {
30
- :a => { :display_name => 'Group:A', :identifier => 'c6347f2a0375db1e2ebfe0ad70e24172a3193037', :name => 'gA' },
31
- :b => { :display_name => 'Group:B', :identifier => '341af322e54bea31f8d08d4f2c627a4db341781a', :name => 'gB' }
32
- }
30
+ @groups = {}
31
+ [ :a, :b ].each do |sym|
32
+ @groups[sym] = { :display_name => "Group:#{ sym.to_s.upcase }",
33
+ :identifier => Digest::SHA1.hexdigest( sym.to_s ),
34
+ :klass => 'Goz::Group',
35
+ :name => "g#{ sym.to_s.upcase }"
36
+ }
37
+ end
33
38
 
34
- @services = {
35
- :a => { :name => 'Service A', :klass => 'Goz::Service' },
36
- :b => { :name => 'Service B', :klass => 'Goz::Service' }
37
- }
39
+ @services = {}
40
+ [ :a, :b ].each do |sym|
41
+ @services[sym] = { :name => "Service #{ sym.to_s.upcase }",
42
+ :klass => 'Goz::Service'
43
+ }
44
+ end
38
45
 
39
- @users = {
40
- :a => { :email => 'a@example.org', :login => 'uA', :identifier => '40b071bd23a8fd2b8cff7f59da9211dca7806d47', :name => 'User A' },
41
- :b => { :email => 'b@example.org', :login => 'uB', :identifier => '40b071bd23a8fd2b8cff7f59da9211dca7806d47', :name => 'User B' }
42
- }
46
+ @users = {}
47
+ [ :a, :b ].each do |sym|
48
+ @users[sym] = { :email => "#{ sym.to_s }@example.org",
49
+ :identifier => Digest::SHA1.hexdigest( sym.to_s ),
50
+ :klass => 'Goz::User',
51
+ :login => sym.to_s,
52
+ :name => "User #{ sym.to_s.upcase }"
53
+ }
54
+ end
43
55
  end
44
56
 
45
- end # class TestCase
57
+ end
46
58
 
47
- end # module Goz
59
+ end
48
60
 
data/lib/goz/user.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
+ require 'active_support/inflector'
3
4
  require 'goz/database'
4
5
  require 'goz/event'
6
+ require 'goz/logger'
7
+
5
8
 
6
9
  module Goz # :nodoc:
7
10
 
@@ -35,7 +38,6 @@ module Goz # :nodoc:
35
38
  # https://github.com/blairc/goz/
36
39
  #
37
40
  class User < Sequel::Model
38
- include Comparable
39
41
 
40
42
  plugin :validation_helpers
41
43
 
@@ -55,76 +57,89 @@ module Goz # :nodoc:
55
57
  :after_remove => proc { |u, g| Goz::Event.member_remove(g, u) }
56
58
 
57
59
 
60
+ ATTRIBUTES = [ :email, :identifier, :klass, :login, :name ]
61
+ TAG = self.name
62
+
63
+ @@api = Goz::User # XXX
64
+
65
+
58
66
  #
59
67
  # Initialize new (non-persistent) Goz::User object
60
68
  #
61
- def initialize(*params)
69
+ def initialize( *params )
62
70
  super
63
71
  yield self if block_given?
64
72
  self
65
73
  end
66
74
 
67
75
  #
68
- # Compare equality.
76
+ # TODO
69
77
  #
70
- def <=>(other)
71
- if self.login < other.login ||
72
- self.email < other.email ||
73
- self.name < other.name ||
74
- self.identifier < other.identifier
75
- -1
76
- elsif self.login > other.login ||
77
- self.email > other.email ||
78
- self.name > other.name ||
79
- self.identifier > other.identifier
80
- 1
81
- else
82
- 0
83
- end
78
+ def self.api( klass = nil, configuration = {} )
79
+ return @@api if klass.nil?
80
+ Goz::Logger.info TAG, "changing api from #{@@api} to #{klass}"
81
+ klass_name = klass.kind_of?(String) ? klass : klass.name
82
+ require klass_name.underscore
83
+ klass = klass.constantize if klass.kind_of?(String)
84
+ klass.configuration configuration
85
+ @@api = klass
84
86
  end
85
87
 
86
88
  #
87
- # Create Goz::User or raise +RuntimeError+
89
+ # Find Goz::User by identifier or return +nil+
88
90
  #
89
- def self.create( params = {} )
90
- params = {} unless params.kind_of?(Hash)
91
- [ :email, :identifier, :login, :name ].each do |k|
92
- raise( "invalid #{k.to_s}" ) if ( params[k].nil? || params[k].empty? )
91
+ def self.find_by_identifier(identifier)
92
+ Goz::Logger.debug TAG, "find_by_identifier( identifier=#{identifier} )"
93
+ u = self.find :identifier => identifier
94
+ return u unless u.nil?
95
+ return nil if Goz::User == self.api
96
+ u = self.api.find_by_identifier identifier
97
+ return nil if u.nil?
98
+ begin
99
+ return self.find_or_create u.to_hash
100
+ rescue => e
101
+ Goz::Logger.error TAG, "find_by_identifier( identifier=#{identifier} ) => #{ e.to_s }"
93
102
  end
94
- super
103
+ return nil
95
104
  end
96
105
 
97
106
  #
98
107
  # Find Goz::User by login or return +nil+
99
108
  #
100
109
  def self.find_by_login(login)
101
- Goz::Database.instance do |db|
102
- return User.find( :login => login )
103
- end
110
+ Goz::Logger.debug TAG, "find_by_login( login=#{login} )"
111
+ u = self.find :login => login
112
+ return u unless u.nil?
113
+ return nil if Goz::User == self.api
114
+ u = self.api.find_by_login login
115
+ return nil if u.nil?
116
+ return self.find_or_create u.to_hash
104
117
  end
105
118
 
106
119
  #
107
120
  # Synchronize user with external data sources (if relevant).
108
121
  #
109
122
  def sync(force = false)
110
- if force || synchronized_at.nil? || synchronized_at < ( Time.now - ( 1 * 60 * 60 ) ) # XXX
111
- # XXX Synchronize user with remote source (if necessary)
112
- # XXX Synchronize groups
113
- # XXX Synchronize memberships
114
- self.synchronized_at = Time.now
115
- self.save
116
- Goz::Event.user_sync(self)
117
- return true
123
+ Goz::Logger.debug TAG, "#{self.login} - #sync( force=#{force} )"
124
+ if sync_user && sync_groups && sync_memberships
125
+ self.synchronized_at = Time.now
126
+ self.save
127
+ Goz::Event.user_sync(self)
128
+ return true
118
129
  end
119
130
  false
120
131
  end
121
132
 
133
+ def to_hash
134
+ Hash[ ATTRIBUTES.map { |k| [ k, self[k] ] } ]
135
+ end
136
+
122
137
  #
123
138
  # Perform model valiations.
124
139
  #
125
140
  def validate
126
141
  super
127
- validates_presence [ :email, :identifier, :login, :name ]
142
+ validates_presence [ :email, :identifier, :klass, :login, :name ]
128
143
  validates_type Time, [ :created_at, :modified_at, :synchronized_at ]
129
144
  validates_unique [ :email, :identifier, :login ]
130
145
  end
@@ -134,12 +149,12 @@ module Goz # :nodoc:
134
149
 
135
150
  def after_destroy
136
151
  super
137
- Event.create :event_type_id => Goz::EventType::USER_REMOVE, :user_id => self.id
152
+ Goz::Event.user_remove(self)
138
153
  end
139
154
 
140
155
  def after_create
141
156
  super
142
- Event.create :event_type_id => Goz::EventType::USER_ADD, :user_id => self.id
157
+ Goz::Event.user_add(self)
143
158
  end
144
159
 
145
160
  def before_create
@@ -158,6 +173,52 @@ module Goz # :nodoc:
158
173
  self.modified_at = Time.now
159
174
  end
160
175
 
176
+ def klass_instance
177
+ return @@api if @@api.name == self.klass
178
+ unless @k
179
+ @k = self.klass.constantize
180
+ require self.klass.underscore
181
+ end
182
+ return @k
183
+ end
184
+
185
+ # Synchronize user groups with external data source
186
+ def sync_groups
187
+ Goz::Logger.debug TAG, "#{self.login} - #sync_groups()"
188
+ # TODO Does Sequel provide a better option for this?
189
+ t = Goz::Group.admin(self)
190
+ t.each { |_| self.add_group(_) unless self.groups.include?(_) }
191
+ self.groups.each { |_| self.remove_group(_) unless t.include?(_) }
192
+ # TODO Log! if modified?
193
+ true
194
+ end
195
+
196
+ # Synchronize user memberships with external data source
197
+ def sync_memberships
198
+ Goz::Logger.debug TAG, "#{self.login} - #sync_memberships()"
199
+ # TODO Does Sequel provide a better option for this?
200
+ t = Goz::Group.member(self)
201
+ t.each { |_| self.add_membership(_) unless self.memberships.include?(_) }
202
+ self.memberships.each { |_| self.remove_membership(_) unless t.include?(_) }
203
+ # TODO Log! if modified?
204
+ true
205
+ end
206
+
207
+ # Synchronize user with external data source
208
+ def sync_user
209
+ Goz::Logger.debug TAG, "#{self.login} - #sync_user()"
210
+ return true if Goz::User.name == self.klass
211
+ u = klass_instance.find_by_login self.login
212
+ return false if u.nil?
213
+ [ :email, :identifier, :login, :name ].each do |attr|
214
+ unless self[attr] == u[attr]
215
+ Goz::Logger.info TAG, "#{self.login} = #sync_user() - #{attr} changed"
216
+ self[attr] = u[attr]
217
+ end
218
+ end
219
+ true
220
+ end
221
+
161
222
  end # class User
162
223
 
163
224
  end # module Goz
@@ -0,0 +1,81 @@
1
+ # encoding: utf-8
2
+
3
+ require 'goz/logger'
4
+ require 'goz/user'
5
+
6
+
7
+ module Goz # :nodoc:
8
+ class User # :nodoc:
9
+
10
+ #
11
+ # = Goz::User::Base - TODO
12
+ #
13
+ # == Usage
14
+ #
15
+ # TODO
16
+ #
17
+ # == Author
18
+ #
19
+ # blair christensen. <mailto:blair.christensen@gmail.com>
20
+ #
21
+ # == Homepage
22
+ #
23
+ # https://github.com/blairc/goz/
24
+ #
25
+ class Base
26
+
27
+ TAG = self.name
28
+
29
+ attr_accessor :email, :identifier, :klass, :login, :name
30
+
31
+ @@cf = {}
32
+
33
+
34
+ #
35
+ # TODO
36
+ #
37
+ def [](key)
38
+ send key.to_sym
39
+ end
40
+
41
+ #
42
+ # Set configuration.
43
+ #
44
+ def self.configuration(configuration)
45
+ @@cf = configuration
46
+ end
47
+
48
+ #
49
+ # Find Goz::User by login or return +nil+.
50
+ #
51
+ # MUST be implemented by API extensions.
52
+ #
53
+ def self.find_by_login(login)
54
+ raise RuntimeError, "not implemented"
55
+ end
56
+
57
+ #
58
+ # Convert to Goz::User-style hash
59
+ #
60
+ def to_hash
61
+ return { :email => self.email,
62
+ :identifier => self.identifier,
63
+ :klass => self.klass,
64
+ :login => self.login,
65
+ :name => self.name
66
+ }
67
+ end
68
+
69
+ #
70
+ # TODO
71
+ #
72
+ def to_s
73
+ "email=#{email} | identifier=#{identifier} | klass=#{klass} | login=#{login} | name=#{name}"
74
+ end
75
+
76
+
77
+ end
78
+
79
+ end
80
+ end
81
+