Browse Source

Feature: Mobile - Improve handling template interpolation errors.

Martin Gruner 1 year ago
parent
commit
6afd8996f0

+ 1 - 1
app/graphql/gql/types/object_attribute_value_type.rb

@@ -18,7 +18,7 @@ module Gql::Types
         template:   template,
         escape:     false,
         url_encode: true,
-      ).render
+      ).render(debug_errors: false)
     end
   end
 end

+ 1 - 1
app/graphql/gql/types/signature_type.rb

@@ -21,7 +21,7 @@ module Gql::Types
         objects:  { user: context.current_user, ticket: ticket },
         template: @object.body,
         escape:   false
-      ).render
+      ).render(debug_errors: false)
     end
   end
 end

+ 1 - 1
app/graphql/gql/types/text_module_type.rb

@@ -26,7 +26,7 @@ module Gql::Types
         objects:  template_render_context.to_context_hash,
         template: @object.content,
         escape:   false
-      ).render
+      ).render(debug_errors: false)
 
     end
   end

+ 14 - 9
lib/notification_factory/renderer.rb

@@ -38,7 +38,8 @@ examples how to use
     @url_encode = url_encode
   end
 
-  def render
+  def render(debug_errors: true)
+    @debug_errors = debug_errors
     ERB.new(@template.to_s).result(binding)
   rescue Exception => e # rubocop:disable Lint/RescueException
     raise StandardError, e.message if e.is_a? SyntaxError
@@ -83,16 +84,16 @@ examples how to use
     object_name    = object_methods.shift
 
     # if no object is given, just return
-    return '#{no such object}' if object_name.blank? # rubocop:disable Lint/InterpolationCheck
+    return debug("\#{no such object}") if object_name.blank?
 
     object_refs = @objects[object_name] || @objects[object_name.to_sym]
 
     # if object is not in available objects, just return
-    return "\#{#{object_name} / no such object}" if !object_refs
+    return debug("\#{#{object_name} / no such object}") if !object_refs
 
     # if content of method is a complex datatype, just return
     if object_methods.blank? && object_refs.class != String && object_refs.class != Float && object_refs.class != Integer
-      return "\#{#{key} / no such method}"
+      return debug("\#{#{key} / no such method}")
     end
 
     previous_object_refs = ''
@@ -115,7 +116,7 @@ examples how to use
       next if method == 'value'
 
       if object_methods_s == ''
-        value = "\#{#{object_name}.#{object_methods_s} / no such method}"
+        value = debug("\#{#{object_name}.#{object_methods_s} / no such method}")
         break
       end
 
@@ -123,7 +124,7 @@ examples how to use
       if %r{\A(?<method_id>[^(]+)\((?<parameter>[^)]+)\)\z} =~ method
 
         if parameter != parameter.to_i.to_s
-          value = "\#{#{object_name}.#{object_methods_s} / invalid parameter: #{parameter}}"
+          value = debug("\#{#{object_name}.#{object_methods_s} / invalid parameter: #{parameter}}")
           break
         end
 
@@ -131,14 +132,14 @@ examples how to use
           arguments = Array(parameter.to_i)
           method    = method_id
         rescue
-          value = "\#{#{object_name}.#{object_methods_s} / #{e.message}}"
+          value = debug("\#{#{object_name}.#{object_methods_s} / #{e.message}}")
           break
         end
       end
 
       # if method exists
       if !object_refs.respond_to?(method.to_sym)
-        value = "\#{#{object_name}.#{object_methods_s} / no such method}"
+        value = debug("\#{#{object_name}.#{object_methods_s} / no such method}")
         break
       end
       begin
@@ -150,7 +151,7 @@ examples how to use
           previous_object_refs.should_clone_inline_attachments = true
         end
       rescue => e
-        value = "\#{#{object_name}.#{object_methods_s} / #{e.message}}"
+        value = debug("\#{#{object_name}.#{object_methods_s} / #{e.message}}")
         break
       end
     end
@@ -183,6 +184,10 @@ examples how to use
 
   private
 
+  def debug(message)
+    @debug_errors ? message : '-'
+  end
+
   def convert_to_timezone(value)
     return Translation.timestamp(@locale, @timezone, value) if value.instance_of?(ActiveSupport::TimeWithZone)
     return Translation.date(@locale, value) if value.instance_of?(Date)

+ 4 - 3
spec/graphql/gql/queries/current_user_spec.rb

@@ -77,7 +77,7 @@ RSpec.describe Gql::Queries::CurrentUser, type: :graphql do
         let(:object_attribute) do
           screens = { create: { 'admin.organization': { shown: true, required: false } } }
           create(:object_manager_attribute_text, name: 'UserLink', object_name: 'User', screens: screens).tap do |oa|
