Skip to content

Commit

Permalink
Merge pull request #16 from prey/action-view-renderer
Browse files Browse the repository at this point in the history
Action view renderer & JSON support
  • Loading branch information
michelson authored May 15, 2018
2 parents 82c7c45 + bbc9a86 commit ee52ed6
Show file tree
Hide file tree
Showing 22 changed files with 262 additions and 107 deletions.
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ gem 'mysql2'
# To use a debugger
gem 'pry-byebug', group: [:development, :test]
gem 'puma'
gem 'haml'
gem 'jbuilder'

# Added at 2018-04-02 12:15:56 -0300 by michelson:
gem "capybara", "~> 2.18"
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ PolicyManager (Aka GDPR RAILS) was created with flexibility in mind to comply wi
+ JSON endpoints to handle pending policies and portability logic in order to be implemented in *client only* interfaces, ie: frontend apps like React, Vue, Backbone, you name it.

#### Portability
Portability module lets you define export options, that will generate a navigable static site with all the data you've defined in the **portability rules**
Portability module lets you define export options, that will generate a navigable static HTML site with all the data you've defined in the **portability rules** with json support too.
+ Seamless data export with configurable templates
+ Configurable Mailer templates for progress & download completion
+ Downloads images to the local filesystem in order to comply with GDPR requirements on data accessibility.
Expand Down Expand Up @@ -210,8 +210,8 @@ Export option & Portability rules will allow you to set up how and which data yo
#### Exporter:
+ **path**: where the folder will be generated, usually can be set on /tmp, this will need a pathname, like `Rails.root.join("tmp/export")`
+ **resource**: which model , ie: `User`
+ **index_template**: The first page. defaults to a simple ul li list of links tied to your rules, this expects a Pathname or a String with yout template
+ **layout**: A layout template to wrap the static site, this expects a Pathname or a String with your template
+ **index_template**: The first page. defaults to a simple ul li list of links tied to your rules, this expects a Pathname or a String with your template
+ **layout**: A layout template this expects a layout name which has to be available on your app.
+ **after_zip**: a callback to handle the zip file on the resource, something like:
```ruby
after_zip: ->(zip_path, resource){
Expand Down Expand Up @@ -245,6 +245,8 @@ PolicyManager::Config.setup do |c|
name: "exportable_data",
collection: :articles,
template: "hello, a collection will be rendered here use @collection.to_json",
json_template: "collection.json.jbuilder", # or Rails.root.join("app/views/collection.json.jbuilder")

per: 10
})

Expand Down
7 changes: 7 additions & 0 deletions app/controllers/policy_manager/exporter_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module PolicyManager
class ExporterController < ActionController::Base

include ExporterHelper

end
end
29 changes: 29 additions & 0 deletions app/helpers/policy_manager/exporter_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module PolicyManager
module ExporterHelper

def image_tag(remote_image, opts={})
begin
basename = File.basename(remote_image)
id = opts[:id] || SecureRandom.hex(10)
composed_name = [id, basename].compact.join("-")
path = "#{File.dirname(@base_path)}/#{composed_name}"
save_image(remote_image, path)
tag(:img, {src: "./#{id}-#{File.basename(URI(remote_image).path)}" }.merge(opts))
rescue => e
Config.error_notifier_method(e)
content_tag(:p, "broken image")
end
end

private

def save_image(remote_image, path)
open(URI(path).path, 'wb') do |file|
file << open(remote_image).read
end
end

end
end


5 changes: 1 addition & 4 deletions app/models/policy_manager/concerns/user_behavior.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,7 @@ def portability_member_for(rule)
self.send(rule.member)
end

def portability_collection_for(rule, page)
# if kaminari
# self.send(rule.collection).page(1)
# if will paginate
def portability_collection_for(rule, page = nil)
self.send(rule.collection).paginate(page: page, per_page: rule.per)
end

Expand Down
2 changes: 2 additions & 0 deletions lib/policy_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
require "policy_manager/exporter"
require "policy_manager/exporter/handler.rb"
require "policy_manager/exporter/view.rb"
require "policy_manager/exporter/json_view.rb"
require "policy_manager/exporter/zip_generator.rb"
require "policy_manager/exporter/paginator_renderer.rb"
require "policy_manager/exporter/json_link.rb"

require "policy_manager/config"

Expand Down
3 changes: 2 additions & 1 deletion lib/policy_manager/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ def self.setup
end

def self.error_notifier_method(error)
@@error_notifier.call(error)
puts error
@@error_notifier.call(error) unless @@error_notifier.blank?
end

def self.admin_email(user)
Expand Down
67 changes: 51 additions & 16 deletions lib/policy_manager/exporter/handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,37 +66,72 @@ def render_member(rule)
return unless resource.respond_to?(:portability_member_for)
o = resource.portability_member_for(rule)
base_dir = self.base_path.join(rule.name)
resource_path = base_dir.join("index.html")
FileUtils.mkdir_p(base_dir)
view = ExporterView.new({member: o}, {build_path: self.base_path, base_path: resource_path, template: rule.template, rule: rule})
resource_path = base_dir.join("index.html")

view = ExporterView.new({
assigns: {member: o},
build_path: self.base_path,
base_path: resource_path,
template: rule.template,
rule: rule
}).save(resource_path)

puts "saving at #{self.path.join rule.name}"
view.save(resource_path )

json = JsonExporterView.new({
assigns: {member: o},
template: rule.json_template,
folder: base_dir
}).save if rule.json_template.present?
end

def render_collection(rule)
return unless resource.respond_to?(:portability_collection_for)
o = resource.portability_collection_for(rule ,1)

o = resource.portability_collection_for(rule, 1)

base_dir = self.base_path.join(rule.name)
FileUtils.mkdir_p(base_dir)

(1..o.total_pages).to_a.each do |i|
o = resource.portability_collection_for(rule,i)
page_name = i #== 1 ? "index" : i
base_dir = self.base_path.join(rule.name)
base_dir = base_dir.join(page_name.to_s) unless page_name == 1
FileUtils.mkdir_p(base_dir)
resource_path = base_dir.join("index.html")
view = ExporterView.new({collection: o}, {build_path: self.base_path, base_path: resource_path, template: rule.template, rule: rule})
o = resource.portability_collection_for(rule, i)

page_name = i
folder_dir = page_name == 1 ? base_dir : base_dir.join(page_name.to_s)
FileUtils.mkdir_p(folder_dir)
resource_path = folder_dir.join("index.html")

view = ExporterView.new({
assigns: {collection: o} ,
build_path: self.base_path,
base_path: resource_path,
template: rule.template,
rule: rule
}).save(resource_path)


json = JsonExporterView.new({
assigns: {collection: o},
template: rule.json_template,
folder: folder_dir
}).save if rule.json_template.present?

puts "saving at #{self.path.join rule.name}"
view.save( resource_path )
end
end

def render_index
resource_path = self.base_path.join("index.html")
template = PolicyManager::Config.exporter.index_template
view = ExporterView.new({collection: PolicyManager::Config.portability_rules},
{build_path: self.base_path, base_path: resource_path, template: template})
view = ExporterView.new({
assigns: {
collection: PolicyManager::Config.portability_rules
},
build_path: self.base_path,
base_path: resource_path,
template: template
}).save( resource_path )
puts "saving at #{resource_path}"
view.save( resource_path )
end

def generate_zip
Expand Down
19 changes: 19 additions & 0 deletions lib/policy_manager/exporter/json_link.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module PolicyManager
class JsonLink

def self.render(collection = nil)
ActionController::Base.helpers.content_tag(:a, "Open as JSON", href: link(collection), target: '_blank')
end

private

def self.link(collection)
if collection.nil? || collection.current_page == 1
return "./data.json"
else
return "./../data.json"
end
end

end
end
47 changes: 47 additions & 0 deletions lib/policy_manager/exporter/json_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
require "fileutils"

module PolicyManager
class JsonExporterView
attr_accessor :template, :folder, :assigns

def initialize(vars={}, options)
self.folder = options[:folder]
self.assigns = options[:assigns]
@template = options.fetch(:template) #, self.class.template)
return self
end

def save
render_json
end

def save_json(file, data)
File.open(file, "w") do |f|
f.write(data)
end
end

def render_json
ac = PolicyManager::ExporterController.new()
options = handled_template.merge!({assigns: self.assigns })
content = ac.render_to_string(options)
save_json("#{folder}/data.json", content)
end

def handled_template
begin
if URI.parse(@template)
return {template: @template}
end
rescue URI::InvalidURIError
end

if @template.is_a?(String)
return {inline: @template}
elsif @template.is_a?(Pathname)
return {file: @template }
end
end

end
end
1 change: 1 addition & 0 deletions lib/policy_manager/exporter/paginator_renderer.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "will_paginate"
require 'will_paginate/view_helpers/action_view'
require 'will_paginate/array'

module PolicyManager
class PaginatorRenderer < WillPaginate::ActionView::LinkRenderer
Expand Down
72 changes: 24 additions & 48 deletions lib/policy_manager/exporter/view.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,19 @@ class ExporterView
include WillPaginate::ViewHelpers #if defined?(WillPaginate)
include WillPaginate::ActionView #if defined?(WillPaginate)

attr_accessor :template, :base_path
attr_accessor :template, :base_path, :assigns

def self.template
"Welcome, <%= @name %>"
end

def initialize(vars={}, options={}, date=Time.now)
# collection or member, or wathever!?
vars.each{|k, v| self.instance_variable_set("@#{k}", v)}
def initialize(options={}, date=Time.now)
@base_path = options[:base_path]
@build_path = options[:build_path]

self.assigns = options[:assigns]
index_path

@template = options.fetch(:template, self.class.template)

return self
end

def index_path
Expand All @@ -47,60 +44,39 @@ def index_path
end
end

def image_tag(remote_image, opts={})
begin
basename = File.basename(remote_image)
id = opts[:id] || SecureRandom.hex(10)
composed_name = [id, basename].compact.join("-")
path = "#{File.dirname(base_path)}/#{composed_name}"
self.save_image(remote_image, path)
tag(:img, {src: "./#{id}-#{File.basename(URI(remote_image).path)}" }.merge(opts))
rescue => e
Config.error_notifier_method(e)
content_tag(:p, "broken image")
end
end

def save_image(remote_image, path)
open(URI(path).path, 'wb') do |file|
file << open(remote_image).read
end
end

def render()
#template_layout = Tilt::ERBTemplate.new {PolicyManager::Config.exporter.layout}
context = self
#template_layout.render {
# view = Tilt::ERBTemplate.new{handled_template}
# view.render(context)
#}

render_with_layout()
end

def render_with_layout(context = self)
render_layout do
ERB.new(handled_template).result(binding)
end
end

def render_layout
layout = PolicyManager::Config.exporter.layout #File.read('views/layouts/app.html.erb')
ERB.new(layout).result(binding)
ac = PolicyManager::ExporterController.new()
options = handled_template.merge!({
assigns: self.assigns.merge!({
base_path: base_path,
build_path: @build_path,
index_path: index_path
}),
layout: PolicyManager::Config.exporter.layout
})
ac.render_to_string(options)
end


def save(file)
File.open(file, "w+") do |f|
f.write(render)
end
end

# TODO: method duplicated from json
def handled_template
begin
if URI.parse(@template)
return {template: @template}
end
rescue URI::InvalidURIError
end

if @template.is_a?(String)
@template
return {inline: @template}
elsif @template.is_a?(Pathname)
File.open(@template).read
return {file: @template }
end
end

Expand Down
Loading

0 comments on commit ee52ed6

Please sign in to comment.