goz 0.0.3 → 0.1.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.
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  *.gem
3
3
  .bundle
4
4
  coverage/
5
+ fake_service.yaml
5
6
  Gemfile.lock
6
7
  goz.log
7
8
  html/
data/HISTORY.rdoc CHANGED
@@ -1,5 +1,11 @@
1
1
  = Goz History
2
2
 
3
+ == YYYY-MM-DD v0.0.4
4
+
5
+ * Added +Goz::Group::EtcGroup+
6
+ * Added +Goz::User::EtcPasswd+
7
+ * TBD
8
+
3
9
  == 2012-04-30 v0.0.3
4
10
 
5
11
  * Added +Goz::Database+
data/README.rdoc CHANGED
@@ -2,22 +2,7 @@
2
2
 
3
3
  == Usage
4
4
 
5
-
6
- # Cache
7
- require 'goz/cache'
8
- Goz::Cache.instance do |cache|
9
- ... do stuff ...
10
- end
11
-
12
- # Logger
13
- require 'goz/logger'
14
- Goz::Logger.instance('MyApp') do |logger|
15
- ... do stuff ...
16
- end
17
-
18
- == See Also
19
-
20
- Goz::Cache, Goz::Group, Goz::Logger, Goz::User
5
+ See https://github.com/blairc/goz-sinatra for an example implementation
21
6
 
22
7
  == Author
23
8
 
@@ -29,5 +14,5 @@ https://github.com/blairc/goz/
29
14
 
30
15
  == See Also
31
16
 
32
- https://github.com/blairc/goz-rails/
17
+ https://github.com/blairc/goz-sinatra/, https://github.com/blairc/goz-rails/
33
18
 
data/TODO.md ADDED
@@ -0,0 +1,16 @@
1
+ Goz To Do
2
+ =========
3
+
4
+ Goz v0.1.0
5
+ ----------
6
+ * Release v0.1.0
7
+
8
+
9
+ Future
10
+ ------
11
+ * Documentation!
12
+ * Add a real service
13
+ * Revisit-or-remove `Goz::Cache`
14
+ * Add support for asynchronous jobs (eg. interacting with external services)
15
+ * Rework API definition to support multiple implementations
16
+
data/goz.gemspec CHANGED
@@ -18,12 +18,16 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ['lib']
20
20
 
21
+ s.add_runtime_dependency 'activesupport'
22
+ s.add_runtime_dependency 'grouper-rest-client'
23
+ s.add_runtime_dependency 'json'
21
24
  s.add_runtime_dependency 'sequel'
25
+ s.add_runtime_dependency 'sqlite3'
22
26
 
27
+ s.add_development_dependency 'mocha'
23
28
  s.add_development_dependency 'rake'
24
29
  s.add_development_dependency 'rdoc'
25
30
  s.add_development_dependency 'rdoc-readme', '~> 0.1.2'
26
31
  s.add_development_dependency 'simplecov'
27
- s.add_development_dependency 'sqlite3'
28
32
  end
29
33
 
data/lib/goz.rb CHANGED
@@ -1,35 +1,19 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'goz/cache'
4
- require 'goz/event'
5
- require 'goz/event_type'
6
- require 'goz/group'
7
- require 'goz/logger'
8
- require 'goz/service'
9
- require 'goz/user'
10
- require 'goz/version'
3
+ require_relative 'goz/event'
4
+ require_relative 'goz/event_type'
5
+ require_relative 'goz/group'
6
+ require_relative 'goz/logger'
7
+ require_relative 'goz/service'
8
+ require_relative 'goz/user'
9
+ require_relative 'goz/version'
11
10
 
12
11
  #
13
12
  # = Goz - Generic self-service provisioning system
14
13
  #
15
14
  # == Usage
16
15
  #
17
- #
18
- # # Cache
19
- # require 'goz/cache'
20
- # Goz::Cache.instance do |cache|
21
- # ... do stuff ...
22
- # end
23
- #
24
- # # Logger
25
- # require 'goz/logger'
26
- # Goz::Logger.instance('MyApp') do |logger|
27
- # ... do stuff ...
28
- # end
29
- #
30
- # == See Also
31
- #
32
- # Goz::Cache, Goz::Group, Goz::Logger, Goz::User
16
+ # See https://github.com/blairc/goz-sinatra for an example implementation
33
17
  #
