ruby-jss 0.14.0 → 1.0.0b2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ruby-jss might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b50f5c9f41b90f37fd146d236cb0a5934337321b
4
- data.tar.gz: a8e3308d642f4f595cf0a0ade55e1b9e965ec672
3
+ metadata.gz: e2cda3beb0c57a922fa2bae9be0ed07ddb0ad3f4
4
+ data.tar.gz: a5c707f859c044e7d7021b9e6c7d4a0c5f6900a9
5
5
  SHA512:
6
- metadata.gz: 77b67a03425123953b9dac37453834c746f81c0339eb33a1d5b0edcf0cc6b8552ee8d5b4ca4b0dd8108e390b802aa702fa9d3d4a9fa6d8f975660206baeb12fd
7
- data.tar.gz: 397fd3251d80dbf3bd8a4d0eedeec6d3eb6541881bcfdc7d0c18494f9acc7aebf29194fa111a8da53691135f6ecf6b05bf037a475536bfd555f4df9cc997dbee
6
+ metadata.gz: 2f655fcf07b79416bcccef6eceacec0c023e7fccb4507c4588df60c38c7a40c226951539eecdaa85dd094e3fbcd9682417e04e20b371ceeb1e2f1ac6d1422b8c
7
+ data.tar.gz: 60e672418b4fff07a72df15cbe2e8aa5963566db72425c1640a11bf0355a8f79ef196783c74dbeff2f983da143a3d10971d333598ee243190279d3199c22acef
data/CHANGES.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Change History
2
2
 
3
+ ## v 1.0.0b2, 2018-06-x26
4
+
5
+ Finally we're going to version 1.0, which we should have done when we went opensource.
6
+
7
+ - requirement: Jamf Pro API version must be 10.4 or higher
8
+
9
+ - add: JSS::PatchSource metaclass and the subclassses JSS::PatchInternalSource, and JSS::PatchExternalSource. These provide acecss to the patchavailabletitles enpoint, which is needed to acquire name_id's for creating/activating JSS::PatchTitles
10
+
11
+ - add: JSS::PatchTitle, which also gives access to the patchreports endpoint. Also uses the JSS::PatchTitle::Version class to handle patch versions within a title, and assign packages to them.
12
+
13
+ - add: JSS::PatchPolicy. PatchPolicies are creatable when providing an active PatchTitle and an approiate PatchTitle::Version that has a package assigned to it.
14
+
15
+ - add: the Group metaclass now has a calculate_members option (bool) to the #create method. When true, the membership of the group will be updated in the existing ruby instance immediately after the group is created in the JSS. Doesn't do much for static groups, but is useful for smart groups. Defaults to true. If you don't care about the membership immediately, or don't want to wait for the membership to be calculated on the server, set this to false.
16
+
17
+ - improvement: better handling of http error responses
18
+
19
+ - add: more generic data validation methods in JSS::Validate module, and more use of them throughout the code.
20
+
21
+ - add: 'support' in SelfServable for notifications - note that there are API bugs limiting the usefulness of this.
22
+
23
+ - add: regex options to JSS::Criteriable::Criterion objects
24
+
25
+ - remove: the .new class method on APIObject subclasses no longer works. Even thought its the standard ruby way to create instances of a class, it was confusing, since it implied creating new objects in the JSS. Instead you must now use .fetch to instantiate existing objects and .make to instantiate local instances of objects to be created in the JSS.
26
+
27
+ - update: API connections now default to TLSv1.2. If you're connecting from a machine that doesn't support TLSv1.2 (like the os-supplied ruby in macOS < 10.13) then you can specify `ssl_version: 'TLSv1'` when you connect, as long as your Jamf Pro server supports it.
28
+
29
+ - add: there is now a, sort-of, spec/testing framework. While based on ruby's minitest specifications, its wrapped in a very custom executable with a helper module. See the README in the test directory for details. Specs will be added slowly over time.
30
+
31
+ - fix: as Apple says: various bugfixes and improvements.
32
+
33
+
3
34
  ## v 0.14.0, 2018-05-30
4
35
 
