Skip to content

Commit

Permalink
Merge pull request #31 from gtt-project/dkastl/issue27
Browse files Browse the repository at this point in the history
Enables server-side proxy
  • Loading branch information
dkastl authored Jun 6, 2024
2 parents 3f51079 + 81f8350 commit c8a9dd7
Show file tree
Hide file tree
Showing 16 changed files with 216 additions and 84 deletions.
144 changes: 108 additions & 36 deletions app/controllers/subscription_templates_controller.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
require 'net/http'

class SubscriptionTemplatesController < ApplicationController
layout 'base'

before_action :find_project_by_project_id, except: [:index, :set_subscription_id]
before_action :get_issue_statuses, only: [:new, :create, :edit, :update]
before_action :get_issue_priorities, only: [:new, :create, :edit, :update]
before_action :get_issue_categories, only: [:new, :create, :edit, :update]
before_action :find_subscription_template, only: [:edit, :update, :destroy, :copy, :publish, :unpublish, :update_subscription_id]
before_action :check_fiware_broker_auth_token, only: [:publish, :unpublish]

accept_api_auth :set_subscription_id
before_action :authorize, except: [:set_subscription_id]
Expand All @@ -19,9 +23,7 @@ def new
@subscription_template = SubscriptionTemplate.new
end

def edit
@subscription_template = find_subscription_template
end
def edit; end

def create
r = RedmineGttFiware::SaveSubscriptionTemplate.(subscription_template_params, project: @project)
Expand All @@ -34,8 +36,6 @@ def create
end

def update
@subscription_template = find_subscription_template

r = RedmineGttFiware::SaveSubscriptionTemplate.(subscription_template_params, subscription_template: @subscription_template)
if r.subscription_template_saved?
redirect_to index_path
Expand All @@ -55,15 +55,13 @@ def update_subscription_id
end

def set_subscription_id
# Check if a valid API key is provided
unless User.current.logged?
render json: { error: 'API key is missing or invalid' }, status: :unauthorized
return
end

@subscription_template = SubscriptionTemplate.find(params[:subscription_template_id])

# Check if the user has permissions to manage subscription templates
unless User.current.allowed_to?(:manage_subscription_templates, @subscription_template.project)
render json: { error: 'You do not have permission to manage subscription templates' }, status: :forbidden
return
Expand All @@ -75,7 +73,6 @@ def set_subscription_id
end

def destroy
@subscription_template = find_subscription_template
@subscription_template.destroy
redirect_to index_path
end
Expand All @@ -89,36 +86,53 @@ def copy
end

def publish
prepare_payload

respond_to do |format|
format.js # This will render `publish.js.erb`
end
handle_publish_unpublish('publish', l(:subscription_published), 'publish.js.erb')
end

def unpublish
@subscription_template = SubscriptionTemplate.find(params[:id])
@broker_url = URI.join(@subscription_template.broker_url, "/v2/subscriptions/", @subscription_template.subscription_id).to_s
handle_publish_unpublish('unpublish', l(:subscription_unpublished), 'unpublish.js.erb')
end

respond_to do |format|
format.js # This will render `unpublish.js.erb`
private

def handle_publish_unpublish(action, success_message, js_template)
prepare_payload if action == 'publish'

if Setting.plugin_redmine_gtt_fiware['connect_via_proxy']
if handle_fiware_action(action)
render_subscription_templates(success_message)
else
render_subscription_templates(@error_message)
end
else
respond_to do |format|
format.js { render js_template }
end
end
end

private
def render_subscription_templates(message)
@subscription_templates = subscription_template_scope
respond_to do |format|
format.html {
response.headers['X-Redmine-Message'] = message
render partial: 'subscription_templates/subscription_template', collection: @subscription_templates, as: :subscription_template
}
end
end

def prepare_payload
@subscription_template = SubscriptionTemplate.find(params[:id])
@broker_url = URI.join(@subscription_template.broker_url, "/v2/subscriptions").to_s
@entity_url = URI.join(@subscription_template.broker_url, "/v2/entities").to_s
@member = Member.find(@subscription_template.member_id)

httpCustom = {
http_custom = {
url: URI.join(request.base_url, "/fiware/subscription_template/#{@subscription_template.id}/notification").to_s,
headers: {
"Content-Type": "application/json",
"X-Redmine-API-Key": User.find(@member.user_id).api_key,
"X-Redmine-GTT-Subscription-Template-URL": URI.join(request.base_url, "/fiware/subscription_template/#{@subscription_template.id}/registration/").to_s
"Content-Type" => "application/json",
"X-Redmine-API-Key" => User.find(@member.user_id).api_key,
"X-Redmine-GTT-Subscription-Template-URL" => URI.join(request.base_url, "/fiware/subscription_template/#{@subscription_template.id}/registration/").to_s
},
method: "POST",
json: {
Expand All @@ -131,10 +145,8 @@ def prepare_payload
}
}

httpCustom[:json][:attachments] = @subscription_template.attachments if @subscription_template.attachments

@json_payload = {
description: CGI::escape(@subscription_template.name),
description: CGI.escape(@subscription_template.name),
subject: {
entities: @subscription_template.entities,
condition: {
Expand All @@ -146,7 +158,7 @@ def prepare_payload
metadata: ["dateCreated", "*"],
onlyChangedAttrs: false,
covered: false,
httpCustom: httpCustom
httpCustom: http_custom
},
throttling: Setting.plugin_redmine_gtt_fiware['fiware_broker_subscription_throttling'].to_i || 1,
status: @subscription_template.status
Expand All @@ -169,14 +181,7 @@ def prepare_payload
@json_payload[:subject][:condition][:attrs] = JSON.parse(@subscription_template.attrs) if @subscription_template.attrs.present?
@json_payload[:subject][:condition][:alterationTypes] = @subscription_template.alteration_types if @subscription_template.alteration_types.present?

@json_payload = JSON.pretty_generate(@json_payload)
.gsub("\\", "\\\\\\\\") # escape backslashes
.gsub("\r", "\\r") # escape carriage return
.gsub("\n", "\\n") # escape newline
.gsub("\t", "\\t") # escape tab
.gsub("\f", "\\f") # escape form feed
.gsub("\b", "\\b") # escape backspace
.gsub("\"", "\\\"") # escape double quotes
@json_payload = JSON.generate(@json_payload)
end

def new_path
Expand All @@ -188,11 +193,11 @@ def index_path
end

def find_subscription_template
subscription_template_scope.find params[:id]
@subscription_template = subscription_template_scope.find(params[:id])
end

def find_project_by_project_id
@project = Project.find params[:project_id]
@project = Project.find(params[:project_id])
end

def subscription_template_scope
Expand All @@ -216,4 +221,71 @@ def subscription_template_params
params.require(:subscription_template).permit(:standard, :broker_url, :fiware_service, :fiware_servicepath, :subscription_id, :name, :expires, :status, :context, :entities_string, :attrs, :expression_query, :expression_georel, :expression_geometry, :expression_coords, :notify_on_metadata_change, :subject, :description, :attachments_string, :is_private, :project_id, :tracker_id, :version_id, :issue_status_id, :issue_category_id, :issue_priority_id, :member_id, :comment, :threshold_create, :threshold_create_hours, :notes, :geometry, :geometry_string, alteration_types: [])
end

def check_fiware_broker_auth_token
@fiware_broker_auth_token = request.headers['HTTP_FIWARE_BROKER_AUTH_TOKEN']
end

def handle_fiware_action(action)

if @fiware_broker_auth_token.blank?
Rails.logger.error "FIWARE Broker Auth Token is missing"
@error_message = l(:subscription_unauthorized_error)
return false
end

uri = URI(@broker_url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.scheme == 'https')

request = case action
when 'publish'
Net::HTTP::Post.new(uri.path, initheader = {
'Content-Type' => 'application/json',
'Authorization' => "Bearer #{@fiware_broker_auth_token}"
}).tap { |req| req.body = @json_payload }
when 'unpublish'
Net::HTTP::Delete.new(uri.path, initheader = {
'Authorization' => "Bearer #{@fiware_broker_auth_token}"
})
else
Rails.logger.error "Unknown action: #{action}"
@error_message = l(:general_action_error)
return false
end

response = http.request(request)

Rails.logger.info "FIWARE Broker Response Code: #{response.code}"
Rails.logger.info "FIWARE Broker Response Message: #{response.message}"

if response.code.to_i == 201 && action == 'publish'
location_header = response['location'] || response['Location']
if location_header
subscription_id = location_header.split('/').last
@subscription_template.update(subscription_id: subscription_id)
return true
else
Rails.logger.error "Location header is missing in the response"
@error_message = l(:general_action_error)
return false
end
elsif response.code.to_i == 204 && action == 'unpublish'
@subscription_template.update(subscription_id: nil)
return true
end

if response.code.to_i >= 400
Rails.logger.error "FIWARE Broker error: #{response.body}"
@error_message = l(:general_action_error)
false
else
true
end
rescue StandardError => e
Rails.logger.error "Error handling FIWARE action: #{e.message}"
Rails.logger.error e.backtrace.join("\n")
@error_message = l(:general_action_error)
false
end

end
8 changes: 7 additions & 1 deletion app/views/gtt_fiware/_settings.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,19 @@
],
@settings['ngsi_ld_format']) %>
</p>
</div>

<div class="box tabular settings">
<h3><%= l(:gtt_fiware_settings_broker) %></h3>

<p>
<%= content_tag(:label, l(:field_connect_via_proxy)) %>
<%= check_box_tag 'settings[connect_via_proxy]', 1, Setting.plugin_redmine_gtt_fiware['connect_via_proxy'] %>
</p>

<p>
<%= content_tag(:label, l(:field_fiware_broker_subscription_throttling)) %>
<%= number_field_tag 'settings[fiware_broker_subscription_throttling]',
@settings['fiware_broker_subscription_throttling'], :min => 0, :step => 1 %>
</p>

</div>
39 changes: 35 additions & 4 deletions app/views/subscription_templates/_list.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
<div class="box tabular">
<p class="min-width">
<%= content_tag :label, l(:field_subscription_auth_token) %>
<%= text_field_tag :subscription_auth_token, "", :size => 70, :placeholder => l(:field_subscription_auth_token_placeholder) %><br>
<em><%= l(:field_subscription_auth_token_hint) %></em>
<%= text_field_tag :subscription_auth_token, "", :size => 60, :placeholder => l(:field_subscription_auth_token_placeholder) %>
<%= button_tag l(:button_connect_via_proxy_text), type: 'button', id: 'connect_via_proxy_status' %>
<br><small><i><%= l(:field_subscription_auth_token_hint).html_safe %></i></small>
</p>
</div>

Expand All @@ -26,9 +27,39 @@
</tbody>
</table>

<div id="temporaryNotification" class="temporaryNotification">
</div>
<% if Setting.plugin_redmine_gtt_fiware['connect_via_proxy'] %>
<script>
document.addEventListener("DOMContentLoaded", function() {
if (Rails) {
document.addEventListener('ajax:beforeSend', function(event) {
var xhr = event.detail[0];
xhr.setRequestHeader('FIWARE-Broker-Auth-Token', document.getElementById('subscription_auth_token').value);
});

document.addEventListener('ajax:success', function(event) {
var detail = event.detail;
var data = detail[0], status = detail[1], xhr = detail[2];

// Update the subscription templates list with the response data
document.getElementById('subscriptionTemplateList').innerHTML = xhr.responseText;
showNotification(xhr.getResponseHeader('X-Redmine-Message'));
});

document.addEventListener('ajax:error', function(event) {
var detail = event.detail;
var data = detail[0], status = detail[1], xhr = detail[2];

console.error("Error during publish:", data);
showNotification(xhr.getResponseHeader('X-Redmine-Message'));
});
}

document.getElementById('connect_via_proxy_status').style.backgroundColor = '#d3ffc6';
});
</script>
<% end %>

<div id="temporaryNotification" class="temporaryNotification"></div>
<% else %>
<p class="nodata"><%= l :label_no_data %></p>
<% end %>
39 changes: 29 additions & 10 deletions app/views/subscription_templates/_subscription_template.html.erb
Original file line number Diff line number Diff line change
@@ -1,17 +1,36 @@
<tr>
<td class="text"><%= link_to subscription_template.name, edit_project_subscription_template_path(subscription_template.project, subscription_template) %></td>
<td><%= textilizable subscription_template.standard %></td>
<td class="text"><code><%= subscription_template.broker_url %></code></td>
<td><%= textilizable subscription_template.issue_status.name %></td>
<td><%= textilizable subscription_template.tracker.name %></td>
<td><%= textilizable subscription_template.status %></td>
<td><%= link_to l(:link_to_copy), copy_project_subscription_template_path(@project, subscription_template), remote: true, method: :get, class: 'copy-command-link icon icon-copy', title: l(:link_to_copy_hint) %></td>
<td class="text">
<%= link_to subscription_template.name, edit_project_subscription_template_path(subscription_template.project, subscription_template) %>
</td>
<td>
<%= textilizable subscription_template.standard %>
</td>
<td class="text">
<code><%= subscription_template.broker_url %></code>
</td>
<td>
<%= textilizable subscription_template.issue_status.name %>
</td>
<td>
<%= textilizable subscription_template.tracker.name %>
</td>
<td>
<%= textilizable subscription_template.status %>
</td>
<td>
<%= link_to l(:link_to_copy), copy_project_subscription_template_path(@project, subscription_template),
method: :get, remote: true,class: 'copy-command-link icon icon-copy', title: l(:link_to_copy_hint) %>
</td>
<td>
<% if subscription_template.subscription_id.present? %>
<%= link_to l(:link_to_unpublish), unpublish_project_subscription_template_path(@project, subscription_template), method: :get, remote: true, class: 'icon icon-shared' %>
<%= link_to l(:link_to_unpublish), unpublish_project_subscription_template_path(@project, subscription_template),
method: :get, remote: true, class: 'icon icon-shared' %>
<% else %>
<%= link_to l(:link_to_publish), publish_project_subscription_template_path(@project, subscription_template), method: :get, remote: true, class: 'icon icon-shared' %>
<%= link_to l(:link_to_publish), publish_project_subscription_template_path(@project, subscription_template),
method: :get, remote: true, class: 'icon icon-shared' %>
<% end %>
</td>
<td><%= delete_link(subscription_template.project ? project_subscription_template_path(subscription_template.project, subscription_template) : subscription_template_path(subscription_template)) %>
<td>
<%= delete_link(subscription_template.project ? project_subscription_template_path(subscription_template.project, subscription_template) : subscription_template_path(subscription_template)) %>
</td>
</tr>
16 changes: 0 additions & 16 deletions app/views/subscription_templates/publish.js.erb
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,6 @@ var requestOptions = {
redirect: 'follow'
};

function showNotification(message) {
// Get the notification box
var notification = document.getElementById('temporaryNotification');

// Change the text of the notification box
notification.textContent = message;

// Show the notification box
notification.classList.add('visible');

// Hide the notification box after 3 seconds
setTimeout(function() {
notification.classList.remove('visible');
}, 3000);
}

// Send the POST request
fetch('<%= @broker_url %>', requestOptions)
.then(response => {
Expand Down
Loading

0 comments on commit c8a9dd7

Please sign in to comment.