34
18
  # == Author
35
19
  #
@@ -41,7 +25,7 @@ require 'goz/version'
41
25
  #
42
26
  # == See Also
43
27
  #
44
- # https://github.com/blairc/goz-rails/
28
+ # https://github.com/blairc/goz-sinatra/, https://github.com/blairc/goz-rails/
45
29
  #
46
30
  module Goz
47
31
  # Your code goes here...
data/lib/goz/database.rb CHANGED
@@ -32,6 +32,8 @@ module Goz # :nodoc:
32
32
  #
33
33
  class Database
34
34
 
35
+ # XXX Better method for setting db url
36
+
35
37
  #
36
38
  # Sequel database instance
37
39
  #
@@ -39,6 +41,14 @@ module Goz # :nodoc:
39
41
  Goz::Database::Migrations.migrate!
40
42
 
41
43
 
44
+ # XXX http://sequel.rubyforge.org/rdoc/classes/Sequel/Model/ClassMethods.html#method-i-db-3D
45
+ def self.connect!(url)
46
+ self.send( :remove_const, :'DB' ) if self.const_defined?( :'DB' )
47
+ self.const_set :'DB', Sequel.connect(url)
48
+ Goz::Database::Migrations.migrate!
49
+ self.instance
50
+ end
51
+
42
52
  #
43
53
  # Get database instance
44
54
  #
@@ -31,10 +31,11 @@ module Goz # :nodoc:
31
31
  change do
32
32
  DB.create_table(:groups) do
33
33
  primary_key :id
34
- String :display_name, :null => false
35
- String :identifier, :null => false
36
- String :name, :null => false
37
- timestamp :created_at, :null => false
34
+ String :display_name, :null => false
35
+ String :identifier, :null => false
36
+ String :klass, :null => false
37
+ String :name, :null => false
38
+ timestamp :created_at, :null => false
38
39
  timestamp :modified_at
39
40
  timestamp :synchronized_at
40
41
 
@@ -49,9 +50,9 @@ module Goz # :nodoc:
49
50
  change do
50
51
  DB.create_table(:services) do
51
52
  primary_key :id
52
- String :name, :null => false
53
- String :klass, :null => false
54
- timestamp :created_at, :null => false
53
+ String :name, :null => false
54
+ String :klass, :null => false
55
+ timestamp :created_at, :null => false
55
56
  timestamp :modified_at
56
57
  timestamp :synchronized_at
57
58
 
@@ -68,6 +69,7 @@ module Goz # :nodoc:
68
69
  String :identifier, :null => false
69
70
  String :login, :null => false
70
71
  String :name, :null => false
72
+ String :klass, :null => false
71
73
  timestamp :created_at, :null => false
72
74
  timestamp :modified_at
73
75
  timestamp :synchronized_at
@@ -126,6 +128,7 @@ module Goz # :nodoc:
126
128
  end
127
129
  end
128
130
 
131
+ # TODO Consider removing?
129
132
  Sequel.migration do
130
133
  change do
131
134
  event_types = DB[:event_types]
@@ -146,15 +149,18 @@ module Goz # :nodoc:
146
149
  change do
147
150
  DB.create_table(:events) do
148
151
  primary_key :id
149
- Integer :event_type_id, :null => false
152
+ String :event_type, :null => false
153
+ String :group, :null => true
150
154
  Integer :group_id, :null => true
155
+ String :service, :null => true
151
156
  Integer :service_id, :null => true
157
+ String :user, :null => true
152
158
  Integer :user_id, :null => true
153
159
  # TODO Some sort of boolean or enum completion status?
154
160
  timestamp :created_at, :null => false
155
161
  # TODO Some sort of completed_at timestamp?
156
162
 
157
- index :event_type_id
163
+ index :event_type
158
164
  index :group_id
159
165
  index :service_id
160
166
  index :user_id
data/lib/goz/event.rb CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  require 'goz/database'
4
4
  require 'goz/event_type'