5
36
  - Fix: RestClient no longer uses RestClient::Request::Unauthorized, only RestClient::Unauthorized
data/lib/jss.rb CHANGED
@@ -65,9 +65,9 @@ module JSS
65
65
  ### Constants
66
66
  #####################################
67
67
 
68
- ### The minimum JSS version that works with this gem, as returned by the API
68
+ ### The minimum JSS version that works with this module, as returned by the API
69
69
  ### in the deprecated 'jssuser' resource
70
- MINIMUM_SERVER_VERSION = '9.4'.freeze
70
+ MINIMUM_SERVER_VERSION = '10.4.0'.freeze
71
71
 
72
72
  ### The current local UTC offset as a fraction of a day (Time.now.utc_offset is the offset in seconds,
73
73
  ### 60*60*24 is the seconds in a day)
@@ -120,8 +120,7 @@ module JSS
120
120
  class Server; end
121
121
  class Icon; end
122
122
  class Preferences; end
123
- class Client; end
124
-
123
+ class Client; end # TODO: see if this can be made into a module.
125
124
 
126
125
  ### SubClasses
127
126
  #####################################
@@ -192,6 +191,7 @@ module JSS
192
191
  module MDM; end
193
192
  module ManagementHistory; end
194
193
 
194
+
195
195
  end # module JSS
196
196
 
197
197
  ### Load the rest of the module
@@ -209,3 +209,4 @@ require 'jss/configuration'
209
209
  require 'jss/db_connection'
210
210
  require 'jss/validate'
211
211
  require 'jss/version'
212
+ require 'jss/xml_workaround'
@@ -320,17 +320,16 @@ module JSS
320
320
  DFT_TIMEOUT = 60
321
321
 
322
322
  # The Default SSL Version
323
- # As of Casper 9.61 we can't use SSL, must use TLS, since SSLv3 was susceptible to poodles.
324
- # NOTE - this requires rest-client v 1.7.0 or higher
325
- # which requires mime-types 2.0 or higher, which requires ruby 1.9.2 or higher!
326
- # That means that support for ruby 1.8.7 stops with Casper 9.6
327
- DFT_SSL_VERSION = 'TLSv1'.freeze
323
+ DFT_SSL_VERSION = 'TLSv1_2'.freeze
324
+
325
+ RSRC_NOT_FOUND_MSG = 'The requested resource was not found'.freeze
328
326
 
329
327
  # Attributes
330
328
  #####################################
331
329
 
332
330
  # @return [String] the username who's connected to the JSS API
333
- attr_reader :jss_user
331
+ attr_reader :user
332
+ alias jss_user user
334
333
 
335
334
  # @return [RestClient::Resource] the underlying connection resource
336
335
  attr_reader :cnx
@@ -433,7 +432,7 @@ module JSS
433
432
  # parse our ssl situation
434
433
  verify_ssl args
435
434
 
436
- @jss_user = args[:user]
435
+ @user = args[:user]
437
436
 
438
437
  @rest_url = build_rest_url args
439
438
 
@@ -445,7 +444,7 @@ module JSS
445
444
 
446
445
  verify_server_version
447
446
 
448
- @name = "#{@jss_user}@#{@server_host}:#{@port}" if @name.nil? || @name == :disconnected
447
+ @name = "#{@user}@#{@server_host}:#{@port}" if @name.nil? || @name == :disconnected
449
448
  @connected ? hostname : nil
450
449
  end # connect
451
450
 
@@ -454,7 +453,7 @@ module JSS
454
453
  # @return [String]
455
454
  #
456
455
  def to_s
457
- @connected ? "Using #{@rest_url} as user #{@jss_user}" : 'not connected'
456
+ @connected ? "Using #{@rest_url} as user #{@user}" : 'not connected'
458
457
  end
459
458
 
460
459
  # Reset the response timeout for the rest connection
@@ -483,7 +482,7 @@ module JSS
483
482
  # @return [void]
484
483
  #
485
484
  def disconnect
486
- @jss_user = nil
485
+ @user = nil
487
486
  @rest_url = nil
