mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-16 23:30:12 +01:00
Extract rendering to helper method. Shift filename sanitization to controller.
This commit is contained in:
parent
7801364662
commit
ccf13418f4
12 changed files with 105 additions and 78 deletions
|
|
@ -31,7 +31,7 @@ class DataController < ApplicationController
|
||||||
#save file for later
|
#save file for later
|
||||||
begin
|
begin
|
||||||
uploaded_file = params[:file]
|
uploaded_file = params[:file]
|
||||||
@filename = Tracks::Utils.sanitize_filename(uploaded_file.original_filename)
|
@filename = sanitize_filename(uploaded_file.original_filename)
|
||||||
path_and_file = Rails.root.join('public', 'uploads', 'csv', @filename)
|
path_and_file = Rails.root.join('public', 'uploads', 'csv', @filename)
|
||||||
File.open(path_and_file, "wb") { |f| f.write(uploaded_file.read) }
|
File.open(path_and_file, "wb") { |f| f.write(uploaded_file.read) }
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
|
|
@ -57,7 +57,7 @@ class DataController < ApplicationController
|
||||||
|
|
||||||
def csv_import
|
def csv_import
|
||||||
begin
|
begin
|
||||||
filename = Tracks::Utils.sanitize_filename(params[:file])
|
filename = sanitize_filename(params[:file])
|
||||||
path_and_file = Rails.root.join('public', 'uploads', 'csv', filename)
|
path_and_file = Rails.root.join('public', 'uploads', 'csv', filename)
|
||||||
case params[:import_to]
|
case params[:import_to]
|
||||||
when 'projects'
|
when 'projects'
|
||||||
|
|
@ -209,4 +209,9 @@ class DataController < ApplicationController
|
||||||
raise "YAML loading is disabled"
|
raise "YAML loading is disabled"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def sanitize_filename(filename)
|
||||||
|
filename.gsub(/[^0-9A-z.\-]/, '_')
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
module NotesHelper
|
module NotesHelper
|
||||||
def truncated_note(note, characters = 50)
|
def truncated_note(note, characters = 50)
|
||||||
Tracks::Utils.render_text(truncate(note.body, :length => characters, :omission => "..."))
|
render_text(truncate(note.body, :length => characters, :omission => "..."))
|
||||||
end
|
end
|
||||||
|
|
||||||
def rendered_note(note)
|
def rendered_note(note)
|
||||||
Tracks::Utils.render_text(note.body)
|
render_text(note.body)
|
||||||
end
|
end
|
||||||
|
|
||||||
def link_to_delete_note(note, descriptor = sanitize(note.id.to_s))
|
def link_to_delete_note(note, descriptor = sanitize(note.id.to_s))
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ module ProjectsHelper
|
||||||
|
|
||||||
def project_summary(project)
|
def project_summary(project)
|
||||||
project_description = ''
|
project_description = ''
|
||||||
project_description += Tracks::Utils.render_text( project.description ) if project.description.present?
|
project_description += render_text( project.description ) if project.description.present?
|
||||||
project_description += content_tag(:p,
|
project_description += content_tag(:p,
|
||||||
"#{count_undone_todos_phrase(p)}. #{t('projects.project_state', :state => project.state)}".html_safe
|
"#{count_undone_todos_phrase(p)}. #{t('projects.project_state', :state => project.state)}".html_safe
|
||||||
)
|
)
|
||||||
|
|
|
||||||
41
app/helpers/rendering_helper.rb
Normal file
41
app/helpers/rendering_helper.rb
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
module RenderingHelper
|
||||||
|
AUTO_LINK_MESSAGE_RE = %r{message://<[^>]+>} unless const_defined?(:AUTO_LINK_MESSAGE_RE)
|
||||||
|
|
||||||
|
# Converts message:// links to href. This URL scheme is used on Mac OS X
|
||||||
|
# to link to a mail message in Mail.app.
|
||||||
|
def auto_link_message(text)
|
||||||
|
text.gsub(AUTO_LINK_MESSAGE_RE) do
|
||||||
|
href = $&
|
||||||
|
left = $`
|
||||||
|
right = $'
|
||||||
|
# detect already linked URLs and URLs in the middle of a tag
|
||||||
|
if left =~ /<[^>]+$/ && right =~ /^[^>]*>/
|
||||||
|
# do not change string; URL is alreay linked
|
||||||
|
href
|
||||||
|
else
|
||||||
|
content_tag(:a, h(href), :href => h(href))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_text(text)
|
||||||
|
rendered = auto_link_message(text)
|
||||||
|
rendered = textile(rendered)
|
||||||
|
rendered = auto_link(rendered, link: :urls, html: {target: '_blank'})
|
||||||
|
|
||||||
|
relaxed_config = Sanitize::Config::RELAXED
|
||||||
|
config = relaxed_config
|
||||||
|
|
||||||
|
# add onenote and message protocols, allow a target
|
||||||
|
a_href_config = relaxed_config[:protocols]['a']['href'] + %w(onenote message)
|
||||||
|
a_attributes = relaxed_config[:attributes]['a'] + ['target']
|
||||||
|
config = Sanitize::Config.merge(config, protocols: {'a' => {'href' => a_href_config}}, :attributes => {'a' => a_attributes})
|
||||||
|
|
||||||
|
rendered = Sanitize.fragment(rendered, config)
|
||||||
|
return rendered.html_safe
|
||||||
|
end
|
||||||
|
|
||||||
|
def textile(text)
|
||||||
|
RedCloth.new(text).to_html
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -220,7 +220,7 @@ module TodosHelper
|
||||||
notes = content_tag(:div, {
|
notes = content_tag(:div, {
|
||||||
:class => "todo_notes",
|
:class => "todo_notes",
|
||||||
:id => dom_id(todo, 'notes'),
|
:id => dom_id(todo, 'notes'),
|
||||||
:style => "display:none"}) { raw todo.rendered_notes }
|
:style => "display:none"}) { raw render_text(todo.notes) }
|
||||||
return link+notes
|
return link+notes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -429,7 +429,7 @@ module TodosHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def feed_content_for_todo(todo)
|
def feed_content_for_todo(todo)
|
||||||
item_notes = todo.notes ? todo.rendered_notes : ''
|
item_notes = todo.notes ? render_text(todo.notes) : ''
|
||||||
due = todo.due ? content_tag(:div, t('todos.feeds.due', :date => format_date(todo.due))) : ''
|
due = todo.due ? content_tag(:div, t('todos.feeds.due', :date => format_date(todo.due))) : ''
|
||||||
done = todo.completed? ? content_tag(:div, t('todos.feeds.completed', :date => format_date(todo.completed_at))) : ''
|
done = todo.completed? ? content_tag(:div, t('todos.feeds.completed', :date => format_date(todo.completed_at))) : ''
|
||||||
context_link = link_to(context_url(todo.context), todo.context.name)
|
context_link = link_to(context_url(todo.context), todo.context.name)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ class Todo < ActiveRecord::Base
|
||||||
MAX_DESCRIPTION_LENGTH = 300
|
MAX_DESCRIPTION_LENGTH = 300
|
||||||
MAX_NOTES_LENGTH = 60000
|
MAX_NOTES_LENGTH = 60000
|
||||||
|
|
||||||
before_save :render_note
|
|
||||||
after_save :save_predecessors
|
after_save :save_predecessors
|
||||||
|
|
||||||
# associations
|
# associations
|
||||||
|
|
@ -378,14 +377,6 @@ class Todo < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_note
|
|
||||||
unless self.notes.nil?
|
|
||||||
self.rendered_notes = Tracks::Utils.render_text(self.notes)
|
|
||||||
else
|
|
||||||
self.rendered_notes = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.import(filename, params, user)
|
def self.import(filename, params, user)
|
||||||
default_context = user.contexts.order('id').first
|
default_context = user.contexts.order('id').first
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
<%= link_to_edit_project(project, t('projects.edit_project_settings')) %>
|
<%= link_to_edit_project(project, t('projects.edit_project_settings')) %>
|
||||||
</div>
|
</div>
|
||||||
<% if project.description.present? -%>
|
<% if project.description.present? -%>
|
||||||
<div class="project_description"><%= Tracks::Utils.render_text(project.description) %></div>
|
<div class="project_description"><%= render_text(project.description) %></div>
|
||||||
<% end -%>
|
<% end -%>
|
||||||
</div>
|
</div>
|
||||||
<div id="<%= dom_id(project, 'edit') %>" class="edit-form" style="display:none;">
|
<div id="<%= dom_id(project, 'edit') %>" class="edit-form" style="display:none;">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<h2><%= raw "#{t('todos.next_action_description')} (#{link_to(t('common.go_back'), @return_path)}" %>)</h2>
|
<h2><%= raw "#{t('todos.next_action_description')} (#{link_to(t('common.go_back'), @return_path)}" %>)</h2>
|
||||||
<%= link_to @todo.description, todo_path(@todo, :format => 'm') -%>
|
<%= link_to @todo.description, todo_path(@todo, :format => 'm') -%>
|
||||||
<h2><%= t('todos.notes') %></h2>
|
<h2><%= t('todos.notes') %></h2>
|
||||||
<%= Tracks::Utils.render_text(@todo.notes) %>
|
<%= render_text(@todo.notes) %>
|
||||||
<%= link_to t('common.back'), @return_path %>
|
<%= link_to t('common.back'), @return_path %>
|
||||||
|
|
|
||||||
15
db/migrate/20150413194512_remove_rendered_notes.rb
Normal file
15
db/migrate/20150413194512_remove_rendered_notes.rb
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
class RemoveRenderedNotes < ActiveRecord::Migration
|
||||||
|
def self.up
|
||||||
|
remove_column :todos, 'rendered_notes'
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
add_column :todos, 'rendered_notes', :text
|
||||||
|
|
||||||
|
# Call save on each todo to force generation of rendered_notes
|
||||||
|
# Copied from 20120412072508_add_rendered_notes
|
||||||
|
say "Rendering todo notes..."
|
||||||
|
Todo.all.each{ |todo| todo.save(validate: false) }
|
||||||
|
say "Finished rendering todo notes."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
require 'redcloth'
|
|
||||||
|
|
||||||
module Tracks
|
|
||||||
|
|
||||||
class Utils
|
|
||||||
AUTO_LINK_MESSAGE_RE = %r{message://<[^>]+>} unless const_defined?(:AUTO_LINK_MESSAGE_RE)
|
|
||||||
|
|
||||||
# Converts message:// links to href. This URL scheme is used on Mac OS X
|
|
||||||
# to link to a mail message in Mail.app.
|
|
||||||
def self.auto_link_message(text)
|
|
||||||
text.gsub(AUTO_LINK_MESSAGE_RE) do
|
|
||||||
href = $&
|
|
||||||
left = $`
|
|
||||||
right = $'
|
|
||||||
# detect already linked URLs and URLs in the middle of a tag
|
|
||||||
if left =~ /<[^>]+$/ && right =~ /^[^>]*>/
|
|
||||||
# do not change string; URL is alreay linked
|
|
||||||
href
|
|
||||||
else
|
|
||||||
content = helpers.content_tag(:a, h(href), :href => h(href))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.render_text(text)
|
|
||||||
rendered = auto_link_message(text)
|
|
||||||
rendered = textile(rendered)
|
|
||||||
rendered = helpers.auto_link(rendered, :link => :urls, :html => {:target => '_blank'})
|
|
||||||
|
|
||||||
relaxed_config = Sanitize::Config::RELAXED
|
|
||||||
config = relaxed_config
|
|
||||||
|
|
||||||
# add onenote and message protocols, allow a target
|
|
||||||
a_href_config = relaxed_config[:protocols]['a']['href'] + %w(onenote message)
|
|
||||||
a_attributes = relaxed_config[:attributes]['a'] + ['target']
|
|
||||||
config = Sanitize::Config.merge(config, :protocols => {'a' => {'href' => a_href_config}}, :attributes => {'a' => a_attributes})
|
|
||||||
|
|
||||||
rendered = Sanitize.fragment(rendered, config)
|
|
||||||
return rendered.html_safe
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.textile(text)
|
|
||||||
RedCloth.new(text).to_html
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.sanitize_filename(filename)
|
|
||||||
filename.gsub(/[^0-9A-z.\-]/, '_')
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def self.helpers
|
|
||||||
ActionController::Base.helpers
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
35
test/helpers/rendering_helper_test.rb
Normal file
35
test/helpers/rendering_helper_test.rb
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
class RenderingHelperTest < ActionView::TestCase
|
||||||
|
include RenderingHelper
|
||||||
|
|
||||||
|
test "auto_link_message" do
|
||||||
|
html = "This is a sample with a message - message://<123456789>. There we go."
|
||||||
|
rendered_html = auto_link_message(html)
|
||||||
|
assert(
|
||||||
|
rendered_html.include?(%|<a href="message://<123456789>">message://<123456789></a>|),
|
||||||
|
"Message was not correctly rendered. Rendered message:\n#{rendered_html}"
|
||||||
|
)
|
||||||
|
|
||||||
|
html = %|This message is already tagged: <a href="message://<12345>">Call bob</a>."|
|
||||||
|
rendered_html = auto_link_message(html)
|
||||||
|
assert_equal(html, rendered_html)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "textile" do
|
||||||
|
raw_textile = "This should end up *strong*."
|
||||||
|
rendered_textile = textile(raw_textile)
|
||||||
|
assert_equal("<p>This should end up <strong>strong</strong>.</p>", rendered_textile)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "render_text" do
|
||||||
|
simple_textile = render_text("This is *strong*.")
|
||||||
|
assert_equal("<p>This is <strong>strong</strong>.</p>", simple_textile)
|
||||||
|
|
||||||
|
autolink_message = render_text("Call message://<123>.")
|
||||||
|
assert_equal(%|<p>Call <a href="message://<123>">message://<123></a>.</p>|, autolink_message)
|
||||||
|
|
||||||
|
onenote_links = render_text(%|Link to onenote <a href="onenote://foobar">here</a>.|)
|
||||||
|
assert_equal(%|<p>Link to onenote <a href="onenote://foobar">here</a>.</p>|, onenote_links)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -532,14 +532,12 @@ class TodoTest < ActiveSupport::TestCase
|
||||||
todo = user.todos.create(:description => "test", :context => @completed.context)
|
todo = user.todos.create(:description => "test", :context => @completed.context)
|
||||||
|
|
||||||
assert_nil todo.notes
|
assert_nil todo.notes
|
||||||
assert_nil todo.rendered_notes
|
|
||||||
|
|
||||||
todo.notes = "*test*"
|
todo.notes = "*test*"
|
||||||
todo.save!
|
todo.save!
|
||||||
todo.reload
|
todo.reload
|
||||||
|
|
||||||
assert_equal "*test*", todo.notes
|
assert_equal "*test*", todo.notes
|
||||||
assert_equal "<p><strong>test</strong></p>", todo.rendered_notes
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_attachments_are_removed_after_delete
|
def test_attachments_are_removed_after_delete
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue