service_now 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/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ Gemfile.lock
6
+ InstalledFiles
7
+ coverage
8
+ doc/
9
+ coverage
10
+ InstalledFiles
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+
19
+ # YARD artifacts
20
+ .yardoc
21
+ _yardoc
22
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in service_now.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Yale Student Technology Collaborative
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 hengchu
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # ServiceNow
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'service_now'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install service_now
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
30
+ =======
31
+ service_now
32
+ ===========
33
+
34
+ A gem to interface with Service Now
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,44 @@
1
+ module ServiceNow
2
+ class Configuration
3
+
4
+ def self.configure(auth_hash = {})
5
+ $root_url = auth_hash[:sn_url].sub(/(\/)+$/, '') #remove trailing slash if there are any
6
+ $username = auth_hash[:sn_username]
7
+ $password = auth_hash[:sn_password]
8
+ "SN::Success: Configuration successful"
9
+ end
10
+
11
+ def self.get_resource(query_hash = {}, displayvalue = false, table)
12
+ # to be filled in
13
+ RestClient::Resource.new(URI.escape($root_url + "/#{table}.do?JSON&sysparm_action=getRecords&sysparm_query=#{hash_to_query(query_hash)}&displayvalue=#{displayvalue}"), $username, $password)
14
+ end
15
+
16
+ def self.post_resource(table)
17
+ RestClient::Resource.new(URI.escape($root_url + "/#{table}.do?JSON&sysparm_action=insert"), $username, $password)
18
+ end
19
+
20
+ def self.update_resource(incident_number, table)
21
+ RestClient::Resource.new(URI.escape($root_url + "/#{table}.do?JSON&sysparm_query=number=#{incident_number}&sysparm_action=update"), $username, $password)
22
+ end
23
+
24
+ private
25
+ def self.hash_to_query(query_hash = {})
26
+ if query_hash.empty?
27
+ return ""
28
+ end
29
+ query_string = []
30
+ query_hash.each do |k, v|
31
+ key_str = k.to_s
32
+ value_str = v.to_s
33
+ # if we are querying based on short_description or description
34
+ # we use a partial match
35
+ if key_str == "short_description" || key_str == "description"
36
+ query_string << key_str + "LIKE" + value_str
37
+ else
38
+ query_string << key_str + "=" + value_str
39
+ end
40
+ end
41
+ query_string.join('^')
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,105 @@
1
+ module ServiceNow
2
+ class Incident
3
+
4
+ def inspect
5
+ @attributes.each do |k, v|
6
+ puts "#{k} => #{v}"
7
+ end
8
+ end
9
+
10
+ def initialize(attributes = {}, saved_on_sn = false, internal_call = false)
11
+ Incident.check_configuration
12
+ symbolized_attributes = Hash[attributes.map{|k, v| [k.to_sym, v]}]
13
+ if !symbolized_attributes[:number].nil? && !internal_call # allow setting INC number if it's called internally
14
+ raise "SN::ERROR: You are not allowed to set INC Number manually, the server will take care of that"
15
+ end
16
+ @attributes = symbolized_attributes
17
+ @saved_on_sn = saved_on_sn
18
+ end
19
+
20
+ def attributes
21
+ @attributes
22
+ end
23
+
24
+ def client # must be used only when displayvable is false
25
+ return User.find_by_sys_id(self.caller_id)
26
+ end
27
+
28
+ def method_missing(method, args = nil)
29
+ method_name = method.to_s
30
+ if match = method_name.match(/(.*)=/) # writer method
31
+ attribute = match[1]
32
+ if attribute == "number" && @saved_on_sn
33
+ raise "SN::ERROR: You are not allowed to set INC Number manually, the server will take care of that"
34
+ end
35
+ @attributes[attribute.to_sym] = args
36
+ else # reader method
37
+ @attributes[method_name.to_sym]
38
+ end
39
+ end
40
+
41
+ def save!
42
+ # if this is a new incident (still in memory and not on SN), and the user set the Incident number
43
+ # we raise an exception
44
+ if !@attributes[:number].nil? && !@saved_on_sn
45
+ raise "SN::ERROR: You are not allowed to set INC Number manually, the server will take care of that"
46
+ end
47
+ # we only create new incidents if it's not saved already
48
+ if !@saved_on_sn
49
+ response = Configuration.post_resource(table = "incident").post(self.attributes.to_json)
50
+ else
51
+ response = Configuration.update_resource(self.number, table = "incident").post(self.attributes.to_json)
52
+ end
53
+ hash = JSON.parse(response, { :symbolize_names => true })
54
+ # this is the object
55
+ # and there is always only one
56
+ # since we're creating or updating
57
+ inc_object = hash[:records][0]
58
+ inc_object.each do |key, value|
59
+ key_name = key.to_s
60
+ eval("self.#{key_name} = value")
61
+ end
62
+ @saved_on_sn = true
63
+ self
64
+ end
65
+
66
+ def self.find(inc_number)
67
+ Incident.check_configuration
68
+ inc_string = inc_number.to_s.match(/[123456789]+\d*$/).to_s
69
+ if inc_string.length > 7
70
+ raise "SN::Error: invalid Incident number"
71
+ end
72
+ query_hash = {}
73
+ query_hash[:number] = "INC" + "0"*(7-inc_string.length) + inc_string
74
+ response = Configuration.get_resource(query_hash, table = "incident").get();
75
+ # returned hash
76
+ hash = JSON.parse(response, { :symbolize_names => true })
77
+ # return the Incident object
78
+ inc_obj = Incident.new(attributes = hash[:records][0], saved_on_sn = true, internal_call = true)
79
+ if inc_obj.attributes.nil?
80
+ "SN::Alert: No incident with incident number #{query_hash[:number]} found"
81
+ else
82
+ inc_obj
83
+ end
84
+ end
85
+
86
+ def self.where(query_hash = {})
87
+ Incident.check_configuration
88
+ response = Configuration.get_resource(query_hash, table = "incident").get();
89
+ hash = JSON.parse(response, { :symbolize_names => true })
90
+ array_of_records = hash[:records]
91
+ array_of_inc = []
92
+ array_of_records.each do |record|
93
+ array_of_inc << Incident.new(attributes = record, saved_on_sn = true, internal_call = true)
94
+ end
95
+ array_of_inc
96
+ end
97
+
98
+ private
99
+ def self.check_configuration
100
+ if $root_url.nil? || $username.nil? || $password.nil?
101
+ raise "SN::Error: You have not configured yet, please run ServiceNow::Configuration.configure() first"
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,67 @@
1
+ module ServiceNow
2
+ class User
3
+
4
+ def initialize(attributes = {})
5
+ @attributes = attributes
6
+ end
7
+
8
+ def attributes
9
+ @attributes
10
+ end
11
+
12
+ def self.find(netid)
13
+ User.check_configuration
14
+ query_hash = {}
15
+ query_hash[:user_name] = netid
16
+ response = Configuration.get_resource(query_hash = query_hash, table = "sys_user").get()
17
+ hash = JSON.parse(response, { :symbolize_names => true })
18
+ # there should be only one
19
+ user = User.new(hash[:records][0])
20
+ if user.attributes.nil?
21
+ "SN::Alert: No user with netID: #{netid} found"
22
+ else
23
+ user
24
+ end
25
+ end
26
+
27
+ def self.find_by_sys_id(sys_id)
28
+ User.check_configuration
29
+ query_hash = {}
30
+ query_hash[:sys_id] = sys_id
31
+ response = Configuration.get_resource(query_hash = query_hash, table = "sys_user").get()
32
+ hash = JSON.parse(response, { :symbolize_names => true })
33
+ user = User.new(hash[:records][0])
34
+ if user.attributes.nil?
35
+ "SN::Alert: No user with sys_id: #{sys_id} found"
36
+ else
37
+ user
38
+ end
39
+ end
40
+
41
+ def self.find_by_name(name)
42
+ User.check_configuration
43
+ query_hash = {}
44
+ query_hash[:name] = name
45
+ response = Configuration.get_resource(query_hash = query_hash, table = "sys_user").get()
46
+ hash = JSON.parse(response, { :symbolize_names => true })
47
+ user = User.new(hash[:records][0])
48
+ if user.attributes.nil?
49
+ "SN::Alert: No user with user_name: #{name} found"
50
+ else
51
+ user
52
+ end
53
+ end
54
+
55
+ def method_missing(method, args = nil)
56
+ method_name = method.to_s
57
+ @attributes[method_name.to_sym]
58
+ end
59
+
60
+ private
61
+ def self.check_configuration
62
+ if $root_url.nil? || $username.nil? || $password.nil?
63
+ raise "SN::Error: You have not configured yet, please run ServiceNow::Configuration.configure() first"
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,3 @@
1
+ module ServiceNow
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,14 @@
1
+ require "service_now/version"
2
+ require "classes/configuration"
3
+ require "classes/incident"
4
+ require "classes/user"
5
+ require "rest_client"
6
+ require "json"
7
+ require "uri"
8
+
9
+
10
+ module ServiceNow
11
+ $root_url = nil
12
+ $username = nil
13
+ $password = nil
14
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'service_now/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "service_now"
8
+ spec.version = ServiceNow::VERSION
9
+ spec.authors = ["YaleSTC::hengchu zhang"]
10
+ spec.email = ["hengchu.zhang@yale.edu"]
11
+ spec.description = %q{Ruby wrapper for SN API requests}
12
+ spec.summary = %q{Ruby wrapper for SN API requests}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.add_dependency('rest-client')
17
+ spec.add_dependency('json')
18
+
19
+ spec.files = `git ls-files`.split($/)
20
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ end
data/specs.md ADDED
@@ -0,0 +1,51 @@
1
+
2
+ The main open question in the specs below (at least right now) is how to handle associating users with incidents. That is, what are the properties used by SN to reliably identify clients for incidents, requests, etc. Do we create a class such as SN::Client that wraps the properties of an incident's client?
3
+
4
+ ## Configuration
5
+
6
+ Ideally, users of this gem would be able to do something like:
7
+
8
+ SN::Configuration.configure auth_user: "my_user", auth_pass: "my_pass", sn_url: "http://yaletest.service-now.com"
9
+
10
+ ## Incidents
11
+
12
+ ### Creating
13
+
14
+ incident = SN::Incident.new(client: "Adam Bray", short_description: "Computer has a virus")
15
+ incident.save! # submits request to SN; returns SN::Incident which wraps the newly created incident
16
+
17
+ ### Searching
18
+
19
+ incidents = SN::Incident.where(description: "virus", client: "Adam Bray")
20
+ # returns an array of objects of class 'SN::Incident'
21
+ # note we need to discuss the exact names for things like 'client', 'client netid', etc
22
+
23
+ incident = SN::Incident.find("INC0003123")
24
+ # same as:
25
+ incident = SN::Incident.find(3123)
26
+ # returns on SN::Incident
27
+
28
+ ### Reading
29
+
30
+ incident = SN::Incident.find(3123)
31
+ incident.short_description
32
+ # "Client has a computer virus after watching lolcats"
33
+ incident.description
34
+ # Returns the full description
35
+ client = incident.client
36
+ # This should ideally return something that behaves like a user object, maybe a class SN::Client
37
+ client.name
38
+ # "Adam Bray"
39
+ client.email
40
+ # "adam.bray@example.com"
41
+
42
+ ### Updating
43
+
44
+ incident = SN::Incident.find(3123)
45
+ incident.short_description = "Client has a computer virus after watching loldogs"
46
+ incident.save!
47
+
48
+ ### Destroying
49
+
50
+ For now, I don't think we should implement destroying incidents.
51
+
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: service_now
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - YaleSTC::hengchu zhang
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-08-01 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rest-client
16
+ requirement: &70254494557040 !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: *70254494557040
25
+ - !ruby/object:Gem::Dependency
26
+ name: json
27
+ requirement: &70254494555560 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70254494555560
36
+ - !ruby/object:Gem::Dependency
37
+ name: bundler
38
+ requirement: &70254494550320 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '1.3'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70254494550320
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: &70254494549700 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70254494549700
58
+ description: Ruby wrapper for SN API requests
59
+ email:
60
+ - hengchu.zhang@yale.edu
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - .gitignore
66
+ - Gemfile
67
+ - LICENSE
68
+ - LICENSE.txt
69
+ - README.md
70
+ - Rakefile
71
+ - lib/classes/configuration.rb
72
+ - lib/classes/incident.rb
73
+ - lib/classes/user.rb
74
+ - lib/service_now.rb
75
+ - lib/service_now/version.rb
76
+ - service_now.gemspec
77
+ - specs.md
78
+ homepage: ''
79
+ licenses:
80
+ - MIT
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 1.8.10
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: Ruby wrapper for SN API requests
103
+ test_files: []