ldap_disambiguate 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rubocop.yml +57 -0
- data/.rubocop_todo.yml +19 -0
- data/.travis.yml +10 -0
- data/Gemfile +9 -0
- data/README.md +44 -0
- data/Rakefile +28 -0
- data/VERSION +1 -0
- data/config/hydra-ldap.yml.sample +24 -0
- data/ldap_disambiguate.gemspec +32 -0
- data/lib/ldap_disambiguate.rb +22 -0
- data/lib/ldap_disambiguate/base.rb +35 -0
- data/lib/ldap_disambiguate/email.rb +27 -0
- data/lib/ldap_disambiguate/ldap_user.rb +102 -0
- data/lib/ldap_disambiguate/name.rb +101 -0
- data/lib/ldap_disambiguate/version.rb +4 -0
- metadata +158 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 76ca8867744e6cb0102707bf64529554acdccd14
|
4
|
+
data.tar.gz: 3a7fc8ab6ca648fd67d0113ca541968123d37f37
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b25d698df46f01b22f019cbfa79f337729e4be4f655862d6261623df0a58aaafd5fc2e13de26ab0d2345a943ca5e2a1bb76eaec044b4aeac7dc0fb101a45aa3e
|
7
|
+
data.tar.gz: ded15695850d2820b7cb4c98662fc8f6a58efb93b7478647b20e966437a7830d8144c4bf10f086254f9091e00a6637cb1dd26aa46e50514b44d3d8fb6373d5f3
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
AllCops:
|
2
|
+
DisplayCopNames: true
|
3
|
+
Include:
|
4
|
+
- '**/Rakefile'
|
5
|
+
|
6
|
+
Metrics/LineLength:
|
7
|
+
Enabled: false
|
8
|
+
|
9
|
+
Metrics/AbcSize:
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
Style/IndentationConsistency:
|
13
|
+
EnforcedStyle: rails
|
14
|
+
|
15
|
+
Style/CollectionMethods:
|
16
|
+
PreferredMethods:
|
17
|
+
collect: 'map'
|
18
|
+
collect!: 'map!'
|
19
|
+
inject: 'reduce'
|
20
|
+
detect: 'find'
|
21
|
+
find_all: 'select'
|
22
|
+
|
23
|
+
Style/WordArray:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Style/RegexpLiteral:
|
27
|
+
Enabled: false
|
28
|
+
|
29
|
+
Style/StringLiterals:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
Style/ClassAndModuleChildren:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
Style/Documentation:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
Style/SingleLineBlockParams:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
Style/SignalException:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
RSpec/ExampleWording:
|
45
|
+
CustomTransform:
|
46
|
+
be: is
|
47
|
+
have: has
|
48
|
+
not: does not
|
49
|
+
NOT: does NOT
|
50
|
+
IgnoredWords:
|
51
|
+
- only
|
52
|
+
|
53
|
+
RSpec/FilePath:
|
54
|
+
Enabled: false
|
55
|
+
|
56
|
+
RSpec/InstanceVariable:
|
57
|
+
Enabled: false
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2016-03-24 06:26:32 -0400 using RuboCop version 0.37.2.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 1
|
10
|
+
# Configuration parameters: CountComments.
|
11
|
+
Metrics/ClassLength:
|
12
|
+
Max: 111
|
13
|
+
|
14
|
+
# Offense count: 1
|
15
|
+
Style/Documentation:
|
16
|
+
Exclude:
|
17
|
+
- 'spec/**/*'
|
18
|
+
- 'test/**/*'
|
19
|
+
- 'lib/ldap_disambiguate.rb'
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# ldap_disambiguate
|
2
|
+
Use ldap to disambiguate a user name against the PSU LDAP.
|
3
|
+
|
4
|
+
## Useage
|
5
|
+
|
6
|
+
Instantiate the servercive with a string `LdapDisambiguate::Name.new("jbd123")`
|
7
|
+
Call the disambiguate method which returns an array of people in the format `[{:id=>"jbd123", :given_name=>"Jane B", :surname=>"Doe", :email=>"jbd123@psu.edu", :affiliation=>["STAFF"]}]`
|
8
|
+
|
9
|
+
What you pass in as the nam can vary from an id to a list of names and or emails.
|
10
|
+
|
11
|
+
### Basic usage with a id
|
12
|
+
|
13
|
+
You can call dismabiguate with an id, which then call ldap and returns a record containing the
|
14
|
+
|
15
|
+
```
|
16
|
+
service = LdapDisambiguate::Name.new("cam156") # #<LdapDisambiguate::Name:0x007fab36190710 @name="cam156", @email_for_name_cache={}, @results=[]>
|
17
|
+
service.disambiguate #[{:id=>"cam156", :given_name=>"CAROLYN A", :surname=>"COLE", :email=>"cam156@psu.edu", :affiliation=>["STAFF"]}]
|
18
|
+
```
|
19
|
+
|
20
|
+
### Basic usage with a name
|
21
|
+
|
22
|
+
```
|
23
|
+
service = LdapDisambiguate::Name.new("Carolyn Cole") # #<LdapDisambiguate::Name:0x007fab36190710 @name="Carolyn Cole", @email_for_name_cache={}, @results=[]>
|
24
|
+
service.disambiguate #[{:id=>"cam156", :given_name=>"CAROLYN A", :surname=>"COLE", :email=>"cam156@psu.edu", :affiliation=>["STAFF"]}]
|
25
|
+
```
|
26
|
+
|
27
|
+
### Useage with last name and first name part
|
28
|
+
```
|
29
|
+
service = LdapDisambiguate::Name.new("Carol Cole") # #<LdapDisambiguate::Name:0x007fab36190710 @name="Carol Cole", @email_for_name_cache={}, @results=[]>
|
30
|
+
service.disambiguate #[{:id=>"cam156", :given_name=>"CAROLYN A", :surname=>"COLE", :email=>"cam156@psu.edu", :affiliation=>["STAFF"]}]
|
31
|
+
```
|
32
|
+
|
33
|
+
### Useage with last name and first name part
|
34
|
+
```
|
35
|
+
service = LdapDisambiguate::Name.new("Carol Cole, cam156") # #<LdapDisambiguate::Name:0x007fab36190710 @name="Carol Cole", @email_for_name_cache={}, @results=[]>
|
36
|
+
service.disambiguate #[{:id=>"cam156", :given_name=>"CAROLYN A", :surname=>"COLE", :email=>"cam156@psu.edu", :affiliation=>["STAFF"]}]
|
37
|
+
```
|
38
|
+
|
39
|
+
### Useage with a list of names
|
40
|
+
```
|
41
|
+
service = LdapDisambiguate::Name.new("Carol Cole; Adam Wead") ##<LdapDisambiguate::Name:0x007fab32cf2418 @name="Carol Cole; Adam Wead", @email_for_name_cache={}, @results=[]>
|
42
|
+
service.disambiguate #[{:id=>"cam156", :given_name=>"CAROLYN A", :surname=>"COLE", :email=>"cam156@psu.edu", :affiliation=>["STAFF"]}, {:id=>"agw13", :given_name=>"ADAM GARNER", :surname=>"WEAD", :email=>"agw13@psu.edu", :affiliation=>["STAFF"]}]
|
43
|
+
```
|
44
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
3
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
4
|
+
begin
|
5
|
+
require 'bundler/setup'
|
6
|
+
rescue LoadError
|
7
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
8
|
+
end
|
9
|
+
|
10
|
+
Bundler::GemHelper.install_tasks
|
11
|
+
|
12
|
+
Dir.glob('tasks/*.rake').each { |r| import r }
|
13
|
+
|
14
|
+
require 'rspec/core/rake_task'
|
15
|
+
require 'rubocop/rake_task'
|
16
|
+
|
17
|
+
RSpec::Core::RakeTask.new(:spec)
|
18
|
+
|
19
|
+
desc "Run style checker"
|
20
|
+
RuboCop::RakeTask.new(:rubocop) do |task|
|
21
|
+
task.requires << 'rubocop-rspec'
|
22
|
+
task.fail_on_error = true
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Run continuous integration tests"
|
26
|
+
task ci: [:rubocop, :spec]
|
27
|
+
|
28
|
+
task default: :ci
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,24 @@
|
|
1
|
+
development:
|
2
|
+
host: ldap.example.com
|
3
|
+
port: 389
|
4
|
+
# username: cn=admin,dc=example,dc=com
|
5
|
+
# password: simple77
|
6
|
+
group_base: dc=psu,dc=edu
|
7
|
+
base: dc=example,dc=com
|
8
|
+
uid: uid
|
9
|
+
test:
|
10
|
+
host: ldap.example.com
|
11
|
+
port: 389
|
12
|
+
# username: cn=admin,dc=example,dc=com
|
13
|
+
# password: simple77
|
14
|
+
group_base: dc=psu,dc=edu
|
15
|
+
# base: dc=example,dc=com
|
16
|
+
# uid: uid
|
17
|
+
production:
|
18
|
+
host: ldap.example.com
|
19
|
+
port: 389
|
20
|
+
#username: cn=admin,dc=example,dc=com
|
21
|
+
#password: <%= ENV['LDAP_PASSWORD'] %>
|
22
|
+
group_base: dc=psu,dc=edu
|
23
|
+
base: dc=example,dc=com
|
24
|
+
uid: uid
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ldap_disambiguate/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'ldap_disambiguate'
|
8
|
+
s.version = LdapDisambiguate::VERSION
|
9
|
+
s.date = '2016-03-14'
|
10
|
+
s.summary = 'Use ldap to diambiguate a text name'
|
11
|
+
s.description = 'Queries the PSU ldap to see if it can find a user that matches the text to get the prefered name and email'
|
12
|
+
s.authors = ['Carolyn Cole']
|
13
|
+
s.email = 'cam156@psu.edu'
|
14
|
+
s.files = ['lib/ldap_disambiguate.rb']
|
15
|
+
s.homepage =
|
16
|
+
'https://github.com/psu-stewardship/ldap_disambiguate'
|
17
|
+
s.license = 'APACHE2'
|
18
|
+
|
19
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
20
|
+
s.bindir = 'exe'
|
21
|
+
s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
s.require_paths = ['lib']
|
23
|
+
|
24
|
+
s.add_dependency 'hydra-ldap'
|
25
|
+
s.add_dependency 'net-ldap', '0.13.0'
|
26
|
+
s.add_dependency 'namae', '0.9.3'
|
27
|
+
|
28
|
+
s.add_development_dependency 'bundler', '~> 1.11'
|
29
|
+
s.add_development_dependency 'rake', '~> 10.0'
|
30
|
+
s.add_development_dependency 'rspec', '~> 3.0'
|
31
|
+
s.add_development_dependency 'rspec-its'
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# require 'rspec/its'
|
3
|
+
require 'net-ldap'
|
4
|
+
require 'hydra-ldap'
|
5
|
+
require 'namae'
|
6
|
+
require 'logger'
|
7
|
+
|
8
|
+
def logger
|
9
|
+
Logger.new(STDOUT)
|
10
|
+
end
|
11
|
+
|
12
|
+
# defines the classes availabel for the LdapDisambiguate gem
|
13
|
+
#
|
14
|
+
# LdapUser is the interface to the PSU LDAP
|
15
|
+
# Name uses the name to disambiguate via name
|
16
|
+
#
|
17
|
+
module LdapDisambiguate
|
18
|
+
autoload :Base, 'ldap_disambiguate/base'
|
19
|
+
autoload :Name, 'ldap_disambiguate/name'
|
20
|
+
autoload :Email, 'ldap_disambiguate/email'
|
21
|
+
autoload :LdapUser, 'ldap_disambiguate/ldap_user'
|
22
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module LdapDisambiguate
|
3
|
+
# This class allows you to use LDAP to disambiguate a text name
|
4
|
+
#
|
5
|
+
class Base
|
6
|
+
class << self
|
7
|
+
private
|
8
|
+
|
9
|
+
def ldap_attributes_for_id(id)
|
10
|
+
attrs = LdapUser.directory_attributes(id, ldap_attrs)
|
11
|
+
return nil if attrs.count < 1
|
12
|
+
[results_hash(attrs.first)]
|
13
|
+
end
|
14
|
+
|
15
|
+
def results_hash(opts)
|
16
|
+
{
|
17
|
+
id: fetch(opts, :uid).first,
|
18
|
+
given_name: fetch(opts, :givenname).first,
|
19
|
+
surname: fetch(opts, :sn).first,
|
20
|
+
email: fetch(opts, :mail).first,
|
21
|
+
affiliation: fetch(opts, :eduPersonPrimaryAffiliation, []),
|
22
|
+
displayname: fetch(opts, :displayname).first
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def fetch(opts, key, default = [''])
|
27
|
+
opts[key].blank? ? default : opts[key]
|
28
|
+
end
|
29
|
+
|
30
|
+
def ldap_attrs
|
31
|
+
[:uid, :givenname, :sn, :mail, :eduPersonPrimaryAffiliation, :displayname]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module LdapDisambiguate
|
3
|
+
# This class allows you to use LDAP to extract user information
|
4
|
+
# from an email or list of emails
|
5
|
+
#
|
6
|
+
class Email < Base
|
7
|
+
class << self
|
8
|
+
def disambiguate(email)
|
9
|
+
return unless email.include?('@')
|
10
|
+
email_in_name(email)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def email_in_name(email_list)
|
16
|
+
parts = email_list.split(' ')
|
17
|
+
emails = parts.reject { |part| !part.include?('@') }
|
18
|
+
results = []
|
19
|
+
Array(emails).each do |email|
|
20
|
+
id = email.split('@')[0]
|
21
|
+
results << (ldap_attributes_for_id(id) || [results_hash(mail: [email])]).first
|
22
|
+
end
|
23
|
+
results
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module LdapDisambiguate
|
3
|
+
# This class provides an api for quering LDAP with different portions of the user's
|
4
|
+
# information (name parts or id)
|
5
|
+
class LdapUser
|
6
|
+
class << self
|
7
|
+
def directory_attributes(login, attrs = [])
|
8
|
+
filter = Net::LDAP::Filter.eq('uid', login)
|
9
|
+
get_ldap_response(:get_user, filter, attrs)
|
10
|
+
end
|
11
|
+
|
12
|
+
def query_ldap_by_name_or_id(id_or_name_part)
|
13
|
+
filter = Net::LDAP::Filter.construct("(& (| (uid=#{id_or_name_part}* ) (givenname=#{id_or_name_part}*) (sn=#{id_or_name_part}*)) #{person_filter})")
|
14
|
+
users = get_ldap_response(:get_user, filter, %w(uid displayname))
|
15
|
+
|
16
|
+
# handle the issue that searching with a few letters returns more than 1000 items wich causes an error in the system
|
17
|
+
users = get_user_by_partial_id(id_or_name_part) if size_limit_exceeded?
|
18
|
+
users.map { |u| { id: u[:uid].first, text: "#{u[:displayname].first} (#{u[:uid].first})" } }
|
19
|
+
end
|
20
|
+
|
21
|
+
def query_ldap_by_name(given_name, surname, attrs = [])
|
22
|
+
return if given_name.blank? # this method only work if we have a first name to play with
|
23
|
+
|
24
|
+
first_names = given_name.split(/[\s.]+/)
|
25
|
+
users = []
|
26
|
+
name_filters(first_names[0], first_names[1], surname).each do |filter|
|
27
|
+
users = get_users(filter, attrs)
|
28
|
+
break if users.count > 0 # stop running through the filters if we get results
|
29
|
+
end
|
30
|
+
format_users(users, attrs)
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_users(name_filter, attrs = [])
|
34
|
+
attrs = (attrs + default_attributes).uniq
|
35
|
+
person_filter = '(| (eduPersonPrimaryAffiliation=STUDENT) (eduPersonPrimaryAffiliation=FACULTY) (eduPersonPrimaryAffiliation=STAFF) (eduPersonPrimaryAffiliation=EMPLOYEE) (eduPersonPrimaryAffiliation=RETIREE) (eduPersonPrimaryAffiliation=EMERITUS) (eduPersonPrimaryAffiliation=MEMBER)))'
|
36
|
+
filter = Net::LDAP::Filter.construct("(& (& #{name_filter}) #{person_filter})")
|
37
|
+
get_ldap_response(:get_user, filter, attrs)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def format_users(users, attrs)
|
43
|
+
user_attrs = attrs - default_attributes
|
44
|
+
users.map { |u| format_user(u, user_attrs) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def format_user(user, extra_attrs)
|
48
|
+
hash = { id: user[:uid].first, given_name: user[:givenname].first, surname: user[:sn].first, email: user[:mail].first, affiliation: user[:eduPersonPrimaryAffiliation] }
|
49
|
+
extra_attrs.each { |attr| hash[attr] = user[attr].first }
|
50
|
+
hash
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_user_by_partial_id(_id)
|
54
|
+
filter = Net::LDAP::Filter.construct("(& (uid=#{id_or_name_part}* ) #{person_filter})")
|
55
|
+
get_ldap_response(:get_user, filter, %w(uid displayname))
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_ldap_response(_method, filter, attributes)
|
59
|
+
tries.times.each do
|
60
|
+
result = Hydra::LDAP.get_user(filter, attributes)
|
61
|
+
return result unless unwilling?
|
62
|
+
sleep(sleep_time)
|
63
|
+
end
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def tries
|
68
|
+
7
|
69
|
+
end
|
70
|
+
|
71
|
+
# Numeric code returned by LDAP if it is feeling "unwilling"
|
72
|
+
def unwilling?
|
73
|
+
Hydra::LDAP.connection.get_operation_result.code == 53
|
74
|
+
end
|
75
|
+
|
76
|
+
def size_limit_exceeded?
|
77
|
+
Hydra::LDAP.connection.get_operation_result[:message] == 'Size Limit Exceeded'
|
78
|
+
end
|
79
|
+
|
80
|
+
def sleep_time
|
81
|
+
1.0
|
82
|
+
end
|
83
|
+
|
84
|
+
def person_filter
|
85
|
+
'(| (eduPersonPrimaryAffiliation=STUDENT) (eduPersonPrimaryAffiliation=FACULTY) (eduPersonPrimaryAffiliation=STAFF) (eduPersonPrimaryAffiliation=EMPLOYEE))))'
|
86
|
+
end
|
87
|
+
|
88
|
+
def name_filters(first_name, middle_name, surname)
|
89
|
+
filters = []
|
90
|
+
filters << "(givenname=#{first_name}*) (givenname=* #{middle_name}*) (sn=#{surname})" unless middle_name.blank?
|
91
|
+
filters << "(givenname=#{first_name}) (sn=#{surname})"
|
92
|
+
filters << "(givenname=#{first_name}*) (sn=#{surname})"
|
93
|
+
filters << "(givenname=*#{first_name}*) (sn=#{surname})"
|
94
|
+
filters
|
95
|
+
end
|
96
|
+
|
97
|
+
def default_attributes
|
98
|
+
[:uid, :givenname, :sn, :mail, :eduPersonPrimaryAffiliation]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module LdapDisambiguate
|
3
|
+
# This class allows you to use LDAP to disambiguate a text name
|
4
|
+
#
|
5
|
+
class Name < Base
|
6
|
+
class << self
|
7
|
+
def disambiguate(name)
|
8
|
+
return if name.blank?
|
9
|
+
results = ldap_attributes_for_id(name) # text includes login id
|
10
|
+
results ||= Email.disambiguate(name) # text includes email(s)
|
11
|
+
results ||= text_only_names(name) # straight text we need to query ldap
|
12
|
+
results
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def text_only_names(multi_name)
|
18
|
+
results = []
|
19
|
+
multi_name.split(/and|;/).each do |n|
|
20
|
+
n.gsub!(/\([^)]*\)/, '')
|
21
|
+
n.strip!
|
22
|
+
query_result = email_for_name(n)
|
23
|
+
query_result ||= title_after_name(n) # try again without the titles
|
24
|
+
results << query_result unless query_result.blank?
|
25
|
+
end
|
26
|
+
results
|
27
|
+
end
|
28
|
+
|
29
|
+
# titles after the name that namae had trouble parsing
|
30
|
+
def title_after_name(text_name)
|
31
|
+
result = nil
|
32
|
+
if text_name.count(',') > 0
|
33
|
+
new_name = text_name.split(',')[0]
|
34
|
+
result = email_for_name(new_name) if new_name.count(' ') > 0
|
35
|
+
end
|
36
|
+
result
|
37
|
+
end
|
38
|
+
|
39
|
+
def email_for_name(text_name)
|
40
|
+
return '' if text_name.blank?
|
41
|
+
return email_for_name_cache[text_name] unless email_for_name_cache[text_name].blank?
|
42
|
+
|
43
|
+
email_for_name_cache[text_name] = find_email_for_name(text_name)
|
44
|
+
email_for_name_cache[text_name]
|
45
|
+
end
|
46
|
+
|
47
|
+
def email_for_name_cache
|
48
|
+
@email_for_name_cache ||= {}
|
49
|
+
end
|
50
|
+
|
51
|
+
def find_email_for_name(text_name)
|
52
|
+
text_name.gsub!(/[^\w\s,']/, ' ')
|
53
|
+
parsed = Namae::Name.parse(text_name)
|
54
|
+
result = try_name(parsed.given, parsed.family)
|
55
|
+
result ||= title_before_name(parsed)
|
56
|
+
result ||= two_words_in_last_name(text_name)
|
57
|
+
|
58
|
+
logger.error("got zero for #{text_name}") if result.nil?
|
59
|
+
result
|
60
|
+
end
|
61
|
+
|
62
|
+
def try_name(given, family)
|
63
|
+
return nil if family.blank?
|
64
|
+
possible_users = LdapUser.query_ldap_by_name(given, family, ldap_attrs)
|
65
|
+
return nil if possible_users.count == 0
|
66
|
+
if possible_users.count > 1
|
67
|
+
logger.error("Returning #{possible_users.first} but got more than name for given name #{given} and family name #{name}")
|
68
|
+
return nil
|
69
|
+
end
|
70
|
+
possible_users.first
|
71
|
+
end
|
72
|
+
|
73
|
+
def name_parts(text_name, last_name_count)
|
74
|
+
parts = text_name.split(' ')
|
75
|
+
first_name_count = parts.count - last_name_count
|
76
|
+
return nil if first_name_count < 1
|
77
|
+
{ given: parts.first(first_name_count).join(' '), family: parts.last(last_name_count).join(' ') }
|
78
|
+
end
|
79
|
+
|
80
|
+
# take first name and break it into first and last with last name conatining one word
|
81
|
+
def title_before_name(parsed)
|
82
|
+
return unless parsed
|
83
|
+
result = nil
|
84
|
+
if parsed.given && parsed.given.count(' ') >= 1
|
85
|
+
parts = name_parts(parsed.given, 1)
|
86
|
+
result = try_name(parts[:family], parsed.family)
|
87
|
+
end
|
88
|
+
result
|
89
|
+
end
|
90
|
+
|
91
|
+
def two_words_in_last_name(text_name)
|
92
|
+
result = nil
|
93
|
+
if text_name.count(' ') > 2
|
94
|
+
parts = name_parts(text_name, 2)
|
95
|
+
result = try_name(parts[:given], parts[:family])
|
96
|
+
end
|
97
|
+
result
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
metadata
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ldap_disambiguate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Carolyn Cole
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: hydra-ldap
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: net-ldap
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.13.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.13.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: namae
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.9.3
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.9.3
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.11'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.11'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec-its
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Queries the PSU ldap to see if it can find a user that matches the text
|
112
|
+
to get the prefered name and email
|
113
|
+
email: cam156@psu.edu
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- ".gitignore"
|
119
|
+
- ".rubocop.yml"
|
120
|
+
- ".rubocop_todo.yml"
|
121
|
+
- ".travis.yml"
|
122
|
+
- Gemfile
|
123
|
+
- README.md
|
124
|
+
- Rakefile
|
125
|
+
- VERSION
|
126
|
+
- config/hydra-ldap.yml.sample
|
127
|
+
- ldap_disambiguate.gemspec
|
128
|
+
- lib/ldap_disambiguate.rb
|
129
|
+
- lib/ldap_disambiguate/base.rb
|
130
|
+
- lib/ldap_disambiguate/email.rb
|
131
|
+
- lib/ldap_disambiguate/ldap_user.rb
|
132
|
+
- lib/ldap_disambiguate/name.rb
|
133
|
+
- lib/ldap_disambiguate/version.rb
|
134
|
+
homepage: https://github.com/psu-stewardship/ldap_disambiguate
|
135
|
+
licenses:
|
136
|
+
- APACHE2
|
137
|
+
metadata: {}
|
138
|
+
post_install_message:
|
139
|
+
rdoc_options: []
|
140
|
+
require_paths:
|
141
|
+
- lib
|
142
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
requirements: []
|
153
|
+
rubyforge_project:
|
154
|
+
rubygems_version: 2.5.1
|
155
|
+
signing_key:
|
156
|
+
specification_version: 4
|
157
|
+
summary: Use ldap to diambiguate a text name
|
158
|
+
test_files: []
|