488
487
  @server_host = nil
489
488
  @cnx = nil
@@ -509,10 +508,16 @@ module JSS
509
508
  #
510
509
  def get_rsrc(rsrc, format = :json)
511
510
  # puts object_id
512
- raise JSS::InvalidConnectionError, 'Not Connected. Use .connect first.' unless @connected
511
+ validate_connected
512
+ raise JSS::InvalidDataError, 'format must be :json or :xml' unless %i[json xml].include? format
513
+
513
514
  rsrc = URI.encode rsrc
514
- @last_http_response = @cnx[rsrc].get(accept: format)
515
- return JSON.parse(@last_http_response, symbolize_names: true) if format == :json
515
+ begin
516
+ @last_http_response = @cnx[rsrc].get(accept: format)
517
+ rescue RestClient::ExceptionWithResponse => e
518
+ handle_http_error e
519
+ end
520
+ format == :json ? JSON.parse(@last_http_response, symbolize_names: true) : @last_http_response
516
521
  end
517
522
 
518
523
  # Change an existing JSS resource
@@ -524,15 +529,15 @@ module JSS
524
529
  # @return [String] the xml response from the server.
525
530
  #
526
531
  def put_rsrc(rsrc, xml)
527
- raise JSS::InvalidConnectionError, 'Not Connected. Use .connect first.' unless @connected
532
+ validate_connected
528
533
 
529
534
  # convert CRs & to &#13;
530
535
  xml.gsub!(/\r/, '&#13;')
531
536
 
532
537
  # send the data
533
538
  @last_http_response = @cnx[rsrc].put(xml, content_type: 'text/xml')
534
- rescue RestClient::Conflict => exception
535
- raise_conflict_error(exception)
539
+ rescue RestClient::ExceptionWithResponse => e
540
+ handle_http_error e
536
541
  end
537
542
 
538
543
  # Create a new JSS resource
@@ -544,15 +549,15 @@ module JSS
544
549
  # @return [String] the xml response from the server.
545
550
  #
546
551
  def post_rsrc(rsrc, xml = '')
547
- raise JSS::InvalidConnectionError, 'Not Connected. Use .connect first.' unless @connected
552
+ validate_connected
548
553
 
549
554
  # convert CRs & to &#13;
550
555
  xml.gsub!(/\r/, '&#13;') if xml
551
556
 
552
557
  # send the data
553
558
  @last_http_response = @cnx[rsrc].post xml, content_type: 'text/xml', accept: :json
554
- rescue RestClient::Conflict => exception
555
- raise_conflict_error(exception)
559
+ rescue RestClient::ExceptionWithResponse => e
560
+ handle_http_error e
556
561
  end # post_rsrc
557
562
 
558
563
  # Delete a resource from the JSS
@@ -562,7 +567,7 @@ module JSS
562
567
  # @return [String] the xml response from the server.
563
568
  #
564
569
  def delete_rsrc(rsrc, xml = nil)
565
- raise JSS::InvalidConnectionError, 'Not Connected. Use .connect first.' unless @connected
570
+ validate_connected
566
571
  raise MissingDataError, 'Missing :rsrc' if rsrc.nil?
567
572
 
568
573
  # payload?
@@ -570,6 +575,8 @@ module JSS
570
575
 
571
576
  # delete the resource
572
577
  @last_http_response = @cnx[rsrc].delete
578
+ rescue RestClient::ExceptionWithResponse => e
579
+ handle_http_error e
573
580
  end # delete_rsrc
574
581
 
575
582
  # Test that a given hostname & port is a JSS API server
@@ -623,7 +630,6 @@ module JSS
623
630
  alias connected? connected
624
631
  alias host hostname
625
632
 
626
-
627
633
  #################
628
634
 
629
635
  # Call one of the 'all*' methods on a JSS::APIObject subclass
@@ -641,7 +647,7 @@ module JSS
641
647
  #
642
648
  # @return [Array] The list of items for the class
643
649
  #
644
- def all(class_name, refresh = false, only: nil )
650
+ def all(class_name, refresh = false, only: nil)
645
651
  the_class = JSS.api_object_class(class_name)