5
+ require 'goz/group'
6
+ require 'goz/service'
7
+ require 'json'
5
8
 
6
9
  module Goz # :nodoc:
7
10
 
@@ -18,6 +21,9 @@ module Goz # :nodoc:
18
21
  #
19
22
  class Event < Sequel::Model
20
23
 
24
+ plugin :serialization, :json, :group
25
+ plugin :serialization, :json, :service
26
+ plugin :serialization, :json, :user
21
27
  plugin :validation_helpers
22
28
 
23
29
 
@@ -31,68 +37,124 @@ module Goz # :nodoc:
31
37
  end
32
38
 
33
39
  def self.admin_add(group, user)
34
- self.create( :event_type_id => Goz::EventType::ADMIN_ADD, :group_id => group.id, :user_id => user.id )
40
+ self.create :event_type => Goz::EventType::ADMIN_ADD,
41
+ :group => group,
42
+ :group_id => group.id,
43
+ :user => user,
44
+ :user_id => user.id
35
45
  end
36
46
 
37
47
  def self.admin_remove(group, user)
38
- self.create( :event_type_id => Goz::EventType::ADMIN_REMOVE, :group_id => group.id, :user_id => user.id )
48
+ self.create :event_type => Goz::EventType::ADMIN_REMOVE,
49
+ :group => group,
50
+ :group_id => group.id,
51
+ :user => user,
52
+ :user_id => user.id
39
53
  end
40
54
 
41
55
  def self.group_add(group)
42
- self.create :event_type_id => Goz::EventType::GROUP_ADD, :group_id => group.id
56
+ self.create :event_type => Goz::EventType::GROUP_ADD,
57
+ :group => group,
58
+ :group_id => group.id
43
59
  end
44
60
 
45
61
  def self.group_remove(group)
46
- self.create :event_type_id => Goz::EventType::GROUP_REMOVE, :group_id => group.id
62
+ self.create :event_type => Goz::EventType::GROUP_REMOVE,
63
+ :group => group,
64
+ :group_id => group.id
47
65
  end
48
66
 
49
67
  def self.group_sync(group)
50
- self.create :event_type_id => Goz::EventType::GROUP_SYNC, :group_id => group.id
68
+ self.create :event_type => Goz::EventType::GROUP_SYNC,
69
+ :group => group,
70
+ :group_id => group.id
51
71
  end
52
72
 
53
73
  def self.group_service_add(group, service)
54
- self.create( :event_type_id => Goz::EventType::GROUP_SERVICE_ADD, :group_id => group.id, :service_id => service.id )
74
+ self.create :event_type => Goz::EventType::GROUP_SERVICE_ADD,
75
+ :group => group,
76
+ :group_id => group.id,
77
+ :service => service,
78
+ :service_id => service.id
55
79
  end
56
80
 
57
81
  def self.group_service_remove(group, service)
58
- self.create( :event_type_id => Goz::EventType::GROUP_SERVICE_REMOVE, :group_id => group.id, :service_id => service.id )
82
+ self.create :event_type => Goz::EventType::GROUP_SERVICE_REMOVE,
83
+ :group => group,
84
+ :group_id => group.id,
85
+ :service => service,
86
+ :service_id => service.id
59
87
  end
60
88
 
61
89
  def self.group_service_sync(group, service)
62
- self.create( :event_type_id => Goz::EventType::GROUP_SERVICE_SYNC, :group_id => group.id, :service_id => service.id )
90
+ self.create :event_type => Goz::EventType::GROUP_SERVICE_SYNC,
91
+ :group => group,
92
+ :group_id => group.id,
93
+ :service => service,
94
+ :service_id => service.id
63
95
  end
64
96
 
65
97
  def self.member_add(group, user)
66
- self.create( :event_type_id => Goz::EventType::MEMBER_ADD, :group_id => group.id, :user_id => user.id )
98
+ self.create :event_type => Goz::EventType::MEMBER_ADD,
99
+ :group => group,
100
+ :group_id => group.id,
101
+ :user => user,
102
+ :user_id => user.id
67
103
  end
68
104
 
69
105
  def self.member_remove(group, user)
