lusi_api 0.1.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +58 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +235 -0
- data/Rakefile +8 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/lusi_api.rb +5 -0
- data/lib/lusi_api/calendar.rb +234 -0
- data/lib/lusi_api/core/api.rb +190 -0
- data/lib/lusi_api/core/code.rb +101 -0
- data/lib/lusi_api/core/exceptions.rb +47 -0
- data/lib/lusi_api/core/lookup.rb +612 -0
- data/lib/lusi_api/core/util.rb +102 -0
- data/lib/lusi_api/core/xml.rb +168 -0
- data/lib/lusi_api/country.rb +111 -0
- data/lib/lusi_api/course.rb +1300 -0
- data/lib/lusi_api/enrolment.rb +247 -0
- data/lib/lusi_api/organisation.rb +291 -0
- data/lib/lusi_api/person/staff.rb +115 -0
- data/lib/lusi_api/person/student.rb +551 -0
- data/lib/lusi_api/service_account.rb +121 -0
- data/lib/lusi_api/service_method.rb +52 -0
- data/lib/lusi_api/version.rb +5 -0
- data/lib/lusi_api/vle.rb +329 -0
- data/lusi_api.gemspec +36 -0
- metadata +182 -0
@@ -0,0 +1,247 @@
|
|
1
|
+
require 'lusi_api/core/api'
|
2
|
+
require 'lusi_api/core/code'
|
3
|
+
require 'lusi_api/core/xml'
|
4
|
+
|
5
|
+
|
6
|
+
module LUSI
|
7
|
+
module API
|
8
|
+
module Enrolment
|
9
|
+
|
10
|
+
# Represents an enrolment role in the LUSI API
|
11
|
+
class EnrolmentRole < LUSI::API::Core::Code
|
12
|
+
|
13
|
+
# @!attribute [rw] vle_role_description
|
14
|
+
# @return [String, nil] the VLE role description a member has against this enrolment
|
15
|
+
attr_accessor :vle_role_description
|
16
|
+
|
17
|
+
# Initialises a new EnrolmentRole instance
|
18
|
+
# @param (see LUSI::API::Core::Code#initialize)
|
19
|
+
# @param vle_role_description [String, nil] the default VLE role description
|
20
|
+
# @return [void]
|
21
|
+
def initialize(xml = nil, lookup = nil, vle_role_description: nil, **kwargs)
|
22
|
+
super(xml, lookup, **kwargs)
|
23
|
+
@vle_role_description = LUSI::API::Core::XML.xml_content_at(xml, 'xmlns:VLERoleDescription',
|
24
|
+
vle_role_description)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
# The abstract base class for enrolment classes
|
31
|
+
# @abstract Subclasses must define the lusi_ws_* endpoint methods and additional attributes
|
32
|
+
class EnrolmentBase
|
33
|
+
|
34
|
+
extend LUSI::API::Core::Endpoint
|
35
|
+
|
36
|
+
# @!attribute [rw] enrolment_role
|
37
|
+
# @return [LUSI::API::Enrolment::EnrolmentRole, nil] the role that members have against this enrolment
|
38
|
+
attr_accessor :enrolment_role
|
39
|
+
|
40
|
+
# @!attribute [rw] identity
|
41
|
+
# @return [LUSI::API::Enrolment::EnrolmentIdentity] the identity of the subject (person) of the enrolment
|
42
|
+
attr_accessor :identity
|
43
|
+
|
44
|
+
# @!attribute [rw] is_current_enrolment
|
45
|
+
# @return [Boolean, nil] true if the enrolment is current, false otherwise
|
46
|
+
attr_accessor :is_current_enrolment
|
47
|
+
|
48
|
+
# @!attribute [rw] is_current_identity
|
49
|
+
# @return [Boolean, nil] true if the member's identity is current, false otherwise
|
50
|
+
attr_accessor :is_current_identity
|
51
|
+
|
52
|
+
# @!attribute [rw] username
|
53
|
+
# @return [String, nil] the username of the subject (person) of the enrolment
|
54
|
+
attr_accessor :username
|
55
|
+
|
56
|
+
# Initalises a new Enrolment instance
|
57
|
+
# @param xml [Nokogiri::XML::Document, Nokogiri::XML::Node] the parsed XML root of the enrolment
|
58
|
+
# @param lookup [LUSI::API::Core::Lookup::LookupService, nil] the lookup service for object resolution
|
59
|
+
# @param enrolment_role [LUSI::API::Enrolment::EnrolmentRole, nil] the default enrolment role
|
60
|
+
# @param identity [String, nil] the default user identity code
|
61
|
+
# @param is_current_enrolment [Boolean, nil] the default current enrolment flag
|
62
|
+
# @param is_current_identity [Boolean, nil] the default current identity flag
|
63
|
+
# @param username [String, nil] the default username
|
64
|
+
# @return [void]
|
65
|
+
def initialize(xml = nil, lookup = nil, enrolment_role: nil, identity: nil, is_current_enrolment: nil,
|
66
|
+
is_current_identity: nil, username: nil)
|
67
|
+
is_current_enrolment = is_current_enrolment.nil? || is_current_enrolment ? true : false
|
68
|
+
is_current_identity = is_current_identity.nil? || is_current_identity ? true : false
|
69
|
+
@enrolment_role = EnrolmentRole.new(LUSI::API::Core::XML.xml_at(xml, 'xmlns:EnrolmentRole', enrolment_role),
|
70
|
+
lookup)
|
71
|
+
@identity = LUSI::API::Core::XML.xml_content_at(xml, 'xmlns:Identity', identity)
|
72
|
+
@is_current_enrolment = LUSI::API::Core::XML.xml_boolean_at(xml, 'xmlns:IsCurrentEnrolment',
|
73
|
+
is_current_enrolment)
|
74
|
+
@is_current_identity = LUSI::API::Core::XML.xml_boolean_at(xml, 'xmlns:IsCurrentIdentity',
|
75
|
+
is_current_identity)
|
76
|
+
@username = LUSI::API::Core::XML.xml_content_at(xml, 'xmlns:Username', username)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns an array of instances matching the specified search criteria
|
80
|
+
# @param api [LUSI::API::Core::API] the LUSI API instance to use for searching
|
81
|
+
# @param lookup [LUSI::API::Core::Lookup::LookupService, nil] the lookup service for object resolution
|
82
|
+
# @param (see #get_instance_params)
|
83
|
+
# @yield [obj] Passes the instance to the block
|
84
|
+
def self.get_instance(api, lookup = nil, current_only: nil, **kwargs)
|
85
|
+
current_only = current_only.nil? || current_only ? true : false
|
86
|
+
if current_only
|
87
|
+
# Filter nodes which have current enrolments and user identities
|
88
|
+
filter = Proc.new do |node|
|
89
|
+
LUSI::API::Core::XML.xml_boolean_at(node, 'xmlns:IsCurrentEnrolment', false) &&
|
90
|
+
LUSI::API::Core::XML.xml_boolean_at(node, 'xmlns:IsCurrentIdentity', false)
|
91
|
+
end
|
92
|
+
else
|
93
|
+
filter = nil
|
94
|
+
end
|
95
|
+
params = self.get_instance_params(**kwargs)
|
96
|
+
xml = api.call(self.lusi_ws_path, self.lusi_ws_endpoint, self.lusi_ws_method, **params)
|
97
|
+
result = LUSI::API::Core::XML.xml(xml, "xmlns:#{self.lusi_ws_xml_root}", filter: filter) do |m|
|
98
|
+
obj = self.new(m, lookup)
|
99
|
+
yield(obj) if block_given?
|
100
|
+
obj
|
101
|
+
end
|
102
|
+
# Return the array of instances
|
103
|
+
result
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns the lookup indices supported by this enrolment type
|
107
|
+
# @return [Array<Symbol>] the supported lookup indices
|
108
|
+
def lookup_indices
|
109
|
+
[:identity, :role, :username]
|
110
|
+
end
|
111
|
+
|
112
|
+
# Returns the value to be used as a key for the specified lookup index
|
113
|
+
# @return [Object] the key value
|
114
|
+
def lookup_key(index = nil)
|
115
|
+
case index
|
116
|
+
when :identity
|
117
|
+
self.identity
|
118
|
+
when :role
|
119
|
+
self.enrolment_role ? self.enrolment_role.identity : nil
|
120
|
+
when :username
|
121
|
+
self.username
|
122
|
+
else
|
123
|
+
nil
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# @see (LUSI::API::Core::Endpoint#lusi_ws_path)
|
128
|
+
def self.lusi_ws_path
|
129
|
+
'UserDetails'
|
130
|
+
end
|
131
|
+
|
132
|
+
protected
|
133
|
+
|
134
|
+
# Returns a hash of parameters for the LUSI API call. Subclasses may extend or override this method.
|
135
|
+
# @param active_vle_space_only [Boolean, nil] if true, restrict results to active VLE spaces only
|
136
|
+
# @param asp_identity [String, nil] return instances matching the academically significant period (ASP) identity
|
137
|
+
# @param cohort_identity [String, nil] return instances matching the cohort identity
|
138
|
+
# @param course_identity [String, nil] return instances matching the course identity
|
139
|
+
# @param current_student_only [Boolean, nil] if true, restrict results to current students only
|
140
|
+
# @param department_identity [String, nil] return instances matching the department identity
|
141
|
+
# @param require_username [Boolean, nil] if true, include the student username, ignore students with no username
|
142
|
+
# @param year_identity (String, nil) return instances matching the year identity
|
143
|
+
# @return [Hash<String, String>] the parameters for the LUSI API call
|
144
|
+
def self.get_instance_params(**kwargs)
|
145
|
+
result = {
|
146
|
+
ActiveVLESpaceOnly: kwargs.fetch(:active_vle_space_only, true) ? 'true' : 'false',
|
147
|
+
ASPIdentity: kwargs.fetch(:asp_identity, ''),
|
148
|
+
CohortIdentity: kwargs.fetch(:cohort_identity, ''),
|
149
|
+
CourseIdentity: kwargs.fetch(:course_identity, ''),
|
150
|
+
DepartmentIdentity: kwargs.fetch(:department_identity, ''),
|
151
|
+
RequireUsername: kwargs.fetch(:require_username, true) ? 'true' : 'false',
|
152
|
+
YearIdentity: kwargs.fetch(:year_identity, '')
|
153
|
+
}
|
154
|
+
if self.lusi_ws_endpoint == 'Student.asmx'
|
155
|
+
result[:CurrentStudentOnly] = kwargs.fetch(:current_student_only, true) ? 'true' : 'false'
|
156
|
+
end
|
157
|
+
result
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
class EnrolmentLookup
|
164
|
+
|
165
|
+
# Initialises a new EnrolmentLookup instance
|
166
|
+
def initialize(enrolments = nil, *indices, &block)
|
167
|
+
@default_proc = block
|
168
|
+
@indices = {}
|
169
|
+
enrolments.each { |e| add(e, *indices) }
|
170
|
+
end
|
171
|
+
|
172
|
+
# @see (LUSI::API::Enrolment::EnrolmentLookup#fetch)
|
173
|
+
def [](key, *indices)
|
174
|
+
fetch(key, *indices)
|
175
|
+
end
|
176
|
+
|
177
|
+
# Adds an enrolment to specified indices (default is all indices if unspecified)
|
178
|
+
# @param enrolment [LUSI::API::Enrolment::EnrolmentBase] the enrolment to add
|
179
|
+
# Reminaing positional parameters specify the indices to update
|
180
|
+
# @return [void]
|
181
|
+
def add(enrolment = nil, *indices)
|
182
|
+
indices = enrolment.lookup_indices if indices.nil? || indices.empty?
|
183
|
+
indices.each { |index| add_enrolment(enrolment, index) }
|
184
|
+
nil
|
185
|
+
end
|
186
|
+
|
187
|
+
# Searches the specified indices for the lookup key and returns the first match
|
188
|
+
# @param key [Object] the lookup key. If the key defines method #enrolment_lookup_keys, this method determines
|
189
|
+
# which keys are searched for.
|
190
|
+
# Remaining positional parameters specify the indices to search. If no indices are specified, but the key
|
191
|
+
# instance defines method #enrolment_lookup_indices, this method determines which indices are searched.
|
192
|
+
# @return [Array<LUSI::API::Enrolment::EnrolmentBase>, nil] the enrolments corresponding to key, or nil
|
193
|
+
# if match was found
|
194
|
+
def fetch(key = nil, *indices)
|
195
|
+
|
196
|
+
# If no index is specified, infer it from the key type if possible
|
197
|
+
if indices.nil? || indices.empty?
|
198
|
+
indices = key.respond_to?(:enrolment_lookup_indices) ? key.enrolment_lookup_indices : nil
|
199
|
+
end
|
200
|
+
return nil if indices.nil? || indices.empty?
|
201
|
+
|
202
|
+
# Use the lookup keys specified by the key instance if possible, otherwise use the literal key value
|
203
|
+
keys = key.respond_to?(:enrolment_lookup_keys) ? key.enrolment_lookup_keys : [key]
|
204
|
+
|
205
|
+
# Search the specified indices until a match is found, then return matches for all key values from this index
|
206
|
+
unless keys.nil? || keys.empty?
|
207
|
+
result = []
|
208
|
+
indices.each do |index|
|
209
|
+
i = @indices[index]
|
210
|
+
if i
|
211
|
+
keys.each { |key| result += i[key] || [] }
|
212
|
+
end
|
213
|
+
return result unless result.empty?
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
# If we get here, the search failed in all indices - call the default_proc if available, otherwise return nil
|
218
|
+
@default_proc ? @default_proc.call(key) : nil
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
protected
|
223
|
+
|
224
|
+
# Adds an enrolment to the specified index
|
225
|
+
# @param enrolment [LUSI::API::Enrolment::EnrolmentBase] the enrolment
|
226
|
+
# @param index [Symbol] the index to be updated
|
227
|
+
def add_enrolment(enrolment, index)
|
228
|
+
# Get the specified index hash
|
229
|
+
@indices[index] = {} unless @indices.include?(index)
|
230
|
+
hash = @indices[index]
|
231
|
+
# Add the enrolment to the list
|
232
|
+
key = enrolment.lookup_key(index)
|
233
|
+
if hash.include?(key)
|
234
|
+
hash[key].push(enrolment)
|
235
|
+
else
|
236
|
+
hash[key] = [enrolment]
|
237
|
+
end
|
238
|
+
# Return the list containing the enrolment
|
239
|
+
hash[key]
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
@@ -0,0 +1,291 @@
|
|
1
|
+
require 'lusi_api/core/xml'
|
2
|
+
|
3
|
+
|
4
|
+
module LUSI
|
5
|
+
module API
|
6
|
+
|
7
|
+
# Classes representation organisation structure
|
8
|
+
module Organisation
|
9
|
+
|
10
|
+
# Represents an organisation as a hierarchy of Units.
|
11
|
+
#
|
12
|
+
# The position in the hierarchy is defined by the Unit.type attribute.
|
13
|
+
#
|
14
|
+
# For each hierarchy level (Unit type) the Organisation maintains three indices, identified as follows:
|
15
|
+
# :identity allows retrieval by the Unit.identity attribute
|
16
|
+
# :mnemonic allows retrieval by the Unit.mnemonic attribute
|
17
|
+
# :title allows retrieval by the Unit.title attribute
|
18
|
+
#
|
19
|
+
# Once an instance is created, it should be populated by calling the #load method
|
20
|
+
# @example Populating an Organisation instance
|
21
|
+
# api = LUSI::API::Core::API.new(...)
|
22
|
+
# org = LUSI::API::Organisation::Organisation.new
|
23
|
+
# begin
|
24
|
+
# org.load(api, in_use_only: false)
|
25
|
+
# rescue LUSI::API::Core::APIError => e
|
26
|
+
# # API error handling
|
27
|
+
# end
|
28
|
+
class Organisation
|
29
|
+
|
30
|
+
# Defines the organisation hierarchy as a mapping from unit type to its child unit type and corresponding XPath.
|
31
|
+
# A leaf unit with no children maps to nil. The reserved unit type "_root" defines the root of the hierarchy.
|
32
|
+
HIERARCHY = {
|
33
|
+
_root: { type: :institution, path: '//xmlns:Institution' },
|
34
|
+
institution: { type: :faculty, path: 'xmlns:Faculties/xmlns:Faculty' },
|
35
|
+
faculty: { type: :department, path: 'xmlns:Departments/xmlns:Department' },
|
36
|
+
department: nil
|
37
|
+
}
|
38
|
+
|
39
|
+
# Initialises a new Organisation instance
|
40
|
+
# @param api [LUSI::API::Core::API, nil] an optional LUSI API instance used to retrieve data
|
41
|
+
# @param lookup [LUSI::API::Core::Lookup::LookupService, nil] the lookup service for object resolution
|
42
|
+
# @return [void]
|
43
|
+
def initialize(api = nil, lookup = nil)
|
44
|
+
@api = api
|
45
|
+
clear
|
46
|
+
end
|
47
|
+
|
48
|
+
# Searches the organisation top-down for the specified identity code and returns the first matching Unit
|
49
|
+
# @param identity [any] the identity code
|
50
|
+
# @return [Unit, nil] the matching Unit instance, or nil if no match is found
|
51
|
+
def [](identity = nil)
|
52
|
+
key = self.class.key(identity)
|
53
|
+
type = HIERARCHY[:_root][:type]
|
54
|
+
until type.nil? do
|
55
|
+
if @indices[type]
|
56
|
+
unit = @indices[type][:identity][key]
|
57
|
+
return unit if unit
|
58
|
+
end
|
59
|
+
type = HIERARCHY[type] ? HIERARCHY[type][:type] : nil
|
60
|
+
end
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
|
64
|
+
# Adds a new Unit to the Organisation
|
65
|
+
# Child units are recursively added
|
66
|
+
# @param unit [LUSI::API::Organisation::Unit] the Unit instance
|
67
|
+
# @return void
|
68
|
+
def add(unit)
|
69
|
+
|
70
|
+
# Require a Unit instance
|
71
|
+
return unless unit.is_a?(Unit)
|
72
|
+
|
73
|
+
# Initialise the indices for this Unit type if required
|
74
|
+
@indices[unit.type] = { identity: {}, mnemonic: {}, title: {} } unless @indices.include?(unit.type)
|
75
|
+
|
76
|
+
# Index the unit
|
77
|
+
hash = @indices[unit.type]
|
78
|
+
hash[:identity][self.class.key(unit.identity)] = unit
|
79
|
+
hash[:mnemonic][self.class.key(unit.mnemonic)] = unit
|
80
|
+
hash[:title][self.class.key(unit.title)] = unit
|
81
|
+
|
82
|
+
# Index the unit's child units
|
83
|
+
unit.children.each { |child| add(child) } if unit.children
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
# Clears the organisation structure
|
88
|
+
# @return [void]
|
89
|
+
def clear
|
90
|
+
@indices = {}
|
91
|
+
end
|
92
|
+
|
93
|
+
# Iterates over selected parts of the organisation hierarchy
|
94
|
+
# @param type [Symbol, nil] the Unit type to iterate over
|
95
|
+
# @param index [Symbol, nil] the Unit type's index to iterate over (:identity | :mnemonic | :title)
|
96
|
+
# @return [void]
|
97
|
+
# @yield Passes a Unit instance to the block
|
98
|
+
# @yieldparam unit [LUSI::API::Organisation::Unit] the current unit of the iterator
|
99
|
+
def each(type = nil, index = nil, &block)
|
100
|
+
if type
|
101
|
+
# Iterate over the selected type; ignore invalid types
|
102
|
+
hash = @indices[type]
|
103
|
+
if hash
|
104
|
+
hash_index = hash.include?(index) ? index : :identity
|
105
|
+
hash[hash_index].each_value(&block) if hash[hash_index]
|
106
|
+
end
|
107
|
+
else
|
108
|
+
# Iterate over all types
|
109
|
+
@indices.each_value do |type|
|
110
|
+
hash_index = type.include?(index) ? index : :identity
|
111
|
+
type[hash_index].each_value(&block) if type[hash_index]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Iterates over each unit type in the organisation hierarchy starting from the root
|
117
|
+
# @return [void]
|
118
|
+
# @yield [unit_type] Passes the unit type to the block
|
119
|
+
# @yieldparam unit_type [Symbol] the current unit type of the iterator
|
120
|
+
def each_unit_type
|
121
|
+
unit_type = HIERARCHY[:_root][:type]
|
122
|
+
while unit_type
|
123
|
+
yield(unit_type)
|
124
|
+
unit_type = HIERARCHY[unit_type] ? HIERARCHY[unit_type][:type] : nil
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Indicates whether the organisation is empty (contains units) or not
|
129
|
+
# @return [Boolean] true if the organisation contains no units, otherwise false
|
130
|
+
def empty?
|
131
|
+
# If @indices is not empty, use the #length method to determine emptiness
|
132
|
+
@indices.nil? || @indices.empty? || length == 0
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns the Unit instance matching the given parameters
|
136
|
+
# Key values are case-insensitive and normalised by removing leading, trailing and redundant whitespace.
|
137
|
+
# Title matching is based on the exact title after key normalisation.
|
138
|
+
# @param key [any] the Unit attribute value to search for
|
139
|
+
# @param type [Symbol, nil] the Unit type to search for (defaults to the root type of the organisation hierarchy)
|
140
|
+
# @param index [Symbol, nil] the Unit index to search (:identity, :mnemonic, :title)
|
141
|
+
# @return [Unit, nil] the matching Unit instance, or nil if no matches are found
|
142
|
+
def get(key, type = nil, index: nil)
|
143
|
+
hash = @indices[type] || @indices[HIERARCHY[:_root][:type]]
|
144
|
+
if hash
|
145
|
+
index = :identity unless hash.include?(index)
|
146
|
+
hash[index][self.class.key(key)]
|
147
|
+
else
|
148
|
+
nil
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Returns the number of Units matching the given parameters
|
153
|
+
# @param type [Symbol, nil] the Unit type to count (defaults to all units)
|
154
|
+
# @param index [Symbol, nil] the Unit index to count (:identity, :mnemonic, :title)
|
155
|
+
# @return [Integer, nil] the number of Unit instances for the given parameters, or nil
|
156
|
+
def length(type = nil, index: nil)
|
157
|
+
count = 0
|
158
|
+
types = type.nil? ? @indices.keys : [type]
|
159
|
+
types.each do |unit_type|
|
160
|
+
hash = @indices[unit_type]
|
161
|
+
if hash
|
162
|
+
hash_index = hash.include?(index) ? hash[index] : hash[:identity]
|
163
|
+
count += hash_index.length if hash_index
|
164
|
+
end
|
165
|
+
end
|
166
|
+
count
|
167
|
+
end
|
168
|
+
|
169
|
+
# Populates the Organisation instance from the LUSI API
|
170
|
+
# @param api [LUSI::API::Core::API, nil] the LUSI API instance to use (defaults to the Organisation's @api)
|
171
|
+
# @param in_use_only [Boolean] if true, include only current Units; if false, additionally include historic Units
|
172
|
+
# @return [Nokogiri::XML::Node] the parsed XML <body/> content from the LUSI API call
|
173
|
+
def load(api = nil, in_use_only: true)
|
174
|
+
|
175
|
+
# Call the LUSI API
|
176
|
+
api ||= @api
|
177
|
+
xml = api.call('LUSIReference', 'General.asmx', 'GetOrganisationStructure', InUseOnly: in_use_only)
|
178
|
+
|
179
|
+
# Clear the existing organisation structure
|
180
|
+
clear
|
181
|
+
|
182
|
+
# Add each organisation unit to the structure
|
183
|
+
root = HIERARCHY[:_root]
|
184
|
+
LUSI::API::Core::XML.xml(xml, root[:path]) do |u|
|
185
|
+
add(Unit.new(u, type: root[:type], hierarchy: HIERARCHY))
|
186
|
+
end
|
187
|
+
|
188
|
+
# Return the parsed XML body content from the LUSI API call
|
189
|
+
xml
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
protected
|
194
|
+
|
195
|
+
# Returns a normalised index key
|
196
|
+
# Normalisation removes redundant whitespace and converts to uppercase for case-insensitivity
|
197
|
+
# @param key [any] the key value
|
198
|
+
# @return [String, nil] the normalised key value
|
199
|
+
def self.key(key)
|
200
|
+
return nil if key.nil?
|
201
|
+
key = key.to_s.strip
|
202
|
+
key.squeeze!(' ')
|
203
|
+
key.upcase!
|
204
|
+
key
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
# Represents a single unit (component) of an Organisation
|
211
|
+
class Unit
|
212
|
+
|
213
|
+
# @!attribute [rw] children
|
214
|
+
# @return [Array<Unit>, nil] an array of child Unit instances
|
215
|
+
attr_accessor :children
|
216
|
+
# @!attribute [rw] identity
|
217
|
+
# @return [any, nil] the identity code of the unit
|
218
|
+
attr_accessor :identity
|
219
|
+
# @!attribute [rw] in_use
|
220
|
+
# @return [Boolean, nil] true if the unit is currently in use, or false if historic
|
221
|
+
attr_accessor :in_use
|
222
|
+
# @!attribute [rw] is_academic
|
223
|
+
# @return [Boolean, nil] true if the unit is an academic unit, or false if not (e.g. administrative)
|
224
|
+
attr_accessor :is_academic
|
225
|
+
# @!attribute [rw] mnemonic
|
226
|
+
# @return [String, nil] a short mnemonic code for the unit
|
227
|
+
attr_accessor :mnemonic
|
228
|
+
# @!attribute [rw] parent
|
229
|
+
# @return [Unit, nil] the parent of this unit in the organisation hierarchy, or nil if this is a top-level unit
|
230
|
+
attr_accessor :parent
|
231
|
+
# @!attribute [rw] talis_code
|
232
|
+
# @return [String, nil] the code for this unit used by Talis Aspire reading lists
|
233
|
+
attr_accessor :talis_code
|
234
|
+
# @!attribute [rw] title
|
235
|
+
# @return [String, nil] the title (name) of the unit
|
236
|
+
attr_accessor :title
|
237
|
+
# @!attribute [rw] type
|
238
|
+
# @return [Symbol, nil] the type of the unit (e.g. :institution, :faculty, :department)
|
239
|
+
attr_accessor :type
|
240
|
+
|
241
|
+
# Initialises a new Unit instance
|
242
|
+
# If the hierarchy definition for the unit type specifies child units, the child unit instances are recursively
|
243
|
+
# created and added to the @children attribute.
|
244
|
+
# @param xml [Nokogiri::XML::Document, Nokogiri::XML::Node] the XML root of the unit from the LUSI API call
|
245
|
+
# @param lookup [LUSI::API::Core::Lookup::LookupService, nil] the lookup service for object resolution
|
246
|
+
# @param type [Symbol] the unit type
|
247
|
+
# @param hierarchy [Hash] the organisation's hierarchy definition
|
248
|
+
# @see LUSI::API::Organisation::Organisation::HIERARCHY
|
249
|
+
# @param parent [Unit, nil] the parent Unit of this unit, or nil for a top-level unit
|
250
|
+
# @param identity [any, nil] the default identity code
|
251
|
+
# @param in_use [Boolean, nil] the default in-use flag value
|
252
|
+
# @param is_academic [Boolean, nil] the default is-academic flag value
|
253
|
+
# @param mnemonic [any, nil] the default mnemonic code
|
254
|
+
# @param talis_code [any, nil] the default Talis code
|
255
|
+
# @param title [any, nil] the default unit title (name)
|
256
|
+
def initialize(xml = nil, lookup = nil, type: nil, hierarchy: nil, parent: nil, identity: nil, in_use: nil,
|
257
|
+
is_academic: nil, mnemonic: nil, talis_code: nil, title: nil)
|
258
|
+
|
259
|
+
@identity = LUSI::API::Core::XML.xml_content_at(xml, 'xmlns:Identity', identity)
|
260
|
+
@in_use = LUSI::API::Core::XML.xml_boolean_at(xml, 'xmlns:InUse', in_use)
|
261
|
+
@is_academic = LUSI::API::Core::XML.xml_boolean_at(xml, 'xmlns:IsAcademic', is_academic)
|
262
|
+
@mnemonic = LUSI::API::Core::XML.xml_content_at(xml, 'xmlns:Mnemonic', mnemonic)
|
263
|
+
@parent = parent
|
264
|
+
@talis_code = LUSI::API::Core::XML.xml_content_at(xml, 'xmlns:TalisCode', talis_code)
|
265
|
+
@title = LUSI::API::Core::XML.xml_content_at(xml, 'xmlns:Title', title)
|
266
|
+
@type = type
|
267
|
+
|
268
|
+
# Get the child units of this unit
|
269
|
+
# If a block is given, yield each child to the block
|
270
|
+
child = hierarchy ? hierarchy[type] : nil
|
271
|
+
if child
|
272
|
+
@children = LUSI::API::Core::XML.xml(xml, child[:path]) do |u|
|
273
|
+
Unit.new(u, lookup, type: child[:type], parent: self, hierarchy: hierarchy)
|
274
|
+
end
|
275
|
+
else
|
276
|
+
@children = nil
|
277
|
+
end
|
278
|
+
|
279
|
+
end
|
280
|
+
|
281
|
+
# Returns a string representation of the unit
|
282
|
+
def to_s
|
283
|
+
"#{@type}: #{@title}"
|
284
|
+
end
|
285
|
+
|
286
|
+
end
|
287
|
+
|
288
|
+
end
|
289
|
+
|
290
|
+
end
|
291
|
+
end
|