646
652
  list_method = only ? :"all_#{only}" : :all
647
653
 
@@ -813,7 +819,7 @@ module JSS
813
819
  @master_distribution_point =
814
820
  case all_dps.size
815
821
  when 0
816
- raise JSS::NoSuchItemError, "No distribution points defined"
822
+ raise JSS::NoSuchItemError, 'No distribution points defined'
817
823
  when 1
818
824
  JSS::DistributionPoint.fetch id: all_dps.first[:id], api: self
819
825
  else
@@ -919,6 +925,11 @@ module JSS
919
925
  ####################################
920
926
  private
921
927
 
928
+ # raise exception if not connected
929
+ def validate_connected
930
+ raise JSS::InvalidConnectionError, 'Not Connected. Use .connect first.' unless connected?
931
+ end
932
+
922
933
  # Apply defaults from the JSS::CONFIG,
923
934
  # then from the JSS::Client,
924
935
  # then from the module defaults
@@ -1020,11 +1031,12 @@ module JSS
1020
1031
  begin
1021
1032
  @server = JSS::Server.new get_rsrc('jssuser')[:user], self
1022
1033
  rescue RestClient::Unauthorized
1023
- raise JSS::AuthenticationError, "Incorrect JSS username or password for '#{@jss_user}@#{@server_host}:#{@port}'."
1034
+ raise JSS::AuthenticationError, "Incorrect JSS username or password for '#{@user}@#{@server_host}:#{@port}'."
1024
1035
  end
1025
1036
 
1026
1037
  min_vers = JSS.parse_jss_version(JSS::MINIMUM_SERVER_VERSION)[:version]
1027
- return unless @server.version < min_vers
1038
+ return if @server.version >= min_vers # we're good...
1039
+
1028
1040
  err_msg = "JSS version #{@server.raw_version} to low. Must be >= #{min_vers}"
1029
1041
  @connected = false
1030
1042
  raise JSS::UnsupportedError, err_msg
@@ -1091,19 +1103,37 @@ module JSS
1091
1103
  end
1092
1104
  end
1093
1105
 
1094
- # Parses the HTTP body of a RestClient::Conflict (409 conflict)
1095
- # exception and re-raises a JSS::ConflictError with a more
1106
+ # Parses the HTTP body of a RestClient::ExceptionWithResponse
1107
+ # (the parent of all HTTP error responses) and its subclasses
1108
+ # and re-raises a JSS::APIError with a more
1096
1109
  # useful error message.
1097
1110
  #
1098
- # @param exception[RestClient::Conflict] the exception to parse
1111
+ # @param exception[RestClient::ExceptionWithResponse] the exception to parse
1099
1112
  #
1100
1113
  # @return [void]
1101
1114
  #
1102
- def raise_conflict_error(exception)
1103
- exception.http_body =~ %r{<p>Error:(.*)</p>}
1104
- conflict_reason = Regexp.last_match(1)
1105
- conflict_reason ||= exception.http_body
1106
- raise JSS::ConflictError, conflict_reason
1115
+ def handle_http_error(exception)
1116
+ @last_http_response = exception.response
1117
+ case exception
1118
+ when RestClient::ResourceNotFound
1119
+ # other methods catch this and report more details
1120
+ raise exception
1121
+ when RestClient::Conflict
1122
+ err = JSS::ConflictError
1123
+ msg_matcher = /<p>Error:(.*)(<|$)/m
1124
+ when RestClient::BadRequest
1125
+ err = JSS::BadRequestError
1126
+ msg_matcher = %r{>Bad Request</p>\n<p>(.*?)</p>\n<p>You can get technical detail}m
1127
+ when RestClient::Unauthorized
1128
+ raise
1129
+ else
1130
+ err = JSS::APIRequestError
1131
+ msg_matcher = %r{<body.*?>(.*)</body>}m
1132
+ end
1133
+ exception.http_body =~ msg_matcher
1134
+ msg = Regexp.last_match(1)
1135
+ msg ||= exception.http_body
1136
+ raise err, msg
1107
1137
  end
1108
1138
 
1109
1139
  # RestClient::Resource#delete doesn't take an HTTP payload,
@@ -1134,6 +1164,8 @@ module JSS
1134
1164
  ),
1135
1165
  &(block || @block)
1136
1166
  )
1167
+ rescue RestClient::ExceptionWithResponse => e
1168
+ handle_http_error e
1137
1169
  end # delete_with_payload
1138
1170
 
1139
1171
  end # class APIConnection
@@ -1186,6 +1218,7 @@ module JSS
1186
1218
 
1187
1219
  # aliases of module methods
1188
1220
  class << self
1221
+
1189
1222
  alias api_connection api
1190
1223
  alias connection api
1191
1224
  alias active_connection api
@@ -1196,6 +1229,7 @@ module JSS
1196
1229
  alias use_api use_api_connection
1197
1230
  alias use_connection use_api_connection
1198
1231
  alias activate_connection use_api_connection
1232
+
1199
1233
  end
1200
1234
 
1201
1235
  # create the default connection
@@ -120,6 +120,11 @@ module JSS
120
120
  #
121
121
  class APIObject
122
122
 
123
+ # Constants
124
+ ####################################
125
+
126
+ OK_INSTANTIATORS = ['make', 'fetch', 'block in fetch'].freeze
127
+
123
128
  # Class Methods
124
129
  #####################################
125
130
 
@@ -288,13 +293,12 @@ module JSS
288
293
  #
289
294
  def self.valid_id(identifier, refresh = false, api: JSS.api)
290
295
  return identifier if all_ids(refresh, api: api).include? identifier
291
- id = nil
292
296
  all_lookup_keys.keys.each do |key|
293
297
  next if key == :id
294
298
  id = map_all_ids_to(key).invert[identifier]
295
299
  return id if id
296
300
  end # do key
297
- id
301
+ nil
298
302
  end
299
303
 
300
304
  # Convert an Array of Hashes of API object data to a
@@ -426,14 +430,13 @@ module JSS
426
430
  # Retrieve an object from the API.
427
431
  #
428
432
  # This is the preferred way to retrieve existing objects from the JSS.
429
- # It's a wrapper for using APIObject.new
430
- # and avoids the confusion of using ruby's .new class method when you're not
431
- # creating a new object.
433
+ # It's a wrapper for using APIObject.new and avoids the confusion of using
434
+ # ruby's .new class method when you're not creating a new object in the JSS
432
435
  #
433
436
  # For creating new objects in the JSS, use {APIObject.make}
434
437
  #
435
438
  # @param args[Hash] The data for fetching an object, such as id: or name:
436
- # See {APIObject#initialize}
439
+ # Each APIObject subclass can define additional lookup keys for fetching.
437
440
  #
438
441
  # @return [APIObject] The ruby-instance of a JSS object
439
442
  #
@@ -456,7 +459,7 @@ module JSS
456
459
  end # each key
457
460
 
458
461
  # if we're here, we couldn't find a matching object
459
- raise NoSuchItemError, "No #{self::RSRC_OBJECT_KEY} found matching '#{arg}'"
462
+ raise NoSuchItemError, "No matching #{self::RSRC_OBJECT_KEY} found"
460
463
  end # fetch
461
464
 
462
465
  # Make a ruby instance of a not-yet-existing APIObject.
@@ -483,6 +486,15 @@ module JSS
483
486
  new args
484
487
  end
485
488
 
489
+ # Disallow direct use of ruby's .new class method for creating instances.
490
+ # Require use of .fetch or .make
491
+ def self.new(**args)
492
+ calling_method = caller_locations(1..1).first.label
493
+ # puts "Called By: #{calling_method}"
494
+ raise JSS::UnsupportedError, 'Use .fetch or .make to instantiate APIObject classes' unless OK_INSTANTIATORS.include? calling_method
495
+ super
496
+ end
497
+
486
498
  # Delete one or more API objects by jss_id without instantiating them.
487
499
  # Non-existent id's are skipped and an array of skipped ids is returned.