70
- self.create( :event_type_id => Goz::EventType::MEMBER_REMOVE, :group_id => group.id, :user_id => user.id )
106
+ self.create :event_type => Goz::EventType::MEMBER_REMOVE,
107
+ :group => group,
108
+ :group_id => group.id,
109
+ :user => user,
110
+ :user_id => user.id
71
111
  end
72
112
 
73
113
  def self.service_add(service)
74
- self.create( :event_type_id => Goz::EventType::SERVICE_ADD, :service_id => service.id )
114
+ self.create :event_type => Goz::EventType::SERVICE_ADD,
115
+ :service => service,
116
+ :service_id => service.id
75
117
  end
76
118
 
77
119
  def self.service_remove(service)
78
- self.create( :event_type_id => Goz::EventType::SERVICE_REMOVE, :service_id => service.id )
120
+ self.create :event_type => Goz::EventType::SERVICE_REMOVE,
121
+ :service => service,
122
+ :service_id => service.id
79
123
  end
80
124
 
81
125
  def self.service_sync(service)
82
- self.create( :event_type_id => Goz::EventType::SERVICE_SYNC, :service_id => service.id )
126
+ self.create :event_type => Goz::EventType::SERVICE_SYNC,
127
+ :service => service,
128
+ :service_id => service.id
129
+ end
130
+
131
+ def self.user_add(user)
132
+ self.create :event_type => Goz::EventType::USER_ADD,
133
+ :user => user,
134
+ :user_id => user.id
135
+ end
136
+
137
+ def self.user_remove(user)
138
+ self.create :event_type => Goz::EventType::USER_REMOVE,
139
+ :user => user,
140
+ :user_id => user.id
83
141
  end
84
142
 
85
143
  def self.user_sync(user)
86
- self.create( :event_type_id => Goz::EventType::USER_SYNC, :user_id => user.id )
144
+ self.create :event_type => Goz::EventType::USER_SYNC,
145
+ :user => user,
146
+ :user_id => user.id
87
147
  end
88
148
 
149
+
89
150
  #
90
151
  # Perform model valiations.
91
152
  #
92
153
  def validate
93
154
  super
94
- validates_presence :event_type_id
95
- validates_type Integer, [ :event_type_id, :group_id, :service_id, :user_id ]
155
+ validates_presence :event_type
156
+ validates_includes Goz::EventType::TYPES, :event_type
157
+ validates_type Integer, [ :group_id, :service_id, :user_id ]
96
158
  end
97
159
 
98
160
 
@@ -19,8 +19,8 @@ module Goz # :nodoc:
19
19
 
20
20
  plugin :validation_helpers
21
21
 
22
- TYPES = EventType.to_hash(:name, :id)
23
- TYPES.each_pair { |k, v| const_set k.upcase.to_s, v }
22
+ TYPES = EventType.map(:name)
23
+ TYPES.each { |t| const_set t.upcase.to_s, t }
24
24
 
25
25
 
26
26
  #
@@ -41,7 +41,7 @@ module Goz # :nodoc:
41
41
  self.created_at ||= Time.now
42
42
  end
43
43
 
44
- end # class EventType
44
+ end
45
45
 
46
- end # module Goz
46
+ end
47
47
 
data/lib/goz/group.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  # encoding: utf-8
2
2
 
3
+ require 'active_support/inflector'
3
4
  require 'goz/database'
4
5
  require 'goz/event'
5
6
  require 'goz/group_service'
7
+ require 'goz/logger'
8
+
6
9
 
7
10
  module Goz # :nodoc:
8
11
 
@@ -34,7 +37,6 @@ module Goz # :nodoc:
34
37
  # https://github.com/blairc/goz/
35
38
  #
36
39
  class Group < Sequel::Model
37
- include Comparable
38
40
 
39
41
  plugin :validation_helpers
40
42
 
@@ -57,67 +59,85 @@ module Goz # :nodoc:
57
59
  :right_key => :service_id,
58
60
  :join_table => :group_services,
59
61
  :class => :'Goz::Service',
