yext-api 0.1.5 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yext
4
+ module Api
5
+ module Powerlistings
6
+ # This controller processes Yext listing webhook callbacks.
7
+ #
8
+ # The controller will instrument the "listing.powerlistings.yext" ActiveSupport Notification.
9
+ # The params hash will include:
10
+ # * meta - the `meta` value of the webhook.
11
+ # * listing - a Yext::Api::KnowledgeApi::Powerlistings::Listing object that is the Listing
12
+ # being reported on.
13
+
14
+ # :webhooks:
15
+ # :listing:
16
+ # :endpoint: https://[your_hostname]/[your_listings_webhook_path]
17
+ # :default_version: 20161012
18
+ # :documentation: http://developer.yext.com/docs/webhooks/#operation/listingsWebhook
19
+ # :sandbox_only: false
20
+ class ListingController < Yext::Api::ApplicationController
21
+ extend Memoist
22
+
23
+ def create
24
+ listing = Yext::Api::KnowledgeApi::Powerlistings::Listing.new(listing_hash[:listing])
25
+
26
+ ActiveSupport::Notifications.instrument "listing.powerlistings.yext",
27
+ meta: listing_hash[:meta],
28
+ listing: listing do
29
+ # do your custom stuff here
30
+ end
31
+
32
+ head :ok
33
+ end
34
+
35
+ private
36
+
37
+ # rubocop:disable MethodLength
38
+
39
+ def listing_hash
40
+ params.
41
+ permit(meta: %i[eventType uuid timestamp accountId actor appSpecificAccountId],
42
+ listing: [:id,
43
+ :locationId,
44
+ :publisherId,
45
+ :status,
46
+ :additionalStatus,
47
+ :listingUrl,
48
+ :loginUrl,
49
+ :screenshotUrl,
50
+ { statusDetails: %i[code message type] },
51
+ { alternateBrands: %i[brandName listingUrl] }]).
52
+ to_hash.
53
+ with_indifferent_access
54
+ end
55
+
56
+ # rubocop:enable MethodLength
57
+
58
+ memoize :listing_hash
59
+ end
60
+ end
61
+ end
62
+ end
@@ -4,4 +4,8 @@ Yext::Api::Engine.routes.draw do
4
4
  scope :agreements, module: :agreements do
5
5
  resources :add_request, only: %i[create]
6
6
  end
7
+
8
+ scope :powerlistings, module: :powerlistings do
9
+ resources :listing, only: %i[create]
10
+ end
7
11
  end
@@ -420,9 +420,9 @@
420
420
  :documentation: http://developer.yext.com/docs/api-reference/#operation/deleteAsset
421
421
  :sandbox_only: false
422
422
  :power_listings:
423
- :module_name: PowerListings
423
+ :module_name: Powerlistings
424
424
  :objects:
425
- :publishser:
425
+ :publisher:
426
426
  :actions:
427
427
  - :action: :index
