Skip to content

Commit

Permalink
Add Registrant API contact update action
Browse files Browse the repository at this point in the history
Closes #849
  • Loading branch information
Artur Beljajev committed Sep 19, 2018
1 parent 3f1ef21 commit da7cc2f
Show file tree
Hide file tree
Showing 41 changed files with 1,232 additions and 58 deletions.
10 changes: 10 additions & 0 deletions app/controllers/api/v1/registrant/base_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ class BaseController < ActionController::API
before_action :authenticate
before_action :set_paper_trail_whodunnit

rescue_from ActiveRecord::RecordNotFound, with: :show_not_found_error
rescue_from ActiveRecord::RecordInvalid, with: :show_invalid_record_error
rescue_from(ActionController::ParameterMissing) do |parameter_missing_exception|
error = {}
error[parameter_missing_exception.param] = ['parameter is required']
Expand Down Expand Up @@ -49,6 +51,14 @@ def authenticate
def set_paper_trail_whodunnit
::PaperTrail.whodunnit = current_registrant_user.id_role_username
end

def show_not_found_error
render json: { errors: [{ base: ['Not found'] }] }, status: :not_found
end

def show_invalid_record_error(exception)
render json: { errors: exception.record.errors }, status: :bad_request
end
end
end
end
Expand Down
57 changes: 57 additions & 0 deletions app/controllers/api/v1/registrant/contacts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,63 @@ def show
end
end

def update
contact = @contacts_pool.find_by!(uuid: params[:uuid])
contact.name = params[:name] if params[:name].present?
contact.email = params[:email] if params[:email].present?
contact.phone = params[:phone] if params[:phone].present?

if Setting.address_processing && params[:address]
address = Contact::Address.new(params[:address][:street],
params[:address][:zip],
params[:address][:city],
params[:address][:state],
params[:address][:country_code])
contact.address = address
end

if !Setting.address_processing && params[:address]
error_msg = 'Address processing is disabled and therefore cannot be updated'
render json: { errors: [{ address: [error_msg] }] }, status: :bad_request and return
end

if ENV['fax_enabled'] == 'true'
contact.fax = params[:fax] if params[:fax].present?
end

if ENV['fax_enabled'] != 'true' && params[:fax]
error_msg = 'Fax processing is disabled and therefore cannot be updated'
render json: { errors: [{ address: [error_msg] }] }, status: :bad_request and return
end

contact.transaction do
contact.save!
action = current_registrant_user.actions.create!(contact: contact, operation: :update)
contact.registrar.notify(action)
end

render json: { id: contact.uuid,
name: contact.name,
code: contact.code,
ident: {
code: contact.ident,
type: contact.ident_type,
country_code: contact.ident_country_code,
},
email: contact.email,
phone: contact.phone,
fax: contact.fax,
address: {
street: contact.street,
zip: contact.zip,
city: contact.city,
state: contact.state,
country_code: contact.country_code,
},
auth_info: contact.auth_info,
statuses: contact.statuses }
end

private

def set_contacts_pool
Expand Down
85 changes: 85 additions & 0 deletions app/controllers/registrant/contacts_controller.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
class Registrant::ContactsController < RegistrantController
helper_method :domain_ids
helper_method :domain
helper_method :fax_enabled?
skip_authorization_check only: %i[edit update]

def show
@contact = Contact.where(id: contacts).find_by(id: params[:id])

authorize! :read, @contact
end

def edit
@contact = Contact.where(id: contacts).find(params[:id])
end

def update
@contact = Contact.where(id: contacts).find(params[:id])
@contact.attributes = contact_params
response = update_contact_via_api(@contact.uuid)
updated = response.is_a?(Net::HTTPSuccess)

if updated
redirect_to registrant_domain_contact_url(domain, @contact), notice: t('.updated')
else
parsed_response = JSON.parse(response.body, symbolize_names: true)
@errors = parsed_response[:errors]
render :edit
end
end

private

def contacts
Expand Down Expand Up @@ -41,4 +62,68 @@ def current_user_domains
current_registrant_user.domains
end
end

def contact_params
permitted = %i[
name
email
phone
]

permitted << :fax if fax_enabled?
permitted += %i[street zip city state country_code] if Contact.address_processing?
params.require(:contact).permit(*permitted)
end

def access_token
uri = URI.parse("#{ENV['registrant_api_url']}/v1/registrant/auth/eid")
request = Net::HTTP::Post.new(uri)
request.form_data = access_token_request_params

response = Net::HTTP.start(uri.hostname, uri.port) do |http|
http.request(request)
end

json_doc = JSON.parse(response.body, symbolize_names: true)
json_doc[:access_token]
end

def access_token_request_params
{ ident: current_registrant_user.ident,
first_name: current_registrant_user.first_name,
last_name: current_registrant_user.last_name }
end

def fax_enabled?
ENV['fax_enabled'] == 'true'
end

def contact_update_api_params
params = contact_params
params = normalize_address_attributes_for_api(params) if Contact.address_processing?
params
end

def normalize_address_attributes_for_api(params)
normalized = params

Contact.address_attribute_names.each do |attr|
attr = attr.to_sym
normalized["address[#{attr}]"] = params[attr]
normalized.delete(attr)
end

normalized
end

def update_contact_via_api(uuid)
uri = URI.parse("#{ENV['registrant_api_url']}/v1/registrant/contacts/#{uuid}")
request = Net::HTTP::Patch.new(uri)
request['Authorization'] = "Bearer #{access_token}"
request.form_data = contact_update_api_params

