CollegiateLink 0.0.2
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/lib/collegiatelink.rb +46 -0
- data/lib/collegiatelink/client.rb +79 -0
- data/lib/collegiatelink/organization.rb +98 -0
- data/lib/collegiatelink/request.rb +122 -0
- data/lib/collegiatelink/response.rb +30 -0
- metadata +130 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require 'net/https'
|
3
|
+
require 'net/ssh'
|
4
|
+
require 'guid'
|
5
|
+
require 'nokogiri'
|
6
|
+
require 'happymapper'
|
7
|
+
|
8
|
+
require 'collegiatelink/response'
|
9
|
+
require 'collegiatelink/request'
|
10
|
+
require 'collegiatelink/client'
|
11
|
+
require 'collegiatelink/organization'
|
12
|
+
|
13
|
+
##
|
14
|
+
# This gem provides a CollegiateLink API client in Ruby. It's still under
|
15
|
+
# development, so let me know if you plan to use it. (tomdooner@gmail.com)
|
16
|
+
#
|
17
|
+
module CollegiateLink
|
18
|
+
# URL base for all requests. The API key will be substituted into this when
|
19
|
+
# the request is made.
|
20
|
+
URL_BASE = 'https://%s.collegiatelink.net/ws/'
|
21
|
+
|
22
|
+
# Currently-supported CollegiateLink action request types
|
23
|
+
ACTIONS = [
|
24
|
+
'organization/list',
|
25
|
+
'organization/roster',
|
26
|
+
#'user/memberships',
|
27
|
+
#'user/position',
|
28
|
+
'event/list',
|
29
|
+
]
|
30
|
+
|
31
|
+
# Raised when performing a CollegiateLink::Request for an action that is not
|
32
|
+
# supported by the gem (as defined by CollegiateLink::ACTIONS).
|
33
|
+
class UnknownAction < Exception; end
|
34
|
+
|
35
|
+
# Raised when something unexpected goes wrong.
|
36
|
+
class UnknownException < Exception; end
|
37
|
+
|
38
|
+
# Raised when the CollegiateLink::Request HTTP request fails.
|
39
|
+
class NetworkException < Exception; end
|
40
|
+
|
41
|
+
# Raised when CollegiateLink returns that the combination of IP and SSL fails.
|
42
|
+
class AuthenticationException < Exception; end
|
43
|
+
|
44
|
+
# Raised for the CollegiateLink VALIDATION_ERROR case.
|
45
|
+
class ValidationException < Exception; end
|
46
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module CollegiateLink
|
2
|
+
|
3
|
+
# The Client is what makes the requests to CollegiateLink.
|
4
|
+
class Client
|
5
|
+
##
|
6
|
+
# Creates a CollegiateLink client.
|
7
|
+
#
|
8
|
+
# ==== Parameters:
|
9
|
+
# * +apikey+ - The CollegiateLink "apikey" for your institution. For example, at Case Western Reserve University we go to http://casewestern.collegiatelink.net, so our "apikey" is "casewestern"
|
10
|
+
# * +ip+ - The IP address that the +sharedkey+ is approved for.
|
11
|
+
# * +sharedkey+ - The shared key granted by CollegiateLink to your IP and institution.
|
12
|
+
#
|
13
|
+
def initialize(apikey, ip, sharedkey)
|
14
|
+
@params = {
|
15
|
+
apikey: apikey,
|
16
|
+
ip: ip
|
17
|
+
}
|
18
|
+
@opts = {
|
19
|
+
sharedkey: sharedkey
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Return a complete list of CollegiateLink::Organization instances for your
|
25
|
+
# institution.
|
26
|
+
#
|
27
|
+
# ==== Required Parameters:
|
28
|
+
# None
|
29
|
+
#
|
30
|
+
# ==== Optional Parameters:
|
31
|
+
# See CollegiateLink::Request#initialize for a list of optional parameters
|
32
|
+
#
|
33
|
+
def organizations(params = {})
|
34
|
+
orgs = request('organization/list', params)
|
35
|
+
orgs.map{ |o| CollegiateLink::Organization.parse(o.to_s) }
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Return a complete list of CollegiateLink::Event instances for your
|
40
|
+
# institution.
|
41
|
+
#
|
42
|
+
# ==== Required Parameters:
|
43
|
+
# * <tt>:startdate</tt> - Time instance or the Unix integral timestamp for the beginning of results.
|
44
|
+
# * <tt>:enddate</tt> - Time instance or the Unix integral timestamp for the end of results.
|
45
|
+
#
|
46
|
+
# ==== Optional Parameters:
|
47
|
+
# See CollegiateLink::Request#initialize for a list of additional parameters
|
48
|
+
# that requests can use.
|
49
|
+
def events(params = {})
|
50
|
+
# Default to showing events in the past 7 days
|
51
|
+
seven_days = 7 * 24 * 60 * 60
|
52
|
+
params[:startdate] ||= (Time.now.to_i - seven_days)
|
53
|
+
params[:enddate] ||= (Time.now.to_i)
|
54
|
+
|
55
|
+
# Convert to milliseconds...
|
56
|
+
params[:startdate] = params[:startdate].to_i * 1000
|
57
|
+
params[:enddate] = params[:enddate].to_i * 1000
|
58
|
+
|
59
|
+
events = request('event/list', params)
|
60
|
+
events.map{ |o| CollegiateLink::Event.parse(o.to_s) }
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def request(action, params = {})
|
66
|
+
cl_request = CollegiateLink::Request.new(action, params.merge(@params), @opts)
|
67
|
+
cl_resp = cl_request.perform
|
68
|
+
|
69
|
+
all_items = cl_resp.items
|
70
|
+
|
71
|
+
while cl_resp.has_next_page?
|
72
|
+
cl_resp = cl_request.request_for_next_page.perform
|
73
|
+
all_items += cl_resp.items
|
74
|
+
end
|
75
|
+
|
76
|
+
all_items
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module CollegiateLink
|
2
|
+
##
|
3
|
+
# Address object returned by CollegiateLink as part of an Organization or
|
4
|
+
# Event record.
|
5
|
+
#
|
6
|
+
# ==== Properties:
|
7
|
+
# * <tt>:city </tt> - String
|
8
|
+
# * <tt>:country </tt> - String
|
9
|
+
# * <tt>:postalcode</tt> - String
|
10
|
+
# * <tt>:state </tt> - String
|
11
|
+
# * <tt>:street1 </tt> - String
|
12
|
+
# * <tt>:street2 </tt> - String
|
13
|
+
# * <tt>:type </tt> - Integer
|
14
|
+
class Address
|
15
|
+
include HappyMapper
|
16
|
+
|
17
|
+
element :city, String
|
18
|
+
element :country, String
|
19
|
+
element :postalcode, String
|
20
|
+
element :state, String
|
21
|
+
element :street1, String
|
22
|
+
element :street2, String
|
23
|
+
element :type, Integer
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Category object returned by CollegiateLink as part of an Organization record
|
28
|
+
# See: # http://support.collegiatelink.net/entries/332558-web-services-developer-documentation#orgList
|
29
|
+
#
|
30
|
+
# ==== Properties:
|
31
|
+
# * <tt>:id </tt> - Integer
|
32
|
+
# * <tt>:ishidden</tt> - String
|
33
|
+
# * <tt>:name </tt> - String
|
34
|
+
class Category
|
35
|
+
include HappyMapper
|
36
|
+
|
37
|
+
element :id, Integer
|
38
|
+
element :ishidden, String
|
39
|
+
element :name, String
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# An Organization record returned by CollegiateLink
|
44
|
+
# See: http://support.collegiatelink.net/entries/332558-web-services-developer-documentation#orgList
|
45
|
+
#
|
46
|
+
# ==== Properties:
|
47
|
+
# * <tt>:id </tt> - Integer
|
48
|
+
# * <tt>:ishidden</tt> - String
|
49
|
+
# * <tt>:name </tt> - String
|
50
|
+
# * <tt>:addresses </tt> - Array of Address objects
|
51
|
+
# * <tt>:categories </tt> - Array of Category objects
|
52
|
+
class Organization
|
53
|
+
include HappyMapper
|
54
|
+
|
55
|
+
element :id, Integer
|
56
|
+
element :parentId, Integer
|
57
|
+
element :name, String
|
58
|
+
element :description, String
|
59
|
+
element :shortName, String
|
60
|
+
element :siteUrl, String
|
61
|
+
element :status, String
|
62
|
+
element :type, String
|
63
|
+
has_many :addresses, Address
|
64
|
+
has_many :categories, Category
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# An Event record returned by CollegiateLink
|
69
|
+
# See: http://support.collegiatelink.net/entries/332558-web-services-developer-documentation#eventList
|
70
|
+
#
|
71
|
+
# ==== Properties:
|
72
|
+
# * <tt>:id </tt> - Integer
|
73
|
+
# * <tt>:name </tt> - String
|
74
|
+
# * <tt>:description</tt> - String
|
75
|
+
# * <tt>:startDate </tt> - Integer
|
76
|
+
# * <tt>:endDate </tt> - Integer
|
77
|
+
# * <tt>:location </tt> - String
|
78
|
+
# * <tt>:status </tt> - String
|
79
|
+
# * <tt>:urlLarge </tt> - String
|
80
|
+
# * <tt>:urlSmall </tt> - String
|
81
|
+
# * <tt>:organization</tt> - The hosting Organization
|
82
|
+
#
|
83
|
+
class Event
|
84
|
+
include HappyMapper
|
85
|
+
|
86
|
+
element :id, Integer
|
87
|
+
element :name, String
|
88
|
+
element :description, String
|
89
|
+
element :startDate, Integer
|
90
|
+
element :endDate, Integer
|
91
|
+
element :location, String
|
92
|
+
element :status, String
|
93
|
+
element :urlLarge, String
|
94
|
+
element :urlSmall, String
|
95
|
+
|
96
|
+
has_one :organization, Organization
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module CollegiateLink
|
2
|
+
##
|
3
|
+
# Represents a single HTTP request to the CollegiateLink API.
|
4
|
+
#
|
5
|
+
class Request
|
6
|
+
##
|
7
|
+
# Create a new Request instance. See +CollegiateLink::ACTIONS+ for a list of
|
8
|
+
# eligible actions.
|
9
|
+
#
|
10
|
+
# ==== Parameters:
|
11
|
+
# All parameters are provided in the URL of the request to CollegiateLink.
|
12
|
+
#
|
13
|
+
# * <tt>:page</tt> - The desired page number of results. (default = 1)
|
14
|
+
# * <tt>:pagesize</tt> - The desired number of records to return (default = 100)
|
15
|
+
# * <tt>:modelformatting</tt> - Either "normal" or "humanreadable". (default = "normal")
|
16
|
+
#
|
17
|
+
# ==== Options:
|
18
|
+
# Options are ways to pass in additional parameters about the request. The
|
19
|
+
# following options are supported.
|
20
|
+
#
|
21
|
+
# * <tt>:sharedkey</tt> - (Required) The shared key which is used, but not included in the URL of requests
|
22
|
+
# * <tt>:debug</tt> - Print debug information as the request happens.
|
23
|
+
#
|
24
|
+
def initialize(action, params = {}, opts = {})
|
25
|
+
raise UnknownAction unless ACTIONS.include?(action)
|
26
|
+
raise AuthenticationException unless opts.include?(:sharedkey)
|
27
|
+
|
28
|
+
@action = action
|
29
|
+
@params = params
|
30
|
+
@opts = opts
|
31
|
+
|
32
|
+
# URL Query String Parameters
|
33
|
+
@params[:page] ||= 1
|
34
|
+
@params[:pagesize] ||= 100
|
35
|
+
@params[:modelformatting] ||= 'normal'
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Execute the request by sending the HTTP request.
|
40
|
+
#
|
41
|
+
def perform
|
42
|
+
# First, add the time-sensitive bits...
|
43
|
+
request_params = @params.merge({
|
44
|
+
time: Time.now.to_i * 1000,
|
45
|
+
random: Guid.new
|
46
|
+
})
|
47
|
+
request_params[:hash] = hash(request_params.merge(sharedkey: @opts[:sharedkey]))
|
48
|
+
|
49
|
+
# Then, compute the URL...
|
50
|
+
url = URI([
|
51
|
+
URL_BASE % @params[:apikey]
|
52
|
+
@action
|
53
|
+
'?'
|
54
|
+
URI.encode_www_form(request_params)
|
55
|
+
].join)
|
56
|
+
|
57
|
+
puts "requesting: \n#{url}" if @opts[:debug]
|
58
|
+
|
59
|
+
# Make the Request!
|
60
|
+
res = Net::HTTP.new(url.host, url.port)
|
61
|
+
res.use_ssl = true
|
62
|
+
res.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
63
|
+
|
64
|
+
resp = res.start { |h|
|
65
|
+
h.request_get(url.to_s);
|
66
|
+
}
|
67
|
+
|
68
|
+
case resp
|
69
|
+
when Net::HTTPSuccess
|
70
|
+
return parse_response(resp.body)
|
71
|
+
when Net::HTTPError
|
72
|
+
raise NetworkException
|
73
|
+
else
|
74
|
+
raise UnknownException
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# Increment the page number and return a request instance that would receive
|
80
|
+
# the next bunch of pages.
|
81
|
+
#
|
82
|
+
def request_for_next_page
|
83
|
+
Request.new(@action, @params.merge(page: @params[:page] + 1), @opts)
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def parse_response(body)
|
89
|
+
d = Nokogiri::XML::Document.parse(body)
|
90
|
+
|
91
|
+
# Parse exceptions
|
92
|
+
if d.xpath("//results/error").length > 0
|
93
|
+
type = d.xpath('//results/error/type').inner_html
|
94
|
+
message = d.xpath('//results/error/message').inner_html
|
95
|
+
case type
|
96
|
+
when 'AUTHENTICATION_ERROR'
|
97
|
+
raise AuthenticationException, message
|
98
|
+
when 'VALIDATION_ERROR'
|
99
|
+
raise ValidationException, message
|
100
|
+
when 'UNKNOWN_SERVICE'
|
101
|
+
raise UnknownAction, message
|
102
|
+
when 'GENERAL_ERROR'
|
103
|
+
raise UnknownException, message
|
104
|
+
else
|
105
|
+
raise UnknownException, message
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
Response.new(d)
|
110
|
+
end
|
111
|
+
|
112
|
+
def hash(params = {})
|
113
|
+
Digest::MD5.hexdigest [
|
114
|
+
params[:apikey],
|
115
|
+
params[:ip],
|
116
|
+
params[:time].to_i,
|
117
|
+
params[:random],
|
118
|
+
params[:sharedkey],
|
119
|
+
].join
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module CollegiateLink
|
2
|
+
##
|
3
|
+
# Container for the XML gunk returned from CollegiateLink
|
4
|
+
#
|
5
|
+
class Response
|
6
|
+
# Create the response.
|
7
|
+
#
|
8
|
+
# ==== Parameters:
|
9
|
+
# * +document+ - The Nokogiri document of the returned XML
|
10
|
+
def initialize(document)
|
11
|
+
raise UnknownException unless document.xpath('//results/page')
|
12
|
+
|
13
|
+
@document = document
|
14
|
+
@page_size = document.xpath('//results/page/pageSize').inner_html.to_i
|
15
|
+
@page_number = document.xpath('//results/page/pageNumber').inner_html.to_i
|
16
|
+
@total_items = document.xpath('//results/page/totalItems').inner_html.to_i
|
17
|
+
@total_pages = document.xpath('//results/page/totalPages').inner_html.to_i
|
18
|
+
end
|
19
|
+
|
20
|
+
# Extract the items from the response. Returns a Nokogiri NodeSet.
|
21
|
+
def items
|
22
|
+
@document.xpath('//results/page/items/*')
|
23
|
+
end
|
24
|
+
|
25
|
+
# Utility method to determine if the request has another page to retrieve.
|
26
|
+
def has_next_page?
|
27
|
+
@page_number < @total_pages
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: CollegiateLink
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tom Dooner
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: guid
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: nokogiri
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: happymapper
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: net-ssh
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description:
|
95
|
+
email: ted27@case.edu
|
96
|
+
executables: []
|
97
|
+
extensions: []
|
98
|
+
extra_rdoc_files: []
|
99
|
+
files:
|
100
|
+
- lib/collegiatelink.rb
|
101
|
+
- lib/collegiatelink/request.rb
|
102
|
+
- lib/collegiatelink/response.rb
|
103
|
+
- lib/collegiatelink/client.rb
|
104
|
+
- lib/collegiatelink/organization.rb
|
105
|
+
homepage:
|
106
|
+
licenses: []
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
none: false
|
113
|
+
requirements:
|
114
|
+
- - ! '>='
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ! '>='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 1.8.24
|
126
|
+
signing_key:
|
127
|
+
specification_version: 3
|
128
|
+
summary: CollegiateLink Client Gem
|
129
|
+
test_files: []
|
130
|
+
has_rdoc:
|