428
428
  :method: :get
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spyke"
4
+ require "memoist"
5
+ require "validation"
6
+ require "validation/validator"
7
+ require "validation/rule/not_empty"
8
+ require "yext/api"
9
+ require "yext/api/engine"
10
+ require "yext/api/concerns/enum_all"
11
+ require "yext/api/enumerations/add_request_location_mode"
12
+ require "yext/api/enumerations/add_request_status"
13
+ require "yext/api/enumerations/error_codes/agreements_errors"
14
+ require "yext/api/enumerations/error_codes/analytics_errors"
15
+ require "yext/api/enumerations/error_codes/customers_errros"
16
+ require "yext/api/enumerations/error_codes/ecl_errors"
17
+ require "yext/api/enumerations/error_codes/feedback_errors"
18
+ require "yext/api/enumerations/error_codes/general_errors"
19
+ require "yext/api/enumerations/error_codes/live_api_errors"
20
+ require "yext/api/enumerations/error_codes/locations_errors"
21
+ require "yext/api/enumerations/error_codes/optimizations_errors"
22
+ require "yext/api/enumerations/error_codes/publisher_suggestions_errors"
23
+ require "yext/api/enumerations/error_codes/reviews_errors"
24
+ require "yext/api/enumerations/error_codes/social_errors"
25
+ require "yext/api/enumerations/error_codes/subscriptions_errors"
26
+ require "yext/api/enumerations/error_codes/suppression_errors"
27
+ require "yext/api/enumerations/error_codes/users_errors"
28
+ require "yext/api/enumerations/error_codes"
29
+ require "yext/api/enumerations/listing_status"
30
+ require "yext/api/enumerations/location_type"
31
+ require "yext/api/enumerations/optimization_link_mode"
32
+ require "yext/api/enumerations/validation"
33
+ require "yext/api/utils/configuration"
34
+ require "yext/api/concerns/rate_limits"
35
+ require "yext/api/live_api"
36
+ require "yext/api/utils/api_finder"
37
+ require "yext/api/utils/middleware/api_rate_limits"
38
+ require "yext/api/utils/middleware/default_parameters"
39
+ require "yext/api/utils/middleware/response_parser"
40
+ require "yext/api/utils/middleware/uri_cleanup"
41
+ require "yext/api/concerns/faraday_connection"
42
+ require "yext/api/concerns/default_scopes"
43
+ require "yext/api/utils/api_base"
44
+ require "yext/api/concerns/account_child"
45
+ require "yext/api/concerns/account_relations"
46
+ require "yext/api/knowledge_api"
47
+ require "yext/api/knowledge_api/account_settings/account"
48
+ require "yext/api/administrative_api"
49
+ require "yext/api/administrative_api/account"
50
+ require "yext/api/live_api/location"
51
+ require "yext/api/validators/account_validator"
52
+ require "yext/api/administrative_api/add_request"
53
+ require "yext/api/administrative_api/service"
54
+ require "yext/api/knowledge_api/account_settings/role"
55
+ require "yext/api/knowledge_api/account_settings/user"
56
+ require "yext/api/knowledge_api/health_check/health"
57
+ require "yext/api/knowledge_api/knowledge_manager/category"
58
+ require "yext/api/knowledge_api/knowledge_manager/location"
59
+ require "yext/api/knowledge_api/optimization_tasks/optimization_link"
60
+ require "yext/api/knowledge_api/optimization_tasks/optimization_task"
61
+ require "yext/api/knowledge_api/powerlistings/listing"
62
+ require "yext/api/knowledge_api/powerlistings/publisher"
63
+ require_relative "../app/controllers/yext/api/application_controller"
64
+ require_relative "../app/controllers/yext/api/agreements/add_request_controller"
65
+ require_relative "../app/controllers/yext/api/powerlistings/listing_controller"
@@ -30,8 +30,6 @@ module Yext
30
30
  class Account < Yext::Api::Utils::ApiBase
31
31
  include Yext::Api::Concerns::AccountRelations
32
32
 
33
- after_save :save_account_id
34
-
35
33
  # The save action only allows the saving of the account_id and the accountName
36
34
  #
37
35
  # Furthermore, the account_id cannot be changed by the partner, but only by the customer
@@ -48,24 +46,6 @@ module Yext
48
46
 
49
47
  save_account_id
50
48
  end
51
-
52
- # rubocop:disable Naming/MethodName
53
-
54
- # Yext field names don't match the Ruby naming standard, this is the field name they use.
55
- # Because I use `account_id` in the route, I need that attribute defined. Because
56
- # Yext uses accountId, when it is set, I need to set `account_id` so they will match.
57
- def accountId=(value)
58
- super
59
- attributes[:account_id] ||= value
60
- end
61
-
62
- # rubocop:enable Naming/MethodName
63
-
64
- private
65
-
66
- def save_account_id
67
- attributes[:account_id] = accountId
68
- end
69
49
  end
70
50
  end
71
51
  end
@@ -47,6 +47,19 @@ module Yext
47
47
 
48
48
  include Yext::Api::Concerns::AccountChild
49
49
 
50
+ # rubocop:disable Naming/MethodName
51
+
52
+ # helper function to extract the affected location ID based on the locationMode
53
+ def locationId
54
+ if locationMode == Yext::Api::Enumerations::AddRequestLocationMode::NEW
55
+ newLocationId
56
+ else
57
+ existingLocationId
58
+ end
59
+ end
60
+
61
+ # rubocop:enable Naming/MethodName
62
+
50
63
  # This is a helper method to try to simplify changing the status of an AddRequest if you
51
64
  # don't have an AddRequest object.
52
65
  #
@@ -89,6 +102,8 @@ module Yext
89
102
  post
90
103
  end)
91
104
 
105
+ # After successfully creating a new add request, the object attributes will be updated/
106
+ # changed to the values of the created add request.
92
107
  def save
93
108
  if persisted?
94
109
  change_status
@@ -104,6 +119,12 @@ module Yext
104
119
  with(Yext::Api::Concerns::AccountChild.with_account_path("newlocationaddrequests")).
105
120
  where(attributes.reverse_merge(account_id: Yext::Api.configuration.param_account_id)).
106
121
  post
