lom 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -0
- data/lib/lom/filtered.rb +55 -35
- data/lib/lom/ldap/extensions.rb +1 -1
- data/lib/lom/mapper.rb +73 -23
- data/lib/lom/version.rb +1 -1
- data/lom.gemspec +4 -6
- metadata +8 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d37a56b9ef6c9dad3ae785439cb49560c641304fdb12f3d3d070541e8bf27b9
|
4
|
+
data.tar.gz: cd71e20fd089ab2b489bcdb2f857f508b8c283c0d4f2de875b81cfc722fab05b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 956540737ca9944e790aeead959ef079f61f8d9469b22867969858c993bd97897f742fd9ca43ef3b99110e76e81902474f88fd6a95e0bd216fee0b620ca5377e
|
7
|
+
data.tar.gz: 7340668aaeef6a7821e88d95bf5da772aedfcb4a3dce9ab89d858c08c2b4be9165e127f0c5871decce112edc06337ba0c7e611601d12b56a6cbfe5b52e490202
|
data/README.md
CHANGED
@@ -104,7 +104,13 @@ class User < Dry::Struct
|
|
104
104
|
}
|
105
105
|
end
|
106
106
|
|
107
|
+
ldap_list :query, ->(str) do
|
108
|
+
Filtered.match(:uid, str) |
|
109
|
+
Filtered.match(:cn, str) |
|
110
|
+
Filtered.match(:givenName, str) | Filtered.match(:sn, str)
|
111
|
+
end
|
107
112
|
|
113
|
+
|
108
114
|
#
|
109
115
|
# Object structure
|
110
116
|
#
|
data/lib/lom/filtered.rb
CHANGED
@@ -13,10 +13,19 @@ class Filtered
|
|
13
13
|
NONE = Object.new.freeze
|
14
14
|
ANY = Object.new.freeze
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
class NoSource < Error
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(filter = nil, src: nil, paged: nil)
|
20
|
+
if filter.is_a?(Filtered)
|
21
|
+
@filter = filter.filter
|
22
|
+
@src = src || filter.src
|
23
|
+
@paged = paged || filter.paged
|
24
|
+
else
|
25
|
+
@filter = filter
|
26
|
+
@src = src
|
27
|
+
@paged = paged
|
28
|
+
end
|
20
29
|
end
|
21
30
|
attr_reader :src, :filter, :paged
|
22
31
|
|
@@ -30,7 +39,7 @@ class Filtered
|
|
30
39
|
_operator_2('&', o)
|
31
40
|
end
|
32
41
|
|
33
|
-
# Take the negation of this
|
42
|
+
# Take the negation of this filter
|
34
43
|
def ~@
|
35
44
|
_operator_1('!')
|
36
45
|
end
|
@@ -51,24 +60,26 @@ class Filtered
|
|
51
60
|
end
|
52
61
|
|
53
62
|
# Iterate over matching data
|
54
|
-
def each(*args, &block)
|
55
|
-
|
63
|
+
def each(*args, rawfilter: nil, &block)
|
64
|
+
raise NoSource if @src.nil?
|
65
|
+
@src.each(*args, filter: @filter, rawfilter: rawfilter,
|
66
|
+
paged: self.paged, &block)
|
56
67
|
end
|
57
68
|
|
58
69
|
# Retrieve matching data as a list of object
|
59
70
|
#
|
60
71
|
# @return [Array<Object>]
|
61
72
|
#
|
62
|
-
def all
|
63
|
-
each(:object).to_a
|
73
|
+
def all(&rawfilter)
|
74
|
+
each(:object, rawfilter: rawfilter).to_a
|
64
75
|
end
|
65
76
|
|
66
77
|
# Retrieve matching data as a list of id
|
67
78
|
#
|
68
79
|
# @return [Array<String>]
|
69
80
|
#
|
70
|
-
def list
|
71
|
-
each(:id).to_a
|
81
|
+
def list(&rawfilter)
|
82
|
+
each(:id, rawfilter: rawfilter).to_a
|
72
83
|
end
|
73
84
|
|
74
85
|
# Escape (and convert) a value for correct processing.
|
@@ -89,20 +100,20 @@ class Filtered
|
|
89
100
|
|
90
101
|
# Test if an attribute exists
|
91
102
|
def self.exists(attr, predicate: true)
|
92
|
-
case predicate
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
103
|
+
self.new(case predicate
|
104
|
+
when true, nil then "(#{attr}=*)"
|
105
|
+
when false, :none then "(!(#{attr}=*))"
|
106
|
+
else raise ArgumentError
|
107
|
+
end)
|
97
108
|
end
|
98
109
|
|
99
110
|
# Test if an attribute is of the specified value
|
100
111
|
def self.is(attr, val, predicate: true)
|
101
|
-
case predicate
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
112
|
+
self.new(case predicate
|
113
|
+
when true, nil then "(#{attr}=#{escape(val)})"
|
114
|
+
when false then "(!(#{attr}=#{escape(val)}))"
|
115
|
+
else raise ArgumentError
|
116
|
+
end)
|
106
117
|
end
|
107
118
|
|
108
119
|
# Test if an attribute has the specified value.
|
@@ -110,11 +121,20 @@ class Filtered
|
|
110
121
|
def self.has(attr, val)
|
111
122
|
val = yield(val) if block_given?
|
112
123
|
|
113
|
-
case val
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
124
|
+
self.new(case val
|
125
|
+
when ANY then "(#{attr}=*)"
|
126
|
+
when NONE then "(!(#{attr}=*))"
|
127
|
+
else "(#{attr}=#{escape(val)})"
|
128
|
+
end)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Test if an attribute match the specified value
|
132
|
+
def self.match(attr, val, predicate: true)
|
133
|
+
self.new(case predicate
|
134
|
+
when true, nil then "(#{attr}=*#{escape(val)}*)"
|
135
|
+
when false then "(!(#{attr}=*#{escape(val)}*))"
|
136
|
+
else raise ArgumentError
|
137
|
+
end)
|
118
138
|
end
|
119
139
|
|
120
140
|
# Test if an attribute as a time before the specified timestamp
|
@@ -122,7 +142,7 @@ class Filtered
|
|
122
142
|
def self.before(attr, ts, predicate: true)
|
123
143
|
ts = Date.today + ts if ts.kind_of?(Integer)
|
124
144
|
ts = LOM.to_ldap_time(ts)
|
125
|
-
"(#{attr}<=#{ts})".then {|f| predicate ? f : "(!#{f})" }
|
145
|
+
self.new("(#{attr}<=#{ts})".then {|f| predicate ? f : "(!#{f})" })
|
126
146
|
end
|
127
147
|
|
128
148
|
# Test if an attribute as a time after the specified timestamp
|
@@ -130,40 +150,40 @@ class Filtered
|
|
130
150
|
def self.after(attr, ts, predicate: true)
|
131
151
|
ts = Date.today - ts if ts.kind_of?(Integer)
|
132
152
|
ts = LOM.to_ldap_time(ts)
|
133
|
-
"(#{attr}>=#{ts})".then {|f| predicate ? f : "(!#{f})" }
|
153
|
+
self.new("(#{attr}>=#{ts})".then {|f| predicate ? f : "(!#{f})" })
|
134
154
|
end
|
135
155
|
|
136
156
|
private
|
137
157
|
|
138
158
|
# Operation with 2 elements
|
139
159
|
def _operator_2(op, o)
|
140
|
-
if @src != o.src
|
160
|
+
if !@src.nil? && !o.src.nil? && @src != o.src
|
141
161
|
raise ArgumentError, 'filter defined with different sources'
|
142
162
|
end
|
143
163
|
_filter = if !@filter.nil? && !o.filter.nil?
|
144
164
|
then Net::LDAP.filter(op, @filter, o.filter)
|
145
165
|
else @filter || o.filter
|
146
166
|
end
|
147
|
-
Filtered.new(@src
|
167
|
+
Filtered.new(_filter, src: @src || o.src, paged: o.paged || self.paged)
|
148
168
|
end
|
149
169
|
|
150
170
|
# Operation with 1 element
|
151
171
|
def _operator_1(op)
|
152
|
-
Filtered.new(
|
172
|
+
Filtered.new(Net::LDAP.filter(op, @filter), src: @src,
|
153
173
|
paged: self.paged)
|
154
174
|
end
|
155
175
|
|
156
176
|
# Check if an ldap_list has been defined with that name
|
157
177
|
def respond_to_missing?(method_name, include_private = false)
|
178
|
+
return super if @src.nil?
|
158
179
|
@src.ldap_listing.include?(method_name) || super
|
159
180
|
end
|
160
181
|
|
161
182
|
# Call the ldap_list defined with that name
|
162
183
|
def method_missing(method_name, *args, &block)
|
163
|
-
if @src
|
164
|
-
|
165
|
-
else
|
166
|
-
super
|
184
|
+
if @src&.ldap_listing.include?(method_name)
|
185
|
+
then self & @src.send(method_name, *args, &block)
|
186
|
+
else super
|
167
187
|
end
|
168
188
|
end
|
169
189
|
|
data/lib/lom/ldap/extensions.rb
CHANGED
data/lib/lom/mapper.rb
CHANGED
@@ -37,7 +37,8 @@ module InstanceMethods
|
|
37
37
|
# @return [true, false]
|
38
38
|
#
|
39
39
|
def save!
|
40
|
-
|
40
|
+
model = self.class
|
41
|
+
attrs = instance_exec(self, &model.ldap_to)
|
41
42
|
.transform_values {|v|
|
42
43
|
# Don't use Array(), not what you think on
|
43
44
|
# some classes such as Time
|
@@ -45,9 +46,9 @@ module InstanceMethods
|
|
45
46
|
v = [ v ] unless v.is_a?(Array)
|
46
47
|
v.to_ldap
|
47
48
|
}
|
48
|
-
id, _ = Array(attrs[
|
49
|
+
id, _ = Array(attrs[model.ldap_prefix])
|
49
50
|
raise MappingError, 'prefix for dn has multiple values' if _
|
50
|
-
dn =
|
51
|
+
dn = model.ldap_dn_from_id(id)
|
51
52
|
|
52
53
|
lh.update(dn: dn, attributes: attrs).then {|res|
|
53
54
|
break res unless res.nil?
|
@@ -101,7 +102,10 @@ module Mapper
|
|
101
102
|
@__ldap_lh = lh
|
102
103
|
end
|
103
104
|
|
104
|
-
|
105
|
+
# Return the list of defined list (using ldap_list).
|
106
|
+
#
|
107
|
+
# @return [Array<Symbol>] list of defined ldap list
|
108
|
+
#
|
105
109
|
def ldap_listing
|
106
110
|
@__ldap_list
|
107
111
|
end
|
@@ -118,16 +122,18 @@ module Mapper
|
|
118
122
|
@__ldap_list << name
|
119
123
|
define_singleton_method(name) do |*args|
|
120
124
|
filter = body.call(*args)
|
121
|
-
LOM::Filtered.new(
|
125
|
+
LOM::Filtered.new(filter, src: self)
|
122
126
|
end
|
123
127
|
end
|
124
128
|
|
125
129
|
|
126
|
-
def ldap_branch(v)
|
130
|
+
def ldap_branch(v = nil)
|
131
|
+
return _ldap_branch if v.nil?
|
127
132
|
@__ldap_branch = v
|
128
133
|
end
|
129
134
|
|
130
|
-
def ldap_prefix(v)
|
135
|
+
def ldap_prefix(v = nil)
|
136
|
+
return _ldap_prefix if v.nil?
|
131
137
|
@__ldap_prefix = v
|
132
138
|
end
|
133
139
|
|
@@ -154,6 +160,8 @@ module Mapper
|
|
154
160
|
|
155
161
|
# @note block will be executed in the mapped object instance
|
156
162
|
def ldap_to(p=nil, &b)
|
163
|
+
return _ldap_to if p.nil? && b.nil?
|
164
|
+
|
157
165
|
if (! p.nil? ^ b.nil?) || (p && !p.kind_of?(Proc))
|
158
166
|
raise ArgumentError,
|
159
167
|
'one and only one of proc/lamba/block need to be defined'
|
@@ -162,7 +170,15 @@ module Mapper
|
|
162
170
|
end
|
163
171
|
|
164
172
|
|
165
|
-
|
173
|
+
# Convert a dn to it's corresponding id the current mapping.
|
174
|
+
#
|
175
|
+
# @raise [Error] dn belongs to this mapping (it is in the mapping
|
176
|
+
# branch), but is malformed (not a direct child, or
|
177
|
+
# wrong prefix)
|
178
|
+
#
|
179
|
+
# @return [String] id
|
180
|
+
# @return [nil] dn is not from this mapping
|
181
|
+
#
|
166
182
|
def ldap_dn_to_id(dn)
|
167
183
|
prefix = _ldap_prefix.to_s
|
168
184
|
branch = _ldap_branch
|
@@ -171,8 +187,8 @@ module Mapper
|
|
171
187
|
case prefix
|
172
188
|
when String, Symbol
|
173
189
|
k, v, _ = sub.to_a
|
174
|
-
raise
|
175
|
-
raise
|
190
|
+
raise Error, "not a direct child" if _
|
191
|
+
raise Error, "wrong prefix" if k.casecmp(prefix) != 0
|
176
192
|
v
|
177
193
|
end
|
178
194
|
end
|
@@ -190,24 +206,45 @@ module Mapper
|
|
190
206
|
self.new(*args)
|
191
207
|
end
|
192
208
|
|
193
|
-
|
194
|
-
|
209
|
+
|
210
|
+
# Iterate over matching data.
|
211
|
+
#
|
212
|
+
# @note If using `rawfilter`, no optimization will be performed
|
213
|
+
# aned the ldap attributes will be retrieved,
|
214
|
+
# even if desired type is :id
|
215
|
+
#
|
216
|
+
# @param type [:object, :id] return object or id
|
217
|
+
# @param filter [String] extra ldap search filter
|
218
|
+
# @param rawfilter [Proc] filter on ldap entry
|
219
|
+
# @param paged [Array<Integer,Integer>] pagination information
|
220
|
+
#
|
221
|
+
# @yieldparam obj_or_id [Object, String] ldap converted element according to type
|
222
|
+
#
|
223
|
+
# @return [Enumerator] if no block given
|
224
|
+
# @return [self] if block given
|
225
|
+
#
|
226
|
+
def each(type = :object, filter: nil, rawfilter: nil, paged: nil)
|
195
227
|
# Create Enumerator if no block given
|
196
228
|
unless block_given?
|
197
|
-
return enum_for(:each, type,
|
229
|
+
return enum_for(:each, type,
|
230
|
+
filter: filter, rawfilter: rawfilter, paged: paged)
|
198
231
|
end
|
199
232
|
|
200
233
|
# Merging filters
|
201
|
-
|
202
|
-
filter = filters.size == 2 ? "(&#{filters.join})" : filters.first
|
234
|
+
filter = Net::LDAP.filter('&', *[ filter, _ldap_filter ].compact)
|
203
235
|
|
204
236
|
# Define attributes/converter according to selected type
|
205
237
|
attributes, converter =
|
206
238
|
case type
|
207
|
-
when :id then [
|
208
|
-
|
239
|
+
when :id then [ rawfilter ? _ldap_attrs : :dn,
|
240
|
+
->(e) { ldap_dn_to_id(e.dn) }
|
241
|
+
]
|
242
|
+
when :object then [ _ldap_attrs,
|
243
|
+
->(e) { _ldap_to_obj(e) }
|
244
|
+
]
|
209
245
|
else raise ArgumentError, 'type must be either :object or :id'
|
210
246
|
end
|
247
|
+
|
211
248
|
|
212
249
|
# Paginate
|
213
250
|
# XXX: pagination is emulated, should be avoided
|
@@ -222,7 +259,9 @@ module Mapper
|
|
222
259
|
:attributes => attributes,
|
223
260
|
:scope => _ldap_scope) {|entry|
|
224
261
|
|
225
|
-
if
|
262
|
+
if rawfilter && !rawfilter.call(entry)
|
263
|
+
next
|
264
|
+
elsif paged.nil?
|
226
265
|
yield(converter.(entry))
|
227
266
|
elsif skip > 0
|
228
267
|
skip -= 1
|
@@ -233,18 +272,29 @@ module Mapper
|
|
233
272
|
yield(converter.(entry))
|
234
273
|
end
|
235
274
|
}
|
275
|
+
|
276
|
+
# Return self
|
277
|
+
self
|
236
278
|
end
|
237
279
|
|
238
280
|
def paginate(page, page_size)
|
239
|
-
LOM::Filtered.new(self, paged: [ page, page_size ])
|
281
|
+
LOM::Filtered.new(src: self, paged: [ page, page_size ])
|
240
282
|
end
|
241
283
|
|
242
|
-
|
243
|
-
|
284
|
+
# Retrieve matching data as a list of object
|
285
|
+
#
|
286
|
+
# @return [Array<Object>]
|
287
|
+
#
|
288
|
+
def all(&rawfilter)
|
289
|
+
each(:object, rawfilter: rawfilter).to_a
|
244
290
|
end
|
245
291
|
|
246
|
-
|
247
|
-
|
292
|
+
# Retrieve matching data as a list of id
|
293
|
+
#
|
294
|
+
# @return [Array<String>]
|
295
|
+
#
|
296
|
+
def list(&rawfilter)
|
297
|
+
each(:id, rawfilter: rawfilter).to_a
|
248
298
|
end
|
249
299
|
|
250
300
|
def get(name)
|
data/lib/lom/version.rb
CHANGED
data/lom.gemspec
CHANGED
@@ -8,15 +8,13 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.summary = "LDAP Object Mapper"
|
9
9
|
s.description = <<~EOF
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
Creation of mapping between ldap entry and ruby object.
|
12
|
+
Allowing easy retrieval of information, building of search filter,
|
13
|
+
and updating ldap.
|
13
14
|
|
14
|
-
Example:
|
15
|
-
want! :user, Dry::Types::String, User
|
16
|
-
want? :expired, Dry::Types::Params::Bool.default(true)
|
17
15
|
EOF
|
18
16
|
|
19
|
-
s.homepage = 'https://
|
17
|
+
s.homepage = 'https://github.com/sdalu/lom'
|
20
18
|
s.license = 'MIT'
|
21
19
|
|
22
20
|
s.authors = [ "Stéphane D'Alu" ]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lom
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stéphane D'Alu
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: net-ldap
|
@@ -52,14 +52,12 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '13'
|
55
|
-
description: |2
|
55
|
+
description: |2+
|
56
56
|
|
57
|
-
|
58
|
-
|
57
|
+
Creation of mapping between ldap entry and ruby object.
|
58
|
+
Allowing easy retrieval of information, building of search filter,
|
59
|
+
and updating ldap.
|
59
60
|
|
60
|
-
Example:
|
61
|
-
want! :user, Dry::Types::String, User
|
62
|
-
want? :expired, Dry::Types::Params::Bool.default(true)
|
63
61
|
email:
|
64
62
|
- stephane.dalu@insa-lyon.fr
|
65
63
|
executables: []
|
@@ -77,7 +75,7 @@ files:
|
|
77
75
|
- lib/lom/mapper.rb
|
78
76
|
- lib/lom/version.rb
|
79
77
|
- lom.gemspec
|
80
|
-
homepage: https://
|
78
|
+
homepage: https://github.com/sdalu/lom
|
81
79
|
licenses:
|
82
80
|
- MIT
|
83
81
|
metadata: {}
|
@@ -101,3 +99,4 @@ signing_key:
|
|
101
99
|
specification_version: 4
|
102
100
|
summary: LDAP Object Mapper
|
103
101
|
test_files: []
|
102
|
+
...
|