Net::HTTP.start(uri.hostname, uri.port) do |http|
http.request(request)
end
end
end
17 changes: 17 additions & 0 deletions app/models/action.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class Action < ActiveRecord::Base
belongs_to :user
belongs_to :contact

validates :operation, inclusion: { in: proc { |action| action.class.valid_operations } }

class << self
def valid_operations
%w[update]
end
end

def notification_key
raise 'Action object is missing' unless contact
"contact_#{operation}".to_sym
end
end
16 changes: 16 additions & 0 deletions app/models/contact.rb
Original file line number Diff line number Diff line change
Expand Up @@ -526,4 +526,20 @@ def domain_names_with_roles

domain_names
end

def address=(address)
self.street = address.street
self.zip = address.zip
self.city = address.city
self.state = address.state
self.country_code = address.country_code
end

def address
Address.new(street, zip, city, state, country_code)
end

def managed_by?(registrant_user)
ident == registrant_user.ident
end
end
25 changes: 25 additions & 0 deletions app/models/contact/address.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class Contact
class Address
attr_reader :street
attr_reader :zip
attr_reader :city
attr_reader :state
attr_reader :country_code

def initialize(street, zip, city, state, country_code)
@street = street
@zip = zip
@city = city
@state = state
@country_code = country_code
end

def ==(other)
(street == other.street) &&
(zip == other.zip) &&
(city == other.city) &&
(state == other.state) &&
(country_code == other.country_code)
end
end
end
4 changes: 3 additions & 1 deletion app/models/notification.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
class Notification < ActiveRecord::Base
include Versions # version/notification_version.rb

belongs_to :registrar
belongs_to :action

scope :unread, -> { where(read: false) }

Expand All @@ -20,7 +22,7 @@ def unread?

# Needed for EPP log
def name
"-"
''
end

private
Expand Down
8 changes: 8 additions & 0 deletions app/models/registrant_user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ def to_s
username
end

def first_name
username.split.first
end

def last_name
username.split.second
end

class << self
def find_or_create_by_idc_data(idc_data, issuer_organization)
return false if idc_data.blank?
Expand Down
5 changes: 5 additions & 0 deletions app/models/registrar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ def effective_vat_rate
end
end

def notify(action)
text = I18n.t("notifications.texts.#{action.notification_key}", contact: action.contact.code)
notifications.create!(text: text)
end

private

def set_defaults
Expand Down
2 changes: 2 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
class User < ActiveRecord::Base
include Versions # version/user_version.rb

has_many :actions, dependent: :restrict_with_exception

attr_accessor :phone

def id_role_username
Expand Down
9 changes: 9 additions & 0 deletions app/views/epp/poll/_action.xml.builder
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
builder.extension do
builder.tag!('changePoll:changeData',
'xmlns:changePoll' => 'https://epp.tld.ee/schema/changePoll-1.0.xsd') do
builder.tag!('changePoll:operation', action.operation)
builder.tag!('changePoll:date', action.created_at.utc.xmlschema)
builder.tag!('changePoll:svTRID', action.id)
builder.tag!('changePoll:who', action.user)
end
end
72 changes: 72 additions & 0 deletions app/views/epp/poll/_contact.xml.builder
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
builder.resData do
builder.tag!('contact:infData', 'xmlns:contact' => 'https://epp.tld.ee/schema/contact-ee-1.1.xsd') do
builder.tag!('contact:id', contact.code)
builder.tag!('contact:roid', contact.roid)

contact.statuses.each do |status|
builder.tag!('contact:status', s: status)
end

builder.tag!('contact:postalInfo', type: 'int') do
builder.tag!('contact:name', contact.name)
if can? :view_full_info, contact, @password
builder.tag!('contact:org', contact.org_name) if contact.org_name.present?

if address_processing
builder.tag!('contact:addr') do
builder.tag!('contact:street', contact.street)
builder.tag!('contact:city', contact.city)
builder.tag!('contact:sp', contact.state)
builder.tag!('contact:pc', contact.zip)
builder.tag!('contact:cc', contact.country_code)
end
end

else
builder.tag!('contact:org', 'No access')

if address_processing
builder.tag!('contact:addr') do
builder.tag!('contact:street', 'No access')
builder.tag!('contact:city', 'No access')
builder.tag!('contact:sp', 'No access')
builder.tag!('contact:pc', 'No access')
builder.tag!('contact:cc', 'No access')
end
end

end
end

if can? :view_full_info, contact, @password
builder.tag!('contact:voice', contact.phone)
builder.tag!('contact:fax', contact.fax) if contact.fax.present?
builder.tag!('contact:email', contact.email)
else
builder.tag!('contact:voice', 'No access')
builder.tag!('contact:fax', 'No access')
builder.tag!('contact:email', 'No access')
end

builder.tag!('contact:clID', contact.registrar.try(:code))

builder.tag!('contact:crID', contact.cr_id)
builder.tag!('contact:crDate', contact.created_at.try(:iso8601))

if contact.updated_at > contact.created_at
upID = contact.updator.try(:registrar)
upID = upID.code if upID.present? # Did updator return a kind of User that has a registrar?
builder.tag!('contact:upID', upID) if upID.present? # optional upID
builder.tag!('contact:upDate', contact.updated_at.try(:iso8601))
end
if can? :view_password, contact, @password
builder.tag!('contact:authInfo') do
builder.tag!('contact:pw', contact.auth_info)
end
else
builder.tag!('contact:authInfo') do
builder.tag!('contact:pw', 'No access')
end
end
end
end
Loading

0 comments on commit da7cc2f

Please sign in to comment.