60
- :after_add => proc { |g, s| Goz::Event.group_service_add(g, s) },
61
- :after_remove => proc { |g, s| Goz::Event.group_service_remove(g, s) }
62
+ :after_add => proc { |g, s| after_add_service g, s },
63
+ :after_remove => proc { |g, s| after_remove_service g, s }
64
+
65
+
66
+ ATTRIBUTES = [ :display_name, :identifier, :klass, :name ]
67
+ TAG = self.name
68
+
69
+ @@api = Goz::Group
62
70
 
63
71
 
64
72
  #
65
- # Initialize new (non-persistent) Goz::Group object
73
+ # Return groups where user is an admin.
66
74
  #
67
- def initialize(*params)
68
- super
69
- yield self if block_given?
70
- self
75
+ def self.admin(user)
76
+ Goz::Logger.debug TAG, "admin( user=#{user.login} )"
77
+ return user.groups if Goz::Group.name == @@api.name
78
+ groups = self.api.groups(user).collect { |g| self.find_or_create g.to_hash }
79
+ groups.each { |g| yield g } if block_given?
80
+ groups
71
81
  end
72
82
 
73
- #
74
- # Compare equality.
75
- #
76
- def <=>(other)
77
- if self.display_name < other.display_name ||
78
- self.identifier < other.identifier ||
79
- self.name < other.name
80
- -1
81
- elsif self.display_name > other.display_name ||
82
- self.identifier > other.identifier ||
83
- self.name > other.name
84
- 1
85
- else
86
- 0
87
- end
83
+ # TODO DRY w/ "Service"
84
+ def self.after_add_service(g, s)
85
+ s.create(g) && Goz::Event.group_service_add(g, s)
86
+ end
87
+
88
+ # TODO DRY w/ "Service"
89
+ def self.after_remove_service(g, s)
90
+ s.destroy(g) && Goz::Event.group_service_remove(g, s)
88
91
  end
89
92
 
90
93
  #
91
- # Create Goz::Group or raise +RuntimeError+
94
+ # TODO
92
95
  #
93
- def self.create( params = {} )
94
- params = {} unless params.kind_of?(Hash)
95
- [ :display_name, :identifier, :name ].each do |k|
96
- raise( "invalid #{k.to_s}" ) if ( params[k].nil? || params[k].empty? )
97
- end
98
- super
96
+ def self.api( klass = nil, configuration = {} )
97
+ return @@api if klass.nil?
98
+ Goz::Logger.info TAG, "changing api from #{@@api} to #{klass}"
99
+ klass_name = klass.kind_of?(String) ? klass : klass.name
100
+ require klass_name.underscore
101
+ klass = klass.constantize if klass.kind_of?(String)
102
+ klass.configuration configuration
103
+ @@api = klass
99
104
  end
100
105
 
101
106
  #
102
107
  # Find Goz::Group by name or return +nil+
103
108
  #
104
109
  def self.find_by_name(name)
105
- self.find( :name => name )
110
+ Goz::Logger.debug TAG, "find_by_name( name=#{name} )"
111
+ g = self.find :name => name
112
+ return g unless g.nil?
113
+ return nil if Goz::Group == self.api
114
+ g = self.api.find_by_name name
115
+ return nil if g.nil?
116
+ return self.find_or_create g.to_hash
117
+ end
118
+
119
+ #
120
+ # Return groups where user is a member.
121
+ #
122
+ def self.member(user)
123
+ Goz::Logger.debug TAG, "member( user=#{user.login} )"
124
+ return user.memberships if Goz::Group.name == @@api.name
125
+ groups = self.api.memberships(user).collect { |g| self.find_or_create g.to_hash }
126
+ groups.each { |g| yield g } if block_given?
127
+ groups
106
128
  end
107
129
 
108
130
  #
109
131
  # Synchronize group with external data sources (if relevant).
110
132
  #
111
133
  def sync(force = false)
