collegiatelink 0.0.3

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.
@@ -0,0 +1,87 @@
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
+ def self.proxy
24
+ @@proxy || Net::HTTP
25
+ end
26
+
27
+ def use_socks_proxy(host, port)
28
+ @@proxy = Net::HTTP.SOCKSProxy(host, port)
29
+ end
30
+
31
+ ##
32
+ # Return a complete list of CollegiateLink::Organization instances for your
33
+ # institution.
34
+ #
35
+ # ==== Required Parameters:
36
+ # None
37
+ #
38
+ # ==== Optional Parameters:
39
+ # See CollegiateLink::Request#initialize for a list of optional parameters
40
+ #
41
+ def organizations(params = {})
42
+ orgs = request('organization/list', params)
43
+ orgs.map{ |o| CollegiateLink::Organization.parse(o.to_s) }
44
+ end
45
+
46
+ ##
47
+ # Return a complete list of CollegiateLink::Event instances for your
48
+ # institution.
49
+ #
50
+ # ==== Required Parameters:
51
+ # * <tt>:startdate</tt> - Time instance or the Unix integral timestamp for the beginning of results.
52
+ # * <tt>:enddate</tt> - Time instance or the Unix integral timestamp for the end of results.
53
+ #
54
+ # ==== Optional Parameters:
55
+ # See CollegiateLink::Request#initialize for a list of additional parameters
56
+ # that requests can use.
57
+ def events(params = {})
58
+ # Default to showing events in the past 7 days
59
+ seven_days = 7 * 24 * 60 * 60
60
+ params[:startdate] ||= (Time.now.to_i - seven_days)
61
+ params[:enddate] ||= (Time.now.to_i)
62
+
63
+ # Convert to milliseconds...
64
+ params[:startdate] = params[:startdate].to_i * 1000
65
+ params[:enddate] = params[:enddate].to_i * 1000
66
+
67
+ events = request('event/list', params)
68
+ events.map{ |o| CollegiateLink::Event.parse(o.to_s) }
69
+ end
70
+
71
+ private
72
+
73
+ def request(action, params = {})
74
+ cl_request = CollegiateLink::Request.new(action, params.merge(@params), @opts)
75
+ cl_resp = cl_request.perform
76
+
77
+ all_items = cl_resp.items
78
+
79
+ while cl_resp.has_next_page?
80
+ cl_resp = cl_request.request_for_next_page.perform
81
+ all_items += cl_resp.items
82
+ end
83
+
84
+ all_items
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,103 @@
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>:parentId</tt> - Integer
49
+ # * <tt>:name </tt> - String
50
+ # * <tt>:description </tt> - String
51
+ # * <tt>:shortName </tt> - String
52
+ # * <tt>:siteUrl </tt> - String
53
+ # * <tt>:status </tt> - String
54
+ # * <tt>:type </tt> - String
55
+ # * <tt>:addresses </tt> - Array of CollegiateLink::Address
56
+ # * <tt>:categories </tt> - Array of CollegiateLink::Category
57
+ class Organization
58
+ include HappyMapper
59
+
60
+ element :id, Integer
61
+ element :parentId, Integer
62
+ element :name, String
63
+ element :description, String
64
+ element :shortName, String
65
+ element :siteUrl, String
66
+ element :status, String
67
+ element :type, String
68
+ has_many :addresses, Address
69
+ has_many :categories, Category
70
+ end
71
+
72
+ ##
73
+ # An Event record returned by CollegiateLink
74
+ # See: http://support.collegiatelink.net/entries/332558-web-services-developer-documentation#eventList
75
+ #
76
+ # ==== Properties:
77
+ # * <tt>:id </tt> - Integer
78
+ # * <tt>:name </tt> - String
79
+ # * <tt>:description</tt> - String
80
+ # * <tt>:startDate </tt> - Integer
81
+ # * <tt>:endDate </tt> - Integer
82
+ # * <tt>:location </tt> - String
83
+ # * <tt>:status </tt> - String
84
+ # * <tt>:urlLarge </tt> - String
85
+ # * <tt>:urlSmall </tt> - String
86
+ # * <tt>:organization</tt> - The hosting Organization
87
+ #
88
+ class Event
89
+ include HappyMapper
90
+
91
+ element :id, Integer
92
+ element :name, String
93
+ element :description, String
94
+ element :startDate, Integer
95
+ element :endDate, Integer
96
+ element :location, String
97
+ element :status, String
98
+ element :urlLarge, String
99
+ element :urlSmall, String
100
+
101
+ has_one :organization, Organization
102
+ end
103
+ end
@@ -0,0 +1,125 @@
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
+
37
+ # Default values for optional parameters
38
+ @opts[:url_base] ||= 'https://%s.collegiatelink.net/ws/' % @params[:apikey]
39
+ end
40
+
41
+ ##
42
+ # Execute the request by sending the HTTP request.
43
+ #
44
+ def perform
45
+ # First, add the time-sensitive bits...
46
+ request_params = @params.merge({
47
+ time: Time.now.to_i * 1000,
48
+ random: Guid.new
49
+ })
50
+ request_params[:hash] = hash(request_params.merge(sharedkey: @opts[:sharedkey]))
51
+
52
+ # Then, compute the URL...
53
+ url = URI([
54
+ @opts[:url_base],
55
+ @action,
56
+ '?',
57
+ URI.encode_www_form(request_params),
58
+ ].join)
59
+
60
+ puts "requesting: \n#{url}" if @opts[:debug]
61
+
62
+ # Make the Request!
63
+ res = CollegiateLink::Client.proxy.new(url.host, url.port)
64
+ res.use_ssl = true
65
+ res.verify_mode = OpenSSL::SSL::VERIFY_NONE
66
+
67
+ resp = res.start { |h|
68
+ h.request_get(url.to_s);
69
+ }
70
+
71
+ case resp
72
+ when Net::HTTPSuccess
73
+ return parse_response(resp.body)
74
+ when Net::HTTPError
75
+ raise NetworkException
76
+ else
77
+ raise UnknownException
78
+ end
79
+ end
80
+
81
+ ##
82
+ # Increment the page number and return a request instance that would receive
83
+ # the next bunch of pages.
84
+ #
85
+ def request_for_next_page
86
+ Request.new(@action, @params.merge(page: @params[:page] + 1), @opts)
87
+ end
88
+
89
+ private
90
+
91
+ def parse_response(body)
92
+ d = Nokogiri::XML::Document.parse(body)
93
+
94
+ # Parse exceptions
95
+ if d.xpath("//results/error").length > 0
96
+ type = d.xpath('//results/error/type').inner_html
97
+ message = d.xpath('//results/error/message').inner_html
98
+ case type
99
+ when 'AUTHENTICATION_ERROR'
100
+ raise AuthenticationException, message
101
+ when 'VALIDATION_ERROR'
102
+ raise ValidationException, message
103
+ when 'UNKNOWN_SERVICE'
104
+ raise UnknownAction, message
105
+ when 'GENERAL_ERROR'
106
+ raise UnknownException, message
107
+ else
108
+ raise UnknownException, message
109
+ end
110
+ end
111
+
112
+ Response.new(d)
113
+ end
114
+
115
+ def hash(params = {})
116
+ Digest::MD5.hexdigest [
117
+ params[:apikey],
118
+ params[:ip],
119
+ params[:time].to_i,
120
+ params[:random],
121
+ params[:sharedkey],
122
+ ].join
123
+ end
124
+ end
125
+ 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
@@ -0,0 +1,43 @@
1
+ require 'digest'
2
+ require 'net/https'
3
+ require 'net/ssh'
4
+ require 'guid'
5
+ require 'nokogiri'
6
+ require 'happymapper'
7
+ require 'socksify/http'
8
+
9
+ require 'collegiatelink/response'
10
+ require 'collegiatelink/request'
11
+ require 'collegiatelink/client'
12
+ require 'collegiatelink/organization'
13
+
14
+ ##
15
+ # This gem provides a CollegiateLink API client in Ruby. It's still under
16
+ # development, so let me know if you plan to use it. (tomdooner@gmail.com)
17
+ #
18
+ module CollegiateLink
19
+ # Currently-supported CollegiateLink action request types
20
+ ACTIONS = [
21
+ 'organization/list',
22
+ 'organization/roster',
23
+ #'user/memberships',
24
+ #'user/position',
25
+ 'event/list',
26
+ ]
27
+
28
+ # Raised when performing a CollegiateLink::Request for an action that is not
29
+ # supported by the gem (as defined by CollegiateLink::ACTIONS).
30
+ class UnknownAction < Exception; end
31
+
32
+ # Raised when something unexpected goes wrong.
33
+ class UnknownException < Exception; end
34
+
35
+ # Raised when the CollegiateLink::Request HTTP request fails.
36
+ class NetworkException < Exception; end
37
+
38
+ # Raised when CollegiateLink returns that the combination of IP and SSL fails.
39
+ class AuthenticationException < Exception; end
40
+
41
+ # Raised for the CollegiateLink VALIDATION_ERROR case.
42
+ class ValidationException < Exception; end
43
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: collegiatelink
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tom Dooner
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-01-24 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: socksify
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
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: rspec
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
+ - !ruby/object:Gem::Dependency
95
+ name: net-ssh
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description:
111
+ email: ted27@case.edu
112
+ executables: []
113
+ extensions: []
114
+ extra_rdoc_files: []
115
+ files:
116
+ - lib/collegiatelink.rb
117
+ - lib/collegiatelink/request.rb
118
+ - lib/collegiatelink/response.rb
119
+ - lib/collegiatelink/client.rb
120
+ - lib/collegiatelink/organization.rb
121
+ homepage:
122
+ licenses: []
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ! '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 1.8.24
142
+ signing_key:
143
+ specification_version: 3
144
+ summary: CollegiateLink Client Gem
145
+ test_files: []