-            oa.data_option['linktemplate'] = 'http://test?#{user.fullname}' # rubocop:disable Lint/InterpolationCheck
+            oa.data_option['linktemplate'] = 'http://test?user=#{user.fullname};missing=#{missing.nonexisting}' # rubocop:disable Lint/InterpolationCheck
             oa.save!
             ObjectManager::Attribute.migration_execute
           end
@@ -86,12 +86,13 @@ RSpec.describe Gql::Queries::CurrentUser, type: :graphql do
           object_attribute
           create(:organization)
         end
-        # Space in fullname must be encoded as %20.
+        # Space in fullname must be encoded as %20, missing values must be '-'.
         let(:encoded_fullname) { ERB::Util.url_encode(agent.fullname) }
+        let(:rendered_link)    { "http://test?user=#{encoded_fullname};missing=-" }
 
         it 'has rendered and URL encoded objectAttributeValue data for User' do
           oas = gql.result.data['objectAttributeValues']
-          expect(oas.find { |oa| oa['attribute']['name'].eql?('UserLink') }).to include('value' => '', 'renderedLink' => "http://test?#{encoded_fullname}")
+          expect(oas.find { |oa| oa['attribute']['name'].eql?('UserLink') }).to include('value' => '', 'renderedLink' => rendered_link)
         end
       end
 

+ 3 - 3
spec/graphql/gql/queries/text_module/suggestions_spec.rb

@@ -16,7 +16,7 @@ RSpec.describe Gql::Queries::TextModule::Suggestions, authenticated_as: :agent,
       create_list(:text_module, 4).each_with_index do |tm, i|
         tm.name = "TextModuleTest#{i}"
         tm.keywords = "KeywordTextModuleTest#{i}"
-        tm.content = 't:#{ticket.customer.fullname}-c:#{customer.fullname}-u:#{user.fullname}-g:#{group.name}-o:#{organization.name}' # rubocop:disable Lint/InterpolationCheck
+        tm.content = 't:#{ticket.customer.fullname}-c:#{customer.fullname}-u:#{user.fullname}-g:#{group.name}-o:#{organization.name}-m:#{missing.nonexisting}' # rubocop:disable Lint/InterpolationCheck
         tm.groups = if i <= 2
                       groups
                     elsif i == 3
@@ -82,7 +82,7 @@ RSpec.describe Gql::Queries::TextModule::Suggestions, authenticated_as: :agent,
             'name'            => text_modules.first.name,
             'keywords'        => text_modules.first.keywords,
             'content'         => text_modules.first.content,
-            'renderedContent' => "t:#{ticket.customer.fullname}-c:#{customer.fullname}-u:#{user.fullname}-g:#{group.name}-o:#{organization.name}",
+            'renderedContent' => "t:#{ticket.customer.fullname}-c:#{customer.fullname}-u:#{user.fullname}-g:#{group.name}-o:#{organization.name}-m:-",
           }
         end
         let(:query_string) { text_modules.first.name }
@@ -99,7 +99,7 @@ RSpec.describe Gql::Queries::TextModule::Suggestions, authenticated_as: :agent,
             'name'            => text_modules.first.name,
             'keywords'        => text_modules.first.keywords,
             'content'         => text_modules.first.content,
-            'renderedContent' => "t:#{customer.fullname}-c:#{customer.fullname}-u:#{user.fullname}-g:#{group.name}-o:#{organization.name}",
+            'renderedContent' => "t:#{customer.fullname}-c:#{customer.fullname}-u:#{user.fullname}-g:#{group.name}-o:#{organization.name}-m:-",
           }
         end
         let(:query_string) { text_modules.first.name }

+ 17 - 0
spec/lib/notification_factory/renderer_spec.rb

@@ -58,6 +58,23 @@ RSpec.describe NotificationFactory::Renderer do
       end
     end
 
+    describe 'interpolation error handling' do
+      let(:renderer)   { build(:notification_factory_renderer, objects: {}, template: template) }
+      let(:template)   { '#{ ticket.title }' }
+
+      context 'with debug_errors' do
+        it 'renders an debug message' do
+          expect(renderer.render).to eq "\#{ticket / no such object}"
+        end
+      end
+
+      context 'without debug_errors' do
+        it 'renders a dash' do
+          expect(renderer.render(debug_errors: false)).to eq '-'
+        end
+      end
+    end
+
     it 'correctly renders chained object references' do
       user = User.where(firstname: 'Nicole').first
       ticket = create(:ticket, customer: user)