Actualiza a Redmine 3.4.13
This commit is contained in:
parent
807ff3308d
commit
ecddcaf1d3
224 changed files with 2222 additions and 1000 deletions
20
Gemfile
20
Gemfile
|
@ -1,10 +1,8 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
if Gem::Version.new(Bundler::VERSION) < Gem::Version.new('1.5.0')
|
||||
abort "Redmine requires Bundler 1.5.0 or higher (you're using #{Bundler::VERSION}).\nPlease update with 'gem update bundler'."
|
||||
end
|
||||
gem "bundler", ">= 1.5.0", "< 2.0.0"
|
||||
|
||||
gem "rails", "4.2.8"
|
||||
gem "rails", "4.2.11.1"
|
||||
gem "addressable", "2.4.0" if RUBY_VERSION < "2.0"
|
||||
if RUBY_VERSION < "2.1"
|
||||
gem "public_suffix", (RUBY_VERSION < "2.0" ? "~> 1.4" : "~> 2.0.5")
|
||||
|
@ -23,13 +21,17 @@ gem "mail", "~> 2.6.4"
|
|||
gem "nokogiri", (RUBY_VERSION >= "2.1" ? "~> 1.8.1" : "~> 1.6.8")
|
||||
gem "i18n", "~> 0.7.0"
|
||||
gem "ffi", "1.9.14", :platforms => :mingw if RUBY_VERSION < "2.0"
|
||||
gem "xpath", "< 3.2.0" if RUBY_VERSION < "2.3"
|
||||
|
||||
# Request at least rails-html-sanitizer 1.0.3 because of security advisories
|
||||
gem "rails-html-sanitizer", ">= 1.0.3"
|
||||
|
||||
# TODO: Remove the following line when #32223 is fixed
|
||||
gem "sprockets", "~> 3.7.2"
|
||||
|
||||
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
||||
gem 'tzinfo-data', platforms: [:mingw, :x64_mingw, :mswin]
|
||||
gem "rbpdf", "~> 1.19.3"
|
||||
gem "rbpdf", "~> 1.19.6"
|
||||
|
||||
# Optional gem for LDAP authentication
|
||||
group :ldap do
|
||||
|
@ -38,14 +40,14 @@ end
|
|||
|
||||
# Optional gem for OpenID authentication
|
||||
group :openid do
|
||||
gem "ruby-openid", "~> 2.3.0", :require => "openid"
|
||||
gem "ruby-openid", "~> 2.9.2", :require => "openid"
|
||||
gem "rack-openid"
|
||||
end
|
||||
|
||||
platforms :mri, :mingw, :x64_mingw do
|
||||
# Optional gem for exporting the gantt to a PNG file, not supported with jruby
|
||||
group :rmagick do
|
||||
gem "rmagick", ">= 2.14.0"
|
||||
gem "rmagick", "~> 2.16.0"
|
||||
end
|
||||
|
||||
# Optional Markdown support, not for JRuby
|
||||
|
@ -94,12 +96,12 @@ end
|
|||
group :test do
|
||||
gem "minitest"
|
||||
gem "rails-dom-testing"
|
||||
gem "mocha"
|
||||
gem 'mocha', '>= 1.4.0'
|
||||
gem "simplecov", "~> 0.9.1", :require => false
|
||||
# TODO: remove this after upgrading to Rails 5
|
||||
gem "test_after_commit", "~> 0.4.2"
|
||||
# For running UI tests
|
||||
gem "capybara"
|
||||
gem "capybara", '~> 2.13'
|
||||
gem "selenium-webdriver", "~> 2.53.4"
|
||||
end
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ class AccountController < ApplicationController
|
|||
@user.must_change_passwd = false
|
||||
if @user.save
|
||||
@token.destroy
|
||||
Mailer.password_updated(@user)
|
||||
Mailer.password_updated(@user, { remote_ip: request.remote_ip })
|
||||
flash[:notice] = l(:notice_account_password_updated)
|
||||
redirect_to signin_path
|
||||
return
|
||||
|
|
|
@ -60,7 +60,7 @@ class AttachmentsController < ApplicationController
|
|||
@attachment.increment_download
|
||||
end
|
||||
|
||||
if stale?(:etag => @attachment.digest)
|
||||
if stale?(:etag => @attachment.digest, :template => false)
|
||||
# images are sent inline
|
||||
send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename),
|
||||
:type => detect_content_type(@attachment),
|
||||
|
@ -70,7 +70,7 @@ class AttachmentsController < ApplicationController
|
|||
|
||||
def thumbnail
|
||||
if @attachment.thumbnailable? && tbnail = @attachment.thumbnail(:size => params[:size])
|
||||
if stale?(:etag => tbnail)
|
||||
if stale?(:etag => tbnail, :template => false)
|
||||
send_file tbnail,
|
||||
:filename => filename_for_content_disposition(@attachment.filename),
|
||||
:type => detect_content_type(@attachment),
|
||||
|
|
|
@ -19,7 +19,7 @@ class AutoCompletesController < ApplicationController
|
|||
before_action :find_project
|
||||
|
||||
def issues
|
||||
@issues = []
|
||||
issues = []
|
||||
q = (params[:q] || params[:term]).to_s.strip
|
||||
status = params[:status].to_s
|
||||
issue_id = params[:issue_id].to_s
|
||||
|
@ -32,13 +32,14 @@ class AutoCompletesController < ApplicationController
|
|||
scope = scope.where.not(:id => issue_id.to_i)
|
||||
end
|
||||
if q.match(/\A#?(\d+)\z/)
|
||||
@issues << scope.find_by_id($1.to_i)
|
||||
issues << scope.find_by_id($1.to_i)
|
||||
end
|
||||
|
||||
@issues += scope.like(q).order(:id => :desc).limit(10).to_a
|
||||
@issues.compact!
|
||||
issues += scope.like(q).order(:id => :desc).limit(10).to_a
|
||||
issues.compact!
|
||||
end
|
||||
render :layout => false
|
||||
|
||||
render :json => format_issues_json(issues)
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -50,4 +51,13 @@ class AutoCompletesController < ApplicationController
|
|||
rescue ActiveRecord::RecordNotFound
|
||||
render_404
|
||||
end
|
||||
|
||||
def format_issues_json(issues)
|
||||
issues.map {|issue| {
|
||||
'id' => issue.id,
|
||||
'label' => "#{issue.tracker} ##{issue.id}: #{issue.subject.to_s.truncate(60)}",
|
||||
'value' => issue.id
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -91,8 +91,10 @@ class EnumerationsController < ApplicationController
|
|||
|
||||
def build_new_enumeration
|
||||
class_name = params[:enumeration] && params[:enumeration][:type] || params[:type]
|
||||
@enumeration = Enumeration.new_subclass_instance(class_name, enumeration_params)
|
||||
if @enumeration.nil?
|
||||
@enumeration = Enumeration.new_subclass_instance(class_name)
|
||||
if @enumeration
|
||||
@enumeration.attributes = enumeration_params || {}
|
||||
else
|
||||
render_404
|
||||
end
|
||||
end
|
||||
|
@ -105,6 +107,7 @@ class EnumerationsController < ApplicationController
|
|||
|
||||
def enumeration_params
|
||||
# can't require enumeration on #new action
|
||||
params.permit(:enumeration => [:name, :active, :is_default, :position])[:enumeration]
|
||||
cf_ids = @enumeration.available_custom_fields.map{|c| c.id.to_s}
|
||||
params.permit(:enumeration => [:name, :active, :is_default, :position, :custom_field_values => cf_ids])[:enumeration]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -40,7 +40,8 @@ class IssuesController < ApplicationController
|
|||
helper :timelog
|
||||
|
||||
def index
|
||||
retrieve_query
|
||||
use_session = !request.format.csv?
|
||||
retrieve_query(IssueQuery, use_session)
|
||||
|
||||
if @query.valid?
|
||||
respond_to do |format|
|
||||
|
@ -367,7 +368,12 @@ class IssuesController < ApplicationController
|
|||
when 'destroy'
|
||||
# nothing to do
|
||||
when 'nullify'
|
||||
if Setting.timelog_required_fields.include?('issue_id')
|
||||
flash.now[:error] = l(:field_issue) + " " + ::I18n.t('activerecord.errors.messages.blank')
|
||||
return
|
||||
else
|
||||
time_entries.update_all(:issue_id => nil)
|
||||
end
|
||||
when 'reassign'
|
||||
reassign_to = @project && @project.issues.find_by_id(params[:reassign_to_id])
|
||||
if reassign_to.nil?
|
||||
|
|
|
@ -37,7 +37,7 @@ class SearchController < ApplicationController
|
|||
end
|
||||
|
||||
# quick jump to an issue
|
||||
if (m = @question.match(/^#?(\d+)$/)) && (issue = Issue.visible.find_by_id(m[1].to_i))
|
||||
if !api_request? && (m = @question.match(/^#?(\d+)$/)) && (issue = Issue.visible.find_by_id(m[1].to_i))
|
||||
redirect_to issue_path(issue)
|
||||
return
|
||||
end
|
||||
|
@ -49,7 +49,7 @@ class SearchController < ApplicationController
|
|||
when 'my_projects'
|
||||
User.current.projects
|
||||
when 'subprojects'
|
||||
@project ? (@project.self_and_descendants.active.to_a) : nil
|
||||
@project ? (@project.self_and_descendants.to_a) : nil
|
||||
else
|
||||
@project
|
||||
end
|
||||
|
|
|
@ -114,6 +114,7 @@ class TimelogController < ApplicationController
|
|||
:time_entry => {
|
||||
:project_id => params[:time_entry][:project_id],
|
||||
:issue_id => @time_entry.issue_id,
|
||||
:spent_on => @time_entry.spent_on,
|
||||
:activity_id => @time_entry.activity_id
|
||||
},
|
||||
:back_url => params[:back_url]
|
||||
|
|
|
@ -106,6 +106,6 @@ class TrackersController < ApplicationController
|
|||
return
|
||||
end
|
||||
@trackers = Tracker.sorted.to_a
|
||||
@custom_fields = IssueCustomField.all.sort
|
||||
@custom_fields = IssueCustomField.sorted
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
class WikiController < ApplicationController
|
||||
default_search_scope :wiki_pages
|
||||
before_action :find_wiki, :authorize
|
||||
before_action :find_existing_or_new_page, :only => [:show, :edit, :update]
|
||||
before_action :find_existing_or_new_page, :only => [:show, :edit]
|
||||
before_action :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy, :destroy_version]
|
||||
before_action :find_attachments, :only => [:preview]
|
||||
accept_api_auth :index, :show, :update, :destroy
|
||||
|
@ -42,8 +42,6 @@ class WikiController < ApplicationController
|
|||
helper :watchers
|
||||
include Redmine::Export::PDF
|
||||
|
||||
include ActionView::Helpers::SanitizeHelper
|
||||
|
||||
# List of pages, sorted alphabetically and by parent (hierarchy)
|
||||
def index
|
||||
load_pages_for_index
|
||||
|
@ -109,7 +107,7 @@ class WikiController < ApplicationController
|
|||
send_data(export, :type => 'text/html', :filename => filename_for_content_disposition("#{@page.title}.html"))
|
||||
return
|
||||
elsif params[:format] == 'txt'
|
||||
send_data(strip_tags(@content.text), :type => 'text/plain', :filename => filename_for_content_disposition("#{@page.title}.txt"))
|
||||
send_data(@content.text, :type => 'text/plain', :filename => filename_for_content_disposition("#{@page.title}.txt"))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
@ -152,6 +150,8 @@ class WikiController < ApplicationController
|
|||
|
||||
# Creates a new page or updates an existing one
|
||||
def update
|
||||
@page = @wiki.find_or_new_page(params[:id])
|
||||
|
||||
return render_403 unless editable?
|
||||
was_new_page = @page.new_record?
|
||||
@page.safe_attributes = params[:wiki_page]
|
||||
|
|
|
@ -1272,7 +1272,7 @@ module ApplicationHelper
|
|||
link_to_function '',
|
||||
"toggleCheckboxesBySelector('#{selector}')",
|
||||
:title => "#{l(:button_check_all)} / #{l(:button_uncheck_all)}",
|
||||
:class => 'toggle-checkboxes'
|
||||
:class => 'icon icon-checked'
|
||||
end
|
||||
|
||||
def progress_bar(pcts, options={})
|
||||
|
@ -1423,10 +1423,13 @@ module ApplicationHelper
|
|||
end
|
||||
if email.present?
|
||||
gravatar(email.to_s.downcase, options) rescue nil
|
||||
else
|
||||
elsif user.is_a?(AnonymousUser)
|
||||
options[:size] &&= options[:size].to_s
|
||||
image_tag 'anonymous.png',
|
||||
GravatarHelper::DEFAULT_OPTIONS
|
||||
.except(:default, :rating, :ssl).merge(options)
|
||||
else
|
||||
nil
|
||||
end
|
||||
else
|
||||
''
|
||||
|
|
|
@ -127,8 +127,8 @@ module IssuesHelper
|
|||
content_tag('td', check_box_tag("ids[]", other_issue.id, false, :id => nil), :class => 'checkbox') +
|
||||
content_tag('td', relation.to_s(@issue) {|other| link_to_issue(other, :project => Setting.cross_project_issue_relations?)}.html_safe, :class => 'subject', :style => 'width: 50%') +
|
||||
content_tag('td', other_issue.status, :class => 'status') +
|
||||
content_tag('td', other_issue.start_date, :class => 'start_date') +
|
||||
content_tag('td', other_issue.due_date, :class => 'due_date') +
|
||||
content_tag('td', format_date(other_issue.start_date), :class => 'start_date') +
|
||||
content_tag('td', format_date(other_issue.due_date), :class => 'due_date') +
|
||||
content_tag('td', other_issue.disabled_core_fields.include?('done_ratio') ? '' : progress_bar(other_issue.done_ratio), :class=> 'done_ratio') +
|
||||
content_tag('td', link, :class => 'buttons'),
|
||||
:id => "relation-#{relation.id}",
|
||||
|
@ -246,8 +246,12 @@ module IssuesHelper
|
|||
issue_fields_rows do |rows|
|
||||
values.each_with_index do |value, i|
|
||||
css = "cf_#{value.custom_field.id}"
|
||||
attr_value = show_value(value)
|
||||
if value.custom_field.text_formatting == 'full'
|
||||
attr_value = content_tag('div', attr_value, class: 'wiki')
|
||||
end
|
||||
m = (i < half ? :left : :right)
|
||||
rows.send m, custom_field_name_tag(value.custom_field), show_value(value), :class => css
|
||||
rows.send m, custom_field_name_tag(value.custom_field), attr_value, :class => css
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -310,7 +314,7 @@ module IssuesHelper
|
|||
# Returns an array of users that are proposed as watchers
|
||||
# on the new issue form
|
||||
def users_for_new_issue_watchers(issue)
|
||||
users = issue.watcher_users
|
||||
users = issue.watcher_users.select{|u| u.status == User::STATUS_ACTIVE}
|
||||
if issue.project.users.count <= 20
|
||||
users = (users + issue.project.users.sort).uniq
|
||||
end
|
||||
|
|
|
@ -18,14 +18,11 @@
|
|||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
module SearchHelper
|
||||
include ActionView::Helpers::SanitizeHelper
|
||||
|
||||
def highlight_tokens(text, tokens)
|
||||
return text unless text && tokens && !tokens.empty?
|
||||
re_tokens = tokens.collect {|t| Regexp.escape(t)}
|
||||
regexp = Regexp.new "(#{re_tokens.join('|')})", Regexp::IGNORECASE
|
||||
result = ''
|
||||
text = strip_tags(text)
|
||||
text.split(regexp).each_with_index do |words, i|
|
||||
if result.length > 1200
|
||||
# maximum length of the preview reached
|
||||
|
|
|
@ -156,7 +156,7 @@ class Attachment < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def title
|
||||
title = filename.to_s
|
||||
title = filename.dup
|
||||
if description.present?
|
||||
title << " (#{description})"
|
||||
end
|
||||
|
|
|
@ -217,6 +217,7 @@ class Import < ActiveRecord::Base
|
|||
|
||||
csv_options = {:headers => false}
|
||||
csv_options[:encoding] = settings['encoding'].to_s.presence || 'UTF-8'
|
||||
csv_options[:encoding] = 'bom|UTF-8' if csv_options[:encoding] == 'UTF-8'
|
||||
separator = settings['separator'].to_s
|
||||
csv_options[:col_sep] = separator if separator.size == 1
|
||||
wrapper = settings['wrapper'].to_s
|
||||
|
|
|
@ -275,7 +275,8 @@ class Issue < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
unless options[:watchers] == false
|
||||
self.watcher_user_ids = issue.watcher_user_ids.dup
|
||||
self.watcher_user_ids =
|
||||
issue.watcher_users.select{|u| u.status == User::STATUS_ACTIVE}.map(&:id)
|
||||
end
|
||||
@copied_from = issue
|
||||
@copy_options = options
|
||||
|
@ -1086,7 +1087,7 @@ class Issue < ActiveRecord::Base
|
|||
if leaf?
|
||||
estimated_hours
|
||||
else
|
||||
@total_estimated_hours ||= self_and_descendants.sum(:estimated_hours)
|
||||
@total_estimated_hours ||= self_and_descendants.visible.sum(:estimated_hours)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1300,7 +1301,7 @@ class Issue < ActiveRecord::Base
|
|||
|
||||
# Reschedules the issue on the given date or the next working day and saves the record.
|
||||
# If the issue is a parent task, this is done by rescheduling its subtasks.
|
||||
def reschedule_on!(date)
|
||||
def reschedule_on!(date, journal=nil)
|
||||
return if date.nil?
|
||||
if leaf? || !dates_derived?
|
||||
if start_date.nil? || start_date != date
|
||||
|
@ -1308,6 +1309,9 @@ class Issue < ActiveRecord::Base
|
|||
# Issue can not be moved earlier than its soonest start date
|
||||
date = [soonest_start(true), date].compact.max
|
||||
end
|
||||
if journal
|
||||
init_journal(journal.user)
|
||||
end
|
||||
reschedule_on(date)
|
||||
begin
|
||||
save
|
||||
|
@ -1631,6 +1635,8 @@ class Issue < ActiveRecord::Base
|
|||
copy.author = author
|
||||
copy.project = project
|
||||
copy.parent_issue_id = copied_issue_ids[child.parent_id]
|
||||
copy.fixed_version_id = nil unless child.fixed_version.present? && child.fixed_version.status == 'open'
|
||||
copy.assigned_to = nil unless child.assigned_to_id.present? && child.assigned_to.status == User::STATUS_ACTIVE
|
||||
unless copy.save
|
||||
logger.error "Could not copy subtask ##{child.id} while copying ##{@copied_from.id} to ##{id} due to validation errors: #{copy.errors.full_messages.join(', ')}" if logger
|
||||
next
|
||||
|
@ -1789,7 +1795,7 @@ class Issue < ActiveRecord::Base
|
|||
def reschedule_following_issues
|
||||
if start_date_changed? || due_date_changed?
|
||||
relations_from.each do |relation|
|
||||
relation.set_issue_to_dates
|
||||
relation.set_issue_to_dates(@current_journal)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -122,7 +122,10 @@ class IssueImport < Import
|
|||
end
|
||||
end
|
||||
if issue.project && version_name = row_value(row, 'fixed_version')
|
||||
if version = issue.project.versions.named(version_name).first
|
||||
version =
|
||||
issue.project.versions.named(version_name).first ||
|
||||
issue.project.shared_versions.named(version_name).first
|
||||
if version
|
||||
attributes['fixed_version_id'] = version.id
|
||||
elsif create_versions?
|
||||
version = issue.project.versions.build
|
||||
|
|
|
@ -37,8 +37,8 @@ class IssueQuery < Query
|
|||
QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date"),
|
||||
QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours", :totalable => true),
|
||||
QueryColumn.new(:total_estimated_hours,
|
||||
:sortable => "COALESCE((SELECT SUM(estimated_hours) FROM #{Issue.table_name} subtasks" +
|
||||
" WHERE subtasks.root_id = #{Issue.table_name}.root_id AND subtasks.lft >= #{Issue.table_name}.lft AND subtasks.rgt <= #{Issue.table_name}.rgt), 0)",
|
||||
:sortable => -> { "COALESCE((SELECT SUM(estimated_hours) FROM #{Issue.table_name} subtasks" +
|
||||
" WHERE #{Issue.visible_condition(User.current).gsub(/\bissues\b/, 'subtasks')} AND subtasks.root_id = #{Issue.table_name}.root_id AND subtasks.lft >= #{Issue.table_name}.lft AND subtasks.rgt <= #{Issue.table_name}.rgt), 0)" },
|
||||
:default_order => 'desc'),
|
||||
QueryColumn.new(:done_ratio, :sortable => "#{Issue.table_name}.done_ratio", :groupable => true),
|
||||
QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'),
|
||||
|
@ -221,6 +221,7 @@ class IssueQuery < Query
|
|||
end
|
||||
|
||||
disabled_fields = Tracker.disabled_core_fields(trackers).map {|field| field.sub(/_id$/, '')}
|
||||
disabled_fields << "total_estimated_hours" if disabled_fields.include?("estimated_hours")
|
||||
@available_columns.reject! {|column|
|
||||
disabled_fields.include?(column.name.to_s)
|
||||
}
|
||||
|
@ -373,7 +374,7 @@ class IssueQuery < Query
|
|||
neg = (operator == '!' ? 'NOT' : '')
|
||||
subquery = "SELECT 1 FROM #{Journal.table_name} sj" +
|
||||
" WHERE sj.journalized_type='Issue' AND sj.journalized_id=#{Issue.table_name}.id AND (#{sql_for_field field, '=', value, 'sj', 'user_id'})" +
|
||||
" AND sj.id = (SELECT MAX(#{Journal.table_name}.id) FROM #{Journal.table_name}" +
|
||||
" AND sj.id IN (SELECT MAX(#{Journal.table_name}.id) FROM #{Journal.table_name}" +
|
||||
" WHERE #{Journal.table_name}.journalized_type='Issue' AND #{Journal.table_name}.journalized_id=#{Issue.table_name}.id" +
|
||||
" AND (#{Journal.visible_notes_condition(User.current, :skip_pre_condition => true)}))"
|
||||
|
||||
|
@ -382,8 +383,26 @@ class IssueQuery < Query
|
|||
|
||||
def sql_for_watcher_id_field(field, operator, value)
|
||||
db_table = Watcher.table_name
|
||||
"#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND " +
|
||||
sql_for_field(field, '=', value, db_table, 'user_id') + ')'
|
||||
|
||||
me, others = value.partition { |id| ['0', User.current.id.to_s].include?(id) }
|
||||
sql = if others.any?
|
||||
"SELECT #{Issue.table_name}.id FROM #{Issue.table_name} " +
|
||||
"INNER JOIN #{db_table} ON #{Issue.table_name}.id = #{db_table}.watchable_id AND #{db_table}.watchable_type = 'Issue' " +
|
||||
"LEFT OUTER JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Issue.table_name}.project_id " +
|
||||
"WHERE (" +
|
||||
sql_for_field(field, '=', me, db_table, 'user_id') +
|
||||
') OR (' +
|
||||
Project.allowed_to_condition(User.current, :view_issue_watchers) +
|
||||
' AND ' +
|
||||
sql_for_field(field, '=', others, db_table, 'user_id') +
|
||||
')'
|
||||
else
|
||||
"SELECT #{db_table}.watchable_id FROM #{db_table} " +
|
||||
"WHERE #{db_table}.watchable_type='Issue' AND " +
|
||||
sql_for_field(field, '=', me, db_table, 'user_id')
|
||||
end
|
||||
|
||||
"#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (#{sql})"
|
||||
end
|
||||
|
||||
def sql_for_member_of_group_field(field, operator, value)
|
||||
|
|
|
@ -176,10 +176,10 @@ class IssueRelation < ActiveRecord::Base
|
|||
set_issue_to_dates
|
||||
end
|
||||
|
||||
def set_issue_to_dates
|
||||
def set_issue_to_dates(journal=nil)
|
||||
soonest_start = self.successor_soonest_start
|
||||
if soonest_start && issue_to
|
||||
issue_to.reschedule_on!(soonest_start)
|
||||
issue_to.reschedule_on!(soonest_start, journal)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ class MailHandler < ActionMailer::Base
|
|||
def self.safe_receive(*args)
|
||||
receive(*args)
|
||||
rescue Exception => e
|
||||
logger.error "MailHandler: an unexpected error occurred when receiving email: #{e.message}" if logger
|
||||
Rails.logger.error "MailHandler: an unexpected error occurred when receiving email: #{e.message}"
|
||||
return false
|
||||
end
|
||||
|
||||
|
@ -65,7 +65,7 @@ class MailHandler < ActionMailer::Base
|
|||
%w(project status tracker category priority assigned_to fixed_version).each do |option|
|
||||
options[:issue][option.to_sym] = env[option] if env[option]
|
||||
end
|
||||
%w(allow_override unknown_user no_permission_check no_account_notice default_group project_from_subaddress).each do |option|
|
||||
%w(allow_override unknown_user no_permission_check no_account_notice no_notification default_group project_from_subaddress).each do |option|
|
||||
options[option.to_sym] = env[option] if env[option]
|
||||
end
|
||||
if env['private']
|
||||
|
@ -250,8 +250,8 @@ class MailHandler < ActionMailer::Base
|
|||
|
||||
# add To and Cc as watchers before saving so the watchers can reply to Redmine
|
||||
add_watchers(issue)
|
||||
add_attachments(issue)
|
||||
issue.save!
|
||||
add_attachments(issue)
|
||||
if logger
|
||||
logger.info "MailHandler: issue ##{issue.id} updated by #{user}"
|
||||
end
|
||||
|
@ -286,7 +286,7 @@ class MailHandler < ActionMailer::Base
|
|||
reply
|
||||
else
|
||||
if logger
|
||||
logger.info "MailHandler: ignoring reply from [#{sender_email}] to a locked topic"
|
||||
logger.info "MailHandler: ignoring reply from [#{email.from.first}] to a locked topic"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -311,7 +311,7 @@ class Mailer < ActionMailer::Base
|
|||
end
|
||||
|
||||
# Notifies user that his password was updated
|
||||
def self.password_updated(user)
|
||||
def self.password_updated(user, options={})
|
||||
# Don't send a notification to the dummy email address when changing the password
|
||||
# of the default admin account which is required after the first login
|
||||
# TODO: maybe not the best way to handle this
|
||||
|
@ -320,6 +320,8 @@ class Mailer < ActionMailer::Base
|
|||
security_notification(user,
|
||||
message: :mail_body_password_updated,
|
||||
title: :button_change_password,
|
||||
remote_ip: options[:remote_ip],
|
||||
originator: user,
|
||||
url: {controller: 'my', action: 'password'}
|
||||
).deliver
|
||||
end
|
||||
|
@ -333,7 +335,6 @@ class Mailer < ActionMailer::Base
|
|||
end
|
||||
|
||||
def security_notification(recipients, options={})
|
||||
redmine_headers 'Sender' => User.current.login
|
||||
@user = Array(recipients).detect{|r| r.is_a? User }
|
||||
set_language_if_valid(@user.try :language)
|
||||
@message = l(options[:message],
|
||||
|
@ -341,7 +342,11 @@ class Mailer < ActionMailer::Base
|
|||
value: options[:value]
|
||||
)
|
||||
@title = options[:title] && l(options[:title])
|
||||
@originator = options[:originator] || User.current
|
||||
@remote_ip = options[:remote_ip] || @originator.remote_ip
|
||||
@url = options[:url] && (options[:url].is_a?(Hash) ? url_for(options[:url]) : options[:url])
|
||||
redmine_headers 'Sender' => @originator.login
|
||||
redmine_headers 'Url' => @url
|
||||
mail :to => recipients,
|
||||
:subject => "[#{Setting.app_title}] #{l(:mail_subject_security_notification)}"
|
||||
end
|
||||
|
|
|
@ -319,9 +319,10 @@ class Query < ActiveRecord::Base
|
|||
" INNER JOIN #{table_name_prefix}queries_roles#{table_name_suffix} qr on qr.query_id = q.id" +
|
||||
" INNER JOIN #{MemberRole.table_name} mr ON mr.role_id = qr.role_id" +
|
||||
" INNER JOIN #{Member.table_name} m ON m.id = mr.member_id AND m.user_id = ?" +
|
||||
" INNER JOIN #{Project.table_name} p ON p.id = m.project_id AND p.status <> ?" +
|
||||
" WHERE q.project_id IS NULL OR q.project_id = m.project_id))" +
|
||||
" OR #{table_name}.user_id = ?",
|
||||
VISIBILITY_PUBLIC, VISIBILITY_ROLES, user.id, user.id)
|
||||
VISIBILITY_PUBLIC, VISIBILITY_ROLES, user.id, Project::STATUS_ARCHIVED, user.id)
|
||||
elsif user.logged?
|
||||
scope.where("#{table_name}.visibility = ? OR #{table_name}.user_id = ?", VISIBILITY_PUBLIC, user.id)
|
||||
else
|
||||
|
@ -340,7 +341,7 @@ class Query < ActiveRecord::Base
|
|||
if project
|
||||
(user.roles_for_project(project) & roles).any?
|
||||
else
|
||||
Member.where(:user_id => user.id).joins(:roles).where(:member_roles => {:role_id => roles.map(&:id)}).any?
|
||||
user.memberships.joins(:member_roles).where(:member_roles => {:role_id => roles.map(&:id)}).any?
|
||||
end
|
||||
else
|
||||
user == self.user
|
||||
|
@ -398,6 +399,8 @@ class Query < ActiveRecord::Base
|
|||
params[:v][field] = options[:values]
|
||||
end
|
||||
params[:c] = column_names
|
||||
params[:group_by] = group_by.to_s if group_by.present?
|
||||
params[:t] = totalable_names.map(&:to_s) if totalable_names.any?
|
||||
params[:sort] = sort_criteria.to_param
|
||||
params[:set_filter] = 1
|
||||
params
|
||||
|
|
|
@ -45,7 +45,7 @@ class Version < ActiveRecord::Base
|
|||
scope :like, lambda {|arg|
|
||||
if arg.present?
|
||||
pattern = "%#{arg.to_s.strip}%"
|
||||
where("LOWER(#{Version.table_name}.name) LIKE :p", :p => pattern)
|
||||
where([Redmine::Database.like("#{Version.table_name}.name", '?'), pattern])
|
||||
end
|
||||
}
|
||||
scope :open, lambda { where(:status => 'open') }
|
||||
|
@ -268,7 +268,7 @@ class Version < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def deletable?
|
||||
fixed_issues.empty? && !referenced_by_a_custom_field?
|
||||
fixed_issues.empty? && !referenced_by_a_custom_field? && attachments.empty?
|
||||
end
|
||||
|
||||
def default_project_version
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<%= call_hook :view_account_login_top %>
|
||||
|
||||
<div id="login-form">
|
||||
<h2><%= l(:label_login) %></h2>
|
||||
<%= form_tag(signin_path, onsubmit: 'return keepAnchorOnSignIn(this);') do %>
|
||||
<%= back_url_hidden_field_tag %>
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<% end %>
|
||||
</table>
|
||||
<br />
|
||||
<div class="box">
|
||||
<div class="box autoscroll">
|
||||
<pre><%= Redmine::Info.environment %></pre>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
<%= title l(:label_plugins) %>
|
||||
|
||||
<% if @plugins.any? %>
|
||||
<table class="list plugins">
|
||||
<% @plugins.each do |plugin| %>
|
||||
<tr id="plugin-<%= plugin.id %>">
|
||||
<td class="name"><span class="name"><%= plugin.name %></span>
|
||||
<%= content_tag('span', plugin.description, :class => 'description') unless plugin.description.blank? %>
|
||||
<%= content_tag('span', link_to(plugin.url, plugin.url), :class => 'url') unless plugin.url.blank? %>
|
||||
</td>
|
||||
<td class="author"><%= plugin.author_url.blank? ? plugin.author : link_to(plugin.author, plugin.author_url) %></td>
|
||||
<td class="version"><span class="icon"><%= plugin.version %></span></td>
|
||||
<td class="configure"><%= link_to(l(:button_configure), plugin_settings_path(plugin)) if plugin.configurable? %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
<div class="autoscroll">
|
||||
<table class="list plugins">
|
||||
<% @plugins.each do |plugin| %>
|
||||
<tr id="plugin-<%= plugin.id %>">
|
||||
<td class="name"><span class="name"><%= plugin.name %></span>
|
||||
<%= content_tag('span', plugin.description, :class => 'description') unless plugin.description.blank? %>
|
||||
<%= content_tag('span', link_to(plugin.url, plugin.url), :class => 'url') unless plugin.url.blank? %>
|
||||
</td>
|
||||
<td class="author"><%= plugin.author_url.blank? ? plugin.author : link_to(plugin.author, plugin.author_url) %></td>
|
||||
<td class="version"><span class="icon"><%= plugin.version %></span></td>
|
||||
<td class="configure"><%= link_to(l(:button_configure), plugin_settings_path(plugin)) if plugin.configurable? %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
</div>
|
||||
<p><a href="#" id="check-for-updates"><%= l(:label_check_for_updates) %></a></p>
|
||||
<% else %>
|
||||
<p class="nodata"><%= l(:label_no_data) %></p>
|
||||
|
@ -27,7 +29,7 @@ $(document).ready(function(){
|
|||
dataType: "jsonp",
|
||||
url: "https://www.redmine.org/plugins/check_updates",
|
||||
data: <%= raw_json plugin_data_for_updates(@plugins) %>,
|
||||
timeout: 3000,
|
||||
timeout: 10000,
|
||||
beforeSend: function(){
|
||||
$('#ajax-indicator').show();
|
||||
},
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
<ul>
|
||||
<% @priorities.each do |p| -%>
|
||||
<li><%= context_menu_link p.name, bulk_update_issues_path(:ids => @issue_ids, :issue => {'priority_id' => p}, :back_url => @back), :method => :post,
|
||||
:selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit]) %></li>
|
||||
:selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit] || @issues.any?(&:priority_derived?)) %></li>
|
||||
<% end -%>
|
||||
</ul>
|
||||
</li>
|
||||
|
@ -97,7 +97,7 @@
|
|||
<ul>
|
||||
<% (0..10).map{|x|x*10}.each do |p| -%>
|
||||
<li><%= context_menu_link "#{p}%", bulk_update_issues_path(:ids => @issue_ids, :issue => {'done_ratio' => p}, :back_url => @back), :method => :post,
|
||||
:selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %></li>
|
||||
:selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.any?(&:done_ratio_derived?)) %></li>
|
||||
<% end -%>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
|
@ -6,41 +6,43 @@
|
|||
|
||||
<% delete_allowed = User.current.allowed_to?(:manage_files, @project) %>
|
||||
|
||||
<table class="list files">
|
||||
<thead><tr>
|
||||
<%= sort_header_tag('filename', :caption => l(:field_filename)) %>
|
||||
<%= sort_header_tag('created_on', :caption => l(:label_date), :default_order => 'desc') %>
|
||||
<%= sort_header_tag('size', :caption => l(:field_filesize), :default_order => 'desc') %>
|
||||
<%= sort_header_tag('downloads', :caption => l(:label_downloads_abbr), :default_order => 'desc') %>
|
||||
<th><%= l(:field_digest) %></th>
|
||||
<th></th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<% @containers.each do |container| %>
|
||||
<% next if container.attachments.empty? -%>
|
||||
<% if container.is_a?(Version) -%>
|
||||
<tr>
|
||||
<th colspan="6">
|
||||
<%= link_to(container, {:controller => 'versions', :action => 'show', :id => container}, :class => "icon icon-package") %>
|
||||
</th>
|
||||
</tr>
|
||||
<% end -%>
|
||||
<% container.attachments.each do |file| %>
|
||||
<tr class="file">
|
||||
<td class="filename"><%= link_to_attachment file, :title => file.description -%></td>
|
||||
<td class="created_on"><%= format_time(file.created_on) %></td>
|
||||
<td class="filesize"><%= number_to_human_size(file.filesize) %></td>
|
||||
<td class="downloads"><%= file.downloads %></td>
|
||||
<td class="digest"><%= file.digest_type %>: <%= file.digest %></td>
|
||||
<td class="buttons">
|
||||
<%= link_to_attachment file, class: 'icon-only icon-download', title: l(:button_download), download: true %>
|
||||
<%= link_to(l(:button_delete), attachment_path(file), :class => 'icon-only icon-del',
|
||||
:data => {:confirm => l(:text_are_you_sure)}, :method => :delete) if delete_allowed %>
|
||||
</td>
|
||||
</tr>
|
||||
<div class="autoscroll">
|
||||
<table class="list files">
|
||||
<thead><tr>
|
||||
<%= sort_header_tag('filename', :caption => l(:field_filename)) %>
|
||||
<%= sort_header_tag('created_on', :caption => l(:label_date), :default_order => 'desc') %>
|
||||
<%= sort_header_tag('size', :caption => l(:field_filesize), :default_order => 'desc') %>
|
||||
<%= sort_header_tag('downloads', :caption => l(:label_downloads_abbr), :default_order => 'desc') %>
|
||||
<th><%= l(:field_digest) %></th>
|
||||
<th></th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<% @containers.each do |container| %>
|
||||
<% next if container.attachments.empty? -%>
|
||||
<% if container.is_a?(Version) -%>
|
||||
<tr>
|
||||
<th colspan="6">
|
||||
<%= link_to(container, {:controller => 'versions', :action => 'show', :id => container}, :class => "icon icon-package") %>
|
||||
</th>
|
||||
</tr>
|
||||
<% end -%>
|
||||
<% container.attachments.each do |file| %>
|
||||
<tr class="file">
|
||||
<td class="filename"><%= link_to_attachment file, :title => file.description -%></td>
|
||||
<td class="created_on"><%= format_time(file.created_on) %></td>
|
||||
<td class="filesize"><%= number_to_human_size(file.filesize) %></td>
|
||||
<td class="downloads"><%= file.downloads %></td>
|
||||
<td class="digest"><%= file.digest_type %>: <%= file.digest %></td>
|
||||
<td class="buttons">
|
||||
<%= link_to_attachment file, class: 'icon-only icon-download', title: l(:button_download), download: true %>
|
||||
<%= link_to(l(:button_delete), attachment_path(file), :class => 'icon-only icon-del',
|
||||
:data => {:confirm => l(:text_are_you_sure)}, :method => :delete) if delete_allowed %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<% html_title(l(:label_attachment_plural)) -%>
|
||||
|
|
|
@ -2,6 +2,6 @@ $('#relations').html('<%= escape_javascript(render :partial => 'issues/relations
|
|||
<% if @relation.errors.empty? %>
|
||||
$('#relation_delay').val('');
|
||||
$('#relation_issue_to_id').val('');
|
||||
$('#relation_issue_to_id').focus();
|
||||
<% end %>
|
||||
$('#new-relation-form').show();
|
||||
$('#relation_issue_to_id').focus();
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
<% end %>
|
||||
<br />
|
||||
<span class="author"><%= authoring(changeset.committed_on, changeset.author) %></span></p>
|
||||
<div class="wiki changeset-comments"><%= format_changeset_comments changeset %></div>
|
||||
<div class="wiki changeset-comments">
|
||||
<%= format_changeset_comments changeset %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
<p><strong><%= l(:text_destroy_time_entries_question, :hours => number_with_precision(@hours, :precision => 2)) %></strong></p>
|
||||
<p>
|
||||
<label><%= radio_button_tag 'todo', 'destroy', true %> <%= l(:text_destroy_time_entries) %></label><br />
|
||||
<% unless Setting.timelog_required_fields.include?('issue_id') %>
|
||||
<label><%= radio_button_tag 'todo', 'nullify', false %> <%= l(:text_assign_time_entries_to_project) %></label><br />
|
||||
<% end %>
|
||||
<% if @project %>
|
||||
<label><%= radio_button_tag 'todo', 'reassign', false, :onchange => 'if (this.checked) { $("#reassign_to_id").focus(); }' %> <%= l(:text_reassign_time_entries) %></label>
|
||||
<%= text_field_tag 'reassign_to_id', params[:reassign_to_id], :size => 6, :onfocus => '$("#todo_reassign").attr("checked", true);' %>
|
||||
|
|
|
@ -2,31 +2,28 @@
|
|||
<html lang="<%= current_language %>">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<title><%= html_title %></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<meta name="description" content="<%= Redmine::Info.app_name %>" />
|
||||
<meta name="keywords" content="issue,bug,tracker" />
|
||||
<%= csrf_meta_tag %>
|
||||
<%= favicon %>
|
||||
<%= stylesheet_link_tag 'jquery/jquery-ui-1.11.0', 'cookieconsent.min', 'application', 'responsive', :media => 'all' %>
|
||||
<%= stylesheet_link_tag 'jquery/jquery-ui-1.11.0', 'application', 'responsive', :media => 'all' %>
|
||||
<%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %>
|
||||
<% is_welcome = !User.current.logged? && current_page?(:controller => 'welcome', :action => 'index') %>
|
||||
<%= stylesheet_link_tag 'frontpage', :media => 'all' if is_welcome %>
|
||||
|
||||
<%= javascript_heads %>
|
||||
<script src="/themes/circlepro/javascripts/cookieconsent.min.js"></script>
|
||||
<%= heads_for_theme %>
|
||||
<%= call_hook :view_layouts_base_html_head %>
|
||||
<!-- page specific tags -->
|
||||
<%= yield :header_tags -%>
|
||||
</head>
|
||||
<body class="<%= body_css_classes %><%= ' is-preload' if is_welcome %>">
|
||||
<body class="<%= body_css_classes %>">
|
||||
<%= call_hook :view_layouts_base_body_top %>
|
||||
<div id="wrapper">
|
||||
|
||||
<div class="flyout-menu js-flyout-menu">
|
||||
|
||||
|
||||
<% if User.current.logged? || !Setting.login_required? %>
|
||||
<div class="flyout-menu__search">
|
||||
<%= form_tag({:controller => 'search', :action => 'index', :id => @project}, :method => :get ) do %>
|
||||
|
@ -64,58 +61,45 @@
|
|||
<div id="wrapper2">
|
||||
<div id="wrapper3">
|
||||
<div id="top-menu">
|
||||
<div id="wrapper-top-menu">
|
||||
<ul class="social-menu">
|
||||
<li class="social-link-blog"><a href="https://manuel.cillero.es" title="<%= l(:link_my_blog) %>" class="icon-blog"><span><%= l(:link_my_blog) %></span></a></li>
|
||||
<li class="social-link-twitter"><a href="https://twitter.com/manuelcillero" title="Twitter" target="_blank" class="icon-twitter"><span>Twitter</span></a></li>
|
||||
<li class="social-link-facebook"><a href="https://facebook.com/manuelcillero" title="Facebook" target="_blank" class="icon-facebook"><span>Facebook</span></a></li>
|
||||
<li class="social-link-linkedin"><a href="https://es.linkedin.com/in/manuelcillero" title="Linkedin" target="_blank" class="icon-linkedin"><span>Linkedin</span></a></li>
|
||||
<li class="social-link-gitlab"><a href="https://gitlab.com/manuelcillero" title="Gitlab" target="_blank" class="icon-gitlab"><span>Gitlab</span></a></li>
|
||||
<li class="social-link-mail"><a href="https://manuel.cillero.es/contacto/#suitepro" title="Mail" class="icon-mail"><span>Mail</span></a></li>
|
||||
</ul>
|
||||
<div id="account">
|
||||
<%= render_menu :account_menu -%>
|
||||
</div>
|
||||
<%= content_tag('div', "#{l(:label_logged_as)} #{link_to_user(User.current, :format => :username)}".html_safe, :id => 'loggedas') if User.current.logged? %>
|
||||
<%= render_menu :top_menu if User.current.logged? || !Setting.login_required? -%>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="header">
|
||||
|
||||
<a href="#" class="mobile-toggle-button js-flyout-menu-toggle-button"></a>
|
||||
|
||||
<div id="wrapper-header">
|
||||
<% if User.current.logged? || !Setting.login_required? %>
|
||||
<div id="quick-search" class="hide-when-print">
|
||||
<div id="quick-search">
|
||||
<%= form_tag({:controller => 'search', :action => 'index', :id => @project}, :method => :get ) do %>
|
||||
<%= hidden_field_tag 'scope', default_search_project_scope, :id => nil %>
|
||||
<%= hidden_field_tag(controller.default_search_scope, 1, :id => nil) if controller.default_search_scope %>
|
||||
<label for='q'>
|
||||
<%= link_to l(:label_search), {:controller => 'search', :action => 'index', :id => @project}, :accesskey => accesskey(:search) %>:
|
||||
<%= link_to l(:label_search), {:controller => 'search', :action => 'index', :id => @project, :scope => default_search_project_scope}, :accesskey => accesskey(:search) %>:
|
||||
</label>
|
||||
<%= text_field_tag 'q', @question, :size => 20, :class => 'small', :accesskey => accesskey(:quick_search) %>
|
||||
<% end %>
|
||||
<%= render_project_jump_box %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<h1><%= page_header_title %></h1>
|
||||
</div>
|
||||
|
||||
|
||||
<% if display_main_menu?(@project) %>
|
||||
<div id="main-menu" class="tabs">
|
||||
<div id="wrapper-main-menu">
|
||||
<%= render_main_menu(@project) %>
|
||||
<div class="tabs-buttons" style="display:none;">
|
||||
<button class="tab-left" onclick="moveTabLeft(this); return false;"></button>
|
||||
<button class="tab-right" onclick="moveTabRight(this); return false;"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div id="main" class="<%= sidebar_content? ? '' : 'nosidebar' %>">
|
||||
<div id="wrapper-main">
|
||||
<div id="sidebar">
|
||||
<%= yield :sidebar %>
|
||||
<%= view_layouts_base_sidebar_hook_response %>
|
||||
|
@ -127,51 +111,19 @@
|
|||
<%= call_hook :view_layouts_base_content %>
|
||||
<div style="clear:both;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a href="#" id="scrollup" class="hide-when-print"><%=l(:label_sort_higher)%></a><%= javascript_tag "$('#scrollup').click(function(){$('html,body').animate({scrollTop:0},600);return false;});" %>
|
||||
|
||||
<div id="ajax-indicator" style="display:none;"><span><%= l(:label_loading) %></span></div>
|
||||
<div id="ajax-modal" style="display:none;"></div>
|
||||
|
||||
<div id="footer">
|
||||
<div id="wrapper-footer">
|
||||
<ul class="social-menu">
|
||||
<li class="social-link-blog"><a href="https://manuel.cillero.es" title="<%= l(:link_my_blog) %>" class="icon-blog"><span><%= l(:link_my_blog) %></span></a></li>
|
||||
<li class="social-link-twitter"><a href="https://twitter.com/manuelcillero" title="Twitter" target="_blank" class="icon-twitter"><span>Twitter</span></a></li>
|
||||
<li class="social-link-facebook"><a href="https://facebook.com/manuelcillero" title="Facebook" target="_blank" class="icon-facebook"><span>Facebook</span></a></li>
|
||||
<li class="social-link-linkedin"><a href="https://es.linkedin.com/in/manuelcillero" title="Linkedin" target="_blank" class="icon-linkedin"><span>Linkedin</span></a></li>
|
||||
<li class="social-link-gitlab"><a href="https://gitlab.com/manuelcillero" title="Gitlab" target="_blank" class="icon-gitlab"><span>Gitlab</span></a></li>
|
||||
<li class="social-link-mail"><a href="https://manuel.cillero.es/contacto/#suitepro" title="Mail" class="icon-mail"><span>Mail</span></a></li>
|
||||
</ul>
|
||||
<div class="bgl"><div class="bgr">
|
||||
<div id="legal">
|
||||
<span class="legal-legal"><a href="/projects/suitepro/wiki/Legal"><%= l(:label_legal) %></a></span>
|
||||
<span class="legal-terms"> | <a href="/projects/suitepro/wiki/Condiciones_de_uso"><%= l(:label_legal_terms) %></a></span>
|
||||
<span class="legal-privacy"> | <a href="/projects/suitepro/wiki/Política_de_privacidad"><%= l(:label_legal_privacy) %></a></span>
|
||||
<span class="legal-cookies"> | <a href="/projects/suitepro/wiki/Política_de_cookies"><%= l(:label_legal_cookies) %></a></span>
|
||||
</div>
|
||||
<%= Time.current.year %> © SuitePro (powered by <%= link_to Redmine::Info.app_name, Redmine::Info.url %>)
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="bgl"><div class="bgr">
|
||||
Powered by <%= link_to Redmine::Info.app_name, Redmine::Info.url %> © 2006-2019 Jean-Philippe Lang
|
||||
</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%= call_hook :view_layouts_base_body_bottom %>
|
||||
|
||||
<script>
|
||||
//<![CDATA[
|
||||
window.addEventListener("load", function(){
|
||||
window.cookieconsent.initialise({
|
||||
"palette": { "popup": { "background": "rgba(20,20,20,0.8)" }, "button": { "background": "#fff" } },
|
||||
"theme": "classic",
|
||||
"position": "bottom-left",
|
||||
"content": { "message": "<a href='https://suitepro.cillero.es'>SuitePro</a> requiere el uso de cookies para ofrecer la mejor experiencia de acceso a sus contenidos. Puedes aceptar su uso o abandonar la página si lo deseas.", "dismiss": "ACEPTO SU USO", "link": "Más información", "href": "/projects/suitepro/wiki/Pol%C3%ADtica_de_cookies", "target": "_self" }
|
||||
})});
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<%= content_tag :h1, @title -%>
|
||||
<% end %></p>
|
||||
|
||||
<p><%= l(:field_user) %>: <strong><%= User.current.login %></strong><br/>
|
||||
<%= l(:field_remote_ip) %>: <strong><%= User.current.remote_ip %></strong><br/>
|
||||
<p><%= l(:field_user) %>: <strong><%= @originator.login %></strong><br/>
|
||||
<%= l(:field_remote_ip) %>: <strong><%= @remote_ip %></strong><br/>
|
||||
<%= l(:label_date) %>: <strong><%= format_time Time.now, true, @user %></strong></p>
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<%= @url || @title %>
|
||||
|
||||
<%= l(:field_user) %>: <%= User.current.login %>
|
||||
<%= l(:field_remote_ip) %>: <%= User.current.remote_ip %>
|
||||
<%= l(:field_user) %>: <%= @originator.login %>
|
||||
<%= l(:field_remote_ip) %>: <%= @remote_ip %>
|
||||
<%= l(:label_date) %>: <%= format_time Time.now, true, @user %>
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="box">
|
||||
<legend><%= l(:label_role_plural) %> <%= toggle_checkboxes_link('.roles-selection input') %></legend>
|
||||
<legend><%= toggle_checkboxes_link('.roles-selection input') %><%= l(:label_role_plural) %></legend>
|
||||
<div class="roles-selection">
|
||||
<% User.current.managed_roles(@project).each do |role| %>
|
||||
<label><%= check_box_tag 'membership[role_ids][]', role.id, false, :id => nil %> <%= role %></label>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<fieldset class="box">
|
||||
<legend><%= l(:label_project_plural) %> <%= toggle_checkboxes_link('.projects-selection input:enabled') %></legend>
|
||||
<legend><%= toggle_checkboxes_link('.projects-selection input:enabled') %><%= l(:label_project_plural) %></legend>
|
||||
<div class="objects-selection">
|
||||
<div class="projects-selection">
|
||||
<%= render_project_nested_lists(@projects) do |p| %>
|
||||
|
@ -12,7 +12,7 @@
|
|||
</fieldset>
|
||||
|
||||
<fieldset class="box">
|
||||
<legend><%= l(:label_role_plural) %> <%= toggle_checkboxes_link('.roles-selection input') %></legend>
|
||||
<legend><%= toggle_checkboxes_link('.roles-selection input') %><%= l(:label_role_plural) %></legend>
|
||||
<div class="roles-selection">
|
||||
<% @roles.each do |role| %>
|
||||
<label>
|
||||
|
|
|
@ -3,39 +3,41 @@
|
|||
<% end %>
|
||||
|
||||
<% if @project.repositories.any? %>
|
||||
<table class="list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= l(:field_identifier) %></th>
|
||||
<th><%= l(:field_repository_is_default) %></th>
|
||||
<th><%= l(:label_scm) %></th>
|
||||
<th><%= l(:label_repository) %></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @project.repositories.sort.each do |repository| %>
|
||||
<tr>
|
||||
<td class="name">
|
||||
<%= link_to repository.identifier,
|
||||
{:controller => 'repositories', :action => 'show',:id => @project, :repository_id => repository.identifier_param} if repository.identifier.present? %>
|
||||
</td>
|
||||
<td><%= checked_image repository.is_default? %></td>
|
||||
<td><%= repository.scm_name %></td>
|
||||
<td><%= repository.url %></td>
|
||||
<td class="buttons">
|
||||
<% if User.current.allowed_to?(:manage_repository, @project) %>
|
||||
<%= link_to(l(:label_user_plural), committers_repository_path(repository),
|
||||
:class => 'icon icon-user') %>
|
||||
<%= link_to(l(:button_edit), edit_repository_path(repository),
|
||||
:class => 'icon icon-edit') %>
|
||||
<%= delete_link repository_path(repository) %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="autoscroll">
|
||||
<table class="list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= l(:field_identifier) %></th>
|
||||
<th><%= l(:field_repository_is_default) %></th>
|
||||
<th><%= l(:label_scm) %></th>
|
||||
<th><%= l(:label_repository) %></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @project.repositories.sort.each do |repository| %>
|
||||
<tr>
|
||||
<td class="name">
|
||||
<%= link_to repository.identifier,
|
||||
{:controller => 'repositories', :action => 'show',:id => @project, :repository_id => repository.identifier_param} if repository.identifier.present? %>
|
||||
</td>
|
||||
<td><%= checked_image repository.is_default? %></td>
|
||||
<td><%= repository.scm_name %></td>
|
||||
<td><%= repository.url %></td>
|
||||
<td class="buttons">
|
||||
<% if User.current.allowed_to?(:manage_repository, @project) %>
|
||||
<%= link_to(l(:label_user_plural), committers_repository_path(repository),
|
||||
:class => 'icon icon-user') %>
|
||||
<%= link_to(l(:button_edit), edit_repository_path(repository),
|
||||
:class => 'icon icon-edit') %>
|
||||
<%= delete_link repository_path(repository) %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<% else %>
|
||||
<p class="nodata"><%= l(:label_no_data) %></p>
|
||||
<% end %>
|
||||
|
|
|
@ -33,7 +33,9 @@
|
|||
|
||||
</div>
|
||||
|
||||
<div class="wiki changeset-comments"><%= format_changeset_comments @changeset %></div>
|
||||
<div class="wiki changeset-comments">
|
||||
<%= format_changeset_comments @changeset %>
|
||||
</div>
|
||||
|
||||
<% if @changeset.issues.visible.any? || User.current.allowed_to?(:manage_related_issues, @repository.project) %>
|
||||
<%= render :partial => 'related_issues' %>
|
||||
|
|
|
@ -21,10 +21,11 @@
|
|||
</p>
|
||||
<%= hidden_field_tag 'tracker[core_fields][]', '' %>
|
||||
|
||||
<% if IssueCustomField.all.any? %>
|
||||
<% @issue_custom_fields = IssueCustomField.sorted %>
|
||||
<% if @issue_custom_fields.present? %>
|
||||
<p>
|
||||
<label><%= l(:label_custom_field_plural) %></label>
|
||||
<% IssueCustomField.all.each do |field| %>
|
||||
<% @issue_custom_fields.each do |field| %>
|
||||
<label class="block">
|
||||
<%= check_box_tag 'tracker[custom_field_ids][]',field.id, @tracker.custom_fields.to_a.include?(field), :id => nil %>
|
||||
<%= field.name %>
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
<% if User.current.logged? %>
|
||||
|
||||
<h2><%= l(:label_home) %></h2>
|
||||
|
||||
<div class="splitcontentleft">
|
||||
|
@ -26,149 +24,3 @@
|
|||
<%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :key => User.current.rss_key, :format => 'atom'},
|
||||
:title => "#{Setting.app_title}: #{l(:label_activity)}") %>
|
||||
<% end %>
|
||||
|
||||
<% else %><!-- Frontpage -->
|
||||
|
||||
<div id="fp"><%= text_field_tag 'forcetop', nil, :style => 'display: none;' %>
|
||||
|
||||
<!-- Banner -->
|
||||
<section id="fp-banner">
|
||||
<div class="inner">
|
||||
<h2>SuitePro</h2>
|
||||
<p><%= l(:welcome_suitepro) %></p>
|
||||
<ul class="actions special">
|
||||
<li><a href="#fp-login" class="button primary scrolly"><%= l(:label_login) %></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<a href="#one" class="more scrolly"><%= l(:welcome_discover) %></a>
|
||||
</section>
|
||||
|
||||
<!-- One -->
|
||||
<section id="one" class="frapper style1 special">
|
||||
<div class="inner">
|
||||
<header class="major">
|
||||
<h2>A SIMPLE WAY TO GET WORK DONE ;)</h2>
|
||||
<p><%= raw l(:welcome_suitepro_is_redmine, :suitepro => '<strong>SuitePro</strong>', :redmine => '<a href="https://www.redmine.org"><strong>Redmine</strong></a>') %></p>
|
||||
</header>
|
||||
<ul class="icons major">
|
||||
<li><span class="fp-icon fp-icon_1 major style1"><span class="label">Lorem</span></span></li>
|
||||
<li><span class="fp-icon fp-icon_2 major style2"><span class="label">Ipsum</span></span></li>
|
||||
<li><span class="fp-icon fp-icon_3 major style3"><span class="label">Dolor</span></span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Two -->
|
||||
<section id="two" class="frapper alt style2">
|
||||
<section class="spotlight">
|
||||
<div class="image"><%= image_tag '/themes/circlepro/images/pic01.jpg' %></div><div class="content">
|
||||
<h2><%= raw l(:welcome_spotlight_1_title) %></h2>
|
||||
<p><%= l(:welcome_spotlight_1_text) %></p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="spotlight">
|
||||
<div class="image"><%= image_tag '/themes/circlepro/images/pic02.jpg' %></div><div class="content">
|
||||
<h2><%= raw l(:welcome_spotlight_2_title) %></h2>
|
||||
<p><%= l(:welcome_spotlight_2_text) %></p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="spotlight">
|
||||
<div class="image"><%= image_tag '/themes/circlepro/images/pic03.jpg' %></div><div class="content">
|
||||
<h2><%= raw l(:welcome_spotlight_3_title) %></h2>
|
||||
<p><%= l(:welcome_spotlight_3_text) %></p>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<!-- Three -->
|
||||
<section id="three" class="frapper style3 special">
|
||||
<div class="inner">
|
||||
<header class="major">
|
||||
<h2><%= l(:welcome_other_features) %></h2>
|
||||
</header>
|
||||
<ul class="features">
|
||||
<li class="fp-icon fp-icon_4">
|
||||
<h3><%= l(:welcome_feature_1_title) %></h3>
|
||||
<p><%= l(:welcome_feature_1_text) %></p>
|
||||
</li>
|
||||
<li class="fp-icon fp-icon_5">
|
||||
<h3><%= l(:welcome_feature_2_title) %></h3>
|
||||
<p><%= l(:welcome_feature_2_text) %></p>
|
||||
</li>
|
||||
<li class="fp-icon fp-icon_6">
|
||||
<h3><%= l(:welcome_feature_3_title) %></h3>
|
||||
<p><%= l(:welcome_feature_3_text) %></p>
|
||||
</li>
|
||||
<li class="fp-icon fp-icon_7">
|
||||
<h3><%= l(:welcome_feature_4_title) %></h3>
|
||||
<p><%= l(:welcome_feature_4_text) %></p>
|
||||
</li>
|
||||
<li class="fp-icon fp-icon_8">
|
||||
<h3><%= l(:welcome_feature_5_title) %></h3>
|
||||
<p><%= l(:welcome_feature_5_text) %></p>
|
||||
</li>
|
||||
<li class="fp-icon fp-icon_9">
|
||||
<h3><%= l(:welcome_feature_6_title) %></h3>
|
||||
<p><%= l(:welcome_feature_6_text) %></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Login -->
|
||||
<section id="fp-login" class="frapper style4">
|
||||
<div class="inner">
|
||||
<%= call_hook :view_account_login_top %>
|
||||
|
||||
<div id="login-form">
|
||||
<h2><%= l(:label_login) %></h2>
|
||||
<%= form_tag(signin_path, onsubmit: 'return keepAnchorOnSignIn(this);') do %>
|
||||
<%= back_url_hidden_field_tag %>
|
||||
|
||||
<label for="username"><%=l(:field_login)%></label>
|
||||
<%= text_field_tag 'username', params[:username], :tabindex => '1' %>
|
||||
|
||||
<label for="password">
|
||||
<%=l(:field_password)%>
|
||||
<%= link_to l(:label_password_lost), lost_password_path, :class => "lost_password" if Setting.lost_password? %>
|
||||
</label>
|
||||
<%= password_field_tag 'password', nil, :tabindex => '2' %>
|
||||
|
||||
<% if Setting.openid? %>
|
||||
<label for="openid_url"><%=l(:field_identity_url)%></label>
|
||||
<%= text_field_tag "openid_url", nil, :tabindex => '3' %>
|
||||
<% end %>
|
||||
|
||||
<% if Setting.autologin? %>
|
||||
<label for="autologin"><%= check_box_tag 'autologin', 1, false, :tabindex => 4 %> <%= l(:label_stay_logged_in) %></label>
|
||||
<% end %>
|
||||
|
||||
<input type="submit" name="login" value="<%=l(:button_login)%>" tabindex="5" id="login-submit" />
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section id="fp-cta" class="frapper style4">
|
||||
<div class="inner">
|
||||
<header>
|
||||
<h2><%= l(:welcome_any_questions) %></h2>
|
||||
<p><%= l(:welcome_please_contact) %></p>
|
||||
</header>
|
||||
<ul class="actions stacked">
|
||||
<li><a href="https://manuel.cillero.es/contacto/#suitepro" class="button fit primary"><%= l(:welcome_contact) %></a></li>
|
||||
<li><a href="https://manuel.cillero.es/sobre-mi" class="button fit"><%= l(:welcome_about_me) %></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="/themes/circlepro/javascripts/frontpage/jquery.scrolly.min.js"></script>
|
||||
<script src="/themes/circlepro/javascripts/frontpage/browser.min.js"></script>
|
||||
<script src="/themes/circlepro/javascripts/frontpage/breakpoints.min.js"></script>
|
||||
<script src="/themes/circlepro/javascripts/frontpage/util.js"></script>
|
||||
<script src="/themes/circlepro/javascripts/frontpage/main.js"></script>
|
||||
|
||||
<% end %>
|
||||
|
|
|
@ -46,8 +46,7 @@
|
|||
|
||||
<%= render(:partial => "wiki/content", :locals => {:content => @content}) %>
|
||||
|
||||
<% if @page.attachments.length > 0 || (@editable && authorize_for('wiki', 'add_attachment')) %>
|
||||
<fieldset class="collapsible collapsed<% if @page.attachments.length == 0 %> hide-when-print<% end %>">
|
||||
<fieldset class="collapsible collapsed hide-when-print">
|
||||
<legend onclick="toggleFieldset(this);"><%= l(:label_attachment_plural) %> (<%= @page.attachments.length %>)</legend>
|
||||
<div style="display: none;">
|
||||
|
||||
|
@ -67,7 +66,6 @@
|
|||
<% end %>
|
||||
</div>
|
||||
</fieldset>
|
||||
<% end %>
|
||||
|
||||
<% other_formats_links do |f| %>
|
||||
<%= f.link_to 'PDF', :url => {:id => @page.title, :version => params[:version]} %>
|
||||
|
|
|
@ -1211,8 +1211,8 @@ de:
|
|||
label_table_of_contents: Inhaltsverzeichnis
|
||||
error_no_projects_with_tracker_allowed_for_new_issue: Es gibt keine Projekte mit Trackern, für welche sie Tickets erzeugen können
|
||||
field_textarea_font: Schriftart für Textbereiche
|
||||
label_font_default: Strandardschrift
|
||||
label_font_monospace: Nichtproporzionale Schrift
|
||||
label_font_default: Standardschrift
|
||||
label_font_monospace: Nichtproportionale Schrift
|
||||
label_font_proportional: Proportionale Schrift
|
||||
setting_commit_logs_formatting: Textformatierung für Commit Nachrichten
|
||||
setting_mail_handler_enable_regex_delimiters: Reguläre Ausdrücke erlauben
|
||||
|
|
|
@ -1209,40 +1209,3 @@ en:
|
|||
description_issue_category_reassign: Choose issue category
|
||||
description_wiki_subpages_reassign: Choose new parent page
|
||||
text_repository_identifier_info: 'Only lower case letters (a-z), numbers, dashes and underscores are allowed.<br />Once saved, the identifier cannot be changed.'
|
||||
|
||||
welcome_suitepro: Planning, knowledge sharing, clients support and personal productivity, with both powerful and simplicity in mind.
|
||||
welcome_discover: Discover
|
||||
welcome_suitepro_is_redmine: "%{suitepro} is powered by %{redmine}, the popular project management and issue tracking solution based on the Ruby on Rails framework. Redmine lets us have a powerful workflow for getting tasks done and keep information in one place."
|
||||
|
||||
welcome_spotlight_1_title: "The Basics: Projects,<br /> Tasks, Issue Tracking"
|
||||
welcome_spotlight_1_text: Keep track of everything, with visual indicators to monitorize tasks and subtasks in order to stay up to date with milestones, track of time, workflows and all that requires attention.
|
||||
welcome_spotlight_2_title: "Documents, Wikis,<br /> File Management"
|
||||
welcome_spotlight_2_text: Keep documents and files availables wherever you are. Use the wiki project to save project requeriments, attached files, install and user guides, or meeting minutes at your fingertips.
|
||||
welcome_spotlight_3_title: "Flexible control<br /> of user access"
|
||||
welcome_spotlight_3_text: Using a role-based approach, roles are a collection of permissions outlining how users can operate with the projects. Each member of a project can have one or more roles assigned by administrators.
|
||||
|
||||
welcome_other_features: Other Features
|
||||
welcome_feature_1_title: Gantt Chart And Calendar
|
||||
welcome_feature_1_text: The gantt chart displays issues that have a start date and a due date. The calendar provides an overview of a project as a monthly view.
|
||||
welcome_feature_2_title: News And Forums
|
||||
welcome_feature_2_text: News to show information about the status of projects or any other subjects. The forums allow users from a project to communicate with each others.
|
||||
welcome_feature_3_title: Email notifications And Feeds
|
||||
welcome_feature_3_text: SuitePro can be configured to receive notifications via email. It also provides web feeds to use with external readers or aggregators.
|
||||
welcome_feature_4_title: Code Repositories
|
||||
welcome_feature_4_text: Version Control Systems like Git or Subversion can be used as code repositories and also keep track of changes made to the code.
|
||||
welcome_feature_5_title: Responsive Design
|
||||
welcome_feature_5_text: SuitePro is optimized to look great on mobile devices thanks to its responsive design. All pages adapt automatically to the screen size on a mobile phone, tablet or desktop computer.
|
||||
welcome_feature_6_title: Is Open Source Software
|
||||
welcome_feature_6_text: It means you are not locked into using a particular vendor’s system, and it’s continually evolving in real time as developers add to it and modify it.
|
||||
|
||||
welcome_any_questions: Any Questions?
|
||||
welcome_please_contact: Please feel free to contact me if you need any further information.
|
||||
welcome_contact: Contact
|
||||
welcome_about_me: More About Me
|
||||
|
||||
link_my_blog: My Blog
|
||||
|
||||
label_legal: Legal notice
|
||||
label_legal_terms: Terms of use
|
||||
label_legal_privacy: Privacy policy
|
||||
label_legal_cookies: Cookies policy
|
||||
|
|
|
@ -504,7 +504,7 @@ es:
|
|||
label_loading: Cargando...
|
||||
label_logged_as: Conectado como
|
||||
label_login: Iniciar sesión
|
||||
label_logout: Cerrar sesión
|
||||
label_logout: Terminar sesión
|
||||
label_max_size: Tamaño máximo
|
||||
label_me: yo mismo
|
||||
label_member: Miembro
|
||||
|
@ -543,7 +543,7 @@ es:
|
|||
label_optional_description: Descripción opcional
|
||||
label_options: Opciones
|
||||
label_overall_activity: Actividad global
|
||||
label_overview: Resumen
|
||||
label_overview: Vistazo
|
||||
label_password_lost: ¿Olvidaste la contraseña?
|
||||
label_permissions: Permisos
|
||||
label_permissions_report: Informe de permisos
|
||||
|
@ -1217,7 +1217,7 @@ es:
|
|||
mail_body_security_notification_notify_disabled: Se han desactivado las notificaciones para el correo electrónico %{value}
|
||||
mail_body_settings_updated: ! 'Las siguientes opciones han sido actualizadas:'
|
||||
field_remote_ip: Dirección IP
|
||||
label_wiki_page_new: Nueva página
|
||||
label_wiki_page_new: Nueva pagina wiki
|
||||
label_relations: Relaciones
|
||||
button_filter: Filtro
|
||||
mail_body_password_updated: Su contraseña se ha cambiado.
|
||||
|
@ -1233,7 +1233,7 @@ es:
|
|||
label_font_monospace: Fuente Monospaced
|
||||
label_font_proportional: Fuente Proportional
|
||||
setting_timespan_format: Time span format
|
||||
label_table_of_contents: Tabla de contenidos
|
||||
label_table_of_contents: Table of contents
|
||||
setting_commit_logs_formatting: Apply text formatting to commit messages
|
||||
setting_mail_handler_enable_regex_delimiters: Enable regular expressions
|
||||
error_move_of_child_not_possible: 'Subtask %{child} could not be moved to the new
|
||||
|
@ -1256,41 +1256,3 @@ es:
|
|||
permission_view_news: View news
|
||||
label_no_preview_alternative_html: No preview available. %{link} the file instead.
|
||||
label_no_preview_download: Download
|
||||
|
||||
|
||||
welcome_suitepro: Potencia y sencillez para planificar, compartir conocimiento, prestar soporte a clientes y acelerar la productividad.
|
||||
welcome_discover: Descubre
|
||||
welcome_suitepro_is_redmine: "%{suitepro} es %{redmine}, la conocida herramienta para la gestión de proyectos y el seguimiento de peticiones basada en Ruby on Rails. Redmine apremia la finalización de las tareas y mantiene la información en un único sitio."
|
||||
|
||||
welcome_spotlight_1_title: "Lo Básico: Proyectos,<br /> Tareas, Peticiones"
|
||||
welcome_spotlight_1_text: Podrás hacer un seguimiento completo de todo, monitorizar tareas y subtareas para estar al día de los hitos de proyecto, controlar los tiempos, los flujos de trabajo o cualquier elemento que requiera atención.
|
||||
welcome_spotlight_2_title: "Documentos, Wikis,<br /> Gestión de Archivos"
|
||||
welcome_spotlight_2_text: Organizados para disponer de los documentos y los archivos allá donde se esté. Y el wiki de proyecto para estructurar los requerimientos, las guías de instalación y de usuario, o las actas de trabajo.
|
||||
welcome_spotlight_3_title: "Control de accesos<br /> flexible"
|
||||
welcome_spotlight_3_text: Usando permisos agrupados en roles para establecer cómo pueden operar los usuarios en los proyectos. Cada miembro de un proyecto podrá tener uno o más roles asignados por los administradores.
|
||||
|
||||
welcome_other_features: Otras Características
|
||||
welcome_feature_1_title: Diagrama de Gantt y Calendario
|
||||
welcome_feature_1_text: El diagrama de Gantt muestra las tareas que tienen fecha de inicio y vencimiento. Y el calendario da una visión general de los proyectos en una vista mensual.
|
||||
welcome_feature_2_title: Noticias y Foros
|
||||
welcome_feature_2_text: Las noticias muestran información sobre novedades en los proyectos u otros temas de interés. Y los foros permiten que los usuarios de un proyecto se comuniquen entre sí.
|
||||
welcome_feature_3_title: Notificaciones y Sindicación
|
||||
welcome_feature_3_text: SuitePro se puede configurar para recibir notificaciones por correo electrónico. Y también proporciona sindicaciones para utilizar con agregadores externos.
|
||||
welcome_feature_4_title: Repositorios de Código
|
||||
welcome_feature_4_text: Sistemas de Control de Versiones como Git o Subversion pueden usarse como repositorios de código y seguir desde SuitePro los cambios realizados en el código.
|
||||
welcome_feature_5_title: Responsive Design
|
||||
welcome_feature_5_text: SuitePro está optimizado para visualizarse en dispositivos móviles. Las páginas se adaptan automáticamente al tamaño de la pantalla, ya sea un teléfono móvil, una tableta o un ordenador.
|
||||
welcome_feature_6_title: Es Software de Código Abierto
|
||||
welcome_feature_6_text: Esto supone no estar limitado por ningún proveedor, y seguir en permanente evolución con desarrolladores que se involucran continuamente.
|
||||
|
||||
welcome_any_questions: ¿Alguna Pregunta?
|
||||
welcome_please_contact: No dudar en contactar conmigo para obtener más información.
|
||||
welcome_contact: Contactar
|
||||
welcome_about_me: Más Sobre Mí
|
||||
|
||||
link_my_blog: Mi blog personal
|
||||
|
||||
label_legal: Aviso legal
|
||||
label_legal_terms: Condiciones de uso
|
||||
label_legal_privacy: Política de privacidad
|
||||
label_legal_cookies: Uso de cookies
|
||||
|
|
|
@ -140,8 +140,8 @@ gl:
|
|||
invalid: "non é válido"
|
||||
confirmation: "non coincide coa confirmación"
|
||||
accepted: "debe ser aceptado"
|
||||
empty: "non pode estar valeiro"
|
||||
blank: "non pode estar en blanco"
|
||||
empty: "non pode estar baleiro"
|
||||
blank: "non pode estar en branco"
|
||||
too_long: "é demasiado longo (non máis de %{count} carácteres)"
|
||||
too_short: "é demasiado curto (non menos de %{count} carácteres)"
|
||||
wrong_length: "non ten a lonxitude correcta (debe ser de %{count} carácteres)"
|
||||
|
@ -426,7 +426,7 @@ gl:
|
|||
label_f_hour: "%{value} hora"
|
||||
label_f_hour_plural: "%{value} horas"
|
||||
label_feed_plural: Feeds
|
||||
label_feeds_access_key_created_on: "Clave de acceso por Atom creada hai %{value}"
|
||||
label_feeds_access_key_created_on: "Chave de acceso por Atom creada hai %{value}"
|
||||
label_file_added: Ficheiro engadido
|
||||
label_file_plural: Ficheiros
|
||||
label_filter_add: Engadir o filtro
|
||||
|
@ -435,7 +435,7 @@ gl:
|
|||
label_follows: posterior a
|
||||
label_gantt: Gantt
|
||||
label_general: Xeral
|
||||
label_generate_key: Xerar clave
|
||||
label_generate_key: Xerar chave
|
||||
label_help: Axuda
|
||||
label_history: Histórico
|
||||
label_home: Inicio
|
||||
|
@ -648,7 +648,7 @@ gl:
|
|||
notice_email_error: "Ocorreu un error enviando o correo (%{value})"
|
||||
notice_email_sent: "Enviouse un correo a %{value}"
|
||||
notice_failed_to_save_issues: "Imposible gravar %{count} petición(s) de %{total} seleccionada(s): %{ids}."
|
||||
notice_feeds_access_key_reseted: A súa clave de acceso para Atom reiniciouse.
|
||||
notice_feeds_access_key_reseted: A súa chave de acceso para Atom reiniciouse.
|
||||
notice_file_not_found: A páxina á que tenta acceder non existe.
|
||||
notice_locking_conflict: Os datos modificáronse por outro usuario.
|
||||
notice_no_issue_selected: "Ningunha petición seleccionada. Por favor, comprobe a petición que quere modificar"
|
||||
|
@ -720,8 +720,8 @@ gl:
|
|||
setting_autofetch_changesets: Autorechear as remisións do repositorio
|
||||
setting_autologin: "Identificarse automaticamente."
|
||||
setting_bcc_recipients: Ocultar as copias de carbón (bcc)
|
||||
setting_commit_fix_keywords: Palabras clave para a corrección
|
||||
setting_commit_ref_keywords: Palabras clave para a referencia
|
||||
setting_commit_fix_keywords: Palabras chave para a corrección
|
||||
setting_commit_ref_keywords: Palabras chave para a referencia
|
||||
setting_cross_project_issue_relations: Permitir relacionar peticións de distintos proxectos
|
||||
setting_date_format: Formato da data
|
||||
setting_default_language: Idioma predeterminado
|
||||
|
@ -738,7 +738,7 @@ gl:
|
|||
setting_login_required: Requírese identificación
|
||||
setting_mail_from: Correo dende o que enviar mensaxes
|
||||
setting_mail_handler_api_enabled: Activar o programa para mensaxes entrantes
|
||||
setting_mail_handler_api_key: Clave da API
|
||||
setting_mail_handler_api_key: Chave da API
|
||||
setting_per_page_options: Obxectos por páxina
|
||||
setting_plain_text_mail: só texto plano (non HTML)
|
||||
setting_protocol: Protocolo
|
||||
|
@ -1121,118 +1121,118 @@ gl:
|
|||
setting_link_copied_issue: "Ligar aos tíckets ao copialos"
|
||||
label_link_copied_issue: "Ligar ao tícket copiado"
|
||||
label_ask: "Preguntar"
|
||||
label_search_attachments_yes: Search attachment filenames and descriptions
|
||||
label_search_attachments_no: Do not search attachments
|
||||
label_search_attachments_only: Search attachments only
|
||||
label_search_open_issues_only: Open issues only
|
||||
label_search_attachments_yes: Buscar nomes e descricións dos ficheiros
|
||||
label_search_attachments_no: Non buscar ficheiros
|
||||
label_search_attachments_only: Buscar só ficheiros
|
||||
label_search_open_issues_only: Só peticións abertas
|
||||
field_address: Correo electrónico
|
||||
setting_max_additional_emails: Maximum number of additional email addresses
|
||||
label_email_address_plural: Emails
|
||||
label_email_address_add: Add email address
|
||||
label_enable_notifications: Enable notifications
|
||||
label_disable_notifications: Disable notifications
|
||||
setting_search_results_per_page: Search results per page
|
||||
label_blank_value: blank
|
||||
permission_copy_issues: Copy issues
|
||||
error_password_expired: Your password has expired or the administrator requires you
|
||||
to change it.
|
||||
field_time_entries_visibility: Time logs visibility
|
||||
setting_password_max_age: Require password change after
|
||||
label_parent_task_attributes: Parent tasks attributes
|
||||
label_parent_task_attributes_derived: Calculated from subtasks
|
||||
label_parent_task_attributes_independent: Independent of subtasks
|
||||
label_time_entries_visibility_all: All time entries
|
||||
label_time_entries_visibility_own: Time entries created by the user
|
||||
label_member_management: Member management
|
||||
label_member_management_all_roles: All roles
|
||||
label_member_management_selected_roles_only: Only these roles
|
||||
label_password_required: Confirm your password to continue
|
||||
setting_max_additional_emails: Máximo número de enderezos de correo adicionais
|
||||
label_email_address_plural: Correos
|
||||
label_email_address_add: Engadir enderezo de correo
|
||||
label_enable_notifications: Activar notificacións
|
||||
label_disable_notifications: Desactivar notificacións
|
||||
setting_search_results_per_page: Resultados da busca por páxina
|
||||
label_blank_value: En branco
|
||||
permission_copy_issues: Copiar peticións
|
||||
error_password_expired: A túa contrasinal caducou ou o administrador obrígate
|
||||
a cambiala.
|
||||
field_time_entries_visibility: Visibilidade das entradas de tempo
|
||||
setting_password_max_age: Obrigar a cambiar a contrasinal despois de
|
||||
label_parent_task_attributes: Atributos da tarefa pai
|
||||
label_parent_task_attributes_derived: Calculada a partir das subtarefas
|
||||
label_parent_task_attributes_independent: Independente das subtarefas
|
||||
label_time_entries_visibility_all: Todas as entradas de tempo
|
||||
label_time_entries_visibility_own: Horas creadas polo usuario
|
||||
label_member_management: Xestión de membros
|
||||
label_member_management_all_roles: Todos os roles
|
||||
label_member_management_selected_roles_only: Só estes roles
|
||||
label_password_required: Confirma a túa contrasinal para continuar
|
||||
label_total_spent_time: "Tempo total empregado"
|
||||
notice_import_finished: "%{count} items have been imported"
|
||||
notice_import_finished_with_errors: "%{count} out of %{total} items could not be imported"
|
||||
error_invalid_file_encoding: The file is not a valid %{encoding} encoded file
|
||||
error_invalid_csv_file_or_settings: The file is not a CSV file or does not match the
|
||||
settings below
|
||||
error_can_not_read_import_file: An error occurred while reading the file to import
|
||||
permission_import_issues: Import issues
|
||||
label_import_issues: Import issues
|
||||
label_select_file_to_import: Select the file to import
|
||||
label_fields_separator: Field separator
|
||||
label_fields_wrapper: Field wrapper
|
||||
label_encoding: Encoding
|
||||
label_comma_char: Comma
|
||||
label_semi_colon_char: Semicolon
|
||||
label_quote_char: Quote
|
||||
label_double_quote_char: Double quote
|
||||
label_fields_mapping: Fields mapping
|
||||
label_file_content_preview: File content preview
|
||||
label_create_missing_values: Create missing values
|
||||
button_import: Import
|
||||
field_total_estimated_hours: Total estimated time
|
||||
notice_import_finished: "%{count} elementos foron importados"
|
||||
notice_import_finished_with_errors: "%{count} dun total de %{total} elementos non puideron ser importados"
|
||||
error_invalid_file_encoding: O ficheiro non é un ficheiro codificado %{encoding} válido
|
||||
error_invalid_csv_file_or_settings: O ficheiro non é un arquivo CSV ou non coincide coas
|
||||
opcións de abaixo
|
||||
error_can_not_read_import_file: Aconteceu un erro lendo o ficheiro a importar
|
||||
permission_import_issues: Importar peticións
|
||||
label_import_issues: Importar peticións
|
||||
label_select_file_to_import: Selecciona o ficheiro a importar
|
||||
label_fields_separator: Separador dos campos
|
||||
label_fields_wrapper: Envoltorio dos campos
|
||||
label_encoding: Codificación
|
||||
label_comma_char: Coma
|
||||
label_semi_colon_char: Punto e coma
|
||||
label_quote_char: Comilla simple
|
||||
label_double_quote_char: Comilla dobre
|
||||
label_fields_mapping: Mapeo de campos
|
||||
label_file_content_preview: Vista previa do contido
|
||||
label_create_missing_values: Crear valores non presentes
|
||||
button_import: Importar
|
||||
field_total_estimated_hours: Total de tempo estimado
|
||||
label_api: API
|
||||
label_total_plural: Totals
|
||||
label_assigned_issues: Assigned issues
|
||||
label_field_format_enumeration: Key/value list
|
||||
label_total_plural: Totais
|
||||
label_assigned_issues: Peticións asignadas
|
||||
label_field_format_enumeration: Listaxe chave/valor
|
||||
label_f_hour_short: '%{value} h'
|
||||
field_default_version: Default version
|
||||
error_attachment_extension_not_allowed: Attachment extension %{extension} is not allowed
|
||||
setting_attachment_extensions_allowed: Allowed extensions
|
||||
setting_attachment_extensions_denied: Disallowed extensions
|
||||
label_any_open_issues: any open issues
|
||||
label_no_open_issues: no open issues
|
||||
label_default_values_for_new_users: Default values for new users
|
||||
error_ldap_bind_credentials: Invalid LDAP Account/Password
|
||||
setting_sys_api_key: Clave da API
|
||||
setting_lost_password: "Esqueceu o contrasinal?"
|
||||
mail_subject_security_notification: Security notification
|
||||
mail_body_security_notification_change: ! '%{field} was changed.'
|
||||
mail_body_security_notification_change_to: ! '%{field} was changed to %{value}.'
|
||||
mail_body_security_notification_add: ! '%{field} %{value} was added.'
|
||||
mail_body_security_notification_remove: ! '%{field} %{value} was removed.'
|
||||
mail_body_security_notification_notify_enabled: Email address %{value} now receives
|
||||
notifications.
|
||||
mail_body_security_notification_notify_disabled: Email address %{value} no longer
|
||||
receives notifications.
|
||||
mail_body_settings_updated: ! 'The following settings were changed:'
|
||||
field_remote_ip: IP address
|
||||
label_wiki_page_new: New wiki page
|
||||
label_relations: Relations
|
||||
button_filter: Filter
|
||||
mail_body_password_updated: Your password has been changed.
|
||||
label_no_preview: No preview available
|
||||
error_no_tracker_allowed_for_new_issue_in_project: The project doesn't have any trackers
|
||||
for which you can create an issue
|
||||
label_tracker_all: All trackers
|
||||
label_new_project_issue_tab_enabled: Display the "New issue" tab
|
||||
setting_new_item_menu_tab: Project menu tab for creating new objects
|
||||
label_new_object_tab_enabled: Display the "+" drop-down
|
||||
error_no_projects_with_tracker_allowed_for_new_issue: There are no projects with trackers
|
||||
for which you can create an issue
|
||||
field_textarea_font: Font used for text areas
|
||||
label_font_default: Default font
|
||||
label_font_monospace: Monospaced font
|
||||
label_font_proportional: Proportional font
|
||||
setting_timespan_format: Time span format
|
||||
label_table_of_contents: Table of contents
|
||||
setting_commit_logs_formatting: Apply text formatting to commit messages
|
||||
setting_mail_handler_enable_regex_delimiters: Enable regular expressions
|
||||
error_move_of_child_not_possible: 'Subtask %{child} could not be moved to the new
|
||||
project: %{errors}'
|
||||
error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: Spent time cannot
|
||||
be reassigned to an issue that is about to be deleted
|
||||
setting_timelog_required_fields: Required fields for time logs
|
||||
field_default_version: Versión predeterminada
|
||||
error_attachment_extension_not_allowed: A extensión anexada %{extension} non é permitida
|
||||
setting_attachment_extensions_allowed: Extensións permitidas
|
||||
setting_attachment_extensions_denied: Extensións prohibidas
|
||||
label_any_open_issues: Calquera petición aberta
|
||||
label_no_open_issues: Peticións non abertas
|
||||
label_default_values_for_new_users: Valor predeterminado para novos usuarios
|
||||
error_ldap_bind_credentials: A conta/contrasinal do LDAP non é válida
|
||||
setting_sys_api_key: Chave da API
|
||||
setting_lost_password: Esqueceu a contrasinal?
|
||||
mail_subject_security_notification: Notificación de seguridade
|
||||
mail_body_security_notification_change: ! '%{field} modificado.'
|
||||
mail_body_security_notification_change_to: ! '%{field} modificado por %{value}.'
|
||||
mail_body_security_notification_add: ! '%{field} %{value} engadido.'
|
||||
mail_body_security_notification_remove: ! '%{field} %{value} eliminado.'
|
||||
mail_body_security_notification_notify_enabled: O correo electrónico %{value} agora recibirá
|
||||
notificacións
|
||||
mail_body_security_notification_notify_disabled: O correo electrónico %{value} deixará de recibir
|
||||
notificacións
|
||||
mail_body_settings_updated: ! 'As seguintes opcións foron actualizadas:'
|
||||
field_remote_ip: Enderezo IP
|
||||
label_wiki_page_new: Nova páxina wiki
|
||||
label_relations: Relacións
|
||||
button_filter: Filtro
|
||||
mail_body_password_updated: A súa contrasinal foi cambiada.
|
||||
label_no_preview: Non hai vista previa dispoñible
|
||||
error_no_tracker_allowed_for_new_issue_in_project: O proxecto non ten ningún tipo
|
||||
para que poida crear unha petición
|
||||
label_tracker_all: Tódolos tipos
|
||||
label_new_project_issue_tab_enabled: Amosar a lapela "Nova petición"
|
||||
setting_new_item_menu_tab: Lapela no menú de cada proxecto para creación de novos obxectos
|
||||
label_new_object_tab_enabled: Amosar a lista despregable "+"
|
||||
error_no_projects_with_tracker_allowed_for_new_issue: Non hai proxectos con tipos
|
||||
para as que poida crear unha petición
|
||||
field_textarea_font: Fonte usada nas áreas de texto
|
||||
label_font_default: Fonte por defecto
|
||||
label_font_monospace: Fonte Monospaced
|
||||
label_font_proportional: Fonte Proporcional
|
||||
setting_timespan_format: Formato de período temporal
|
||||
label_table_of_contents: Índice de contidos
|
||||
setting_commit_logs_formatting: Aplicar formateo de texto para as mensaxes de commit
|
||||
setting_mail_handler_enable_regex_delimiters: Activar expresións regulares
|
||||
error_move_of_child_not_possible: 'A subtarefa %{child} non se pode mover ao novo
|
||||
proxecto: %{errors}'
|
||||
error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: O tempo empregado non pode
|
||||
ser reasignado a unha petición que vai ser eliminada
|
||||
setting_timelog_required_fields: Campos obrigatorios para as imputacións de tempo
|
||||
label_attribute_of_object: '%{object_name}''s %{name}'
|
||||
label_user_mail_option_only_assigned: Only for things I watch or I am assigned to
|
||||
label_user_mail_option_only_owner: Only for things I watch or I am the owner of
|
||||
warning_fields_cleared_on_bulk_edit: Changes will result in the automatic deletion
|
||||
of values from one or more fields on the selected objects
|
||||
field_updated_by: Updated by
|
||||
field_last_updated_by: Last updated by
|
||||
field_full_width_layout: Full width layout
|
||||
label_last_notes: Last notes
|
||||
field_digest: Checksum
|
||||
field_default_assigned_to: Default assignee
|
||||
setting_show_custom_fields_on_registration: Show custom fields on registration
|
||||
permission_view_news: View news
|
||||
label_no_preview_alternative_html: No preview available. %{link} the file instead.
|
||||
label_no_preview_download: Download
|
||||
label_user_mail_option_only_assigned: Só para as cousas que sigo ou que teño asignado
|
||||
label_user_mail_option_only_owner: Só para as cousas que sigo ou son o propietario
|
||||
warning_fields_cleared_on_bulk_edit: Os cambios provocarán o borrado automático
|
||||
dos valores de un ou máis campos dos obxectos seleccionados
|
||||
field_updated_by: Actualizado por
|
||||
field_last_updated_by: Última actualización por
|
||||
field_full_width_layout: Deseño para ancho completo
|
||||
label_last_notes: Últimas notas
|
||||
field_digest: Suma de verificación
|
||||
field_default_assigned_to: Asignado por defecto
|
||||
setting_show_custom_fields_on_registration: Amosar os campos personalizados no rexistro
|
||||
permission_view_news: Ver noticias
|
||||
label_no_preview_alternative_html: Non hai vista previa dispoñible. %{link} o ficheiro no seu lugar.
|
||||
label_no_preview_download: Descargar
|
||||
|
|
|
@ -618,7 +618,7 @@ ja:
|
|||
one: 1コメント
|
||||
other: "%{count}コメント"
|
||||
label_comment_add: コメント追加
|
||||
label_comment_added: 追加されたコメント
|
||||
label_comment_added: コメントが追加されました
|
||||
label_comment_delete: コメント削除
|
||||
label_query: カスタムクエリ
|
||||
label_query_plural: カスタムクエリ
|
||||
|
|
|
@ -890,7 +890,7 @@ lt:
|
|||
label_version_sharing_none: Nesidalinama
|
||||
label_version_sharing_descendants: Su sub-projektais
|
||||
label_version_sharing_hierarchy: Su projekto hierarchija
|
||||
label_version_sharing_tree: WiSu projekto medžiu
|
||||
label_version_sharing_tree: Su projekto medžiu
|
||||
label_version_sharing_system: Su visais projektais
|
||||
label_update_issue_done_ratios: Atnaujinti darbo atlikimo progresą
|
||||
label_copy_source: Šaltinis
|
||||
|
|
|
@ -149,9 +149,9 @@ pt-BR:
|
|||
not_same_project: "não pertence ao mesmo projeto"
|
||||
circular_dependency: "Esta relação geraria uma dependência circular"
|
||||
cant_link_an_issue_with_a_descendant: "Uma tarefa não pode ser relacionada a uma de suas subtarefas"
|
||||
earlier_than_minimum_start_date: "cannot be earlier than %{date} because of preceding issues"
|
||||
not_a_regexp: "is not a valid regular expression"
|
||||
open_issue_with_closed_parent: "An open issue cannot be attached to a closed parent task"
|
||||
earlier_than_minimum_start_date: "não pode ser anterior a %{date} por causa de tarefas anteriores"
|
||||
not_a_regexp: "não é uma expressão regular válida"
|
||||
open_issue_with_closed_parent: "Uma tarefa aberta não pode ser associada à uma tarefa pai fechada"
|
||||
|
||||
actionview_instancetag_blank_option: Selecione
|
||||
|
||||
|
@ -159,7 +159,7 @@ pt-BR:
|
|||
general_text_Yes: 'Sim'
|
||||
general_text_no: 'não'
|
||||
general_text_yes: 'sim'
|
||||
general_lang_name: 'Portuguese/Brasil (Português/Brasil)'
|
||||
general_lang_name: 'Portuguese/Brazil (Português/Brasil)'
|
||||
general_csv_separator: ';'
|
||||
general_csv_decimal_separator: ','
|
||||
general_csv_encoding: ISO-8859-1
|
||||
|
@ -1125,7 +1125,7 @@ pt-BR:
|
|||
label_group_non_member: Usuários não membros
|
||||
label_add_projects: Adicionar projetos
|
||||
field_default_status: Situação padrão
|
||||
text_subversion_repository_note: 'Examplos: file:///, http://, https://, svn://, svn+[tunnelscheme]://'
|
||||
text_subversion_repository_note: 'Exemplos: file:///, http://, https://, svn://, svn+[tunnelscheme]://'
|
||||
field_users_visibility: Visibilidade do usuário
|
||||
label_users_visibility_all: Todos usuários ativos
|
||||
label_users_visibility_members_of_visible_projects: Membros de projetos visíveis
|
||||
|
|
|
@ -1166,7 +1166,7 @@ ru:
|
|||
label_cross_project_system: Со всеми проектами
|
||||
button_hide: Скрыть
|
||||
setting_non_working_week_days: Нерабочие дни
|
||||
label_in_the_next_days: в средующие дни
|
||||
label_in_the_next_days: в следующие дни
|
||||
label_in_the_past_days: в прошлые дни
|
||||
label_attribute_of_user: Пользователь %{name}
|
||||
text_turning_multiple_off: Если отключить множественные значения, лишние значения из списка будут удалены, чтобы осталось только по одному значению.
|
||||
|
|
|
@ -134,7 +134,7 @@ sv:
|
|||
not_same_project: "tillhör inte samma projekt"
|
||||
circular_dependency: "Denna relation skulle skapa ett cirkulärt beroende"
|
||||
cant_link_an_issue_with_a_descendant: "Ett ärende kan inte länkas till ett av dess underärenden"
|
||||
earlier_than_minimum_start_date: "kan inte vara tidigare än% {datum} på grund av föregående ärenden"
|
||||
earlier_than_minimum_start_date: "kan inte vara tidigare än %{date} på grund av föregående ärenden"
|
||||
not_a_regexp: "is not a valid regular expression"
|
||||
open_issue_with_closed_parent: "An open issue cannot be attached to a closed parent task"
|
||||
|
||||
|
|
|
@ -1215,12 +1215,12 @@ uk:
|
|||
field_updated_by: Оновлено
|
||||
field_last_updated_by: Востаннє оновлено
|
||||
field_full_width_layout: Макет на повну ширину
|
||||
label_user_mail_option_only_assigned: Only for things I watch or I am assigned to
|
||||
label_user_mail_option_only_owner: Only for things I watch or I am the owner of
|
||||
label_last_notes: Last notes
|
||||
field_digest: Checksum
|
||||
field_default_assigned_to: Default assignee
|
||||
setting_show_custom_fields_on_registration: Show custom fields on registration
|
||||
permission_view_news: View news
|
||||
label_no_preview_alternative_html: No preview available. %{link} the file instead.
|
||||
label_no_preview_download: Download
|
||||
label_user_mail_option_only_assigned: Лише для об'єктів за якими я спостерігаю або до яких прикріплений
|
||||
label_user_mail_option_only_owner: Лише для об'єктів за якими я спостерігаю або є власником
|
||||
label_last_notes: Останні коментарі
|
||||
field_digest: Контрольна сума
|
||||
field_default_assigned_to: Призначити по замовчуванню
|
||||
setting_show_custom_fields_on_registration: Показувати додаткові поля при реєстрації
|
||||
permission_view_news: Переглядати новини
|
||||
label_no_preview_alternative_html: Попередній перегляд недоступний. %{link} файл натомість.
|
||||
label_no_preview_download: Завантажити
|
||||
|
|
|
@ -304,7 +304,7 @@ zh:
|
|||
field_comments_sorting: 显示注释
|
||||
field_parent_title: 上级页面
|
||||
field_editable: 可编辑
|
||||
field_watcher: 跟踪者
|
||||
field_watcher: 关注者
|
||||
field_identity_url: OpenID URL
|
||||
field_content: 内容
|
||||
field_group_by: 根据此条件分组
|
||||
|
@ -393,9 +393,9 @@ zh:
|
|||
permission_save_queries: 保存查询
|
||||
permission_view_gantt: 查看甘特图
|
||||
permission_view_calendar: 查看日历
|
||||
permission_view_issue_watchers: 查看跟踪者列表
|
||||
permission_add_issue_watchers: 添加跟踪者
|
||||
permission_delete_issue_watchers: 删除跟踪者
|
||||
permission_view_issue_watchers: 查看关注者列表
|
||||
permission_add_issue_watchers: 添加关注者
|
||||
permission_delete_issue_watchers: 删除关注者
|
||||
permission_log_time: 登记工时
|
||||
permission_view_time_entries: 查看耗时
|
||||
permission_edit_time_entries: 编辑耗时
|
||||
|
@ -675,7 +675,7 @@ zh:
|
|||
label_options: 选项
|
||||
label_copy_workflow_from: 从以下选项复制工作流程
|
||||
label_permissions_report: 权限报表
|
||||
label_watched_issues: 跟踪的问题
|
||||
label_watched_issues: 关注的问题
|
||||
label_related_issues: 相关的问题
|
||||
label_applied_status: 应用后的状态
|
||||
label_loading: 载入中...
|
||||
|
@ -731,7 +731,7 @@ zh:
|
|||
label_user_mail_option_all: "收取我的项目的所有通知"
|
||||
label_user_mail_option_selected: "收取选中项目的所有通知..."
|
||||
label_user_mail_option_none: "不收取任何通知"
|
||||
label_user_mail_option_only_my_events: "只收取我跟踪或参与的项目的通知"
|
||||
label_user_mail_option_only_my_events: "只收取我关注或参与的项目的通知"
|
||||
label_user_mail_no_self_notified: "不要发送对我自己提交的修改的通知"
|
||||
label_registration_activation_by_email: 通过邮件认证激活帐号
|
||||
label_registration_manual_activation: 手动激活帐号
|
||||
|
@ -751,7 +751,7 @@ zh:
|
|||
label_reverse_chronological_order: 按时间顺序(倒序)
|
||||
label_incoming_emails: 接收邮件
|
||||
label_generate_key: 生成一个key
|
||||
label_issue_watchers: 跟踪者
|
||||
label_issue_watchers: 关注者
|
||||
label_example: 示例
|
||||
label_display: 显示
|
||||
label_sort: 排序
|
||||
|
@ -811,8 +811,8 @@ zh:
|
|||
button_sort: 排序
|
||||
button_log_time: 登记工时
|
||||
button_rollback: 恢复到这个版本
|
||||
button_watch: 跟踪
|
||||
button_unwatch: 取消跟踪
|
||||
button_watch: 关注
|
||||
button_unwatch: 取消关注
|
||||
button_reply: 回复
|
||||
button_archive: 存档
|
||||
button_unarchive: 取消存档
|
||||
|
@ -866,7 +866,7 @@ zh:
|
|||
text_issue_category_destroy_question: "有一些问题(%{count} 个)属于此类别。您想进行哪种操作?"
|
||||
text_issue_category_destroy_assignments: 删除问题的所属类别(问题变为无类别)
|
||||
text_issue_category_reassign_to: 为问题选择其它类别
|
||||
text_user_mail_option: "对于没有选中的项目,您将只会收到您跟踪或参与的项目的通知(比如说,您是问题的报告者, 或被指派解决此问题)。"
|
||||
text_user_mail_option: "对于没有选中的项目,您将只会收到您关注或参与的项目的通知(比如说,您是问题的报告者, 或被指派解决此问题)。"
|
||||
text_no_configuration_data: "角色、跟踪标签、问题状态和工作流程还没有设置。\n强烈建议您先载入默认设置,然后在此基础上进行修改。"
|
||||
text_load_default_configuration: 载入默认设置
|
||||
text_status_changed_by_changeset: "已应用到变更列表 %{value}."
|
||||
|
@ -1008,7 +1008,7 @@ zh:
|
|||
text_issue_conflict_resolution_cancel: 取消我所有的变更并重新刷新显示 %{link} 。
|
||||
permission_manage_related_issues: 相关问题管理
|
||||
field_auth_source_ldap_filter: LDAP 过滤器
|
||||
label_search_for_watchers: 通过查找方式添加跟踪者
|
||||
label_search_for_watchers: 通过查找方式添加关注者
|
||||
notice_account_deleted: 您的账号已被永久删除(账号已无法恢复)。
|
||||
setting_unsubscribe: 允许用户退订
|
||||
button_delete_my_account: 删除我的账号
|
||||
|
|
334
doc/CHANGELOG
334
doc/CHANGELOG
|
@ -4,6 +4,340 @@ Redmine - project management software
|
|||
Copyright (C) 2006-2017 Jean-Philippe Lang
|
||||
http://www.redmine.org/
|
||||
|
||||
== 2019-12-20 v3.4.13
|
||||
|
||||
=== [Attachments]
|
||||
|
||||
* Defect #20277: "Couldn't find template for digesting" error in the log when sending a thumbnail or an attachment
|
||||
|
||||
=== [Gems support]
|
||||
|
||||
* Patch #32592: Require 'mocha/minitest' instead of deprecated 'mocha/setup'
|
||||
|
||||
=== [Text formatting]
|
||||
|
||||
* Patch #25742: Improper markup sanitization in user content for space separated attribute values and different quoting styles
|
||||
|
||||
== 2019-10-19 v3.4.12
|
||||
|
||||
=== [Code cleanup/refactoring]
|
||||
|
||||
* Defect #32022: IssueSubtaskingTest fails with high probability
|
||||
|
||||
=== [Documentation]
|
||||
|
||||
* Defect #32170: Text enclosed in pre tag in Wiki formatting reference is not displayed in monospaced font in Chrome
|
||||
* Defect #32184: Incorrect headings example in Textile help
|
||||
|
||||
=== [Gems support]
|
||||
|
||||
* Defect #32300: Don't use sprockets 4.0.0 in order to avoid Sprockets::Railtie::ManifestNeededError
|
||||
* Patch #32294: Update ruby-openid to 2.9.2
|
||||
|
||||
=== [Issues]
|
||||
|
||||
* Defect #31778: Total estimated time issue query column and issue field might leak information
|
||||
|
||||
=== [Issues list]
|
||||
|
||||
* Defect #31779: Total estimated time column shown even when estimated time field is deactivated
|
||||
|
||||
=== [Translations]
|
||||
|
||||
* Defect #32290: Typo in Russian translation for label_in_the_next_days
|
||||
|
||||
=== [UI]
|
||||
|
||||
* Defect #32012: Broken JavaScript icon in the repository view
|
||||
* Defect #32024: Broken gzip icon in the repository view
|
||||
|
||||
== 2019-06-10 v3.4.11
|
||||
|
||||
=== [Administration]
|
||||
|
||||
* Defect #31125: Don't output ImageMagick version information to stdout
|
||||
|
||||
=== [Code cleanup/refactoring]
|
||||
|
||||
* Defect #30811: "rake db:fixtures:load" does not work
|
||||
|
||||
=== [Email receiving]
|
||||
|
||||
* Defect #30457: MailHandler.safe_receive does not output any error log
|
||||
* Defect #31503: Undefined local variable sender_email in MailHandler#receive_message_reply
|
||||
|
||||
=== [Issues filter]
|
||||
|
||||
* Patch #31276: Serialize group_by and totalable_names in Query#as_params
|
||||
|
||||
=== [SCM]
|
||||
|
||||
* Defect #31120: Garbage lines in the output of 'git branch' break git adapter
|
||||
|
||||
=== [Security]
|
||||
|
||||
* Defect #31520: Persistent XSS in textile formatting
|
||||
|
||||
=== [Translations]
|
||||
|
||||
* Defect #31264: Conflicting translation between "track" and "watch" in Simplified Chinese
|
||||
|
||||
=== [UI - Responsive]
|
||||
|
||||
* Defect #31153: Display horizontal scroll bar of files table when overflow occurs on small screen
|
||||
* Defect #31311: admin/info page: text cut off in pre tag on mobile
|
||||
|
||||
=== [Wiki]
|
||||
|
||||
* Patch #31334: Do not lose content when updating a wiki page that has been renamed in the meantime
|
||||
|
||||
== 2019-03-31 v3.4.10
|
||||
|
||||
=== [Administration]
|
||||
|
||||
* Defect #30939: Timeout for "Check for updates" on Plugins page is too short
|
||||
|
||||
=== [Files]
|
||||
|
||||
* Defect #31087: Deleting a version silently deletes its attachments
|
||||
|
||||
=== [Issues filter]
|
||||
|
||||
* Defect #30367: "Last updated by" filter causes an SQL error with MariaDB
|
||||
|
||||
=== [REST API]
|
||||
|
||||
* Defect #29055: Searching for issue number with REST API redirects to issue HTML page
|
||||
|
||||
=== [Rails support]
|
||||
|
||||
* Feature #31027: Upgrade to Rails 4.2.11.1
|
||||
|
||||
=== [Search engine]
|
||||
|
||||
* Defect #30923: Project search should select subprojects scope when the project has subprojects
|
||||
|
||||
=== [UI]
|
||||
|
||||
* Defect #30872: Copyright is outdated
|
||||
|
||||
== 2019-02-21 v3.4.9
|
||||
|
||||
=== [Gems support]
|
||||
|
||||
* Defect #30114: Installing xpath with Bundler fails in Ruby <=2.2
|
||||
* Patch #30821: Stay in RMagick 2.16.0 and don't update to 3.0.0
|
||||
|
||||
=== [UI]
|
||||
|
||||
* Patch #30818: Issues autocomplete should respond with content type json
|
||||
|
||||
== 2019-01-20 v3.4.8
|
||||
|
||||
=== [Code cleanup/refactoring]
|
||||
|
||||
* Patch #30413: Add ".ruby-version" to svn:ignore, .git:ignore, and .hgignore
|
||||
|
||||
=== [Database]
|
||||
|
||||
* Defect #30171: Decrypting LDAP and SCM passwords fail if the plaintext password is longer than 31 bytes
|
||||
|
||||
=== [Gems support]
|
||||
|
||||
* Defect #30353: Installing rails with Bundler 2.0 fails in 3.x
|
||||
|
||||
=== [Importers]
|
||||
|
||||
* Patch #30412: Import UTF-8 issue CSV files with BOM and quoted strings
|
||||
|
||||
=== [Translations]
|
||||
|
||||
* Patch #30293: Ukrainian translation update for 3.4-stable
|
||||
|
||||
=== [UI]
|
||||
|
||||
* Defect #30426: Table rows are not highlighted on mouseover on some pages
|
||||
* Patch #29951: Quick design fix/proposals for projects index page
|
||||
|
||||
== 2018-12-09 v3.4.7
|
||||
|
||||
=== [Custom fields]
|
||||
|
||||
* Defect #8317: Strip whitespace from integer custom field
|
||||
* Defect #28925: Custom field values for enumerations not saved
|
||||
* Patch #29674: Missing validation for custom field formats based on RecordList
|
||||
|
||||
=== [Email receiving]
|
||||
|
||||
* Defect #28576: Attachments are added even if validation fails when updating an issue via email
|
||||
* Defect #29191: Cannot set no_notification option when receiving emails via IMAP or POP3
|
||||
|
||||
=== [Importers]
|
||||
|
||||
* Defect #30001: CSV importer ignores shared version names of other projects
|
||||
|
||||
=== [Issues]
|
||||
|
||||
* Defect #28946: If assignee is locked subtasks don't get copied
|
||||
* Defect #30009: Empty sort criteria for issue query gives error
|
||||
* Defect #30027: Some styles (for ex: borders for tables) in a custom field with text formatting enabled are not displayed
|
||||
|
||||
=== [Issues filter]
|
||||
|
||||
* Defect #26785: Wrong columns after CSV export
|
||||
|
||||
=== [PDF export]
|
||||
|
||||
* Defect #28125: PNG images on a wiki page don't appear in exported PDF
|
||||
* Defect #28565: PDF export has too many whitespaces
|
||||
|
||||
=== [REST API]
|
||||
|
||||
* Defect #20788: REST API with JSON content missing attributes with false values
|
||||
|
||||
=== [Rails support]
|
||||
|
||||
* Feature #30043: Update Rails to 4.2.11
|
||||
|
||||
=== [SCM]
|
||||
|
||||
* Defect #29413: Mercurial 4.7 compatibility
|
||||
|
||||
=== [Search engine]
|
||||
|
||||
* Defect #28636: Cannot find an issue from a closed subproject when search scope is Project and its subprojects
|
||||
|
||||
=== [Text formatting]
|
||||
|
||||
* Defect #8395: Tags start with 'pre' are handled as 'pre' tag in Textile
|
||||
* Defect #29038: Thumbnail macro causes attachment file not found and broken filename and link
|
||||
* Defect #29247: Textile phrase modifiers break wiki macros
|
||||
* Defect #29756: \f or \v character in Textile markup may cause RegexpError exception
|
||||
|
||||
=== [Time tracking]
|
||||
|
||||
* Patch #29308: Time entry creation: preserve 'spent on' value when using 'Create and Continue'
|
||||
|
||||
=== [Translations]
|
||||
|
||||
* Patch #29702: Brazilian wiki help translation update
|
||||
* Patch #29703: Brazilian translation (jstoolbar-pt-br.js) update
|
||||
* Patch #29718: Brazilian translation update for 3.4-stable
|
||||
* Patch #29735: Galician translation fix for the words empty, blank, and key
|
||||
* Patch #29736: Galician translation update for 3.4-stable
|
||||
|
||||
=== [UI]
|
||||
|
||||
* Defect #29918: Related issues section ignores the date format setting
|
||||
* Defect #29950: Fix list rendering inside project description in projects#index
|
||||
|
||||
=== [UI - Responsive]
|
||||
|
||||
* Defect #24309: Setting page for repository does not scroll horizontally on small screens
|
||||
|
||||
=== [Wiki]
|
||||
|
||||
* Feature #29791: Hide "Files" section in wiki pages when printing
|
||||
|
||||
== 2018-06-10 v3.4.6
|
||||
|
||||
=== [Issues]
|
||||
|
||||
* Defect #27863: If version is closed or locked subtasks don't get copied
|
||||
* Defect #28765: Copying an issue fails if the issue is watched by a locked user
|
||||
* Patch #28649: Log automatic rescheduling of following issues to journal
|
||||
|
||||
=== [Permissions and roles]
|
||||
|
||||
* Defect #28693: Irrelevant permission is required to access some tabs in project settings page
|
||||
|
||||
=== [Project settings]
|
||||
|
||||
* Defect #27122: Filter for version name should be case-insensitive
|
||||
|
||||
=== [SCM]
|
||||
|
||||
* Defect #28725: Mercurial 4.6 compatibility
|
||||
|
||||
=== [Text formatting]
|
||||
|
||||
* Defect #28469: Syntax highlighter does not work if language name is single-quoted
|
||||
|
||||
=== [Translations]
|
||||
|
||||
* Patch #28881: Fix Japanese mistranslation for label_comment_added
|
||||
|
||||
=== [UI]
|
||||
|
||||
* Defect #22023: Issue id input should get focus after adding related issue
|
||||
|
||||
=== [UI - Responsive]
|
||||
|
||||
* Defect #28523: Display horizontal scroll bar of plugins table when overflow occurs on small screen
|
||||
|
||||
=== [Wiki]
|
||||
|
||||
* Patch #27090: Show the number of attachments on wiki pages
|
||||
|
||||
== 2018-04-07 v3.4.5
|
||||
|
||||
=== [Custom fields]
|
||||
|
||||
* Defect #28393: Sort issue custom fields by position in tracker UI
|
||||
|
||||
=== [Email notifications]
|
||||
|
||||
* Defect #28302: Security notification when changing password on password forgotten is empty
|
||||
|
||||
=== [Gantt]
|
||||
|
||||
* Defect #28204: Too large avatar breaks gantt when assignee is a group
|
||||
|
||||
=== [Issues]
|
||||
|
||||
* Defect #27862: Preformatted text overflows in preview
|
||||
* Patch #28168: Allow context-menu edit of % done and priority of parent issues if the fields are not derived
|
||||
|
||||
=== [Issues filter]
|
||||
|
||||
* Defect #28180: Role-base cross-project issue query visibility calculated incorrectly
|
||||
|
||||
=== [Plugin API]
|
||||
|
||||
* Patch #27963: Remove 'unloadable' from bundled sample plugin
|
||||
|
||||
=== [Security]
|
||||
|
||||
* Defect #26857: Fix for CVE-2015-9251 in JQuery 1.11.1
|
||||
|
||||
=== [Text formatting]
|
||||
|
||||
* Defect #27884: RTL wiki class broken in Redmine 3.2.6
|
||||
* Defect #28331: h4, h5 and h6 headings on wiki pages should have a paragraph mark
|
||||
* Patch #28119: Enable lax_spacing for markdown formatting in order to allow markdown blocks not surrounded by empty lines
|
||||
|
||||
=== [Time tracking]
|
||||
|
||||
* Defect #28110: Don't allow reassigning reported hours to the project if issue is a required field for time logs
|
||||
|
||||
=== [Translations]
|
||||
|
||||
* Defect #28109: Incorrect interpolation in Swedish locale
|
||||
* Defect #28113: Fix typo in German label_font_default
|
||||
* Defect #28192: Fix typo in German label_font_monospace
|
||||
* Patch #27994: Galician translation update (jstoolbar-gl.js)
|
||||
* Patch #28102: Fix typo in Lithuanian label_version_sharing_tree
|
||||
|
||||
=== [UI]
|
||||
|
||||
* Defect #28079: The green tick is positioned after the label in the new member modals
|
||||
* Defect #28208: Anonymous icon is wrongly displayed when assignee is a group
|
||||
* Defect #28259: attachments_fields id to class change not properly reflected in all CSS
|
||||
|
||||
=== [Wiki]
|
||||
|
||||
* Defect #25299: Markdown pre-block could derive incorrect wiki sections
|
||||
|
||||
== 2018-01-08 v3.4.4
|
||||
|
||||
=== [Accounts / authentication]
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# Sample plugin controller
|
||||
class ExampleController < ApplicationController
|
||||
unloadable
|
||||
|
||||
layout 'base'
|
||||
before_action :find_project, :authorize
|
||||
menu_item :sample_plugin
|
||||
|
|
|
@ -1,182 +1,182 @@
|
|||
require 'rubygems'
|
||||
|
||||
Gem::manage_gems
|
||||
|
||||
require 'rake/rdoctask'
|
||||
require 'rake/packagetask'
|
||||
require 'rake/gempackagetask'
|
||||
require 'rake/testtask'
|
||||
require 'rake/contrib/rubyforgepublisher'
|
||||
|
||||
PKG_NAME = 'acts_as_versioned'
|
||||
PKG_VERSION = '0.3.1'
|
||||
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
||||
PROD_HOST = "technoweenie@bidwell.textdrive.com"
|
||||
RUBY_FORGE_PROJECT = 'ar-versioned'
|
||||
RUBY_FORGE_USER = 'technoweenie'
|
||||
|
||||
desc 'Default: run unit tests.'
|
||||
task :default => :test
|
||||
|
||||
desc 'Test the calculations plugin.'
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'lib'
|
||||
t.pattern = 'test/**/*_test.rb'
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
desc 'Generate documentation for the calculations plugin.'
|
||||
Rake::RDocTask.new(:rdoc) do |rdoc|
|
||||
rdoc.rdoc_dir = 'rdoc'
|
||||
rdoc.title = "#{PKG_NAME} -- Simple versioning with active record models"
|
||||
rdoc.options << '--line-numbers --inline-source'
|
||||
rdoc.rdoc_files.include('README', 'CHANGELOG', 'RUNNING_UNIT_TESTS')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
||||
|
||||
spec = Gem::Specification.new do |s|
|
||||
s.name = PKG_NAME
|
||||
s.version = PKG_VERSION
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.summary = "Simple versioning with active record models"
|
||||
s.files = FileList["{lib,test}/**/*"].to_a + %w(README MIT-LICENSE CHANGELOG RUNNING_UNIT_TESTS)
|
||||
s.files.delete "acts_as_versioned_plugin.sqlite.db"
|
||||
s.files.delete "acts_as_versioned_plugin.sqlite3.db"
|
||||
s.files.delete "test/debug.log"
|
||||
s.require_path = 'lib'
|
||||
s.autorequire = 'acts_as_versioned'
|
||||
s.has_rdoc = true
|
||||
s.test_files = Dir['test/**/*_test.rb']
|
||||
s.add_dependency 'activerecord', '>= 1.10.1'
|
||||
s.add_dependency 'activesupport', '>= 1.1.1'
|
||||
s.author = "Rick Olson"
|
||||
s.email = "technoweenie@gmail.com"
|
||||
s.homepage = "http://techno-weenie.net"
|
||||
end
|
||||
|
||||
Rake::GemPackageTask.new(spec) do |pkg|
|
||||
pkg.need_tar = true
|
||||
end
|
||||
|
||||
desc "Publish the API documentation"
|
||||
task :pdoc => [:rdoc] do
|
||||
Rake::RubyForgePublisher.new(RUBY_FORGE_PROJECT, RUBY_FORGE_USER).upload
|
||||
end
|
||||
|
||||
desc 'Publish the gem and API docs'
|
||||
task :publish => [:pdoc, :rubyforge_upload]
|
||||
|
||||
desc "Publish the release files to RubyForge."
|
||||
task :rubyforge_upload => :package do
|
||||
files = %w(gem tgz).map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" }
|
||||
|
||||
if RUBY_FORGE_PROJECT then
|
||||
require 'net/http'
|
||||
require 'open-uri'
|
||||
|
||||
project_uri = "http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/"
|
||||
project_data = open(project_uri) { |data| data.read }
|
||||
group_id = project_data[/[?&]group_id=(\d+)/, 1]
|
||||
raise "Couldn't get group id" unless group_id
|
||||
|
||||
# This echos password to shell which is a bit sucky
|
||||
if ENV["RUBY_FORGE_PASSWORD"]
|
||||
password = ENV["RUBY_FORGE_PASSWORD"]
|
||||
else
|
||||
print "#{RUBY_FORGE_USER}@rubyforge.org's password: "
|
||||
password = STDIN.gets.chomp
|
||||
end
|
||||
|
||||
login_response = Net::HTTP.start("rubyforge.org", 80) do |http|
|
||||
data = [
|
||||
"login=1",
|
||||
"form_loginname=#{RUBY_FORGE_USER}",
|
||||
"form_pw=#{password}"
|
||||
].join("&")
|
||||
http.post("/account/login.php", data)
|
||||
end
|
||||
|
||||
cookie = login_response["set-cookie"]
|
||||
raise "Login failed" unless cookie
|
||||
headers = { "Cookie" => cookie }
|
||||
|
||||
release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}"
|
||||
release_data = open(release_uri, headers) { |data| data.read }
|
||||
package_id = release_data[/[?&]package_id=(\d+)/, 1]
|
||||
raise "Couldn't get package id" unless package_id
|
||||
|
||||
first_file = true
|
||||
release_id = ""
|
||||
|
||||
files.each do |filename|
|
||||
basename = File.basename(filename)
|
||||
file_ext = File.extname(filename)
|
||||
file_data = File.open(filename, "rb") { |file| file.read }
|
||||
|
||||
puts "Releasing #{basename}..."
|
||||
|
||||
release_response = Net::HTTP.start("rubyforge.org", 80) do |http|
|
||||
release_date = Time.now.strftime("%Y-%m-%d %H:%M")
|
||||
type_map = {
|
||||
".zip" => "3000",
|
||||
".tgz" => "3110",
|
||||
".gz" => "3110",
|
||||
".gem" => "1400"
|
||||
}; type_map.default = "9999"
|
||||
type = type_map[file_ext]
|
||||
boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor"
|
||||
|
||||
query_hash = if first_file then
|
||||
{
|
||||
"group_id" => group_id,
|
||||
"package_id" => package_id,
|
||||
"release_name" => PKG_FILE_NAME,
|
||||
"release_date" => release_date,
|
||||
"type_id" => type,
|
||||
"processor_id" => "8000", # Any
|
||||
"release_notes" => "",
|
||||
"release_changes" => "",
|
||||
"preformatted" => "1",
|
||||
"submit" => "1"
|
||||
}
|
||||
else
|
||||
{
|
||||
"group_id" => group_id,
|
||||
"release_id" => release_id,
|
||||
"package_id" => package_id,
|
||||
"step2" => "1",
|
||||
"type_id" => type,
|
||||
"processor_id" => "8000", # Any
|
||||
"submit" => "Add This File"
|
||||
}
|
||||
end
|
||||
|
||||
query = "?" + query_hash.map do |(name, value)|
|
||||
[name, URI.encode(value)].join("=")
|
||||
end.join("&")
|
||||
|
||||
data = [
|
||||
"--" + boundary,
|
||||
"Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"",
|
||||
"Content-Type: application/octet-stream",
|
||||
"Content-Transfer-Encoding: binary",
|
||||
"", file_data, ""
|
||||
].join("\x0D\x0A")
|
||||
|
||||
release_headers = headers.merge(
|
||||
"Content-Type" => "multipart/form-data; boundary=#{boundary}"
|
||||
)
|
||||
|
||||
target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php"
|
||||
http.post(target + query, data, release_headers)
|
||||
end
|
||||
|
||||
if first_file then
|
||||
release_id = release_response.body[/release_id=(\d+)/, 1]
|
||||
raise("Couldn't get release id") unless release_id
|
||||
end
|
||||
|
||||
first_file = false
|
||||
end
|
||||
end
|
||||
require 'rubygems'
|
||||
|
||||
Gem::manage_gems
|
||||
|
||||
require 'rake/rdoctask'
|
||||
require 'rake/packagetask'
|
||||
require 'rake/gempackagetask'
|
||||
require 'rake/testtask'
|
||||
require 'rake/contrib/rubyforgepublisher'
|
||||
|
||||
PKG_NAME = 'acts_as_versioned'
|
||||
PKG_VERSION = '0.3.1'
|
||||
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
||||
PROD_HOST = "technoweenie@bidwell.textdrive.com"
|
||||
RUBY_FORGE_PROJECT = 'ar-versioned'
|
||||
RUBY_FORGE_USER = 'technoweenie'
|
||||
|
||||
desc 'Default: run unit tests.'
|
||||
task :default => :test
|
||||
|
||||
desc 'Test the calculations plugin.'
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'lib'
|
||||
t.pattern = 'test/**/*_test.rb'
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
desc 'Generate documentation for the calculations plugin.'
|
||||
Rake::RDocTask.new(:rdoc) do |rdoc|
|
||||
rdoc.rdoc_dir = 'rdoc'
|
||||
rdoc.title = "#{PKG_NAME} -- Simple versioning with active record models"
|
||||
rdoc.options << '--line-numbers --inline-source'
|
||||
rdoc.rdoc_files.include('README', 'CHANGELOG', 'RUNNING_UNIT_TESTS')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
||||
|
||||
spec = Gem::Specification.new do |s|
|
||||
s.name = PKG_NAME
|
||||
s.version = PKG_VERSION
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.summary = "Simple versioning with active record models"
|
||||
s.files = FileList["{lib,test}/**/*"].to_a + %w(README MIT-LICENSE CHANGELOG RUNNING_UNIT_TESTS)
|
||||
s.files.delete "acts_as_versioned_plugin.sqlite.db"
|
||||
s.files.delete "acts_as_versioned_plugin.sqlite3.db"
|
||||
s.files.delete "test/debug.log"
|
||||
s.require_path = 'lib'
|
||||
s.autorequire = 'acts_as_versioned'
|
||||
s.has_rdoc = true
|
||||
s.test_files = Dir['test/**/*_test.rb']
|
||||
s.add_dependency 'activerecord', '>= 1.10.1'
|
||||
s.add_dependency 'activesupport', '>= 1.1.1'
|
||||
s.author = "Rick Olson"
|
||||
s.email = "technoweenie@gmail.com"
|
||||
s.homepage = "http://techno-weenie.net"
|
||||
end
|
||||
|
||||
Rake::GemPackageTask.new(spec) do |pkg|
|
||||
pkg.need_tar = true
|
||||
end
|
||||
|
||||
desc "Publish the API documentation"
|
||||
task :pdoc => [:rdoc] do
|
||||
Rake::RubyForgePublisher.new(RUBY_FORGE_PROJECT, RUBY_FORGE_USER).upload
|
||||
end
|
||||
|
||||
desc 'Publish the gem and API docs'
|
||||
task :publish => [:pdoc, :rubyforge_upload]
|
||||
|
||||
desc "Publish the release files to RubyForge."
|
||||
task :rubyforge_upload => :package do
|
||||
files = %w(gem tgz).map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" }
|
||||
|
||||
if RUBY_FORGE_PROJECT then
|
||||
require 'net/http'
|
||||
require 'open-uri'
|
||||
|
||||
project_uri = "http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/"
|
||||
project_data = open(project_uri) { |data| data.read }
|
||||
group_id = project_data[/[?&]group_id=(\d+)/, 1]
|
||||
raise "Couldn't get group id" unless group_id
|
||||
|
||||
# This echos password to shell which is a bit sucky
|
||||
if ENV["RUBY_FORGE_PASSWORD"]
|
||||
password = ENV["RUBY_FORGE_PASSWORD"]
|
||||
else
|
||||
print "#{RUBY_FORGE_USER}@rubyforge.org's password: "
|
||||
password = STDIN.gets.chomp
|
||||
end
|
||||
|
||||
login_response = Net::HTTP.start("rubyforge.org", 80) do |http|
|
||||
data = [
|
||||
"login=1",
|
||||
"form_loginname=#{RUBY_FORGE_USER}",
|
||||
"form_pw=#{password}"
|
||||
].join("&")
|
||||
http.post("/account/login.php", data)
|
||||
end
|
||||
|
||||
cookie = login_response["set-cookie"]
|
||||
raise "Login failed" unless cookie
|
||||
headers = { "Cookie" => cookie }
|
||||
|
||||
release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}"
|
||||
release_data = open(release_uri, headers) { |data| data.read }
|
||||
package_id = release_data[/[?&]package_id=(\d+)/, 1]
|
||||
raise "Couldn't get package id" unless package_id
|
||||
|
||||
first_file = true
|
||||
release_id = ""
|
||||
|
||||
files.each do |filename|
|
||||
basename = File.basename(filename)
|
||||
file_ext = File.extname(filename)
|
||||
file_data = File.open(filename, "rb") { |file| file.read }
|
||||
|
||||
puts "Releasing #{basename}..."
|
||||
|
||||
release_response = Net::HTTP.start("rubyforge.org", 80) do |http|
|
||||
release_date = Time.now.strftime("%Y-%m-%d %H:%M")
|
||||
type_map = {
|
||||
".zip" => "3000",
|
||||
".tgz" => "3110",
|
||||
".gz" => "3110",
|
||||
".gem" => "1400"
|
||||
}; type_map.default = "9999"
|
||||
type = type_map[file_ext]
|
||||
boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor"
|
||||
|
||||
query_hash = if first_file then
|
||||
{
|
||||
"group_id" => group_id,
|
||||
"package_id" => package_id,
|
||||
"release_name" => PKG_FILE_NAME,
|
||||
"release_date" => release_date,
|
||||
"type_id" => type,
|
||||
"processor_id" => "8000", # Any
|
||||
"release_notes" => "",
|
||||
"release_changes" => "",
|
||||
"preformatted" => "1",
|
||||
"submit" => "1"
|
||||
}
|
||||
else
|
||||
{
|
||||
"group_id" => group_id,
|
||||
"release_id" => release_id,
|
||||
"package_id" => package_id,
|
||||
"step2" => "1",
|
||||
"type_id" => type,
|
||||
"processor_id" => "8000", # Any
|
||||
"submit" => "Add This File"
|
||||
}
|
||||
end
|
||||
|
||||
query = "?" + query_hash.map do |(name, value)|
|
||||
[name, URI.encode(value)].join("=")
|
||||
end.join("&")
|
||||
|
||||
data = [
|
||||
"--" + boundary,
|
||||
"Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"",
|
||||
"Content-Type: application/octet-stream",
|
||||
"Content-Transfer-Encoding: binary",
|
||||
"", file_data, ""
|
||||
].join("\x0D\x0A")
|
||||
|
||||
release_headers = headers.merge(
|
||||
"Content-Type" => "multipart/form-data; boundary=#{boundary}"
|
||||
)
|
||||
|
||||
target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php"
|
||||
http.post(target + query, data, release_headers)
|
||||
end
|
||||
|
||||
if first_file then
|
||||
release_id = release_response.body[/release_id=(\d+)/, 1]
|
||||
raise("Couldn't get release id") unless release_id
|
||||
end
|
||||
|
||||
first_file = false
|
||||
end
|
||||
end
|
||||
end
|
|
@ -126,7 +126,7 @@ Redmine::AccessControl.map do |map|
|
|||
map.permission :log_time, {:timelog => [:new, :create]}, :require => :loggedin
|
||||
map.permission :edit_time_entries, {:timelog => [:edit, :update, :destroy, :bulk_edit, :bulk_update]}, :require => :member
|
||||
map.permission :edit_own_time_entries, {:timelog => [:edit, :update, :destroy,:bulk_edit, :bulk_update]}, :require => :loggedin
|
||||
map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member
|
||||
map.permission :manage_project_activities, {:projects => :settings, :project_enumerations => [:update, :destroy]}, :require => :member
|
||||
end
|
||||
|
||||
map.project_module :news do |map|
|
||||
|
@ -164,7 +164,7 @@ Redmine::AccessControl.map do |map|
|
|||
map.permission :browse_repository, {:repositories => [:show, :browse, :entry, :raw, :annotate, :changes, :diff, :stats, :graph]}, :read => true
|
||||
map.permission :commit_access, {}
|
||||
map.permission :manage_related_issues, {:repositories => [:add_related_issue, :remove_related_issue]}
|
||||
map.permission :manage_repository, {:repositories => [:new, :create, :edit, :update, :committers, :destroy]}, :require => :member
|
||||
map.permission :manage_repository, {:projects => :settings, :repositories => [:new, :create, :edit, :update, :committers, :destroy]}, :require => :member
|
||||
end
|
||||
|
||||
map.project_module :boards do |map|
|
||||
|
@ -174,7 +174,7 @@ Redmine::AccessControl.map do |map|
|
|||
map.permission :edit_own_messages, {:messages => :edit, :attachments => :upload}, :require => :loggedin
|
||||
map.permission :delete_messages, {:messages => :destroy}, :require => :member
|
||||
map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin
|
||||
map.permission :manage_boards, {:boards => [:new, :create, :edit, :update, :destroy]}, :require => :member
|
||||
map.permission :manage_boards, {:projects => :settings, :boards => [:new, :create, :edit, :update, :destroy]}, :require => :member
|
||||
end
|
||||
|
||||
map.project_module :calendar do |map|
|
||||
|
|
|
@ -33,7 +33,7 @@ module Redmine
|
|||
c.iv = iv
|
||||
e = c.update(text.to_s)
|
||||
e << c.final
|
||||
"aes-256-cbc:" + [e, iv].map {|v| Base64.encode64(v).strip}.join('--')
|
||||
"aes-256-cbc:" + [e, iv].map {|v| Base64.strict_encode64(v)}.join('--')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -486,7 +486,7 @@ module Redmine
|
|||
|
||||
def validate_single_value(custom_field, value, customized=nil)
|
||||
errs = super
|
||||
errs << ::I18n.t('activerecord.errors.messages.not_a_number') unless value.to_s =~ /^[+-]?\d+$/
|
||||
errs << ::I18n.t('activerecord.errors.messages.not_a_number') unless value.to_s.strip =~ /^[+-]?\d+$/
|
||||
errs
|
||||
end
|
||||
|
||||
|
@ -736,6 +736,16 @@ module Redmine
|
|||
options
|
||||
end
|
||||
|
||||
def validate_custom_value(custom_value)
|
||||
values = Array.wrap(custom_value.value).reject {|value| value.to_s == ''}
|
||||
invalid_values = values - possible_custom_value_options(custom_value).map(&:last)
|
||||
if invalid_values.any?
|
||||
[::I18n.t('activerecord.errors.messages.inclusion')]
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def order_statement(custom_field)
|
||||
if target_class.respond_to?(:fields_for_order_statement)
|
||||
target_class.fields_for_order_statement(value_join_alias(custom_field))
|
||||
|
|
|
@ -81,7 +81,7 @@ module Redmine
|
|||
# below : list unreadable files, but dont link them.
|
||||
:path => utf_8_path,
|
||||
:kind => (File.directory?(t1) ? 'dir' : 'file'),
|
||||
:size => (File.directory?(t1) ? nil : [File.size(t1)].pack('l').unpack('L').first),
|
||||
:size => (File.directory?(t1) ? nil : File.size(t1)),
|
||||
:lastrev =>
|
||||
Revision.new({:time => (File.mtime(t1)) })
|
||||
})
|
||||
|
|
|
@ -83,6 +83,7 @@ module Redmine
|
|||
io.each_line do |line|
|
||||
branch_rev = line.match('\s*(\*?)\s*(.*?)\s*([0-9a-f]{40}).*$')
|
||||
bran = GitBranch.new(branch_rev[2])
|
||||
next unless branch_rev
|
||||
bran.revision = branch_rev[3]
|
||||
bran.scmid = branch_rev[3]
|
||||
bran.is_default = ( branch_rev[1] == '*' )
|
||||
|
|
|
@ -46,14 +46,22 @@ Output example of rhmanifest::
|
|||
</rhmanifest>
|
||||
"""
|
||||
import re, time, cgi, urllib
|
||||
from mercurial import cmdutil, commands, node, error, hg
|
||||
from mercurial import cmdutil, commands, node, error, hg, registrar
|
||||
|
||||
cmdtable = {}
|
||||
command = cmdutil.command(cmdtable)
|
||||
command = registrar.command(cmdtable) if hasattr(registrar, 'command') else cmdutil.command(cmdtable)
|
||||
|
||||
_x = cgi.escape
|
||||
_u = lambda s: cgi.escape(urllib.quote(s))
|
||||
|
||||
def _changectx(repo, rev):
|
||||
if isinstance(rev, str):
|
||||
rev = repo.lookup(rev)
|
||||
if hasattr(repo, 'changectx'):
|
||||
return repo.changectx(rev)
|
||||
else:
|
||||
return repo[rev]
|
||||
|
||||
def _tip(ui, repo):
|
||||
# see mercurial/commands.py:tip
|
||||
def tiprev():
|
||||
|
@ -61,7 +69,7 @@ def _tip(ui, repo):
|
|||
return len(repo) - 1
|
||||
except TypeError: # Mercurial < 1.1
|
||||
return repo.changelog.count() - 1
|
||||
tipctx = repo.changectx(tiprev())
|
||||
tipctx = _changectx(repo, tiprev())
|
||||
ui.write('<tip revision="%d" node="%s"/>\n'
|
||||
% (tipctx.rev(), _x(node.hex(tipctx.node()))))
|
||||
|
||||
|
@ -94,13 +102,18 @@ def _branches(ui, repo):
|
|||
return repo.branchheads(branch, closed=False)
|
||||
except TypeError: # Mercurial < 1.2
|
||||
return repo.branchheads(branch)
|
||||
def lookup(rev, n):
|
||||
try:
|
||||
return repo.lookup(rev)
|
||||
except RuntimeError:
|
||||
return n
|
||||
for t, n, r in sorted(iterbranches(), key=lambda e: e[2], reverse=True):
|
||||
if repo.lookup(r) in branchheads(t):
|
||||
if lookup(r, n) in branchheads(t):
|
||||
ui.write('<branch revision="%d" node="%s" name="%s"/>\n'
|
||||
% (r, _x(node.hex(n)), _x(t)))
|
||||
|
||||
def _manifest(ui, repo, path, rev):
|
||||
ctx = repo.changectx(rev)
|
||||
ctx = _changectx(repo, rev)
|
||||
ui.write('<manifest revision="%d" path="%s">\n'
|
||||
% (ctx.rev(), _u(path)))
|
||||
|
||||
|
@ -155,7 +168,7 @@ def rhdiff(ui, repo, *pats, **opts):
|
|||
"""diff repository (or selected files)"""
|
||||
change = opts.pop('change', None)
|
||||
if change: # add -c option for Mercurial<1.1
|
||||
base = repo.changectx(change).parents()[0].rev()
|
||||
base = _changectx(repo, change).parents()[0].rev()
|
||||
opts['rev'] = [str(base), change]
|
||||
opts['nodates'] = True
|
||||
return commands.diff(ui, repo, *map(urllib.unquote_plus, pats), **opts)
|
||||
|
|
|
@ -87,6 +87,7 @@ module Redmine
|
|||
private
|
||||
|
||||
def normalize!
|
||||
self.reject! {|s| s.first.blank? }
|
||||
self.collect! {|s| s = Array(s); [s.first, (s.last == false || s.last.to_s == 'desc') ? 'desc' : 'asc']}
|
||||
self.slice!(3)
|
||||
self
|
||||
|
|
|
@ -49,7 +49,12 @@ module Redmine
|
|||
|
||||
def self.convert_available?
|
||||
return @convert_available if defined?(@convert_available)
|
||||
@convert_available = system("#{shell_quote CONVERT_BIN} -version") rescue false
|
||||
begin
|
||||
`#{shell_quote CONVERT_BIN} -version`
|
||||
@convert_available = $?.success?
|
||||
rescue
|
||||
@convert_available = false
|
||||
end
|
||||
logger.warn("Imagemagick's convert binary (#{CONVERT_BIN}) not available") unless @convert_available
|
||||
@convert_available
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ module Redmine
|
|||
module VERSION #:nodoc:
|
||||
MAJOR = 3
|
||||
MINOR = 4
|
||||
TINY = 4
|
||||
TINY = 13
|
||||
|
||||
# Branch values:
|
||||
# * official release: nil
|
||||
|
|
|
@ -48,7 +48,7 @@ module Redmine
|
|||
end
|
||||
|
||||
def method_missing(sym, *args, &block)
|
||||
if args.any?
|
||||
if args.count > 0
|
||||
if args.first.is_a?(Hash)
|
||||
if @struct.last.is_a?(Array)
|
||||
@struct.last << args.first unless block
|
||||
|
|
|
@ -94,15 +94,13 @@ module Redmine
|
|||
i = 0
|
||||
l = 1
|
||||
inside_pre = false
|
||||
@text.split(/(^(?:.+\r?\n\r?(?:\=+|\-+)|#+.+|~~~.*)\s*$)/).each do |part|
|
||||
@text.split(/(^(?:.+\r?\n\r?(?:\=+|\-+)|#+.+|(?:~~~|```).*)\s*$)/).each do |part|
|
||||
level = nil
|
||||
if part =~ /\A~{3,}(\S+)?\s*$/
|
||||
if $1
|
||||
if !inside_pre
|
||||
inside_pre = true
|
||||
end
|
||||
else
|
||||
inside_pre = !inside_pre
|
||||
if part =~ /\A(~{3,}|`{3,})(\S+)?\s*$/
|
||||
if !inside_pre
|
||||
inside_pre = true
|
||||
elsif !$2
|
||||
inside_pre = false
|
||||
end
|
||||
elsif inside_pre
|
||||
# nop
|
||||
|
@ -142,7 +140,8 @@ module Redmine
|
|||
:strikethrough => true,
|
||||
:superscript => true,
|
||||
:no_intra_emphasis => true,
|
||||
:footnotes => true
|
||||
:footnotes => true,
|
||||
:lax_spacing => true
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -120,9 +120,10 @@ module Redmine
|
|||
## replace <pre> content
|
||||
text.gsub!(/<redpre#(\d+)>/) do
|
||||
content = @pre_list[$1.to_i]
|
||||
if content.match(/<code\s+class="(\w+)">\s?(.+)/m)
|
||||
language = $1
|
||||
text = $2
|
||||
# This regex must match any data produced by RedCloth3#rip_offtags
|
||||
if content.match(/<code\s+class=(?:"([^"]+)"|'([^']+)')>\s?(.*)/m)
|
||||
language = $1 || $2
|
||||
text = $3
|
||||
if Redmine::SyntaxHighlighting.language_supported?(language)
|
||||
content = "<code class=\"#{language} syntaxhl\">" +
|
||||
Redmine::SyntaxHighlighting.highlight_by_language(text, language)
|
||||
|
|
|
@ -343,7 +343,7 @@ class RedCloth3 < String
|
|||
A_VLGN = /[\-^~]/
|
||||
C_CLAS = '(?:\([^")]+\))'
|
||||
C_LNGE = '(?:\[[a-z\-_]+\])'
|
||||
C_STYL = '(?:\{[^"}]+\})'
|
||||
C_STYL = '(?:\{[^{][^"}]+\})'
|
||||
S_CSPN = '(?:\\\\\d+)'
|
||||
S_RSPN = '(?:/\d+)'
|
||||
A = "(?:#{A_HLGN}?#{A_VLGN}?|#{A_VLGN}?#{A_HLGN}?)"
|
||||
|
@ -1034,7 +1034,7 @@ class RedCloth3 < String
|
|||
def flush_left( text )
|
||||
indt = 0
|
||||
if text =~ /^ /
|
||||
while text !~ /^ {#{indt}}\S/
|
||||
while text !~ /^ {#{indt}}[^ ]/
|
||||
indt += 1
|
||||
end unless text.empty?
|
||||
if indt.nonzero?
|
||||
|
@ -1049,7 +1049,7 @@ class RedCloth3 < String
|
|||
end
|
||||
|
||||
OFFTAGS = /(code|pre|kbd|notextile)/
|
||||
OFFTAG_MATCH = /(?:(<\/#{ OFFTAGS }>)|(<#{ OFFTAGS }[^>]*>))(.*?)(?=<\/?#{ OFFTAGS }\W|\Z)/mi
|
||||
OFFTAG_MATCH = /(?:(<\/#{ OFFTAGS }\b>)|(<#{ OFFTAGS }\b[^>]*>))(.*?)(?=<\/?#{ OFFTAGS }\b\W|\Z)/mi
|
||||
OFFTAG_OPEN = /<#{ OFFTAGS }/
|
||||
OFFTAG_CLOSE = /<\/?#{ OFFTAGS }/
|
||||
HASTAG_MATCH = /(<\/?\w[^\n]*?>)/m
|
||||
|
@ -1213,7 +1213,13 @@ class RedCloth3 < String
|
|||
|
||||
ALLOWED_TAGS = %w(redpre pre code kbd notextile)
|
||||
def escape_html_tags(text)
|
||||
text.gsub!(%r{<(\/?([!\w]+)[^<>\n]*)(>?)}) {|m| ALLOWED_TAGS.include?($2) ? "<#{$1}#{$3}" : "<#{$1}#{'>' unless $3.blank?}" }
|
||||
text.gsub!(%r{<(\/?([!\w]+)[^<>\n]*)(>?)}) do |m|
|
||||
if ALLOWED_TAGS.include?($2) && $3.present?
|
||||
"<#{$1}#{$3}"
|
||||
else
|
||||
"<#{$1}#{'>' unless $3.blank?}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -209,7 +209,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Nadpis 1. úrovně
|
||||
|
||||
h2. Nadpis 2. úrovně
|
||||
|
||||
h3. Nadpis 3. úrovně
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Titre
|
||||
|
||||
h2. Sous-titre
|
||||
|
||||
h3. Sous-sous-titre
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
|
@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
|
|||
|
||||
<pre>
|
||||
h1. Heading
|
||||
|
||||
h2. Subheading
|
||||
|
||||
h3. Subsubheading
|
||||
</pre>
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue