diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index e48cbcaba..114509d29 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1753,6 +1753,7 @@ Style/SoleNestedConditional:
- 'app/models/version.rb'
- 'app/models/watcher.rb'
- 'app/models/wiki_page.rb'
+ - 'app/models/wiki_annotate.rb'
- 'lib/redmine/core_ext/active_record.rb'
# Cop supports --auto-correct.
diff --git a/app/models/anonymous_user.rb b/app/models/anonymous_user.rb
new file mode 100644
index 000000000..d1b215b8e
--- /dev/null
+++ b/app/models/anonymous_user.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+class AnonymousUser < User
+ validate :validate_anonymous_uniqueness, :on => :create
+
+ self.valid_statuses = [STATUS_ANONYMOUS]
+
+ def validate_anonymous_uniqueness
+ # There should be only one AnonymousUser in the database
+ errors.add :base, 'An anonymous user already exists.' if AnonymousUser.unscoped.exists?
+ end
+
+ def available_custom_fields
+ []
+ end
+
+ # Overrides a few properties
+ def logged?; false end
+ def admin; false end
+ def name(*args); I18n.t(:label_user_anonymous) end
+ def mail=(*args); nil end
+ def mail; nil end
+ def time_zone; nil end
+ def rss_key; nil end
+
+ def pref
+ UserPreference.new(:user => self)
+ end
+
+ # Returns the user's bult-in role
+ def builtin_role
+ @builtin_role ||= Role.anonymous
+ end
+
+ def membership(*args)
+ nil
+ end
+
+ def member_of?(*args)
+ false
+ end
+
+ # Anonymous user can not be destroyed
+ def destroy
+ false
+ end
+
+ protected
+
+ def instantiate_email_address
+ end
+end
diff --git a/app/models/user.rb b/app/models/user.rb
index cb0ad9e3a..681829265 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -999,54 +999,3 @@ class User < Principal
end
end
end
-
-class AnonymousUser < User
- validate :validate_anonymous_uniqueness, :on => :create
-
- self.valid_statuses = [STATUS_ANONYMOUS]
-
- def validate_anonymous_uniqueness
- # There should be only one AnonymousUser in the database
- errors.add :base, 'An anonymous user already exists.' if AnonymousUser.unscoped.exists?
- end
-
- def available_custom_fields
- []
- end
-
- # Overrides a few properties
- def logged?; false end
- def admin; false end
- def name(*args); I18n.t(:label_user_anonymous) end
- def mail=(*args); nil end
- def mail; nil end
- def time_zone; nil end
- def rss_key; nil end
-
- def pref
- UserPreference.new(:user => self)
- end
-
- # Returns the user's bult-in role
- def builtin_role
- @builtin_role ||= Role.anonymous
- end
-
- def membership(*args)
- nil
- end
-
- def member_of?(*args)
- false
- end
-
- # Anonymous user can not be destroyed
- def destroy
- false
- end
-
- protected
-
- def instantiate_email_address
- end
-end
diff --git a/app/models/wiki_annotate.rb b/app/models/wiki_annotate.rb
new file mode 100644
index 000000000..c0411e3a6
--- /dev/null
+++ b/app/models/wiki_annotate.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+class WikiAnnotate
+ attr_reader :lines, :content
+
+ def initialize(content)
+ @content = content
+ current = content
+ current_lines = current.text.split(/\r?\n/)
+ @lines = current_lines.collect {|t| [nil, nil, t]}
+ positions = []
+ current_lines.size.times {|i| positions << i}
+ while current.previous
+ d = current.previous.text.split(/\r?\n/).diff(current.text.split(/\r?\n/)).diffs.flatten
+ d.each_slice(3) do |s|
+ sign, line = s[0], s[1]
+ if sign == '+' && positions[line] && positions[line] != -1
+ if @lines[positions[line]][0].nil?
+ @lines[positions[line]][0] = current.version
+ @lines[positions[line]][1] = current.author
+ end
+ end
+ if sign == '-'
+ positions.insert(line, -1)
+ else
+ positions[line] = nil
+ end
+ end
+ positions.compact!
+ # Stop if every line is annotated
+ break unless @lines.detect {|line| line[0].nil?}
+
+ current = current.previous
+ end
+ @lines.each do |line|
+ line[0] ||= current.version
+ # if the last known version is > 1 (eg. history was cleared), we don't know the author
+ line[1] ||= current.author if current.version == 1
+ end
+ end
+end
diff --git a/app/models/wiki_diff.rb b/app/models/wiki_diff.rb
new file mode 100644
index 000000000..00d35bb0b
--- /dev/null
+++ b/app/models/wiki_diff.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+class WikiDiff < Redmine::Helpers::Diff
+ attr_reader :content_to, :content_from
+
+ def initialize(content_to, content_from)
+ @content_to = content_to
+ @content_from = content_from
+ super(content_to.text, content_from.text)
+ end
+end
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index e6acd0f76..2e76e076e 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -290,53 +290,3 @@ class WikiPage < ActiveRecord::Base
(association(:content).loaded? ? content : content_without_text).try(name)
end
end
-
-class WikiDiff < Redmine::Helpers::Diff
- attr_reader :content_to, :content_from
-
- def initialize(content_to, content_from)
- @content_to = content_to
- @content_from = content_from
- super(content_to.text, content_from.text)
- end
-end
-
-class WikiAnnotate
- attr_reader :lines, :content
-
- def initialize(content)
- @content = content
- current = content
- current_lines = current.text.split(/\r?\n/)
- @lines = current_lines.collect {|t| [nil, nil, t]}
- positions = []
- current_lines.size.times {|i| positions << i}
- while current.previous
- d = current.previous.text.split(/\r?\n/).diff(current.text.split(/\r?\n/)).diffs.flatten
- d.each_slice(3) do |s|
- sign, line = s[0], s[1]
- if sign == '+' && positions[line] && positions[line] != -1
- if @lines[positions[line]][0].nil?
- @lines[positions[line]][0] = current.version
- @lines[positions[line]][1] = current.author
- end
- end
- if sign == '-'
- positions.insert(line, -1)
- else
- positions[line] = nil
- end
- end
- positions.compact!
- # Stop if every line is annotated
- break unless @lines.detect {|line| line[0].nil?}
-
- current = current.previous
- end
- @lines.each do |line|
- line[0] ||= current.version
- # if the last known version is > 1 (eg. history was cleared), we don't know the author
- line[1] ||= current.author if current.version == 1
- end
- end
-end
diff --git a/lib/redmine.rb b/lib/redmine.rb
index 5721667d8..b018779a7 100644
--- a/lib/redmine.rb
+++ b/lib/redmine.rb
@@ -58,8 +58,10 @@ require 'redmine/thumbnail'
require 'redmine/unified_diff'
require 'redmine/utils'
require 'redmine/version'
+require 'redmine/wiki_formatting/links_helper'
require 'redmine/wiki_formatting'
+
require 'redmine/default_data/loader'
require 'redmine/helpers/calendar'
require 'redmine/helpers/diff'
diff --git a/lib/redmine/wiki_formatting.rb b/lib/redmine/wiki_formatting.rb
index 99058462b..471082edc 100644
--- a/lib/redmine/wiki_formatting.rb
+++ b/lib/redmine/wiki_formatting.rb
@@ -115,89 +115,6 @@ module Redmine
end
end
- module LinksHelper
- AUTO_LINK_RE = %r{
- ( # leading text
- <\w+[^>]*?>| # leading HTML tag, or
- [\s\(\[,;]| # leading punctuation, or
- ^ # beginning of line
- )
- (
- (?:https?://)| # protocol spec, or
- (?:s?ftps?://)|
- (?:www\.) # www.*
- )
- (
- ([^<]\S*?) # url
- (\/)? # slash
- )
- ((?:>)?|[^[:alnum:]_\=\/;\(\)\-]*?) # post
- (?=<|\s|$)
- }x unless const_defined?(:AUTO_LINK_RE)
-
- # Destructively replaces urls into clickable links
- def auto_link!(text)
- text.gsub!(AUTO_LINK_RE) do
- all, leading, proto, url, post = $&, $1, $2, $3, $6
- if /=]?/.match?(leading)
- # don't replace URLs that are already linked
- # and URLs prefixed with ! !> !< != (textile images)
- all
- else
- # Idea below : an URL with unbalanced parenthesis and
- # ending by ')' is put into external parenthesis
- if url[-1] == ")" and ((url.count("(") - url.count(")")) < 0)
- url = url[0..-2] # discard closing parenthesis from url
- post = ")" + post # add closing parenthesis to post
- end
- content = proto + url
- href = "#{proto=="www."?"http://www.":proto}#{url}"
- %(#{leading}#{ERB::Util.html_escape content}#{post}).html_safe
- end
- end
- end
-
- # Destructively replaces email addresses into clickable links
- def auto_mailto!(text)
- text.gsub!(/([\w\.!#\$%\-+.\/]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
- mail = $1
- if /]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/.match?(text)
- mail
- else
- %(#{ERB::Util.html_escape mail}).html_safe
- end
- end
- end
-
- def restore_redmine_links(html)
- # restore wiki links eg. [[Foo]]
- html.gsub!(%r{\[(.*?)\]}) do
- "[[#{$2}]]"
- end
- # restore Redmine links with double-quotes, eg. version:"1.0"
- html.gsub!(/(\w):"(.+?)"/) do
- "#{$1}:\"#{$2}\""
- end
- # restore user links with @ in login name eg. [@jsmith@somenet.foo]
- html.gsub!(%r{[@\A](.*?)}) do
- "@#{$2}"
- end
- # restore user links with @ in login name eg. [user:jsmith@somenet.foo]
- html.gsub!(%r{\buser:(.*?)<\/a>}) do
- "user:#{$2}"
- end
- # restore attachments links with @ in file name eg. [attachment:image@2x.png]
- html.gsub!(%r{\battachment:(.*?)}) do
- "attachment:#{$2}"
- end
- # restore hires images which are misrecognized as email address eg. [printscreen@2x.png]
- html.gsub!(%r{(.*?)}) do
- "#{$3}"
- end
- html
- end
- end
-
# Default formatter module
module NullFormatter
class Formatter
diff --git a/lib/redmine/wiki_formatting/links_helper.rb b/lib/redmine/wiki_formatting/links_helper.rb
new file mode 100644
index 000000000..2e057df3e
--- /dev/null
+++ b/lib/redmine/wiki_formatting/links_helper.rb
@@ -0,0 +1,107 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require 'loofah/helpers'
+
+module Redmine
+ module WikiFormatting
+ module LinksHelper
+ AUTO_LINK_RE = %r{
+ ( # leading text
+ <\w+[^>]*?>| # leading HTML tag, or
+ [\s\(\[,;]| # leading punctuation, or
+ ^ # beginning of line
+ )
+ (
+ (?:https?://)| # protocol spec, or
+ (?:s?ftps?://)|
+ (?:www\.) # www.*
+ )
+ (
+ ([^<]\S*?) # url
+ (\/)? # slash
+ )
+ ((?:>)?|[^[:alnum:]_\=\/;\(\)\-]*?) # post
+ (?=<|\s|$)
+ }x unless const_defined?(:AUTO_LINK_RE)
+
+ # Destructively replaces urls into clickable links
+ def auto_link!(text)
+ text.gsub!(AUTO_LINK_RE) do
+ all, leading, proto, url, post = $&, $1, $2, $3, $6
+ if /=]?/.match?(leading)
+ # don't replace URLs that are already linked
+ # and URLs prefixed with ! !> !< != (textile images)
+ all
+ else
+ # Idea below : an URL with unbalanced parenthesis and
+ # ending by ')' is put into external parenthesis
+ if url[-1] == ")" and ((url.count("(") - url.count(")")) < 0)
+ url = url[0..-2] # discard closing parenthesis from url
+ post = ")" + post # add closing parenthesis to post
+ end
+ content = proto + url
+ href = "#{proto=="www."?"http://www.":proto}#{url}"
+ %(#{leading}#{ERB::Util.html_escape content}#{post}).html_safe
+ end
+ end
+ end
+
+ # Destructively replaces email addresses into clickable links
+ def auto_mailto!(text)
+ text.gsub!(/([\w\.!#\$%\-+.\/]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
+ mail = $1
+ if /]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/.match?(text)
+ mail
+ else
+ %(#{ERB::Util.html_escape mail}).html_safe
+ end
+ end
+ end
+
+ def restore_redmine_links(html)
+ # restore wiki links eg. [[Foo]]
+ html.gsub!(%r{\[(.*?)\]}) do
+ "[[#{$2}]]"
+ end
+ # restore Redmine links with double-quotes, eg. version:"1.0"
+ html.gsub!(/(\w):"(.+?)"/) do
+ "#{$1}:\"#{$2}\""
+ end
+ # restore user links with @ in login name eg. [@jsmith@somenet.foo]
+ html.gsub!(%r{[@\A](.*?)}) do
+ "@#{$2}"
+ end
+ # restore user links with @ in login name eg. [user:jsmith@somenet.foo]
+ html.gsub!(%r{\buser:(.*?)<\/a>}) do
+ "user:#{$2}"
+ end
+ # restore attachments links with @ in file name eg. [attachment:image@2x.png]
+ html.gsub!(%r{\battachment:(.*?)}) do
+ "attachment:#{$2}"
+ end
+ # restore hires images which are misrecognized as email address eg. [printscreen@2x.png]
+ html.gsub!(%r{(.*?)}) do
+ "#{$3}"
+ end
+ html
+ end
+ end
+ end
+end