488
500
  #
@@ -609,30 +621,22 @@ module JSS
609
621
  #
610
622
  # @option args :name[String] the name to look up
611
623
  #
612
- # @option args :data[Hash] the JSON output of a separate {JSS::APIConnection} query
613
- # NOTE: This arg is deprecated and will be removed in a future release.
624
+ # @option args :fetch_rsrc[String] a non-standard resource for fetching
625
+ # API data e.g. to limit the data returned
614
626
  #
615
627
  #
616
628
  def initialize(args = {})
617
629
  args[:api] ||= JSS.api
618
630
  @api = args[:api]
619
- raise JSS::UnsupportedError, 'JSS::APIObject cannot be instantiated' if self.class == JSS::APIObject
620
-
621
- ####### Previously looked-up JSON data
622
- # DEPRECATED: pre-lookedup data is never used
623
- # and support for it will be going away.
624
- if args[:data]
625
-
626
- @init_data = args[:data]
631
+ raise JSS::UnsupportedError, 'JSS::APIObject is a metaclass and cannot be instantiated' if self.class == JSS::APIObject
627
632
 
628
- validate_external_init_data
629
-
630
- ###### Make a new one in the JSS, but only if we've included the Creatable module
631
- elsif args[:id] == :new
633
+ # we're making a new one in the JSS
634
+ if args[:id] == :new
632
635
  validate_init_for_creation(args)
633
636
  setup_object_for_creation(args)
634
637
  @need_to_update = true
635
- ###### Look up the data via the API
638
+
639
+ # we're instantiating an existing one in the jss
636
640
  else
637
641
  @init_data = look_up_object_data(args)
638
642
  @need_to_update = false
@@ -771,6 +775,7 @@ module JSS
771
775
  vars = instance_variables.sort
772
776
  vars.delete :@api
773
777
  vars.delete :@init_data
778
+ vars.delete :@main_subset
774
779
  vars
775
780
  end
776
781
 
@@ -871,6 +876,7 @@ module JSS
871
876
 
872
877
  # Private Instance Methods
873
878
  #####################################
879
+
874
880
  private
875
881
 
876
882
  # Raise an exception if object history is not
@@ -892,6 +898,8 @@ module JSS
892
898
  # DEPRECATED: pre-lookedup data is never used
893
899
  # and support for it will be going away.
894
900
  #
901
+ # TODO: delete this and all defined VALID_DATA_KEYS
902
+ #
895
903
  # @return [void]
896
904
  #
897
905
  def validate_external_init_data
@@ -937,21 +945,64 @@ module JSS
937
945
  # @return [Hash] The parsed JSON data for the object from the API
938
946
  #
939
947
  def look_up_object_data(args)
940
- # what lookup key are we using?
948
+ rsrc =
949
+ if args[:fetch_rsrc]
950
+ args[:fetch_rsrc]
951
+ else
952
+ # what lookup key are we using?
953
+ # TODO: simplify this, see the notes at #find_rsrc_keys
954
+ rsrc_key, lookup_value = find_rsrc_keys(args)
955
+ "#{self.class::RSRC_BASE}/#{rsrc_key}/#{lookup_value}"
956
+ end
957
+
958
+ # if needed, a non-standard object key can be passed by a subclass.
959
+ # e.g. User when loookup is by email.
960
+ args[:rsrc_object_key] ||= self.class::RSRC_OBJECT_KEY
961
+
962
+ raw_json =
963
+ if defined? self.class::USE_XML_WORKAROUND
964
+ # if we're here, the API JSON is borked, so use the XML
965
+ JSS::XMLWorkaround.data_via_xml rsrc, self.class::USE_XML_WORKAROUND, @api
966
+ else
967
+ # otherwise
968
+ @api.get_rsrc(rsrc)
969
+ end
970
+ raw_json[args[:rsrc_object_key]]
971
+ rescue RestClient::ResourceNotFound
972
+ raise NoSuchItemError, "No #{self.class::RSRC_OBJECT_KEY} found matching resource #{rsrc}"
973
+ end
974
+
975
+ # Given initialization args, determine the rsrc key and
976
+ # lookup value to be used in building the GET resource.
977
+ # E.g. for looking up something with id 345,
978
+ # return the rsrc_key :id, and the value 345, which
979
+ # can be used to create the resrouce
980
+ # '/things/id/345'
981
+ #
982
+ # CHANGE: some the new patch-related objects don't have
983
+ # GET resources by name, only id. So this method now always
984
+ # returns the id-based resource.
985
+ #
986
+ # TODO: clean up this and the above methods, since the
987
+ # id-only get rsrcs actually should simplify the code.
988
+ #
989
+ # @param args[Hash] The args passed to #initialize
990
+ #
991
+ # @return [Array] Two item array: [ rsrc_key, lookup_value]
992
+ #
993
+ def find_rsrc_keys(args)
941
994
  lookup_keys = self.class.lookup_keys
