ucb_ldap 1.3.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/CHANGELOG +127 -0
- data/Manifest +25 -0
- data/README +80 -0
- data/Rakefile +22 -0
- data/TODO +2 -0
- data/init.rb +1 -0
- data/lib/person/adv_con_person.rb +0 -0
- data/lib/person/affiliation_methods.rb +212 -0
- data/lib/person/generic_attributes.rb +68 -0
- data/lib/ucb_ldap.rb +177 -0
- data/lib/ucb_ldap_address.rb +106 -0
- data/lib/ucb_ldap_affiliation.rb +84 -0
- data/lib/ucb_ldap_entry.rb +398 -0
- data/lib/ucb_ldap_exceptions.rb +27 -0
- data/lib/ucb_ldap_namespace.rb +42 -0
- data/lib/ucb_ldap_org.rb +369 -0
- data/lib/ucb_ldap_person.rb +135 -0
- data/lib/ucb_ldap_person_job_appointment.rb +79 -0
- data/lib/ucb_ldap_schema.rb +115 -0
- data/lib/ucb_ldap_schema_attribute.rb +153 -0
- data/lib/ucb_ldap_service.rb +109 -0
- data/lib/ucb_ldap_student_term.rb +101 -0
- data/lib/ucb_simple_ldap_entry.rb +201 -0
- data/schema/schema.yml +2954 -0
- data/ucb_ldap.gemspec +40 -0
- data/version.yml +1 -0
- metadata +124 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
= UCB::LDAP Changelog
|
2
|
+
|
3
|
+
== Version 1.2.1, January 22, 2008
|
4
|
+
|
5
|
+
* fixed bug: include UCB::LDAP call at top level that corrupted namespace
|
6
|
+
* fixed rspec tests to use production ldap server to verify Org structure
|
7
|
+
|
8
|
+
|
9
|
+
== Version 1.2.0, September 20, 2007
|
10
|
+
|
11
|
+
* fixed UCB::LDAP::Person.student_not_registered? which was broken
|
12
|
+
* added support for new entities
|
13
|
+
* Affiliation
|
14
|
+
* Service
|
15
|
+
* StudentTerm
|
16
|
+
* added handling of timestamp attributes
|
17
|
+
* various additions and clean-up to the various employee_*, student_*, affiliate_* methods
|
18
|
+
including handling of expiration
|
19
|
+
* fetches schema from url rather than file packaged with gem
|
20
|
+
* made UCB::LDAP::Person searches exclude test entries by default
|
21
|
+
* Rails applications can use UCB::LDAP.bind_for_rails() to get environment-specific binds
|
22
|
+
|
23
|
+
== Version 1.1.1, August 2, 2007
|
24
|
+
|
25
|
+
* fixed bug around deleting LDAP entries.
|
26
|
+
|
27
|
+
== Version 1.1.0, August 1, 2007
|
28
|
+
|
29
|
+
* added Org#level_<n>_code and Org#level_<n>_name where <n> is 1-6. Returns the
|
30
|
+
org node's level "n" code/name
|
31
|
+
* added option to Org.flattened_tree() to restrict levels returned.
|
32
|
+
|
33
|
+
== Version 1.0.1, July 25, 2007
|
34
|
+
|
35
|
+
* do a better job trapping dropped connections in UCB::LDAP.connection_open?
|
36
|
+
* added Person#test? to check for test entries
|
37
|
+
|
38
|
+
== Version 1.0.0
|
39
|
+
|
40
|
+
* got complete schema info for attributes
|
41
|
+
* replaced attribute synonyms in favor of explicit methods
|
42
|
+
* added support for ldap updates
|
43
|
+
* added support for new entities (if your bind supports it):
|
44
|
+
* appointment
|
45
|
+
* address
|
46
|
+
|
47
|
+
== Version 0.8.1, May 18, 2007
|
48
|
+
|
49
|
+
* added Person#dept_org (synonym for Person#deptid)
|
50
|
+
* added Person#dept_name
|
51
|
+
|
52
|
+
== Version 0.8.0, April 27, 2007
|
53
|
+
|
54
|
+
* added support for privileged binds via UCB::LDAP::authenticate()
|
55
|
+
|
56
|
+
== Version 0.7.0, January 16, 2007
|
57
|
+
|
58
|
+
* updated: UCB::LDAP::Entry.search to use Net::LDAP::Filter objects: this fixed the
|
59
|
+
problem with embedded whitespace
|
60
|
+
* updated UCB::LDAP::Person.person_by_uid() to work with an Integer or a String
|
61
|
+
and UCB::LDAP::Person.persons_by_uids() to work with an Array of Integers or Strings.
|
62
|
+
* updated: UCB::LDAP::Person.student? to utilize the new LDAP v2 ou structure
|
63
|
+
* added: UCB::LDAP::Person.student_registered?, UCB::LDAP::Person.student_not_registered?
|
64
|
+
* deprecated: UCB::LDAP::Person.student_summer?, UCB::LDAP::Person.student_summer_only?,
|
65
|
+
UCB::LDAP::Person.spring?, UCB::LDAP::Person.fall?. Except for UCB::LDAP::Person.student_summer_only?,
|
66
|
+
these methods may be added in later versions of UCB::LDAP::Person. Note: accessing these
|
67
|
+
attributes will required a privileged bind.
|
68
|
+
* changed UCB::LDAP::Entry to only allow filter options in hash form: :filter => {:uid => 12345}
|
69
|
+
* updated documentations
|
70
|
+
* updated unit tests.
|
71
|
+
|
72
|
+
== Version 0.6.0, January 10, 2007
|
73
|
+
|
74
|
+
* Added loading/caching of all nodes
|
75
|
+
* Added calculation of all child nodes
|
76
|
+
* Added UCB::LDAP::Org.flattened_tree()
|
77
|
+
* Added UCB::LDAP::Person.org_node()
|
78
|
+
|
79
|
+
== Version 0.5.0, December 20, 2006
|
80
|
+
|
81
|
+
* Added following methods to Org:
|
82
|
+
* child_nodes
|
83
|
+
* parent_node
|
84
|
+
* parent_nodes
|
85
|
+
* persons
|
86
|
+
|
87
|
+
== Version 0.4.0, December 14, 2006
|
88
|
+
|
89
|
+
* Added Person.persons_by_uids to return array of Person for given
|
90
|
+
array of uids.
|
91
|
+
* Changed implementation of Person.person_by_uid to use new Person.persons_by_uid.
|
92
|
+
|
93
|
+
== Version 0.3.1, December 13, 2006
|
94
|
+
|
95
|
+
* Added SchemaAttribute class and methods to load schema
|
96
|
+
attributes in UCB::LDAP. Did not make use of the schema
|
97
|
+
attributes.
|
98
|
+
|
99
|
+
== Version 0.3.0, October 20, 2006
|
100
|
+
|
101
|
+
* Moved to SVN
|
102
|
+
* Reorganized doc directory
|
103
|
+
|
104
|
+
== Version 0.2.2, October 12, 2006
|
105
|
+
|
106
|
+
* Made more "booleans" actually return <tt>true</tt> and <tt>false</tt>
|
107
|
+
rather than expressions that evaluate to <tt>true</tt> and <tt>false</tt>.
|
108
|
+
|
109
|
+
* Added TODO[link:files/TODO.html].
|
110
|
+
|
111
|
+
* Some documentation updates.
|
112
|
+
|
113
|
+
== Version 0.2.1, October 10, 2006
|
114
|
+
|
115
|
+
* Changed module name and namespace from UcbLdap to UCB::LDAP.
|
116
|
+
* Fixed so UCB::LDAP::Entry and subclasses can be marshalled,
|
117
|
+
otherwise can't store in a Rails session.
|
118
|
+
|
119
|
+
== Version 0.2.0, October 9, 2006
|
120
|
+
|
121
|
+
* Packaged as a Ruby Gem.
|
122
|
+
* Converted underlying code to use Net::LDAP instead of LDAP.
|
123
|
+
* Added support for searching the org unit tree.
|
124
|
+
|
125
|
+
== Version 0.1.0, October 5, 2006
|
126
|
+
|
127
|
+
* Initial release.
|
data/Manifest
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
CHANGELOG
|
2
|
+
Manifest
|
3
|
+
README
|
4
|
+
Rakefile
|
5
|
+
TODO
|
6
|
+
init.rb
|
7
|
+
lib/person/adv_con_person.rb
|
8
|
+
lib/person/affiliation_methods.rb
|
9
|
+
lib/person/generic_attributes.rb
|
10
|
+
lib/ucb_ldap.rb
|
11
|
+
lib/ucb_ldap_address.rb
|
12
|
+
lib/ucb_ldap_affiliation.rb
|
13
|
+
lib/ucb_ldap_entry.rb
|
14
|
+
lib/ucb_ldap_exceptions.rb
|
15
|
+
lib/ucb_ldap_namespace.rb
|
16
|
+
lib/ucb_ldap_org.rb
|
17
|
+
lib/ucb_ldap_person.rb
|
18
|
+
lib/ucb_ldap_person_job_appointment.rb
|
19
|
+
lib/ucb_ldap_schema.rb
|
20
|
+
lib/ucb_ldap_schema_attribute.rb
|
21
|
+
lib/ucb_ldap_service.rb
|
22
|
+
lib/ucb_ldap_student_term.rb
|
23
|
+
lib/ucb_simple_ldap_entry.rb
|
24
|
+
schema/schema.yml
|
25
|
+
version.yml
|
data/README
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
=UC Berkeley LDAP
|
2
|
+
|
3
|
+
UCB::LDAP is a wrapper module around Net::LDAP intended to simplify searching the UC Berkeley
|
4
|
+
LDAP directory: http://directory.berkeley.edu
|
5
|
+
|
6
|
+
==Introduction to LDAP
|
7
|
+
If you are blissfully ignorant of LDAP, you should familiarize yourself with some of the basics.
|
8
|
+
Here is a great online resource: http://www.zytrax.com/books/ldap.
|
9
|
+
|
10
|
+
The RDoc for the ruby-net-ldap Gem (http://rubyfurnace.com/docs/ruby-net-ldap-0.0.4/classes/Net/LDAP.html) also has a good introduction to LDAP.
|
11
|
+
|
12
|
+
|
13
|
+
==Examples
|
14
|
+
|
15
|
+
===General Search
|
16
|
+
|
17
|
+
Search the directory specifying tree base and
|
18
|
+
filter, getting back generic UCB::LDAP::Entry instances:
|
19
|
+
|
20
|
+
entries = UCB::LDAP.search(:base => "ou=people,dc=berkeley,dc=edu", :filter => {:uid => 123}
|
21
|
+
|
22
|
+
entry.uid #=> '123'
|
23
|
+
entry.givenname #=> 'John'
|
24
|
+
entry.sn #=> 'Doe'
|
25
|
+
|
26
|
+
See UCB::LDAP::Entry for more information.
|
27
|
+
|
28
|
+
===Person Search
|
29
|
+
|
30
|
+
Search the Person tree getting back UCB::LDAP::Person instances:
|
31
|
+
|
32
|
+
person = UCB::LDAP::Person.person_by_uid "123"
|
33
|
+
|
34
|
+
person.firstname #=> "John"
|
35
|
+
person.affiliations #=> ['EMPLOYEE-TYPE-STAFF']
|
36
|
+
person.employee? #=> true
|
37
|
+
person.employee_staff? #=> true
|
38
|
+
person.employee_academic? #=> false
|
39
|
+
person.student? #=> false
|
40
|
+
|
41
|
+
See UCB::LDAP::Person for more information.
|
42
|
+
|
43
|
+
===Org Unit Search
|
44
|
+
|
45
|
+
Search the Org Unit tree getting back UCB::LDAP::Org instances:
|
46
|
+
|
47
|
+
dept = UCB::LDAP::Org.org_by_ou 'jkasd'
|
48
|
+
|
49
|
+
dept.deptid #=> "JKASD"
|
50
|
+
dept.name #=> "Administrative Systems Dept"
|
51
|
+
|
52
|
+
See UCB::LDAP::Org for more information.
|
53
|
+
|
54
|
+
===Privileged Binds
|
55
|
+
|
56
|
+
If you want access the directory anonomously, no credentials are required.
|
57
|
+
If you want to access via a privileged bind, authenticate before querying:
|
58
|
+
|
59
|
+
p = UCB::LDAP::Person.person_by_uid("123")
|
60
|
+
p.non_public_attr #=> NoMethodError
|
61
|
+
|
62
|
+
UCB::LDAP.authenticate("mybind", "mypassword")
|
63
|
+
p = UCB::LDAP::Person.person_by_uid("123")
|
64
|
+
p.non_public_attr #=> "some value"
|
65
|
+
|
66
|
+
=== Privileged Binds and Rails
|
67
|
+
|
68
|
+
See UCB::LDAP.bind_for_rails()
|
69
|
+
|
70
|
+
==Dependencies
|
71
|
+
|
72
|
+
* Net::LDAP
|
73
|
+
* Ruby 1.8.2 or better
|
74
|
+
|
75
|
+
==Authors
|
76
|
+
|
77
|
+
Steven Hansen runner@berkeley.edu
|
78
|
+
Lucas Rockwell
|
79
|
+
Steve Downey
|
80
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'echoe'
|
4
|
+
require 'hanna/rdoctask'
|
5
|
+
|
6
|
+
Echoe.new('ucb_ldap', '1.3.0') do |p|
|
7
|
+
p.description = "Convenience classes for interacing with UCB's LDAP directory"
|
8
|
+
p.url = "http://ucbrb.rubyforge.org/ucb_ldap"
|
9
|
+
p.author = "Steven Hansen, Steve Downey, Lucas Rockwell"
|
10
|
+
p.email = "runner@berkeley.edu"
|
11
|
+
p.ignore_pattern = ["svn_user.yml", "tasks/ucb_ldap.rake", "spec/**/**", "test/**/**"]
|
12
|
+
p.project = "ucbrb"
|
13
|
+
p.runtime_dependencies = ["ruby-net-ldap", ">= 0.0.4"]
|
14
|
+
p.rdoc_options = "-o doc --inline-source -T hanna lib/*.rb"
|
15
|
+
p.rdoc_pattern = ["README", "lib/**/**"]
|
16
|
+
end
|
17
|
+
|
18
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'ucb_ldap'
|
File without changes
|
@@ -0,0 +1,212 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module UCB::LDAP
|
4
|
+
module AffiliationMethods
|
5
|
+
|
6
|
+
# Returns an <tt>Array</tt> of Person's affiliations.
|
7
|
+
def affiliations
|
8
|
+
@affiliations ||= berkeleyEduAffiliations.map { |a| a.upcase }
|
9
|
+
end
|
10
|
+
|
11
|
+
# Returns <tt>true</tt> if entry's affiliations contain _affiliation_.
|
12
|
+
#
|
13
|
+
# Case-insensitive.
|
14
|
+
def has_affiliation?(affiliation)
|
15
|
+
affiliations.include?(affiliation.upcase)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns <tt>true</tt> if Person's affiliations contain at least one affiliation of a particular type.
|
19
|
+
#
|
20
|
+
# p = Person.find_by_uid ...
|
21
|
+
# p.affiliations #=> ['EMPLOYEE-TYPE-STAFF']
|
22
|
+
# p.has_affiliation_of_type?(:employee) #=> true
|
23
|
+
# p.has_affiliation_of_type?(:student) #=> false
|
24
|
+
def has_affiliation_of_type?(affiliation_type)
|
25
|
+
aff_type_string = affiliation_type.to_s.upcase
|
26
|
+
affiliations.find{|a| a =~ /^#{aff_type_string}-TYPE-/} ? true : false
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
############################################
|
31
|
+
# Determine if the person is an EMPLOYEE #
|
32
|
+
############################################
|
33
|
+
|
34
|
+
# Returns <tt>true</tt> if entry has the "staff" affiliation.
|
35
|
+
def employee_staff?
|
36
|
+
has_affiliation? 'EMPLOYEE-TYPE-STAFF'
|
37
|
+
end
|
38
|
+
|
39
|
+
def employee_academic?
|
40
|
+
has_affiliation? 'EMPLOYEE-TYPE-ACADEMIC'
|
41
|
+
end
|
42
|
+
|
43
|
+
def employee_expired?
|
44
|
+
has_affiliation? 'EMPLOYEE-STATUS-EXPIRED'
|
45
|
+
end
|
46
|
+
|
47
|
+
def employee_expiration_date
|
48
|
+
Date.parse(berkeleyEduEmpExpDate.to_s)
|
49
|
+
end
|
50
|
+
|
51
|
+
def employee?
|
52
|
+
has_affiliation_of_type?(:employee) && !employee_expired?
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
##########################################
|
57
|
+
# Determine if the person is a STUDENT #
|
58
|
+
##########################################
|
59
|
+
|
60
|
+
# Returns +true+ if is an expired student.
|
61
|
+
def student_expired?
|
62
|
+
has_affiliation? 'STUDENT-STATUS-EXPIRED'
|
63
|
+
end
|
64
|
+
|
65
|
+
def student_expiration_date
|
66
|
+
Date.parse(berkeleyEduStuExpDate.to_s)
|
67
|
+
end
|
68
|
+
|
69
|
+
def student_registered?
|
70
|
+
has_affiliation? 'STUDENT-TYPE-REGISTERED'
|
71
|
+
end
|
72
|
+
|
73
|
+
def student_not_registered?
|
74
|
+
has_affiliation? 'STUDENT-TYPE-NOT REGISTERED'
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns <tt>true</tt> if entry has a studend affiliation and
|
78
|
+
# is not expired.
|
79
|
+
def student?
|
80
|
+
has_affiliation_of_type?(:student) && !student_expired?
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
##############################################
|
85
|
+
# Determine if the persone is an AFFILIATE #
|
86
|
+
##############################################
|
87
|
+
|
88
|
+
def affiliate_aws_only?
|
89
|
+
has_affiliation? 'AFFILIATE-TYPE-AWS ONLY'
|
90
|
+
end
|
91
|
+
|
92
|
+
def affiliate_staff_retiree?
|
93
|
+
has_affiliation? 'AFFILIATE-TYPE-STAFF RETIREE'
|
94
|
+
end
|
95
|
+
|
96
|
+
def affiliate_emeritus?
|
97
|
+
has_affiliation? 'AFFILIATE-TYPE-EMERITUS'
|
98
|
+
end
|
99
|
+
|
100
|
+
def affiliate_directory_only?
|
101
|
+
has_affiliation? 'AFFILIATE-TYPE-DIRECTORY ONLY'
|
102
|
+
end
|
103
|
+
|
104
|
+
# Note: there are actually 2 types of visting affiliaties, visiting student and
|
105
|
+
# visiting scholars. But for now we will generalize.
|
106
|
+
def affiliate_visiting?
|
107
|
+
has_affiliation? 'AFFILIATE-TYPE-VISITING'
|
108
|
+
end
|
109
|
+
|
110
|
+
def affiliate_contractor?
|
111
|
+
has_affiliation? 'AFFILIATE-TYPE-CONTRACTOR'
|
112
|
+
end
|
113
|
+
|
114
|
+
def affiliate_lbl_doe_postdoc?
|
115
|
+
has_affiliation? 'AFFILIATE-TYPE-LBL/DOE POSTDOC'
|
116
|
+
end
|
117
|
+
|
118
|
+
def affiliate_lbl_op_staff?
|
119
|
+
has_affiliation? 'AFFILIATE-TYPE-LBLOP STAFF'
|
120
|
+
end
|
121
|
+
|
122
|
+
def affiliate_committee_member?
|
123
|
+
has_affiliation? 'AFFILIATE-TYPE-COMMITTEE MEMBER'
|
124
|
+
end
|
125
|
+
|
126
|
+
def affiliate_consultant?
|
127
|
+
has_affiliation? 'AFFILIATE-TYPE-CONSULTANT'
|
128
|
+
end
|
129
|
+
|
130
|
+
def affiliate_volunteer?
|
131
|
+
has_affiliation? 'AFFILIATE-TYPE-VOLUNTEER'
|
132
|
+
end
|
133
|
+
|
134
|
+
def affiliate_hhmi_researcher?
|
135
|
+
has_affiliation? 'AFFILIATE-TYPE-HHMI RESEARCHER'
|
136
|
+
end
|
137
|
+
|
138
|
+
def affiliate_concurrent_enrollment?
|
139
|
+
has_affiliation? 'AFFILIATE-TYPE-CONCURR ENROLL'
|
140
|
+
end
|
141
|
+
|
142
|
+
def affiliate_temp_agency?
|
143
|
+
has_affiliation? 'AFFILIATE-TYPE-TEMP AGENCY'
|
144
|
+
end
|
145
|
+
|
146
|
+
def affiliate_departmental?
|
147
|
+
has_affiliation? 'AFFILIATE-TYPE-DEPARTMENTAL'
|
148
|
+
end
|
149
|
+
|
150
|
+
def affiliate_test?
|
151
|
+
has_affiliation? 'AFFILIATE-TYPE-TEST'
|
152
|
+
end
|
153
|
+
|
154
|
+
def affiliate_staff_affiliate?
|
155
|
+
has_affiliation? 'AFFILIATE-TYPE-STAFF-AFFILIATE'
|
156
|
+
end
|
157
|
+
|
158
|
+
def affiliate_academic_case_tracking?
|
159
|
+
has_affiliation? 'AFFILIATE-TYPE-ACADEMIC CASE TRACKING'
|
160
|
+
end
|
161
|
+
|
162
|
+
def affiliate_maintenance?
|
163
|
+
has_affiliation? 'AFFILIATE-TYPE-MAINTENANCE'
|
164
|
+
end
|
165
|
+
|
166
|
+
def affiliate_billing_only?
|
167
|
+
has_affiliation? 'AFFILIATE-TYPE-BILLING ONLY'
|
168
|
+
end
|
169
|
+
|
170
|
+
def affiliate_advcon_trustee?
|
171
|
+
has_affiliation? 'AFFILIATE-TYPE-ADVCON-TRUSTEE'
|
172
|
+
end
|
173
|
+
|
174
|
+
def affiliate_advcon_friend?
|
175
|
+
has_affiliation? 'AFFILIATE-TYPE-ADVCON-FRIEND'
|
176
|
+
end
|
177
|
+
|
178
|
+
def affiliate_advcon_alumnus?
|
179
|
+
has_affiliation? 'AFFILIATE-TYPE-ADVCON-ALUMNUS'
|
180
|
+
end
|
181
|
+
|
182
|
+
def affiliate_advcon_caa_member?
|
183
|
+
has_affiliation? 'AFFILIATE-TYPE-ADVCON-CAA-MEMBER'
|
184
|
+
end
|
185
|
+
|
186
|
+
def affiliate_advcon_i_house_resident?
|
187
|
+
has_affiliation? 'AFFILIATE-TYPE-ADVCON-I-HOUSE-RESIDENT'
|
188
|
+
end
|
189
|
+
|
190
|
+
def affiliate_advcon_student?
|
191
|
+
has_affiliation? 'AFFILIATE-TYPE-ADVCON-STUDENT'
|
192
|
+
end
|
193
|
+
|
194
|
+
def affiliate_advcon_attendee?
|
195
|
+
has_affiliation? 'AFFILIATE-TYPE-ADVCON-ATTENDEE'
|
196
|
+
end
|
197
|
+
|
198
|
+
def affiliate_expired?
|
199
|
+
has_affiliation? 'AFFILIATE-STATUS-EXPIRED'
|
200
|
+
end
|
201
|
+
|
202
|
+
def affiliate?
|
203
|
+
has_affiliation_of_type?(:affiliate) && !affiliate_expired?
|
204
|
+
end
|
205
|
+
|
206
|
+
def affiliate_expiration_date
|
207
|
+
Date.parse(berkeleyEduAffExpDate.to_s)
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|