112
- if force || synchronized_at.nil? || synchronized_at < ( Time.now - ( 1 * 60 * 60 ) ) # XXX
113
- # XXX Synchronize group from remote source (if necessary)
114
- # XXX Synchronize admins
115
- # XXX Synchronize members
116
- self.services.each { |s| self.sync_service(s, force) }
117
- self.synchronized_at = Time.now
118
- self.save
119
- Goz::Event.group_sync(self)
120
- return true
134
+ Goz::Logger.debug TAG, "#{self.name} - #sync( force=#{force} )"
135
+ if sync_group && sync_admins && sync_members
136
+ self.services.each { |s| self.sync_service(s, force) } # TODO
137
+ self.synchronized_at = Time.now
138
+ self.save
139
+ Goz::Event.group_sync(self)
140
+ return true
121
141
  end
122
142
  false
123
143
  end
@@ -126,7 +146,12 @@ module Goz # :nodoc:
126
146
  # Synchronize group service with external data soruces (if relevant).
127
147
  #
128
148
  def sync_service(service, force = false )
129
- Goz::GroupService.first( :group_id => self.id, :service_id => service.id ).sync(force)
149
+ Goz::Logger.debug TAG, "#{self.name} - #sync_service( service.name=#{service.name}, force=#{force} )"
150
+ service.sync_group(self) # XXX
151
+ end
152
+
153
+ def to_hash
154
+ Hash[ ATTRIBUTES.map { |k| [ k, self[k] ] } ]
130
155
  end
131
156
 
132
157
  #
@@ -134,7 +159,7 @@ module Goz # :nodoc:
134
159
  #
135
160
  def validate
136
161
  super
137
- validates_presence [ :display_name, :identifier, :name ]
162
+ validates_presence [ :display_name, :identifier, :klass, :name ]
138
163
  validates_type Time, [ :created_at, :modified_at, :synchronized_at ]
139
164
  validates_unique [ :display_name, :identifier, :name ]
140
165
  end
@@ -168,7 +193,59 @@ module Goz # :nodoc:
168
193
  self.modified_at = Time.now
169
194
  end
170
195
 
171
- end # class Group
196
+ def klass_instance
197
+ return @@api if @@api.name == self.klass
198
+ unless @k
199
+ @k = self.klass.constantize
200
+ require self.klass.underscore
201
+ end
202
+ return @k
203
+ end
204
+
205
+ # Synchronize group admins with external data source
206
+ def sync_admins
207
+ Goz::Logger.debug TAG, "#{self.name} - #sync_admins()"
208
+ return true if Goz::Group.name == self.klass
209
+ g = klass_instance.find_by_name self.name
210
+ return false if g.nil?
211
+ t = g.admins.collect { |u| Goz::User.find_by_login u.login } # TODO Should be .find( key => value )
212
+ t.delete_if { |_| _.nil? }
213
+ t.each { |_| self.add_admin(_) unless self.admins.include?(_) }
214
+ self.admins.each { |_| self.remove_admin(_) unless t.include?(_) }
215
+ # TODO Log! if modified?
216
+ true
217
+ end
218
+
219
+ # Synchronize group with external data source
220
+ def sync_group
221
+ Goz::Logger.debug TAG, "#{self.name} - #sync_group()"
222
+ return true if Goz::Group.name == self.klass
223
+ g = klass_instance.find_by_name self.name
224
+ return false if g.nil?
225
+ [ :display_name, :identifier, :name ].each do |attr|
226
+ unless self[attr] == g[attr]
227
+ Goz::Logger.info TAG, "#{self.name} = #sync_group() - #{attr} changed"
228
+ self[attr] = g[attr]
229
+ end
230
+ end
231
+ true
232
+ end
233
+
234
+ # Synchronize groups members with external data source
235
+ def sync_members
236
+ Goz::Logger.debug TAG, "#{self.name} - #sync_members()"
237
+ return true if Goz::Group.name == self.klass
238
+ g = klass_instance.find_by_name self.name
239
+ return false if g.nil?
240
+ t = g.members.collect { |u| Goz::User.find_by_login u.login } # TODO Should be .find( key => value )
241
+ t.delete_if { |_| _.nil? }
242
+ t.each { |_| self.add_member(_) unless self.members.include?(_) }
243
+ self.members.each { |_| self.remove_member(_) unless t.include?(_) }
244
+ # TODO Log! if modified?
245
+ true
246
+ end
247
+
248
+ end
172
249
 
173
- end # module Goz
250
+ end
174
251