122
+
123
+ if Yext::Api::AdministrativeApi.last_status.between?(200, 299)
124
+ self.attributes = Yext::Api::AdministrativeApi.last_data.dup
125
+ else
126
+ self
127
+ end
107
128
  end
108
129
 
109
130
  def change_status
@@ -25,10 +25,12 @@ module Yext
25
25
  end
26
26
 
27
27
  def ensure_relation(klass)
28
- [Yext::Api::KnowledgeApi::AccountSettings::Account, Yext::Api::AdministrativeApi::Account].each do |account_class|
28
+ %w[Yext::Api::KnowledgeApi::AccountSettings::Account Yext::Api::AdministrativeApi::Account].each do |account_class_name|
29
+ account_class = account_class_name.constantize
29
30
  next if account_class.association?(klass)
30
31
 
31
32
  klass_uri = klass.instance_variable_get(:@uri)
33
+
32
34
  klass_uri ||= klass.send(:default_uri)
33
35
  helper_warnings(account_class, klass, klass_uri)
34
36
 
@@ -79,6 +81,8 @@ module Yext
79
81
  end)
80
82
 
81
83
  Yext::Api::Concerns::AccountChild.ensure_relation(self)
84
+
85
+ after_save :save_account_id
82
86
  end
83
87
 
84
88
  class_methods do
@@ -110,11 +114,31 @@ module Yext
110
114
 
111
115
  args[:account_id] ||= Yext::Api.configuration.param_account_id
112
116
 
113
- args[:id] = args.delete(:account_id) if account_scope
117
+ # account_scope means that the scope will be applied to an Account rather than a
118
+ # relation off of an Account.
119
+ args[:id] = args.delete(:account_id) if account_scope
114
120
 
115
121
  args
116
122
  end
117
123
  end
124
+
125
+ # rubocop:disable Naming/MethodName
126
+
127
+ # Yext field names don't match the Ruby naming standard, this is the field name they use.
128
+ # Because I use `account_id` in the route, I need that attribute defined. Because
129
+ # Yext uses accountId, when it is set, I need to set `account_id` so they will match.
130
+ def accountId=(value)
131
+ super
132
+ attributes[:account_id] = value
133
+ end
134
+
135
+ # rubocop:enable Naming/MethodName
136
+
137
+ private
138
+
139
+ def save_account_id
140
+ attributes[:account_id] = attributes[:accountId] if attributes.key?(:accountId)
141
+ end
118
142
  end
119
143
  end
120
144
  end
@@ -34,8 +34,36 @@ module Yext
34
34
  class_name: "Yext::Api::KnowledgeApi::OptimizationTasks::OptimizationLink",
35
35
  uri: Yext::Api::Concerns::AccountChild.with_account_path("optimizationlink")
36
36
 
37
+ # KnowledgeApi::Powerlistings
38
+ has_many :listings,
39
+ class_name: "Yext::Api::KnowledgeApi::Powerlistings::Listing",
40
+ uri: Yext::Api::Concerns::AccountChild.with_account_path("powerlistings/listings/(:id)")
41
+ has_many :publishers,
42
+ class_name: "Yext::Api::KnowledgeApi::Powerlistings::Publisher",
43
+ uri: Yext::Api::Concerns::AccountChild.with_account_path("powerlistings/publishers/(:id)")
44
+
37
45
  # LiveApi
38
46
  has_many :live_locations, class_name: "Yext::Api::LiveApi::Location"
47
+
48
+ after_save :save_account_id
49
+ end
50
+
51
+ # rubocop:disable Naming/MethodName
52
+
53
+ # Yext field names don't match the Ruby naming standard, this is the field name they use.
54
+ # Because I use `account_id` in the route, I need that attribute defined. Because
55
+ # Yext uses accountId, when it is set, I need to set `account_id` so they will match.
56
+ def accountId=(value)
57
+ super
58
+ attributes[:account_id] ||= value
59
+ end
60
+
61
+ # rubocop:enable Naming/MethodName
62
+
63
+ private
64
+
65
+ def save_account_id
66
+ attributes[:account_id] = accountId
39
67
  end
40
68
 
41
69
  class_methods do
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yext
4
+ module Api
5
+ module Enumerations
6
+ # The type of the location in an AddRequest
7
+ class AddRequestLocationMode
8
+ include Yext::Api::Concerns::EnumAll
9
+
10
+ EXISTING = "EXISTING"
11
+ NEW = "NEW"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yext
4
+ module Api
5
+ module Enumerations
6
+ # An enumeration class to contain the possible status values for a listing.
7
+ class ListingStatus
8
+ include Yext::Api::Concerns::EnumAll
9
+
10
+ WAITING_ON_YEXT = "WAITING_ON_YEXT"
11
+ WAITING_ON_CUSTOMER = "WAITING_ON_CUSTOMER"
12
+ WAITING_ON_PUBLISHER = "WAITING_ON_PUBLISHER"
13
+ LIVE = "LIVE"
14
+ UNAVAILABLE = "UNAVAILABLE"
15
+ OPTED_OUT = "OPTED_OUT"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -3,6 +3,7 @@
3
3
  module Yext