942
995
  lookup_key = (self.class.lookup_keys & args.keys)[0]
996
+
943
997
  raise JSS::MissingDataError, "Args must include a lookup key, one of: :#{lookup_keys.join(', :')}" unless lookup_key
944
- rsrc_key = self.class.rsrc_keys[lookup_key]
945
998
 
946
- rsrc = "#{self.class::RSRC_BASE}/#{rsrc_key}/#{args[lookup_key]}"
999
+ vid = self.class.valid_id args[lookup_key], :refresh
947
1000
 
948
- # if needed, a non-standard object key can be passed by a subclass.
949
- # e.g. User when loookup is by email.
950
- rsrc_object_key = args[:rsrc_object_key] ? args[:rsrc_object_key] : self.class::RSRC_OBJECT_KEY
1001
+ raise NoSuchItemError, "No #{self.class::RSRC_OBJECT_KEY} found with #{lookup_key} '#{args[lookup_key]}'" unless vid
951
1002
 
952
- return @api.get_rsrc(rsrc)[rsrc_object_key]
953
- rescue RestClient::ResourceNotFound
954
- raise NoSuchItemError, "No #{self.class::RSRC_OBJECT_KEY} found matching: #{rsrc_key}/#{args[lookup_key]}"
1003
+ [:id, vid]
1004
+ # rsrc_key = self.class.rsrc_keys[lookup_key]
1005
+ # [rsrc_key, args[lookup_key]]
955
1006
  end
956
1007
 
957
1008
  # Start examining the @init_data recieved from the API
@@ -971,7 +1022,7 @@ module JSS
971
1022
  @id = 0
972
1023
  @in_jss = false
973
1024
  else
974
- @id = @main_subset[:id]
1025
+ @id = @main_subset[:id].to_i
975
1026
  @in_jss = true
976
1027
  end
977
1028
 
@@ -1017,7 +1068,7 @@ module JSS
1017
1068
  # @return [void]
1018
1069
  #
1019
1070
  def initialize_category
1020
- parse_category if categorizable?
1071
+ parse_category if categorizable? && @in_jss
1021
1072
  end
1022
1073
 
1023
1074
  # parse site data during initialization
@@ -1145,6 +1196,7 @@ require 'jss/api_object/advanced_search'
1145
1196
  require 'jss/api_object/configuration_profile'
1146
1197
  require 'jss/api_object/extension_attribute'
1147
1198
  require 'jss/api_object/group'
1199
+ require 'jss/api_object/patch_source'
1148
1200
 
1149
1201
  ### APIObject SubClasses without SubClasses
1150
1202
  require 'jss/api_object/account'
@@ -1162,7 +1214,7 @@ require 'jss/api_object/mobile_device_application'
1162
1214
  require 'jss/api_object/netboot_server'
1163
1215
  require 'jss/api_object/network_segment'
1164
1216
  require 'jss/api_object/package'
1165
- require 'jss/api_object/patch'
1217
+ require 'jss/api_object/patch_title'
1166
1218
  require 'jss/api_object/patch_policy'
1167
1219
  require 'jss/api_object/peripheral_type'
1168
1220
  require 'jss/api_object/peripheral'