4
4
  module Api
5
5
  module Enumerations
6
+ # The possible modes to search for when looking up Optimization Links
6
7
  class OptimizationLinkMode
7
8
  include Yext::Api::Concerns::EnumAll
8
9
 
@@ -46,6 +46,30 @@ module Yext
46
46
  class Location < Yext::Api::Utils::ApiBase
47
47
  include Yext::Api::Concerns::AccountChild
48
48
 
49
+ scope(:search, lambda do |*filters|
50
+ args = scope_args true
51
+ args[:filters] = Array.wrap(filters).to_json
52
+
53
+ Yext::Api::AdministrativeApi::Account.
54
+ where(args).
55
+ with(:locationsearch).
56
+ get
57
+ end)
58
+
59
+ def save(*fields_to_update)
60
+ return super if fields_to_update.blank?
61
+
62
+ # To save only certain fields, slice those fields into a new Location so that everything
63
+ # is sent (which is only the fields we want)
64
+ location = Yext::Api::KnowledgeApi::KnowledgeManager::Location.
65
+ new(attributes.with_indifferent_access.slice(*fields_to_update))
66
+
67
+ location.id = id
68
+ location.accountId = accountId
69
+
70
+ location.save
71
+ end
72
+
49
73
  # http://developer.yext.com/docs/administrative-api/#operation/createExistingLocationAddRequest
50
74
  def add_services!(skus:, agreement_id: nil, force_review: false)
51
75
  args = { existingAccountId: account_id, existingLocationId: id }
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yext
4
+ module Api
5
+ module KnowledgeApi
6
+ module Powerlistings
7
+ # :knowledge_api:
8
+ # :powerlistings:
9
+ # :listing:
10
+ # - :action: :index
11
+ # :method: :get
12
+ # :endpoint: https://api.yext.com/v2/accounts/{accountId}/powerlistings/listings
13
+ # :path_regex: v2/accounts/[^/]+?/powerlistings/listings
14
+ # :default_version: 20161012
15
+ # :documentation: http://developer.yext.com/docs/api-reference/#operation/listListings
16
+ # :sandbox_only: false
17
+ # - :action: :opt_in
18
+ # :method: :put
19
+ # :endpoint: https://api.yext.com/v2/accounts/{accountId}/powerlistings/listings/optin
20
+ # :path_regex: v2/accounts/[^/]+?/powerlistings/listings/optin
21
+ # :default_version: 20161012
22
+ # :documentation: http://developer.yext.com/docs/api-reference/#operation/optInListings
23
+ # :sandbox_only: false
24
+ # - :action: :opt_out
25
+ # :method: :put
26
+ # :endpoint: https://api.yext.com/v2/accounts/{accountId}/powerlistings/listings/optout
27
+ # :path_regex: v2/accounts/[^/]+?/powerlistings/listings/optout
28
+ # :default_version: 20161012
29
+ # :documentation: http://developer.yext.com/docs/api-reference/#operation/optOutListings
30
+ # :sandbox_only: false
31
+ class Listing < Yext::Api::Utils::ApiBase
32
+ uri "powerlistings/#{default_uri}"
33
+
34
+ include Yext::Api::Concerns::AccountChild
35
+
36
+ # rubocop:disable Style/Lambda
37
+
38
+ scope(:opt_in!, ->(location_ids: nil, publisher_ids: nil) do
39
+ params = {}
40
+ params[:locationIds] = Array.wrap(location_ids).join(",") if location_ids.present?
41
+ params[:publisherIds] = Array.wrap(publisher_ids).join(",") if publisher_ids.present?
42
+
43
+ where(params).with(:optin).put
44
+ end)
45
+
46
+ scope(:opt_out!, ->(location_ids: nil, publisher_ids: nil) do
47
+ params = {}
48
+ params[:locationIds] = Array.wrap(location_ids) if location_ids.present?
49
+ params[:publisherIds] = Array.wrap(publisher_ids) if publisher_ids.present?
50
+
51
+ where(params).with(:optout).put
52
+ end)
53
+
54
+ # rubocop:enable Style/Lambda
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end