Merge branch 'release-v3.0.0' into stable
This commit is contained in:
commit
11e93ff36a
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,6 +4,7 @@
|
||||
/config/configuration.yml
|
||||
/config/database.yml
|
||||
/config/email.yml
|
||||
/config/setup_load_paths.rb
|
||||
/config/initializers/session_store.rb
|
||||
/coverage
|
||||
/db/*.db
|
||||
|
5
Gemfile
5
Gemfile
@ -1,11 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
source :rubygems
|
||||
|
||||
gem "rails", "2.3.14"
|
||||
|
||||
gem "coderay", "~> 0.9.7"
|
||||
gem "coderay", "~> 1.0.0"
|
||||
gem "i18n", "~> 0.4.2"
|
||||
gem "rubytree", "~> 0.5.2", :require => 'tree'
|
||||
gem "rdoc", ">= 2.4.2"
|
||||
gem "liquid", "~> 2.3.0"
|
||||
gem "acts-as-taggable-on", "= 2.1.0"
|
||||
# Needed only on RUBY_VERSION = 1.8, ruby 1.9+ compatible interpreters should bring their csv
|
||||
gem "fastercsv", "~> 1.5.0", :platforms => [:ruby_18, :jruby, :mingw_18]
|
||||
|
||||
|
@ -19,6 +19,10 @@ class AdminController < ApplicationController
|
||||
|
||||
include SortHelper
|
||||
|
||||
menu_item :projects, :only => [:projects]
|
||||
menu_item :plugins, :only => [:plugins]
|
||||
menu_item :info, :only => [:info]
|
||||
|
||||
def index
|
||||
@no_configuration_data = Redmine::DefaultData::Loader::no_data?
|
||||
end
|
||||
|
@ -65,6 +65,9 @@ class ApplicationController < ActionController::Base
|
||||
filter_parameter_logging :password
|
||||
|
||||
rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token
|
||||
# FIXME: This doesn't work with Rails >= 3.0 anymore
|
||||
# Possible workaround: https://github.com/rails/rails/issues/671#issuecomment-1780159
|
||||
rescue_from ActionController::RoutingError, :with => proc{render_404}
|
||||
|
||||
include Redmine::Search::Controller
|
||||
include Redmine::MenuManager::MenuController
|
||||
@ -75,8 +78,6 @@ class ApplicationController < ActionController::Base
|
||||
end
|
||||
|
||||
def user_setup
|
||||
# Check the settings cache for each request
|
||||
Setting.check_cache
|
||||
# Find the current user
|
||||
User.current = find_current_user
|
||||
end
|
||||
|
@ -13,7 +13,8 @@
|
||||
#++
|
||||
|
||||
class AutoCompletesController < ApplicationController
|
||||
before_filter :find_project
|
||||
before_filter :find_project, :only => :issues
|
||||
before_filter :require_admin, :only => :projects
|
||||
|
||||
def issues
|
||||
@issues = []
|
||||
@ -33,6 +34,38 @@ class AutoCompletesController < ApplicationController
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
def users
|
||||
if params[:remove_group_members].present?
|
||||
@group = Group.find(params[:remove_group_members])
|
||||
@removed_users = @group.users
|
||||
end
|
||||
|
||||
if params[:remove_watchers].present? && params[:klass].present?
|
||||
watcher_class = params[:klass].constantize
|
||||
if watcher_class.included_modules.include?(Redmine::Acts::Watchable) # check class is a watching class
|
||||
@object = watcher_class.find(params[:remove_watchers])
|
||||
@removed_users = @object.watcher_users
|
||||
end
|
||||
end
|
||||
|
||||
@removed_users ||= []
|
||||
|
||||
if params[:include_groups]
|
||||
user_finder = Principal
|
||||
else
|
||||
user_finder = User
|
||||
end
|
||||
|
||||
@users = user_finder.active.like(params[:q]).find(:all, :limit => 100) - @removed_users
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
def projects
|
||||
@principal = Principal.find(params[:id])
|
||||
@projects = Project.active.like(params[:q]).find(:all, :limit => 100) - @principal.projects
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_project
|
||||
|
@ -44,19 +44,32 @@ class DocumentsController < ApplicationController
|
||||
|
||||
def new
|
||||
@document = @project.documents.build(params[:document])
|
||||
if request.post? and @document.save
|
||||
attachments = Attachment.attach_files(@document, params[:attachments])
|
||||
render_attachment_warning_if_needed(@document)
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to :action => 'index', :project_id => @project
|
||||
if request.post?
|
||||
if User.current.allowed_to?(:add_document_watchers, @project) && params[:document]['watcher_user_ids'].present?
|
||||
@document.watcher_user_ids = params[:document]['watcher_user_ids']
|
||||
end
|
||||
|
||||
if @document.save
|
||||
attachments = Attachment.attach_files(@document, params[:attachments])
|
||||
render_attachment_warning_if_needed(@document)
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to :action => 'index', :project_id => @project
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@categories = DocumentCategory.all
|
||||
if request.post? and @document.update_attributes(params[:document])
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to :action => 'show', :id => @document
|
||||
|
||||
if request.post?
|
||||
if User.current.allowed_to?(:add_document_watchers, @project) && params[:document]['watcher_user_ids'].present?
|
||||
@document.watcher_user_ids = params[:document]['watcher_user_ids']
|
||||
end
|
||||
|
||||
if @document.update_attributes(params[:document])
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to :action => 'show', :id => @document
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -69,7 +82,12 @@ class DocumentsController < ApplicationController
|
||||
attachments = Attachment.attach_files(@document, params[:attachments])
|
||||
render_attachment_warning_if_needed(@document)
|
||||
|
||||
Mailer.deliver_attachments_added(attachments[:files]) if attachments.present? && attachments[:files].present? && Setting.notified_events.include?('document_added')
|
||||
if attachments.present? && attachments[:files].present? && Setting.notified_events.include?('document_added')
|
||||
# TODO: refactor
|
||||
attachments.first.container.recipients.each do |recipient|
|
||||
Mailer.deliver_attachments_added(attachments[:files], recipient)
|
||||
end
|
||||
end
|
||||
redirect_to :action => 'show', :id => @document
|
||||
end
|
||||
|
||||
|
@ -42,7 +42,11 @@ class FilesController < ApplicationController
|
||||
render_attachment_warning_if_needed(container)
|
||||
|
||||
if !attachments.empty? && !attachments[:files].blank? && Setting.notified_events.include?('file_added')
|
||||
Mailer.deliver_attachments_added(attachments[:files])
|
||||
# TODO: refactor
|
||||
recipients = attachments[:files].first.container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
|
||||
recipients.each do |recipient|
|
||||
Mailer.deliver_attachments_added(attachments[:files], recipient)
|
||||
end
|
||||
end
|
||||
redirect_to project_files_path(@project)
|
||||
end
|
||||
|
@ -126,16 +126,19 @@ class GroupsController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
def autocomplete_for_user
|
||||
@group = Group.find(params[:id])
|
||||
@users = User.active.not_in_group(@group).like(params[:q]).all(:limit => 100)
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
def edit_membership
|
||||
@group = Group.find(params[:id])
|
||||
@membership = Member.edit_membership(params[:membership_id], params[:membership], @group)
|
||||
@membership.save if request.post?
|
||||
|
||||
if params[:project_ids] # Multiple memberships, one per project
|
||||
params[:project_ids].each do |project_id|
|
||||
@membership = Member.edit_membership(params[:membership_id], (params[:membership]|| {}).merge(:project_id => project_id), @group)
|
||||
@membership.save if request.post?
|
||||
end
|
||||
else # Single membership
|
||||
@membership = Member.edit_membership(params[:membership_id], params[:membership], @group)
|
||||
@membership.save if request.post?
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
if @membership.valid?
|
||||
format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'memberships' }
|
||||
|
@ -12,6 +12,8 @@
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
require 'diff'
|
||||
|
||||
class JournalsController < ApplicationController
|
||||
before_filter :find_journal, :only => [:edit, :diff]
|
||||
before_filter :find_issue, :only => [:new]
|
||||
@ -84,6 +86,22 @@ class JournalsController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
def diff
|
||||
if valid_field?(params[:field])
|
||||
from = @journal.changes[params[:field]][0]
|
||||
to = @journal.changes[params[:field]][1]
|
||||
|
||||
@diff = Redmine::Helpers::Diff.new(to, from)
|
||||
@issue = @journal.journaled
|
||||
respond_to do |format|
|
||||
format.html { }
|
||||
format.js { render :layout => false }
|
||||
end
|
||||
else
|
||||
render_404
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_journal
|
||||
@ -100,4 +118,9 @@ class JournalsController < ApplicationController
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render_404
|
||||
end
|
||||
|
||||
# Is this a valid field for diff'ing?
|
||||
def valid_field?(field)
|
||||
field.to_s.strip == "description"
|
||||
end
|
||||
end
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
class LdapAuthSourcesController < AuthSourcesController
|
||||
|
||||
menu_item :ldap_authentication, :only => [:index]
|
||||
protected
|
||||
|
||||
def auth_source_class
|
||||
|
@ -110,7 +110,7 @@ class MessagesController < ApplicationController
|
||||
content = "#{ll(Setting.default_language, :text_user_wrote, user)}\\n> "
|
||||
content << text.to_s.strip.gsub(%r{<pre>((.|\s)*?)</pre>}m, '[...]').gsub('"', '\"').gsub(/(\r?\n|\r\n?)/, "\\n> ") + "\\n\\n"
|
||||
render(:update) { |page|
|
||||
page << "$('reply_subject').value = \"#{subject}\";"
|
||||
page << "$('message_subject').value = \"#{subject}\";"
|
||||
page.<< "$('message_content').value = \"#{content}\";"
|
||||
page.show 'reply'
|
||||
page << "Form.Element.focus('message_content');"
|
||||
|
@ -20,6 +20,7 @@ class QueriesController < ApplicationController
|
||||
def new
|
||||
@query = Query.new(params[:query])
|
||||
@query.project = params[:query_is_for_all] ? nil : @project
|
||||
@query.display_subprojects = params[:display_subprojects] if params[:display_subprojects].present?
|
||||
@query.user = User.current
|
||||
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
|
||||
|
||||
|
@ -72,8 +72,7 @@ class TimeEntryReportsController < ApplicationController
|
||||
@periods = []
|
||||
# Date#at_beginning_of_ not supported in Rails 1.2.x
|
||||
date_from = @from.to_time
|
||||
# 100 columns max
|
||||
while date_from <= @to.to_time && @periods.length < 100
|
||||
while date_from <= @to.to_time
|
||||
case @columns
|
||||
when 'year'
|
||||
@periods << "#{date_from.year}"
|
||||
@ -161,6 +160,9 @@ class TimeEntryReportsController < ApplicationController
|
||||
@available_criterias = { 'project' => {:sql => "#{TimeEntry.table_name}.project_id",
|
||||
:klass => Project,
|
||||
:label => :label_project},
|
||||
'status' => {:sql => "#{Issue.table_name}.status_id",
|
||||
:klass => IssueStatus,
|
||||
:label => :field_status},
|
||||
'version' => {:sql => "#{Issue.table_name}.fixed_version_id",
|
||||
:klass => Version,
|
||||
:label => :label_version},
|
||||
|
@ -197,8 +197,16 @@ class UsersController < ApplicationController
|
||||
|
||||
|
||||
def edit_membership
|
||||
@membership = Member.edit_membership(params[:membership_id], params[:membership], @user)
|
||||
@membership.save if request.post?
|
||||
if params[:project_ids] # Multiple memberships, one per project
|
||||
params[:project_ids].each do |project_id|
|
||||
@membership = Member.edit_membership(params[:membership_id], (params[:membership] || {}).merge(:project_id => project_id), @user)
|
||||
@membership.save if request.post?
|
||||
end
|
||||
else # Single membership
|
||||
@membership = Member.edit_membership(params[:membership_id], params[:membership], @user)
|
||||
@membership.save if request.post?
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
if @membership.valid?
|
||||
format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }
|
||||
|
@ -16,6 +16,7 @@ class WatchersController < ApplicationController
|
||||
before_filter :find_project
|
||||
before_filter :require_login, :check_project_privacy, :only => [:watch, :unwatch]
|
||||
before_filter :authorize, :only => [:new, :destroy]
|
||||
before_filter :authorize_access_to_object, :only => [:new, :destroy]
|
||||
|
||||
verify :method => :post,
|
||||
:only => [ :watch, :unwatch ],
|
||||
@ -34,9 +35,12 @@ class WatchersController < ApplicationController
|
||||
end
|
||||
|
||||
def new
|
||||
@watcher = Watcher.new(params[:watcher])
|
||||
@watcher.watchable = @watched
|
||||
@watcher.save if request.post?
|
||||
params[:user_ids].each do |user_id|
|
||||
@watcher = Watcher.new((params[:watcher] || {}).merge({:user_id => user_id}))
|
||||
@watcher.watchable = @watched
|
||||
@watcher.save if request.post?
|
||||
end if params[:user_ids].present?
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to :back }
|
||||
format.js do
|
||||
@ -50,7 +54,7 @@ class WatchersController < ApplicationController
|
||||
end
|
||||
|
||||
def destroy
|
||||
@watched.set_watcher(User.find(params[:user_id]), false) if request.post?
|
||||
@watched.set_watcher(Principal.find(params[:user_id]), false) if request.post?
|
||||
respond_to do |format|
|
||||
format.html { redirect_to :back }
|
||||
format.js do
|
||||
@ -94,4 +98,24 @@ private
|
||||
rescue ::ActionController::RedirectBackError
|
||||
render :text => (watching ? 'Watcher added.' : 'Watcher removed.'), :layout => true
|
||||
end
|
||||
|
||||
def authorize_access_to_object
|
||||
permission = ''
|
||||
case params[:action]
|
||||
when 'new'
|
||||
permission << 'add_'
|
||||
when 'destroy'
|
||||
permission << 'delete_'
|
||||
end
|
||||
|
||||
# Ends up like: :delete_wiki_page_watchers
|
||||
permission << "#{@watched.class.name.underscore}_watchers"
|
||||
|
||||
if User.current.allowed_to?(permission.to_sym, @project)
|
||||
return true
|
||||
else
|
||||
deny_access
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
37
app/drops/base_drop.rb
Normal file
37
app/drops/base_drop.rb
Normal file
@ -0,0 +1,37 @@
|
||||
#-- encoding: UTF-8
|
||||
#-- copyright
|
||||
# ChiliProject is a project management system.
|
||||
#
|
||||
# Copyright (C) 2010-2012 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
class BaseDrop < Liquid::Drop
|
||||
def initialize(object)
|
||||
@object = object unless object.respond_to?(:visible?) && !object.visible?
|
||||
end
|
||||
|
||||
# Defines a Liquid method on the drop that is allowed to call the
|
||||
# Ruby method directly. Best used for attributes.
|
||||
#
|
||||
# Based on Module#liquid_methods
|
||||
def self.allowed_methods(*allowed_methods)
|
||||
class_eval do
|
||||
allowed_methods.each do |sym|
|
||||
define_method sym do
|
||||
if @object.respond_to?(:public_send)
|
||||
@object.public_send(sym) rescue nil
|
||||
else
|
||||
@object.send(sym) rescue nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
79
app/drops/issue_drop.rb
Normal file
79
app/drops/issue_drop.rb
Normal file
@ -0,0 +1,79 @@
|
||||
#-- encoding: UTF-8
|
||||
#-- copyright
|
||||
# ChiliProject is a project management system.
|
||||
#
|
||||
# Copyright (C) 2010-2012 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
class IssueDrop < BaseDrop
|
||||
allowed_methods :id
|
||||
allowed_methods :subject
|
||||
allowed_methods :description
|
||||
allowed_methods :project
|
||||
allowed_methods :tracker
|
||||
allowed_methods :status
|
||||
allowed_methods :due_date
|
||||
allowed_methods :category
|
||||
allowed_methods :assigned_to
|
||||
allowed_methods :priority
|
||||
allowed_methods :fixed_version
|
||||
allowed_methods :author
|
||||
allowed_methods :created_on
|
||||
allowed_methods :updated_on
|
||||
allowed_methods :start_date
|
||||
allowed_methods :done_ratio
|
||||
allowed_methods :estimated_hours
|
||||
allowed_methods :parent
|
||||
|
||||
def custom_field(name)
|
||||
return '' unless name.present?
|
||||
custom_field = IssueCustomField.find_by_name(name.strip)
|
||||
return '' unless custom_field.present?
|
||||
custom_value = @object.custom_value_for(custom_field)
|
||||
if custom_value.present?
|
||||
return custom_value.value
|
||||
else
|
||||
return ''
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: both required, method_missing for Ruby and before_method for Liquid
|
||||
|
||||
# Allows accessing custom fields by their name:
|
||||
#
|
||||
# - issue.the_name_of_player => CustomField(:name => "The name Of Player")
|
||||
#
|
||||
def before_method(method_sym)
|
||||
if custom_field_with_matching_name = has_custom_field_with_matching_name?(method_sym)
|
||||
custom_field(custom_field_with_matching_name.name)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# Allows accessing custom fields by their name:
|
||||
#
|
||||
# - issue.the_name_of_player => CustomField(:name => "The name Of Player")
|
||||
#
|
||||
def method_missing(method_sym, *arguments, &block)
|
||||
if custom_field_with_matching_name = has_custom_field_with_matching_name?(method_sym)
|
||||
custom_field(custom_field_with_matching_name.name)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def has_custom_field_with_matching_name?(method_sym)
|
||||
custom_field_with_matching_name = @object.available_custom_fields.detect {|custom_field|
|
||||
custom_field.name.downcase.underscore.gsub(' ','_') == method_sym.to_s
|
||||
}
|
||||
end
|
||||
end
|
17
app/drops/issue_status_drop.rb
Normal file
17
app/drops/issue_status_drop.rb
Normal file
@ -0,0 +1,17 @@
|
||||
#-- encoding: UTF-8
|
||||
#-- copyright
|
||||
# ChiliProject is a project management system.
|
||||
#
|
||||
# Copyright (C) 2010-2012 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
class IssueStatusDrop < BaseDrop
|
||||
allowed_methods :name
|
||||
end
|
17
app/drops/principal_drop.rb
Normal file
17
app/drops/principal_drop.rb
Normal file
@ -0,0 +1,17 @@
|
||||
#-- encoding: UTF-8
|
||||
#-- copyright
|
||||
# ChiliProject is a project management system.
|
||||
#
|
||||
# Copyright (C) 2010-2012 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
class PrincipalDrop < BaseDrop
|
||||
allowed_methods :name
|
||||
end
|
17
app/drops/project_drop.rb
Normal file
17
app/drops/project_drop.rb
Normal file
@ -0,0 +1,17 @@
|
||||
#-- encoding: UTF-8
|
||||
#-- copyright
|
||||
# ChiliProject is a project management system.
|
||||
#
|
||||
# Copyright (C) 2010-2012 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
class ProjectDrop < BaseDrop
|
||||
allowed_methods :name, :identifier
|
||||
end
|
17
app/drops/tracker_drop.rb
Normal file
17
app/drops/tracker_drop.rb
Normal file
@ -0,0 +1,17 @@
|
||||
#-- encoding: UTF-8
|
||||
#-- copyright
|
||||
# ChiliProject is a project management system.
|
||||
#
|
||||
# Copyright (C) 2010-2012 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
class TrackerDrop < BaseDrop
|
||||
allowed_methods :name
|
||||
end
|
17
app/drops/wiki_page_drop.rb
Normal file
17
app/drops/wiki_page_drop.rb
Normal file
@ -0,0 +1,17 @@
|
||||
#-- encoding: UTF-8
|
||||
#-- copyright
|
||||
# ChiliProject is a project management system.
|
||||
#
|
||||
# Copyright (C) 2010-2012 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
class WikiPageDrop < BaseDrop
|
||||
allowed_methods :title
|
||||
end
|
@ -16,7 +16,6 @@ require 'forwardable'
|
||||
require 'cgi'
|
||||
|
||||
module ApplicationHelper
|
||||
include Redmine::WikiFormatting::Macros::Definitions
|
||||
include Redmine::I18n
|
||||
include GravatarHelper::PublicMethods
|
||||
|
||||
@ -224,17 +223,15 @@ module ApplicationHelper
|
||||
end
|
||||
|
||||
# Renders the project quick-jump box
|
||||
def render_project_jump_box
|
||||
projects = User.current.memberships.collect(&:project).compact.uniq
|
||||
def render_project_jump_box(projects = [], html_options = {})
|
||||
projects ||= User.current.memberships.collect(&:project).compact.uniq
|
||||
if projects.any?
|
||||
s = '<select onchange="if (this.value != \'\') { window.location = this.value; }">' +
|
||||
"<option value=''>#{ l(:label_jump_to_a_project) }</option>" +
|
||||
'<option value="" disabled="disabled">---</option>'
|
||||
s << project_tree_options_for_select(projects, :selected => @project) do |p|
|
||||
{ :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }
|
||||
end
|
||||
s << '</select>'
|
||||
s
|
||||
# option_tags = content_tag :option, l(:label_jump_to_a_project), :value => ""
|
||||
option_tags = (content_tag :option, "", :value => "" )
|
||||
option_tags << project_tree_options_for_select(projects, :selected => @project) do |p|
|
||||
{ :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }
|
||||
end
|
||||
select_tag "", option_tags, html_options.merge({ :onchange => "if (this.value != \'\') { window.location = this.value; }" })
|
||||
end
|
||||
end
|
||||
|
||||
@ -288,7 +285,15 @@ module ApplicationHelper
|
||||
def principals_check_box_tags(name, principals)
|
||||
s = ''
|
||||
principals.sort.each do |principal|
|
||||
s << "<label>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n"
|
||||
s << "<label style='display:block;'>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n"
|
||||
end
|
||||
s
|
||||
end
|
||||
|
||||
def projects_check_box_tags(name, projects)
|
||||
s = ''
|
||||
projects.each do |project|
|
||||
s << "<label>#{ check_box_tag name, project.id, false } #{h project}</label>\n"
|
||||
end
|
||||
s
|
||||
end
|
||||
@ -389,7 +394,9 @@ module ApplicationHelper
|
||||
end
|
||||
|
||||
def page_header_title
|
||||
if @project.nil? || @project.new_record?
|
||||
if @page_header_title.present?
|
||||
h(@page_header_title)
|
||||
elsif @project.nil? || @project.new_record?
|
||||
h(Setting.app_title)
|
||||
else
|
||||
b = []
|
||||
@ -429,8 +436,8 @@ module ApplicationHelper
|
||||
css << 'theme-' + theme.name
|
||||
end
|
||||
|
||||
css << 'controller-' + params[:controller]
|
||||
css << 'action-' + params[:action]
|
||||
css << 'controller-' + params[:controller] if params[:controller]
|
||||
css << 'action-' + params[:action] if params[:action]
|
||||
css.join(' ')
|
||||
end
|
||||
|
||||
@ -447,19 +454,51 @@ module ApplicationHelper
|
||||
case args.size
|
||||
when 1
|
||||
obj = options[:object]
|
||||
text = args.shift
|
||||
input_text = args.shift
|
||||
when 2
|
||||
obj = args.shift
|
||||
attr = args.shift
|
||||
text = obj.send(attr).to_s
|
||||
input_text = obj.send(attr).to_s
|
||||
else
|
||||
raise ArgumentError, 'invalid arguments to textilizable'
|
||||
end
|
||||
return '' if text.blank?
|
||||
return '' if input_text.blank?
|
||||
project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
|
||||
only_path = options.delete(:only_path) == false ? false : true
|
||||
|
||||
text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) { |macro, args| exec_macro(macro, obj, args) }
|
||||
begin
|
||||
text = ChiliProject::Liquid::Legacy.run_macros(input_text)
|
||||
liquid_template = ChiliProject::Liquid::Template.parse(text)
|
||||
liquid_variables = get_view_instance_variables_for_liquid
|
||||
liquid_variables.merge!({'current_user' => User.current})
|
||||
liquid_variables.merge!({'toc' => '{{toc}}'}) # Pass toc through to replace later
|
||||
liquid_variables.merge!(ChiliProject::Liquid::Variables.all)
|
||||
|
||||
# Pass :view in a register so this view (with helpers) can be used inside of a tag
|
||||
text = liquid_template.render(liquid_variables, :registers => {:view => self, :object => obj, :attribute => attr})
|
||||
|
||||
# Add Liquid errors to the log
|
||||
if Rails.logger && Rails.logger.debug?
|
||||
msg = ""
|
||||
liquid_template.errors.each do |exception|
|
||||
msg << "[Liquid Error] #{exception.message}\n:\n#{exception.backtrace.join("\n")}"
|
||||
msg << "\n\n"
|
||||
end
|
||||
Rails.logger.debug msg
|
||||
end
|
||||
rescue Liquid::SyntaxError => exception
|
||||
msg = "[Liquid Syntax Error] #{exception.message}"
|
||||
if Rails.logger && Rails.logger.debug?
|
||||
log_msg = "#{msg}\n"
|
||||
log_msg << exception.backtrace.collect{ |str| " #{str}" }.join("\n")
|
||||
log_msg << "\n\n"
|
||||
Rails.logger.debug log_msg
|
||||
end
|
||||
|
||||
# Skip Liquid if there is a syntax error
|
||||
text = content_tag(:div, msg, :class => "flash error")
|
||||
text << h(input_text)
|
||||
end
|
||||
|
||||
@parsed_headings = []
|
||||
text = parse_non_pre_blocks(text) do |text|
|
||||
@ -712,7 +751,7 @@ module ApplicationHelper
|
||||
end
|
||||
end
|
||||
|
||||
TOC_RE = /<p>\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE)
|
||||
TOC_RE = /<p>\{%\s*toc(_right|_left)?\s*%\}<\/p>/i unless const_defined?(:TOC_RE)
|
||||
|
||||
# Renders the TOC with given headings
|
||||
def replace_toc(text, headings)
|
||||
@ -720,10 +759,14 @@ module ApplicationHelper
|
||||
if headings.empty?
|
||||
''
|
||||
else
|
||||
div_class = 'toc'
|
||||
div_class << ' right' if $1 == '>'
|
||||
div_class << ' left' if $1 == '<'
|
||||
out = "<ul class=\"#{div_class}\"><li>"
|
||||
toc_class = 'toc'
|
||||
toc_class << ' right' if $1 == '_right'
|
||||
toc_class << ' left' if $1 == '_left'
|
||||
|
||||
out = "<fieldset class=\"header_collapsible collapsible #{toc_class}\">"
|
||||
out << "<legend onclick=\"toggleFieldset(this);\"><span>#{l(:label_toc)}</span></legend>"
|
||||
out << "<div>"
|
||||
out << "<ul class=\"toc\"><li>"
|
||||
root = headings.map(&:first).min
|
||||
current = root
|
||||
started = false
|
||||
@ -741,6 +784,7 @@ module ApplicationHelper
|
||||
end
|
||||
out << '</li></ul>' * (current - root)
|
||||
out << '</li></ul>'
|
||||
out << '</div></fieldset>'
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -879,6 +923,12 @@ module ApplicationHelper
|
||||
# +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
|
||||
def avatar(user, options = { })
|
||||
if Setting.gravatar_enabled?
|
||||
if user.is_a?(Group)
|
||||
size = options[:size] || 50
|
||||
size = "#{size}x#{size}" # image_tag uses WxH
|
||||
options[:class] ||= 'gravatar'
|
||||
return image_tag("group.png", options.merge(:size => size))
|
||||
end
|
||||
options.merge!({:ssl => (defined?(request) && request.ssl?), :default => Setting.gravatar_default})
|
||||
email = nil
|
||||
if user.respond_to?(:mail)
|
||||
@ -935,6 +985,72 @@ module ApplicationHelper
|
||||
end
|
||||
end
|
||||
|
||||
# Expands the current menu item using JavaScript based on the params
|
||||
def expand_current_menu
|
||||
current_menu_class =
|
||||
case
|
||||
when params[:controller] == "timelog"
|
||||
"reports"
|
||||
when params[:controller] == 'projects' && params[:action] == 'changelog'
|
||||
"reports"
|
||||
when params[:controller] == 'issues' && ['calendar','gantt'].include?(params[:action])
|
||||
"reports"
|
||||
when params[:controller] == 'projects' && params[:action] == 'roadmap'
|
||||
'roadmap'
|
||||
when params[:controller] == 'versions' && params[:action] == 'show'
|
||||
'roadmap'
|
||||
when params[:controller] == 'projects' && params[:action] == 'settings'
|
||||
'settings'
|
||||
when params[:controller] == 'contracts' || params[:controller] == 'deliverables'
|
||||
'contracts'
|
||||
else
|
||||
params[:controller]
|
||||
end
|
||||
|
||||
|
||||
javascript_tag("jQuery.menu_expand({ menuItem: '.#{current_menu_class}' });")
|
||||
end
|
||||
|
||||
# Menu items for the main top menu
|
||||
def main_top_menu_items
|
||||
split_top_menu_into_main_or_more_menus[:main]
|
||||
end
|
||||
|
||||
# Menu items for the more top menu
|
||||
def more_top_menu_items
|
||||
split_top_menu_into_main_or_more_menus[:more]
|
||||
end
|
||||
|
||||
def help_menu_item
|
||||
split_top_menu_into_main_or_more_menus[:help]
|
||||
end
|
||||
|
||||
# Split the :top_menu into separate :main and :more items
|
||||
def split_top_menu_into_main_or_more_menus
|
||||
unless @top_menu_split
|
||||
items_for_main_level = []
|
||||
items_for_more_level = []
|
||||
help_menu = nil
|
||||
menu_items_for(:top_menu) do |item|
|
||||
if item.name == :home || item.name == :my_page
|
||||
items_for_main_level << item
|
||||
elsif item.name == :help
|
||||
help_menu = item
|
||||
elsif item.name == :projects
|
||||
# Remove, present in layout
|
||||
else
|
||||
items_for_more_level << item
|
||||
end
|
||||
end
|
||||
@top_menu_split = {
|
||||
:main => items_for_main_level,
|
||||
:more => items_for_more_level,
|
||||
:help => help_menu
|
||||
}
|
||||
end
|
||||
@top_menu_split
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def wiki_helper
|
||||
@ -946,4 +1062,20 @@ module ApplicationHelper
|
||||
def link_to_content_update(text, url_params = {}, html_options = {})
|
||||
link_to(text, url_params, html_options)
|
||||
end
|
||||
|
||||
def get_view_instance_variables_for_liquid
|
||||
internal_variables = %w{
|
||||
@output_buffer @cookies @helpers @real_format @assigns_added @assigns
|
||||
@view_paths @controller
|
||||
}
|
||||
self.instance_variables.collect(&:to_s).reject do |ivar|
|
||||
ivar.match(/^@_/) || # Rails "internal" variables: @_foo
|
||||
ivar.match(/^@template/) ||
|
||||
internal_variables.include?(ivar)
|
||||
end.inject({}) do |acc,ivar|
|
||||
acc[ivar.sub('@','')] = instance_variable_get(ivar)
|
||||
acc
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -52,13 +52,14 @@ module IssuesHelper
|
||||
"<strong>#{@cached_label_priority}</strong>: #{h(issue.priority.name)}"
|
||||
end
|
||||
|
||||
# TODO: deprecate and/or remove
|
||||
def render_issue_subject_with_tree(issue)
|
||||
s = ''
|
||||
ancestors = issue.root? ? [] : issue.ancestors.all
|
||||
ancestors.each do |ancestor|
|
||||
s << '<div>' + content_tag('p', link_to_issue(ancestor))
|
||||
s << '<div>' + content_tag('h2', link_to_issue(ancestor))
|
||||
end
|
||||
s << '<div>' + content_tag('h3', h(issue.subject))
|
||||
s << '<div class="subject">' + content_tag('h2', h(issue.subject))
|
||||
s << '</div>' * (ancestors.size + 1)
|
||||
s
|
||||
end
|
||||
|
@ -27,24 +27,34 @@ module JournalsHelper
|
||||
|
||||
def render_journal(model, journal, options = {})
|
||||
return "" if journal.initial?
|
||||
journal_content = render_journal_details(journal, :label_updated_time_by)
|
||||
journal_content += render_notes(model, journal, options) unless journal.notes.blank?
|
||||
content_tag "div", journal_content, { :id => "change-#{journal.id}", :class => journal.css_classes }
|
||||
|
||||
journal_classes = journal.css_classes
|
||||
journal_content = render_journal_details(journal, :label_updated_time_by, model, options)
|
||||
|
||||
avatar = avatar(journal.user, :size => "40")
|
||||
unless avatar.blank?
|
||||
profile_wrap = content_tag("div", avatar, {:class => "profile-wrap"}, false)
|
||||
journal_content = profile_wrap + journal_content
|
||||
journal_classes << " has-avatar"
|
||||
end
|
||||
|
||||
content_tag("div", journal_content, :id => "change-#{journal.id}", :class => journal_classes)
|
||||
end
|
||||
|
||||
# This renders a journal entry wiht a header and details
|
||||
def render_journal_details(journal, header_label = :label_updated_time_by)
|
||||
# This renders a journal entry with a header and details
|
||||
def render_journal_details(journal, header_label = :label_updated_time_by, model=nil, options={})
|
||||
header = <<-HTML
|
||||
<h4>
|
||||
<div style="float:right;">#{link_to "##{journal.anchor}", :anchor => "note-#{journal.anchor}"}</div>
|
||||
#{avatar(journal.user, :size => "24")}
|
||||
#{content_tag('a', '', :name => "note-#{journal.anchor}")}
|
||||
<div class="journal-link" style="float:right;">#{link_to "##{journal.anchor}", :anchor => "note-#{journal.anchor}"}</div>
|
||||
#{authoring journal.created_at, journal.user, :label => header_label}
|
||||
#{content_tag('a', '', :name => "note-#{journal.anchor}")}
|
||||
</h4>
|
||||
HTML
|
||||
|
||||
header << render_notes(model, journal, options) unless journal.notes.blank?
|
||||
|
||||
if journal.details.any?
|
||||
details = content_tag "ul", :class => "details" do
|
||||
details = content_tag "ul", :class => "journal-attributes details" do
|
||||
journal.details.collect do |detail|
|
||||
if d = journal.render_detail(detail)
|
||||
content_tag("li", d)
|
||||
@ -53,7 +63,7 @@ module JournalsHelper
|
||||
end
|
||||
end
|
||||
|
||||
content_tag("div", "#{header}#{details}", :id => "change-#{journal.id}", :class => "journal")
|
||||
content_tag "div", "#{header}#{details}", :class => "journal-details"
|
||||
end
|
||||
|
||||
def render_notes(model, journal, options={})
|
||||
|
@ -84,11 +84,12 @@ module QueriesHelper
|
||||
end
|
||||
end
|
||||
@query.group_by = params[:group_by]
|
||||
@query.display_subprojects = params[:display_subprojects] if params[:display_subprojects]
|
||||
@query.column_names = params[:c] || (params[:query] && params[:query][:column_names])
|
||||
session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
|
||||
session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names, :display_subprojects => @query.display_subprojects}
|
||||
else
|
||||
@query = Query.find_by_id(session[:query][:id]) if session[:query][:id]
|
||||
@query ||= Query.new(:name => "_", :project => @project, :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
|
||||
@query ||= Query.new(:name => "_", :project => @project, :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names], :display_subprojects => session[:query][:display_subprojects])
|
||||
@query.project = @project
|
||||
end
|
||||
end
|
||||
|
@ -24,6 +24,7 @@ class Document < ActiveRecord::Base
|
||||
end)
|
||||
|
||||
acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project
|
||||
acts_as_watchable
|
||||
|
||||
validates_presence_of :project, :title, :category
|
||||
validates_length_of :title, :maximum => 60
|
||||
@ -48,4 +49,10 @@ class Document < ActiveRecord::Base
|
||||
end
|
||||
@updated_on
|
||||
end
|
||||
|
||||
def recipients
|
||||
mails = super # from acts_as_event
|
||||
mails += watcher_recipients
|
||||
mails.uniq
|
||||
end
|
||||
end
|
||||
|
@ -14,6 +14,10 @@
|
||||
|
||||
class DocumentObserver < ActiveRecord::Observer
|
||||
def after_create(document)
|
||||
Mailer.deliver_document_added(document) if Setting.notified_events.include?('document_added')
|
||||
if Setting.notified_events.include?('document_added')
|
||||
document.recipients.each do |recipient|
|
||||
Mailer.deliver_document_added(document, recipient)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -22,6 +22,11 @@ class Group < Principal
|
||||
validates_uniqueness_of :lastname, :case_sensitive => false
|
||||
validates_length_of :lastname, :maximum => 30
|
||||
|
||||
# Returns an array of all of the email addresses of the group's users
|
||||
def mails
|
||||
users.collect(&:mail)
|
||||
end
|
||||
|
||||
def to_s
|
||||
lastname.to_s
|
||||
end
|
||||
|
@ -103,6 +103,10 @@ class Issue < ActiveRecord::Base
|
||||
(usr || User.current).allowed_to?(:view_issues, self.project)
|
||||
end
|
||||
|
||||
def to_liquid
|
||||
IssueDrop.new(self)
|
||||
end
|
||||
|
||||
def after_initialize
|
||||
if new_record?
|
||||
# set default values for new records only
|
||||
|
@ -17,7 +17,9 @@ class IssueObserver < ActiveRecord::Observer
|
||||
|
||||
def after_create(issue)
|
||||
if self.send_notification
|
||||
Mailer.deliver_issue_add(issue) if Setting.notified_events.include?('issue_added')
|
||||
(issue.recipients + issue.watcher_recipients).uniq.each do |recipient|
|
||||
Mailer.deliver_issue_add(issue, recipient)
|
||||
end
|
||||
end
|
||||
clear_notification
|
||||
end
|
||||
|
@ -28,6 +28,10 @@ class IssueStatus < ActiveRecord::Base
|
||||
IssueStatus.update_all("is_default=#{connection.quoted_false}", ['id <> ?', id]) if self.is_default?
|
||||
end
|
||||
|
||||
def to_liquid
|
||||
IssueStatusDrop.new(self)
|
||||
end
|
||||
|
||||
# Returns the default status for new issues
|
||||
def self.default
|
||||
find(:first, :conditions =>["is_default=?", true])
|
||||
|
@ -27,11 +27,15 @@ class JournalObserver < ActiveRecord::Observer
|
||||
|
||||
if journal.initial?
|
||||
if Setting.notified_events.include?('wiki_content_added')
|
||||
Mailer.deliver_wiki_content_added(wiki_content)
|
||||
(wiki_content.recipients + wiki_page.wiki.watcher_recipients).uniq.each do |recipient|
|
||||
Mailer.deliver_wiki_content_added(wiki_content, recipient)
|
||||
end
|
||||
end
|
||||
else
|
||||
if Setting.notified_events.include?('wiki_content_updated')
|
||||
Mailer.deliver_wiki_content_updated(wiki_content)
|
||||
(wiki_content.recipients + wiki_page.wiki.watcher_recipients + wiki_page.watcher_recipients).uniq.each do |recipient|
|
||||
Mailer.deliver_wiki_content_updated(wiki_content, recipient)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -43,7 +47,10 @@ class JournalObserver < ActiveRecord::Observer
|
||||
(Setting.notified_events.include?('issue_note_added') && journal.notes.present?) ||
|
||||
(Setting.notified_events.include?('issue_status_updated') && journal.new_status.present?) ||
|
||||
(Setting.notified_events.include?('issue_priority_updated') && journal.new_value_for('priority_id').present?)
|
||||
Mailer.deliver_issue_edit(journal)
|
||||
issue = journal.issue
|
||||
(issue.recipients + issue.watcher_recipients).uniq.each do |recipient|
|
||||
Mailer.deliver_issue_edit(journal, recipient)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -69,6 +69,7 @@ class MailHandler < ActionMailer::Base
|
||||
else
|
||||
# Default behaviour, emails from unknown users are ignored
|
||||
logger.info "MailHandler: ignoring email from unknown user [#{sender_email}]" if logger && logger.info
|
||||
Mailer.deliver_mail_handler_unauthorized_action(user, email.subject.to_s, :to => sender_email) if Setting.mail_handler_confirmation_on_failure
|
||||
return false
|
||||
end
|
||||
end
|
||||
@ -102,12 +103,15 @@ class MailHandler < ActionMailer::Base
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
# TODO: send a email to the user
|
||||
logger.error e.message if logger
|
||||
Mailer.deliver_mail_handler_missing_information(user, email.subject.to_s, e.message) if Setting.mail_handler_confirmation_on_failure
|
||||
false
|
||||
rescue MissingInformation => e
|
||||
logger.error "MailHandler: missing information from #{user}: #{e.message}" if logger
|
||||
Mailer.deliver_mail_handler_missing_information(user, email.subject.to_s, e.message) if Setting.mail_handler_confirmation_on_failure
|
||||
false
|
||||
rescue UnauthorizedAction => e
|
||||
logger.error "MailHandler: unauthorized attempt from #{user}" if logger
|
||||
Mailer.deliver_mail_handler_unauthorized_action(user, email.subject.to_s) if Setting.mail_handler_confirmation_on_failure
|
||||
false
|
||||
end
|
||||
|
||||
@ -141,6 +145,7 @@ class MailHandler < ActionMailer::Base
|
||||
issue.save!
|
||||
add_attachments(issue)
|
||||
logger.info "MailHandler: issue ##{issue.id} created by #{user}" if logger && logger.info
|
||||
Mailer.deliver_mail_handler_confirmation(issue, user, issue.subject) if Setting.mail_handler_confirmation_on_success
|
||||
issue
|
||||
end
|
||||
|
||||
@ -162,6 +167,7 @@ class MailHandler < ActionMailer::Base
|
||||
add_attachments(issue)
|
||||
issue.save!
|
||||
logger.info "MailHandler: issue ##{issue.id} updated by #{user}" if logger && logger.info
|
||||
Mailer.deliver_mail_handler_confirmation(issue.last_journal, user, email.subject) if Setting.mail_handler_confirmation_on_success
|
||||
issue.last_journal
|
||||
end
|
||||
|
||||
@ -190,6 +196,7 @@ class MailHandler < ActionMailer::Base
|
||||
reply.board = message.board
|
||||
message.children << reply
|
||||
add_attachments(reply)
|
||||
Mailer.deliver_mail_handler_confirmation(message, user, reply.subject) if Setting.mail_handler_confirmation_on_success
|
||||
reply
|
||||
else
|
||||
logger.info "MailHandler: ignoring reply from [#{sender_email}] to a locked topic" if logger && logger.info
|
||||
|
@ -30,20 +30,19 @@ class Mailer < ActionMailer::Base
|
||||
{ :host => h, :protocol => Setting.protocol }
|
||||
end
|
||||
|
||||
# Builds a tmail object used to email recipients of the added issue.
|
||||
# Builds a tmail object used to email a recipient of the added issue.
|
||||
#
|
||||
# Example:
|
||||
# issue_add(issue) => tmail object
|
||||
# Mailer.deliver_issue_add(issue) => sends an email to issue recipients
|
||||
def issue_add(issue)
|
||||
# issue_add(issue, 'user@example.com') => tmail object
|
||||
# Mailer.deliver_issue_add(issue, 'user@example.com') => sends an email to 'user@example.com'
|
||||
def issue_add(issue, recipient)
|
||||
redmine_headers 'Project' => issue.project.identifier,
|
||||
'Issue-Id' => issue.id,
|
||||
'Issue-Author' => issue.author.login,
|
||||
'Type' => "Issue"
|
||||
redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
|
||||
message_id issue
|
||||
recipients issue.recipients
|
||||
cc(issue.watcher_recipients - @recipients)
|
||||
recipients [recipient]
|
||||
subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
|
||||
body :issue => issue,
|
||||
:issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
|
||||
@ -53,9 +52,9 @@ class Mailer < ActionMailer::Base
|
||||
# Builds a tmail object used to email recipients of the edited issue.
|
||||
#
|
||||
# Example:
|
||||
# issue_edit(journal) => tmail object
|
||||
# Mailer.deliver_issue_edit(journal) => sends an email to issue recipients
|
||||
def issue_edit(journal)
|
||||
# issue_edit(journal, 'user@example.com') => tmail object
|
||||
# Mailer.deliver_issue_edit(journal, 'user@example.com') => sends an email to issue recipients
|
||||
def issue_edit(journal, recipient)
|
||||
issue = journal.journaled.reload
|
||||
redmine_headers 'Project' => issue.project.identifier,
|
||||
'Issue-Id' => issue.id,
|
||||
@ -65,9 +64,7 @@ class Mailer < ActionMailer::Base
|
||||
message_id journal
|
||||
references issue
|
||||
@author = journal.user
|
||||
recipients issue.recipients
|
||||
# Watchers in cc
|
||||
cc(issue.watcher_recipients - @recipients)
|
||||
recipients [recipient]
|
||||
s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
|
||||
s << "(#{issue.status.name}) " if journal.details['status_id']
|
||||
s << issue.subject
|
||||
@ -93,12 +90,12 @@ class Mailer < ActionMailer::Base
|
||||
# Builds a tmail object used to email users belonging to the added document's project.
|
||||
#
|
||||
# Example:
|
||||
# document_added(document) => tmail object
|
||||
# Mailer.deliver_document_added(document) => sends an email to the document's project recipients
|
||||
def document_added(document)
|
||||
# document_added(document, 'test@example.com') => tmail object
|
||||
# Mailer.deliver_document_added(document, 'test@example.com') => sends an email to the document's project recipients
|
||||
def document_added(document, recipient)
|
||||
redmine_headers 'Project' => document.project.identifier,
|
||||
'Type' => "Document"
|
||||
recipients document.recipients
|
||||
recipients [recipient]
|
||||
subject "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
|
||||
body :document => document,
|
||||
:document_url => url_for(:controller => 'documents', :action => 'show', :id => document)
|
||||
@ -110,7 +107,7 @@ class Mailer < ActionMailer::Base
|
||||
# Example:
|
||||
# attachments_added(attachments) => tmail object
|
||||
# Mailer.deliver_attachments_added(attachments) => sends an email to the project's recipients
|
||||
def attachments_added(attachments)
|
||||
def attachments_added(attachments, recipient)
|
||||
container = attachments.first.container
|
||||
added_to = ''
|
||||
added_to_url = ''
|
||||
@ -118,16 +115,14 @@ class Mailer < ActionMailer::Base
|
||||
when 'Project'
|
||||
added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container)
|
||||
added_to = "#{l(:label_project)}: #{container}"
|
||||
recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
|
||||
when 'Version'
|
||||
added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project)
|
||||
added_to = "#{l(:label_version)}: #{container.name}"
|
||||
recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
|
||||
when 'Document'
|
||||
added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
|
||||
added_to = "#{l(:label_document)}: #{container.title}"
|
||||
recipients container.recipients
|
||||
end
|
||||
recipients [recipient]
|
||||
redmine_headers 'Project' => container.project.identifier,
|
||||
'Type' => "Attachment"
|
||||
subject "[#{container.project.name}] #{l(:label_attachment_new)}"
|
||||
@ -142,11 +137,11 @@ class Mailer < ActionMailer::Base
|
||||
# Example:
|
||||
# news_added(news) => tmail object
|
||||
# Mailer.deliver_news_added(news) => sends an email to the news' project recipients
|
||||
def news_added(news)
|
||||
def news_added(news, recipient)
|
||||
redmine_headers 'Project' => news.project.identifier,
|
||||
'Type' => "News"
|
||||
message_id news
|
||||
recipients news.recipients
|
||||
recipients [recipient]
|
||||
subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
|
||||
body :news => news,
|
||||
:news_url => url_for(:controller => 'news', :action => 'show', :id => news)
|
||||
@ -176,14 +171,13 @@ class Mailer < ActionMailer::Base
|
||||
# Example:
|
||||
# message_posted(message) => tmail object
|
||||
# Mailer.deliver_message_posted(message) => sends an email to the recipients
|
||||
def message_posted(message)
|
||||
def message_posted(message, recipient)
|
||||
redmine_headers 'Project' => message.project.identifier,
|
||||
'Topic-Id' => (message.parent_id || message.id),
|
||||
'Type' => "Forum"
|
||||
message_id message
|
||||
references message.parent unless message.parent.nil?
|
||||
recipients(message.recipients)
|
||||
cc((message.root.watcher_recipients + message.board.watcher_recipients).uniq - @recipients)
|
||||
recipients [recipient]
|
||||
subject "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
|
||||
body :message => message,
|
||||
:message_url => url_for({ :controller => 'messages', :action => 'show', :board_id => message.board, :id => message.root, :r => message, :anchor => "message-#{message.id}" })
|
||||
@ -195,13 +189,12 @@ class Mailer < ActionMailer::Base
|
||||
# Example:
|
||||
# wiki_content_added(wiki_content) => tmail object
|
||||
# Mailer.deliver_wiki_content_added(wiki_content) => sends an email to the project's recipients
|
||||
def wiki_content_added(wiki_content)
|
||||
def wiki_content_added(wiki_content, recipient)
|
||||
redmine_headers 'Project' => wiki_content.project.identifier,
|
||||
'Wiki-Page-Id' => wiki_content.page.id,
|
||||
'Type' => "Wiki"
|
||||
message_id wiki_content
|
||||
recipients wiki_content.recipients
|
||||
cc(wiki_content.page.wiki.watcher_recipients - recipients)
|
||||
recipients [recipient]
|
||||
subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}"
|
||||
body :wiki_content => wiki_content,
|
||||
:wiki_content_url => url_for(:controller => 'wiki', :action => 'show', :project_id => wiki_content.project, :id => wiki_content.page.title)
|
||||
@ -213,13 +206,12 @@ class Mailer < ActionMailer::Base
|
||||
# Example:
|
||||
# wiki_content_updated(wiki_content) => tmail object
|
||||
# Mailer.deliver_wiki_content_updated(wiki_content) => sends an email to the project's recipients
|
||||
def wiki_content_updated(wiki_content)
|
||||
def wiki_content_updated(wiki_content, recipient)
|
||||
redmine_headers 'Project' => wiki_content.project.identifier,
|
||||
'Wiki-Page-Id' => wiki_content.page.id,
|
||||
'Type' => "Wiki"
|
||||
message_id wiki_content
|
||||
recipients wiki_content.recipients
|
||||
cc(wiki_content.page.wiki.watcher_recipients + wiki_content.page.watcher_recipients - recipients)
|
||||
recipients [recipient]
|
||||
subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}"
|
||||
body :wiki_content => wiki_content,
|
||||
:wiki_content_url => url_for(:controller => 'wiki', :action => 'show', :project_id => wiki_content.project, :id => wiki_content.page.title),
|
||||
@ -293,6 +285,44 @@ class Mailer < ActionMailer::Base
|
||||
render_multipart('register', body)
|
||||
end
|
||||
|
||||
def mail_handler_confirmation(object, user, email_subject)
|
||||
recipients user.mail
|
||||
|
||||
case
|
||||
when object.is_a?(Issue)
|
||||
project = object.project.name
|
||||
url = url_for(:controller => 'issues', :action => 'show', :id => object.id)
|
||||
when object.is_a?(Journal)
|
||||
project = object.project.name
|
||||
url = url_for(:controller => 'issues', :action => 'show', :id => object.issue.id)
|
||||
when object.class == Message
|
||||
project = object.project.name
|
||||
url = url_for(object.event_url)
|
||||
else
|
||||
project = ''
|
||||
url = ''
|
||||
end
|
||||
|
||||
subject "[#{project}] #{l(:label_mail_handler_confirmation, :subject => email_subject)}"
|
||||
body(:object => object,
|
||||
:url => url)
|
||||
render_multipart('mail_handler_confirmation', body)
|
||||
end
|
||||
|
||||
def mail_handler_unauthorized_action(user, email_subject, options={})
|
||||
recipients options[:to] || user.mail
|
||||
subject l(:label_mail_handler_failure, :subject => email_subject)
|
||||
body({})
|
||||
render_multipart('mail_handler_unauthorized_action', body)
|
||||
end
|
||||
|
||||
def mail_handler_missing_information(user, email_subject, error_message)
|
||||
recipients user.mail
|
||||
subject l(:label_mail_handler_failure, :subject => email_subject)
|
||||
body({:errors => error_message.to_s})
|
||||
render_multipart('mail_handler_missing_information', body)
|
||||
end
|
||||
|
||||
def test(user)
|
||||
redmine_headers 'Type' => "Test"
|
||||
set_language_if_valid(user.language)
|
||||
@ -395,7 +425,7 @@ class Mailer < ActionMailer::Base
|
||||
# Removes the current user from the recipients and cc
|
||||
# if he doesn't want to receive notifications about what he does
|
||||
@author ||= User.current
|
||||
if @author.pref[:no_self_notified]
|
||||
if @author && @author.mail && @author.pref[:no_self_notified]
|
||||
recipients((recipients.is_a?(Array) ? recipients : [recipients]) - [@author.mail]) if recipients.present?
|
||||
cc((cc.is_a?(Array) ? cc : [cc]) - [@author.mail]) if cc.present?
|
||||
end
|
||||
@ -403,13 +433,6 @@ class Mailer < ActionMailer::Base
|
||||
notified_users = [recipients, cc].flatten.compact.uniq
|
||||
# Rails would log recipients only, not cc and bcc
|
||||
mylogger.info "Sending email notification to: #{notified_users.join(', ')}" if mylogger
|
||||
|
||||
# Blind carbon copy recipients
|
||||
if Setting.bcc_recipients?
|
||||
bcc(notified_users)
|
||||
recipients []
|
||||
cc []
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
|
@ -14,6 +14,13 @@
|
||||
|
||||
class MessageObserver < ActiveRecord::Observer
|
||||
def after_create(message)
|
||||
Mailer.deliver_message_posted(message) if Setting.notified_events.include?('message_posted')
|
||||
if Setting.notified_events.include?('message_posted')
|
||||
recipients = message.recipients
|
||||
recipients += message.root.watcher_recipients
|
||||
recipients += message.board.watcher_recipients
|
||||
recipients.uniq.each do |recipient|
|
||||
Mailer.deliver_message_posted(message, recipient)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -14,6 +14,10 @@
|
||||
|
||||
class NewsObserver < ActiveRecord::Observer
|
||||
def after_create(news)
|
||||
Mailer.deliver_news_added(news) if Setting.notified_events.include?('news_added')
|
||||
if Setting.notified_events.include?('news_added')
|
||||
news.recipients.each do |recipient|
|
||||
Mailer.deliver_news_added(news, recipient)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -31,6 +31,10 @@ class Principal < ActiveRecord::Base
|
||||
|
||||
before_create :set_default_empty_values
|
||||
|
||||
def to_liquid
|
||||
PrincipalDrop.new(self)
|
||||
end
|
||||
|
||||
def name(formatter = nil)
|
||||
to_s
|
||||
end
|
||||
@ -44,6 +48,82 @@ class Principal < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def active?
|
||||
true
|
||||
end
|
||||
|
||||
def logged?
|
||||
true # TODO: should all principals default to logged or not?
|
||||
end
|
||||
|
||||
# Return true if the user is allowed to do the specified action on a specific context
|
||||
# Action can be:
|
||||
# * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
|
||||
# * a permission Symbol (eg. :edit_project)
|
||||
# Context can be:
|
||||
# * a project : returns true if user is allowed to do the specified action on this project
|
||||
# * a group of projects : returns true if user is allowed on every project
|
||||
# * nil with options[:global] set : check if user has at least one role allowed for this action,
|
||||
# or falls back to Non Member / Anonymous permissions depending if the user is logged
|
||||
def allowed_to?(action, context, options={})
|
||||
if context && context.is_a?(Project)
|
||||
# No action allowed on archived projects
|
||||
return false unless context.active?
|
||||
# No action allowed on disabled modules
|
||||
return false unless context.allows_to?(action)
|
||||
# Admin users are authorized for anything else
|
||||
return true if admin?
|
||||
|
||||
roles = roles_for_project(context)
|
||||
return false unless roles
|
||||
roles.detect {|role| (context.is_public? || role.member?) && role.allowed_to?(action)}
|
||||
|
||||
elsif context && context.is_a?(Array)
|
||||
# Authorize if user is authorized on every element of the array
|
||||
context.map do |project|
|
||||
allowed_to?(action,project,options)
|
||||
end.inject do |memo,allowed|
|
||||
memo && allowed
|
||||
end
|
||||
elsif options[:global]
|
||||
# Admin users are always authorized
|
||||
return true if admin?
|
||||
|
||||
# authorize if user has at least one role that has this permission
|
||||
roles = memberships.collect {|m| m.roles}.flatten.uniq
|
||||
roles.detect {|r| r.allowed_to?(action)} || (self.logged? ? Role.non_member.allowed_to?(action) : Role.anonymous.allowed_to?(action))
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# Is the user allowed to do the specified action on any project?
|
||||
# See allowed_to? for the actions and valid options.
|
||||
def allowed_to_globally?(action, options)
|
||||
allowed_to?(action, nil, options.reverse_merge(:global => true))
|
||||
end
|
||||
|
||||
# Return user's roles for project
|
||||
def roles_for_project(project)
|
||||
roles = []
|
||||
# No role on archived projects
|
||||
return roles unless project && project.active?
|
||||
if logged?
|
||||
# Find project membership
|
||||
membership = memberships.detect {|m| m.project_id == project.id}
|
||||
if membership
|
||||
roles = membership.roles
|
||||
else
|
||||
@role_non_member ||= Role.non_member
|
||||
roles << @role_non_member
|
||||
end
|
||||
else
|
||||
@role_anonymous ||= Role.anonymous
|
||||
roles << @role_anonymous
|
||||
end
|
||||
roles
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Make sure we don't try to insert NULL values (see #4632)
|
||||
|
@ -82,6 +82,16 @@ class Project < ActiveRecord::Base
|
||||
named_scope :active, { :conditions => "#{Project.table_name}.status = #{STATUS_ACTIVE}"}
|
||||
named_scope :all_public, { :conditions => { :is_public => true } }
|
||||
named_scope :visible, lambda { { :conditions => Project.visible_by(User.current) } }
|
||||
named_scope :like, lambda {|q|
|
||||
s = "%#{q.to_s.strip.downcase}%"
|
||||
{
|
||||
:conditions => ["LOWER(name) LIKE ?", s]
|
||||
}
|
||||
}
|
||||
|
||||
def to_liquid
|
||||
ProjectDrop.new(self)
|
||||
end
|
||||
|
||||
def initialize(attributes = nil)
|
||||
super
|
||||
@ -131,6 +141,11 @@ class Project < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
# Is the project visible to the current user
|
||||
def visible?
|
||||
User.current.allowed_to?(:view_project, self)
|
||||
end
|
||||
|
||||
def self.allowed_to_condition(user, permission, options={})
|
||||
base_statement = "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"
|
||||
if perm = Redmine::AccessControl.permission(permission)
|
||||
@ -616,7 +631,7 @@ class Project < ActiveRecord::Base
|
||||
while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
|
||||
ancestors.pop
|
||||
end
|
||||
yield project, ancestors.size
|
||||
yield project, ancestors.size if block_given?
|
||||
ancestors << project
|
||||
end
|
||||
end
|
||||
|
@ -12,64 +12,7 @@
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
class QueryColumn
|
||||
attr_accessor :name, :sortable, :groupable, :default_order
|
||||
include Redmine::I18n
|
||||
|
||||
def initialize(name, options={})
|
||||
self.name = name
|
||||
self.sortable = options[:sortable]
|
||||
self.groupable = options[:groupable] || false
|
||||
if groupable == true
|
||||
self.groupable = name.to_s
|
||||
end
|
||||
self.default_order = options[:default_order]
|
||||
@caption_key = options[:caption] || "field_#{name}"
|
||||
end
|
||||
|
||||
def caption
|
||||
l(@caption_key)
|
||||
end
|
||||
|
||||
# Returns true if the column is sortable, otherwise false
|
||||
def sortable?
|
||||
!sortable.nil?
|
||||
end
|
||||
|
||||
def value(issue)
|
||||
issue.send name
|
||||
end
|
||||
end
|
||||
|
||||
class QueryCustomFieldColumn < QueryColumn
|
||||
|
||||
def initialize(custom_field)
|
||||
self.name = "cf_#{custom_field.id}".to_sym
|
||||
self.sortable = custom_field.order_statement || false
|
||||
if %w(list date bool int).include?(custom_field.field_format)
|
||||
self.groupable = custom_field.order_statement
|
||||
end
|
||||
self.groupable ||= false
|
||||
@cf = custom_field
|
||||
end
|
||||
|
||||
def caption
|
||||
@cf.name
|
||||
end
|
||||
|
||||
def custom_field
|
||||
@cf
|
||||
end
|
||||
|
||||
def value(issue)
|
||||
cv = issue.custom_values.detect {|v| v.custom_field_id == @cf.id}
|
||||
cv && @cf.cast_value(cv.value)
|
||||
end
|
||||
end
|
||||
|
||||
class Query < ActiveRecord::Base
|
||||
class StatementInvalid < ::ActiveRecord::StatementInvalid
|
||||
end
|
||||
|
||||
belongs_to :project
|
||||
belongs_to :user
|
||||
@ -90,6 +33,7 @@ class Query < ActiveRecord::Base
|
||||
"*" => :label_all,
|
||||
">=" => :label_greater_or_equal,
|
||||
"<=" => :label_less_or_equal,
|
||||
"><" => :label_between,
|
||||
"<t+" => :label_in_less_than,
|
||||
">t+" => :label_in_more_than,
|
||||
"t+" => :label_in,
|
||||
@ -107,8 +51,8 @@ class Query < ActiveRecord::Base
|
||||
:list_status => [ "o", "=", "!", "c", "*" ],
|
||||
:list_optional => [ "=", "!", "!*", "*" ],
|
||||
:list_subprojects => [ "*", "!*", "=" ],
|
||||
:date => [ "<t+", ">t+", "t+", "t", "w", ">t-", "<t-", "t-" ],
|
||||
:date_past => [ ">t-", "<t-", "t-", "t", "w" ],
|
||||
:date => [ "=", ">=", "<=", "><", "<t+", ">t+", "t+", "t", "w", ">t-", "<t-", "t-" ],
|
||||
:date_past => [ "=", ">=", "<=", "><", ">t-", "<t-", "t-", "t", "w" ],
|
||||
:string => [ "=", "~", "!", "!~" ],
|
||||
:text => [ "~", "!~" ],
|
||||
:integer => [ "=", ">=", "<=", "!*", "*" ] }
|
||||
@ -139,6 +83,7 @@ class Query < ActiveRecord::Base
|
||||
def initialize(attributes = nil)
|
||||
super attributes
|
||||
self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} }
|
||||
self.display_subprojects ||= Setting.display_subprojects_issues?
|
||||
end
|
||||
|
||||
def after_initialize
|
||||
@ -245,7 +190,7 @@ class Query < ActiveRecord::Base
|
||||
|
||||
def add_filter(field, operator, values)
|
||||
# values must be an array
|
||||
return unless values and values.is_a? Array # and !values.first.empty?
|
||||
return unless values.nil? || values.is_a?(Array)
|
||||
# check if field is defined as an available filter
|
||||
if available_filters.has_key? field
|
||||
filter_options = available_filters[field]
|
||||
@ -254,7 +199,7 @@ class Query < ActiveRecord::Base
|
||||
# allowed_values = values & ([""] + (filter_options[:values] || []).collect {|val| val[1]})
|
||||
# filters[field] = {:operator => operator, :values => allowed_values } if (allowed_values.first and !allowed_values.first.empty?) or ["o", "c", "!*", "*", "t"].include? operator
|
||||
#end
|
||||
filters[field] = {:operator => operator, :values => values }
|
||||
filters[field] = {:operator => operator, :values => (values || ['']) }
|
||||
end
|
||||
end
|
||||
|
||||
@ -266,9 +211,9 @@ class Query < ActiveRecord::Base
|
||||
|
||||
# Add multiple filters using +add_filter+
|
||||
def add_filters(fields, operators, values)
|
||||
if fields.is_a?(Array) && operators.is_a?(Hash) && values.is_a?(Hash)
|
||||
if fields.is_a?(Array) && operators.is_a?(Hash) && (values.nil? || values.is_a?(Hash))
|
||||
fields.each do |field|
|
||||
add_filter(field, operators[field], values[field])
|
||||
add_filter(field, operators[field], values && values[field])
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -277,6 +222,10 @@ class Query < ActiveRecord::Base
|
||||
filters and filters[field]
|
||||
end
|
||||
|
||||
def type_for(field)
|
||||
available_filters[field][:type] if available_filters.has_key?(field)
|
||||
end
|
||||
|
||||
def operator_for(field)
|
||||
has_filter?(field) ? filters[field][:operator] : nil
|
||||
end
|
||||
@ -285,6 +234,10 @@ class Query < ActiveRecord::Base
|
||||
has_filter?(field) ? filters[field][:values] : nil
|
||||
end
|
||||
|
||||
def value_for(field, index=0)
|
||||
(values_for(field) || [])[index]
|
||||
end
|
||||
|
||||
def label_for(field)
|
||||
label = available_filters[field][:name] if available_filters.has_key?(field)
|
||||
label ||= field.gsub(/\_id$/, "")
|
||||
@ -410,7 +363,7 @@ class Query < ActiveRecord::Base
|
||||
# all subprojects
|
||||
ids += project.descendants.collect(&:id)
|
||||
end
|
||||
elsif Setting.display_subprojects_issues?
|
||||
elsif display_subprojects?
|
||||
ids += project.descendants.collect(&:id)
|
||||
end
|
||||
project_clauses << "#{Project.table_name}.id IN (%s)" % ids.join(',')
|
||||
@ -519,7 +472,7 @@ class Query < ActiveRecord::Base
|
||||
def issue_count
|
||||
Issue.count(:include => [:status, :project], :conditions => statement)
|
||||
rescue ::ActiveRecord::StatementInvalid => e
|
||||
raise StatementInvalid.new(e.message)
|
||||
raise Query::StatementInvalid.new(e.message)
|
||||
end
|
||||
|
||||
# Returns the issue count by group or nil if query is not grouped
|
||||
@ -539,7 +492,7 @@ class Query < ActiveRecord::Base
|
||||
end
|
||||
r
|
||||
rescue ::ActiveRecord::StatementInvalid => e
|
||||
raise StatementInvalid.new(e.message)
|
||||
raise Query::StatementInvalid.new(e.message)
|
||||
end
|
||||
|
||||
# Returns the issues
|
||||
@ -554,7 +507,7 @@ class Query < ActiveRecord::Base
|
||||
:limit => options[:limit],
|
||||
:offset => options[:offset]
|
||||
rescue ::ActiveRecord::StatementInvalid => e
|
||||
raise StatementInvalid.new(e.message)
|
||||
raise Query::StatementInvalid.new(e.message)
|
||||
end
|
||||
|
||||
# Returns the journals
|
||||
@ -566,7 +519,7 @@ class Query < ActiveRecord::Base
|
||||
:limit => options[:limit],
|
||||
:offset => options[:offset]
|
||||
rescue ::ActiveRecord::StatementInvalid => e
|
||||
raise StatementInvalid.new(e.message)
|
||||
raise Query::StatementInvalid.new(e.message)
|
||||
end
|
||||
|
||||
# Returns the versions
|
||||
@ -575,7 +528,7 @@ class Query < ActiveRecord::Base
|
||||
Version.find :all, :include => :project,
|
||||
:conditions => Query.merge_conditions(project_statement, options[:conditions])
|
||||
rescue ::ActiveRecord::StatementInvalid => e
|
||||
raise StatementInvalid.new(e.message)
|
||||
raise Query::StatementInvalid.new(e.message)
|
||||
end
|
||||
|
||||
private
|
||||
@ -585,11 +538,15 @@ class Query < ActiveRecord::Base
|
||||
sql = ''
|
||||
case operator
|
||||
when "="
|
||||
if value.present?
|
||||
sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
|
||||
if [:date, :date_past].include?(type_for(field))
|
||||
sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), (Date.parse(value.first) rescue nil))
|
||||
else
|
||||
# empty set of allowed values produces no result
|
||||
sql = "0=1"
|
||||
if value.any?
|
||||
sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
|
||||
else
|
||||
# IN an empty set
|
||||
sql = "0=1"
|
||||
end
|
||||
end
|
||||
when "!"
|
||||
if value.present?
|
||||
@ -605,42 +562,58 @@ class Query < ActiveRecord::Base
|
||||
sql = "#{db_table}.#{db_field} IS NOT NULL"
|
||||
sql << " AND #{db_table}.#{db_field} <> ''" if is_custom_filter
|
||||
when ">="
|
||||
if is_custom_filter
|
||||
sql = "#{db_table}.#{db_field} != '' AND CAST(#{db_table}.#{db_field} AS decimal(60,4)) >= #{value.first.to_f}"
|
||||
if [:date, :date_past].include?(type_for(field))
|
||||
sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), nil)
|
||||
else
|
||||
sql = "#{db_table}.#{db_field} >= #{value.first.to_f}"
|
||||
if is_custom_filter
|
||||
sql = "CAST(#{db_table}.#{db_field} AS decimal(60,3)) >= #{value.first.to_i}"
|
||||
else
|
||||
sql = "#{db_table}.#{db_field} >= #{value.first.to_i}"
|
||||
end
|
||||
end
|
||||
when "<="
|
||||
if is_custom_filter
|
||||
sql = "#{db_table}.#{db_field} != '' AND CAST(#{db_table}.#{db_field} AS decimal(60,4)) <= #{value.first.to_f}"
|
||||
if [:date, :date_past].include?(type_for(field))
|
||||
sql = date_clause(db_table, db_field, nil, (Date.parse(value.first) rescue nil))
|
||||
else
|
||||
sql = "#{db_table}.#{db_field} <= #{value.first.to_f}"
|
||||
if is_custom_filter
|
||||
sql = "CAST(#{db_table}.#{db_field} AS decimal(60,3)) <= #{value.first.to_i}"
|
||||
else
|
||||
sql = "#{db_table}.#{db_field} <= #{value.first.to_i}"
|
||||
end
|
||||
end
|
||||
when "><"
|
||||
if [:date, :date_past].include?(type_for(field))
|
||||
sql = date_clause(db_table, db_field, (Date.parse(value[0]) rescue nil), (Date.parse(value[1]) rescue nil))
|
||||
else
|
||||
if is_custom_filter
|
||||
sql = "CAST(#{db_table}.#{db_field} AS decimal(60,3)) BETWEEN #{value[0].to_i} AND #{value[1].to_i}"
|
||||
else
|
||||
sql = "#{db_table}.#{db_field} BETWEEN #{value[0].to_i} AND #{value[1].to_i}"
|
||||
end
|
||||
end
|
||||
when "o"
|
||||
sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_false}" if field == "status_id"
|
||||
when "c"
|
||||
sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_true}" if field == "status_id"
|
||||
when ">t-"
|
||||
sql = date_range_clause(db_table, db_field, - value.first.to_i, 0)
|
||||
sql = relative_date_clause(db_table, db_field, - value.first.to_i, 0)
|
||||
when "<t-"
|
||||
sql = date_range_clause(db_table, db_field, nil, - value.first.to_i)
|
||||
sql = relative_date_clause(db_table, db_field, nil, - value.first.to_i)
|
||||
when "t-"
|
||||
sql = date_range_clause(db_table, db_field, - value.first.to_i, - value.first.to_i)
|
||||
sql = relative_date_clause(db_table, db_field, - value.first.to_i, - value.first.to_i)
|
||||
when ">t+"
|
||||
sql = date_range_clause(db_table, db_field, value.first.to_i, nil)
|
||||
sql = relative_date_clause(db_table, db_field, value.first.to_i, nil)
|
||||
when "<t+"
|
||||
sql = date_range_clause(db_table, db_field, 0, value.first.to_i)
|
||||
sql = relative_date_clause(db_table, db_field, 0, value.first.to_i)
|
||||
when "t+"
|
||||
sql = date_range_clause(db_table, db_field, value.first.to_i, value.first.to_i)
|
||||
sql = relative_date_clause(db_table, db_field, value.first.to_i, value.first.to_i)
|
||||
when "t"
|
||||
sql = date_range_clause(db_table, db_field, 0, 0)
|
||||
sql = relative_date_clause(db_table, db_field, 0, 0)
|
||||
when "w"
|
||||
from = l(:general_first_day_of_week) == '7' ?
|
||||
# week starts on sunday
|
||||
((Date.today.cwday == 7) ? Time.now.at_beginning_of_day : Time.now.at_beginning_of_week - 1.day) :
|
||||
# week starts on monday (Rails default)
|
||||
Time.now.at_beginning_of_week
|
||||
sql = "#{db_table}.#{db_field} BETWEEN '%s' AND '%s'" % [connection.quoted_date(from), connection.quoted_date(from + 7.days)]
|
||||
first_day_of_week = l(:general_first_day_of_week).to_i
|
||||
day_of_week = Date.today.cwday
|
||||
days_ago = (day_of_week >= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week)
|
||||
sql = relative_date_clause(db_table, db_field, - days_ago, - days_ago + 6)
|
||||
when "~"
|
||||
sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
|
||||
when "!~"
|
||||
@ -676,14 +649,19 @@ class Query < ActiveRecord::Base
|
||||
end
|
||||
|
||||
# Returns a SQL clause for a date or datetime field.
|
||||
def date_range_clause(table, field, from, to)
|
||||
def date_clause(table, field, from, to)
|
||||
s = []
|
||||
if from
|
||||
s << ("#{table}.#{field} > '%s'" % [connection.quoted_date((Date.yesterday + from).to_time.end_of_day)])
|
||||
s << ("#{table}.#{field} > '%s'" % [connection.quoted_date((from - 1).to_time.end_of_day)])
|
||||
end
|
||||
if to
|
||||
s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date((Date.today + to).to_time.end_of_day)])
|
||||
s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date(to.to_time.end_of_day)])
|
||||
end
|
||||
s.join(' AND ')
|
||||
end
|
||||
|
||||
# Returns a SQL clause for a date or datetime field using relative dates.
|
||||
def relative_date_clause(table, field, days_from, days_to)
|
||||
date_clause(table, field, (days_from ? Date.today + days_from : nil), (days_to ? Date.today + days_to : nil))
|
||||
end
|
||||
end
|
||||
|
16
app/models/query/statement_invalid.rb
Normal file
16
app/models/query/statement_invalid.rb
Normal file
@ -0,0 +1,16 @@
|
||||
#-- encoding: UTF-8
|
||||
#-- copyright
|
||||
# ChiliProject is a project management system.
|
||||
#
|
||||
# Copyright (C) 2010-2012 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
class Query::StatementInvalid < ActiveRecord::StatementInvalid
|
||||
end
|
42
app/models/query_column.rb
Normal file
42
app/models/query_column.rb
Normal file
@ -0,0 +1,42 @@
|
||||
#-- encoding: UTF-8
|
||||
#-- copyright
|
||||
# ChiliProject is a project management system.
|
||||
#
|
||||
# Copyright (C) 2010-2012 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
class QueryColumn
|
||||
attr_accessor :name, :sortable, :groupable, :default_order
|
||||
include Redmine::I18n
|
||||
|
||||
def initialize(name, options={})
|
||||
self.name = name
|
||||
self.sortable = options[:sortable]
|
||||
self.groupable = options[:groupable] || false
|
||||
if groupable == true
|
||||
self.groupable = name.to_s
|
||||
end
|
||||
self.default_order = options[:default_order]
|
||||
@caption_key = options[:caption] || "field_#{name}"
|
||||
end
|
||||
|
||||
def caption
|
||||
l(@caption_key)
|
||||
end
|
||||
|
||||
# Returns true if the column is sortable, otherwise false
|
||||
def sortable?
|
||||
!sortable.nil?
|
||||
end
|
||||
|
||||
def value(issue)
|
||||
issue.send name
|
||||
end
|
||||
end
|
40
app/models/query_custom_field_column.rb
Normal file
40
app/models/query_custom_field_column.rb
Normal file
@ -0,0 +1,40 @@
|
||||
#-- encoding: UTF-8
|
||||
#-- copyright
|
||||
# ChiliProject is a project management system.
|
||||
#
|
||||
# Copyright (C) 2010-2012 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
class QueryCustomFieldColumn < QueryColumn
|
||||
|
||||
def initialize(custom_field)
|
||||
self.name = "cf_#{custom_field.id}".to_sym
|
||||
self.sortable = custom_field.order_statement || false
|
||||
if %w(list date bool int).include?(custom_field.field_format)
|
||||
self.groupable = custom_field.order_statement
|
||||
end
|
||||
self.groupable ||= false
|
||||
@cf = custom_field
|
||||
end
|
||||
|
||||
def caption
|
||||
@cf.name
|
||||
end
|
||||
|
||||
def custom_field
|
||||
@cf
|
||||
end
|
||||
|
||||
def value(issue)
|
||||
cv = issue.custom_values.detect {|v| v.custom_field_id == @cf.id}
|
||||
cv && @cf.cast_value(cv.value)
|
||||
end
|
||||
end
|
||||
|
@ -97,13 +97,17 @@ class Setting < ActiveRecord::Base
|
||||
|
||||
# Returns the value of the setting named name
|
||||
def self.[](name)
|
||||
Marshal.load(Rails.cache.fetch("chiliproject/setting/#{name}") {Marshal.dump(find_or_default(name).value)})
|
||||
if use_caching?
|
||||
Marshal.load(Rails.cache.fetch(self.cache_key(name)) {Marshal.dump(find_or_default(name).value)})
|
||||
else
|
||||
find_or_default(name).value
|
||||
end
|
||||
end
|
||||
|
||||
def self.[]=(name, v)
|
||||
setting = find_or_default(name)
|
||||
setting.value = (v ? v : "")
|
||||
Rails.cache.delete "chiliproject/setting/#{name}"
|
||||
Rails.cache.delete self.cache_key(name)
|
||||
setting.save
|
||||
setting.value
|
||||
end
|
||||
@ -137,23 +141,42 @@ class Setting < ActiveRecord::Base
|
||||
Object.const_defined?(:OpenID) && self[:openid].to_i > 0
|
||||
end
|
||||
|
||||
# Checks if settings have changed since the values were read
|
||||
# and clears the cache hash if it's the case
|
||||
# Called once per request
|
||||
# Deprecation Warning: This method is no longer available. There is no
|
||||
# replacement.
|
||||
def self.check_cache
|
||||
settings_updated_on = Setting.maximum(:updated_on)
|
||||
cache_cleared_on = Rails.cache.read('chiliproject/setting-cleared_on')
|
||||
cache_cleared_on = cache_cleared_on ? Marshal.load(cache_cleared_on) : Time.now
|
||||
if settings_updated_on && cache_cleared_on <= settings_updated_on
|
||||
clear_cache
|
||||
end
|
||||
# DEPRECATED SINCE 3.0.0beta2
|
||||
ActiveSupport::Deprecation.warn "The Setting.check_cache method is " +
|
||||
"deprecated and will be removed in the future. There should be no " +
|
||||
"replacement for this functionality needed."
|
||||
end
|
||||
|
||||
# Clears all of the Setting caches
|
||||
def self.clear_cache
|
||||
Rails.cache.delete_matched( /^chiliproject\/setting\/.+$/ )
|
||||
Rails.cache.write('chiliproject/setting-cleared_on', Marshal.dump(Time.now))
|
||||
logger.info 'Settings cache cleared.' if logger
|
||||
# DEPRECATED SINCE 3.0.0beta2
|
||||
ActiveSupport::Deprecation.warn "The Setting.clear_cache method is " +
|
||||
"deprecated and will be removed in the future. There should be no " +
|
||||
"replacement for this functionality needed. To sweep the whole " +
|
||||
"cache Rails.cache.clear may be used. To invalidate the Settings " +
|
||||
"only, you may use Setting.first.try(:touch)"
|
||||
end
|
||||
|
||||
# Temporarily deactivate settings caching in the block scope
|
||||
def self.uncached
|
||||
cache_setting = self.use_caching
|
||||
self.use_caching = false
|
||||
yield
|
||||
ensure
|
||||
self.use_caching = cache_setting
|
||||
end
|
||||
|
||||
# Check if Setting caching should be performed
|
||||
def self.use_caching?
|
||||
!Thread.current['chiliproject/settings/do_not_use_caching']
|
||||
end
|
||||
|
||||
# Dis-/En-able Setting caching. This is mainly intended to be used in tests
|
||||
def self.use_caching=(new_value)
|
||||
Thread.current['chiliproject/settings/do_not_use_caching'] = !new_value
|
||||
end
|
||||
|
||||
private
|
||||
@ -165,4 +188,8 @@ private
|
||||
setting = find_by_name(name)
|
||||
setting ||= new(:name => name, :value => @@available_settings[name]['default']) if @@available_settings.has_key? name
|
||||
end
|
||||
|
||||
def self.cache_key(name)
|
||||
"chiliproject/setting/#{Setting.maximum(:updated_on).to_i}/#{name}"
|
||||
end
|
||||
end
|
||||
|
@ -35,6 +35,10 @@ class Tracker < ActiveRecord::Base
|
||||
name <=> tracker.name
|
||||
end
|
||||
|
||||
def to_liquid
|
||||
TrackerDrop.new(self)
|
||||
end
|
||||
|
||||
def self.all
|
||||
find(:all, :order => 'position')
|
||||
end
|
||||
|
@ -345,27 +345,6 @@ class User < Principal
|
||||
!logged?
|
||||
end
|
||||
|
||||
# Return user's roles for project
|
||||
def roles_for_project(project)
|
||||
roles = []
|
||||
# No role on archived projects
|
||||
return roles unless project && project.active?
|
||||
if logged?
|
||||
# Find project membership
|
||||
membership = memberships.detect {|m| m.project_id == project.id}
|
||||
if membership
|
||||
roles = membership.roles
|
||||
else
|
||||
@role_non_member ||= Role.non_member
|
||||
roles << @role_non_member
|
||||
end
|
||||
else
|
||||
@role_anonymous ||= Role.anonymous
|
||||
roles << @role_anonymous
|
||||
end
|
||||
roles
|
||||
end
|
||||
|
||||
# Return true if the user is a member of project
|
||||
def member_of?(project)
|
||||
!roles_for_project(project).detect {|role| role.member?}.nil?
|
||||
@ -388,53 +367,6 @@ class User < Principal
|
||||
@projects_by_role
|
||||
end
|
||||
|
||||
# Return true if the user is allowed to do the specified action on a specific context
|
||||
# Action can be:
|
||||
# * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
|
||||
# * a permission Symbol (eg. :edit_project)
|
||||
# Context can be:
|
||||
# * a project : returns true if user is allowed to do the specified action on this project
|
||||
# * a group of projects : returns true if user is allowed on every project
|
||||
# * nil with options[:global] set : check if user has at least one role allowed for this action,
|
||||
# or falls back to Non Member / Anonymous permissions depending if the user is logged
|
||||
def allowed_to?(action, context, options={})
|
||||
if context && context.is_a?(Project)
|
||||
# No action allowed on archived projects
|
||||
return false unless context.active?
|
||||
# No action allowed on disabled modules
|
||||
return false unless context.allows_to?(action)
|
||||
# Admin users are authorized for anything else
|
||||
return true if admin?
|
||||
|
||||
roles = roles_for_project(context)
|
||||
return false unless roles
|
||||
roles.detect {|role| (context.is_public? || role.member?) && role.allowed_to?(action)}
|
||||
|
||||
elsif context && context.is_a?(Array)
|
||||
# Authorize if user is authorized on every element of the array
|
||||
context.map do |project|
|
||||
allowed_to?(action,project,options)
|
||||
end.inject do |memo,allowed|
|
||||
memo && allowed
|
||||
end
|
||||
elsif options[:global]
|
||||
# Admin users are always authorized
|
||||
return true if admin?
|
||||
|
||||
# authorize if user has at least one role that has this permission
|
||||
roles = memberships.collect {|m| m.roles}.flatten.uniq
|
||||
roles.detect {|r| r.allowed_to?(action)} || (self.logged? ? Role.non_member.allowed_to?(action) : Role.anonymous.allowed_to?(action))
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# Is the user allowed to do the specified action on any project?
|
||||
# See allowed_to? for the actions and valid options.
|
||||
def allowed_to_globally?(action, options)
|
||||
allowed_to?(action, nil, options.reverse_merge(:global => true))
|
||||
end
|
||||
|
||||
safe_attributes 'login',
|
||||
'firstname',
|
||||
'lastname',
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
class Watcher < ActiveRecord::Base
|
||||
belongs_to :watchable, :polymorphic => true
|
||||
belongs_to :user
|
||||
belongs_to :user, :class_name => 'Principal', :foreign_key => 'user_id'
|
||||
|
||||
validates_presence_of :user
|
||||
validates_uniqueness_of :user_id, :scope => [:watchable_type, :watchable_id]
|
||||
|
@ -53,6 +53,10 @@ class WikiPage < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def to_liquid
|
||||
WikiPageDrop.new(self)
|
||||
end
|
||||
|
||||
def visible?(user=User.current)
|
||||
!user.nil? && user.allowed_to?(:view_wiki_pages, project)
|
||||
end
|
||||
|
34
app/views/account/_login.rhtml
Normal file
34
app/views/account/_login.rhtml
Normal file
@ -0,0 +1,34 @@
|
||||
<div id="nav-login-content">
|
||||
<% form_tag({:controller => "account", :action=> "login"}) do %>
|
||||
<%= hidden_field_tag('back_url', CGI.escape(request.url)) %>
|
||||
<table>
|
||||
<tr>
|
||||
<td><label for="username-pulldown"><%= l(:field_login) %></label></td>
|
||||
<td><label for="password-pulldown"><%= l(:field_password) %></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><%= text_field_tag 'username', nil, :tabindex => '1', :id => 'username-pulldown' %></td>
|
||||
<td><%= password_field_tag 'password', nil, :tabindex => '1', :id => 'password-pulldown' %></td>
|
||||
<td><input type="submit" name="login" value="<%=l(:button_login)%>" tabindex="1"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id = "optional_login_fields" style = "top = 10px; white-space:nowrap">
|
||||
<% if Setting.openid? %>
|
||||
<%= text_field_tag "openid_url", nil, :placeholder => l(:field_identity_url), :tabindex => '1' %>
|
||||
<% end %>
|
||||
|
||||
<% if Setting.autologin? %>
|
||||
<label for="autologin"><%= check_box_tag 'autologin', 1, false, :tabindex => 1 %> <%= l(:label_stay_logged_in) %></label>
|
||||
<% end %>
|
||||
|
||||
<% if Setting.lost_password? %>
|
||||
<%= link_to l(:label_password_lost), {:controller => 'account', :action => 'lost_password'}, :tabindex => 1 %>
|
||||
<% end %>
|
||||
|
||||
<% if !User.current.logged? && Setting.self_registration? %>
|
||||
<%= "|" if Setting.lost_password? %>
|
||||
<%= link_to l(:label_register), { :controller => 'account', :action => 'register' }, :tabindex => 1 %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
@ -5,7 +5,7 @@
|
||||
<table>
|
||||
<tr>
|
||||
<td align="right"><label for="username"><%=l(:field_login)%>:</label></td>
|
||||
<td align="left"><%= text_field_tag 'username', nil, :tabindex => '1' %></td>
|
||||
<td align="left"><%= text_field_tag 'username', nil, :tabindex => '2' %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right"><label for="password"><%=l(:field_password)%>:</label></td>
|
||||
|
@ -1,5 +1 @@
|
||||
<div id="admin-menu">
|
||||
<ul>
|
||||
<%= render_menu :admin_menu %>
|
||||
</ul>
|
||||
</div>
|
||||
<%= render_menu :admin_menu %>
|
||||
|
@ -1,5 +1,3 @@
|
||||
<h2><%=l(:label_administration)%></h2>
|
||||
|
||||
<div id="admin-index">
|
||||
<%= render :partial => 'no_data' if @no_configuration_data %>
|
||||
<%= render :partial => 'menu' %>
|
||||
|
1
app/views/auto_completes/projects.html.erb
Normal file
1
app/views/auto_completes/projects.html.erb
Normal file
@ -0,0 +1 @@
|
||||
<%= projects_check_box_tags 'project_ids[]', @projects %>
|
@ -71,3 +71,13 @@
|
||||
<%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@project}: #{@board}") %>
|
||||
<%= stylesheet_link_tag 'scm' %>
|
||||
<% end %>
|
||||
|
||||
<% content_for :sidebar do %>
|
||||
<% if User.current.allowed_to?(:add_board_watchers, @project) ||
|
||||
(@board.watchers.present? && User.current.allowed_to?(:view_board_watchers, @project)) %>
|
||||
<div id="watchers">
|
||||
<%= render :partial => 'watchers/watchers', :locals => {:watched => @board} %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% end %>
|
||||
|
@ -1,52 +1,55 @@
|
||||
<ul>
|
||||
<ul class="menu">
|
||||
<%= call_hook(:view_issues_context_menu_start, {:issues => @issues, :can => @can, :back => @back }) %>
|
||||
|
||||
<% if !@issue.nil? -%>
|
||||
<li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue},
|
||||
<li class="edit"><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue},
|
||||
:class => 'icon-edit', :disabled => !@can[:edit] %></li>
|
||||
<% else %>
|
||||
<li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id)},
|
||||
<li class="edit"><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id)},
|
||||
:class => 'icon-edit', :disabled => !@can[:edit] %></li>
|
||||
<% end %>
|
||||
|
||||
<% if @allowed_statuses.present? %>
|
||||
<li class="folder">
|
||||
<a href="#" class="submenu" onclick="return false;"><%= l(:field_status) %></a>
|
||||
<li class="folder status">
|
||||
<a href="#" class="context_item" onclick="return false;"><%= l(:field_status) %></a>
|
||||
<ul>
|
||||
<% @statuses.each do |s| -%>
|
||||
<li><%= context_menu_link s.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {:status_id => s}, :back_url => @back}, :method => :post,
|
||||
:selected => (@issue && s == @issue.status), :disabled => !(@can[:update] && @allowed_statuses.include?(s)) %></li>
|
||||
<% end -%>
|
||||
</ul>
|
||||
<div class="submenu"></div>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% unless @trackers.nil? %>
|
||||
<li class="folder">
|
||||
<a href="#" class="submenu"><%= l(:field_tracker) %></a>
|
||||
<li class="folder tracker">
|
||||
<a href="#" class="context_item"><%= l(:field_tracker) %></a>
|
||||
<ul>
|
||||
<% @trackers.each do |t| -%>
|
||||
<li><%= context_menu_link t.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'tracker_id' => t}, :back_url => @back}, :method => :post,
|
||||
:selected => (@issue && t == @issue.tracker), :disabled => !@can[:edit] %></li>
|
||||
<% end -%>
|
||||
</ul>
|
||||
<div class="submenu"></div>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<li class="folder">
|
||||
<a href="#" class="submenu"><%= l(:field_priority) %></a>
|
||||
<li class="folder priority">
|
||||
<a href="#" class="context_item"><%= l(:field_priority) %></a>
|
||||
<ul>
|
||||
<% @priorities.each do |p| -%>
|
||||
<li><%= context_menu_link p.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'priority_id' => p}, :back_url => @back}, :method => :post,
|
||||
:selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %></li>
|
||||
<% end -%>
|
||||
</ul>
|
||||
<div class="submenu"></div>
|
||||
</li>
|
||||
|
||||
<% #TODO: allow editing versions when multiple projects %>
|
||||
<% unless @project.nil? || @project.shared_versions.open.empty? -%>
|
||||
<li class="folder">
|
||||
<a href="#" class="submenu"><%= l(:field_fixed_version) %></a>
|
||||
<li class="folder fixed_version">
|
||||
<a href="#" class="context_item"><%= l(:field_fixed_version) %></a>
|
||||
<ul>
|
||||
<% @project.shared_versions.open.sort.each do |v| -%>
|
||||
<li><%= context_menu_link format_version_name(v), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => v}, :back_url => @back}, :method => :post,
|
||||
@ -55,11 +58,13 @@
|
||||
<li><%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => 'none'}, :back_url => @back}, :method => :post,
|
||||
:selected => (@issue && @issue.fixed_version.nil?), :disabled => !@can[:update] %></li>
|
||||
</ul>
|
||||
<div class="submenu"></div>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if @assignables.present? -%>
|
||||
<li class="folder">
|
||||
<a href="#" class="submenu"><%= l(:field_assigned_to) %></a>
|
||||
<li class="folder assigned">
|
||||
<a href="#" class="context_item"><%= l(:field_assigned_to) %></a>
|
||||
<ul>
|
||||
<% @assignables.each do |u| -%>
|
||||
<li><%= context_menu_link u.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => u}, :back_url => @back}, :method => :post,
|
||||
@ -68,11 +73,13 @@
|
||||
<li><%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => 'none'}, :back_url => @back}, :method => :post,
|
||||
:selected => (@issue && @issue.assigned_to.nil?), :disabled => !@can[:update] %></li>
|
||||
</ul>
|
||||
<div class="submenu"></div>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% unless @project.nil? || @project.issue_categories.empty? -%>
|
||||
<li class="folder">
|
||||
<a href="#" class="submenu"><%= l(:field_category) %></a>
|
||||
<a href="#" class="context_item"><%= l(:field_category) %></a>
|
||||
<ul>
|
||||
<% @project.issue_categories.each do |u| -%>
|
||||
<li><%= context_menu_link u.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'category_id' => u}, :back_url => @back}, :method => :post,
|
||||
@ -81,28 +88,30 @@
|
||||
<li><%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'category_id' => 'none'}, :back_url => @back}, :method => :post,
|
||||
:selected => (@issue && @issue.category.nil?), :disabled => !@can[:update] %></li>
|
||||
</ul>
|
||||
</li>
|
||||
<div class="submenu"></div>
|
||||
</li>
|
||||
<% end -%>
|
||||
|
||||
<% if Issue.use_field_for_done_ratio? %>
|
||||
<li class="folder">
|
||||
<a href="#" class="submenu"><%= l(:field_done_ratio) %></a>
|
||||
<li class="folder done_ratio">
|
||||
<a href="#" class="context_item"><%= l(:field_done_ratio) %></a>
|
||||
<ul>
|
||||
<% (0..10).map{|x|x*10}.each do |p| -%>
|
||||
<li><%= context_menu_link "#{p}%", {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'done_ratio' => p}, :back_url => @back}, :method => :post,
|
||||
:selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %></li>
|
||||
<% end -%>
|
||||
</ul>
|
||||
<div class="submenu"></div>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if !@issue.nil? %>
|
||||
<% if @can[:log_time] -%>
|
||||
<li><%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue},
|
||||
:class => 'icon-time-add' %></li>
|
||||
<li class="log_time"><%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue},
|
||||
:class => 'context_item' %></li>
|
||||
<% end %>
|
||||
<% if User.current.logged? %>
|
||||
<li><%= watcher_link(@issue, User.current) %></li>
|
||||
<li class="watch"><%= watcher_link(@issue, User.current) %></li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@ -110,12 +119,13 @@
|
||||
<li><%= context_menu_link l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
|
||||
:class => 'icon-duplicate', :disabled => !@can[:copy] %></li>
|
||||
<% end %>
|
||||
<li><%= context_menu_link l(:button_copy), new_issue_move_path(:ids => @issues.collect(&:id), :copy_options => {:copy => 't'}),
|
||||
:class => 'icon-copy', :disabled => !@can[:move] %></li>
|
||||
<li><%= context_menu_link l(:button_move), new_issue_move_path(:ids => @issues.collect(&:id)),
|
||||
:class => 'icon-move', :disabled => !@can[:move] %></li>
|
||||
<li><%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :ids => @issues.collect(&:id), :back_url => @back},
|
||||
:method => :post, :confirm => l(:text_issues_destroy_confirmation), :class => 'icon-del', :disabled => !@can[:delete] %></li>
|
||||
|
||||
<li class="move"><%= context_menu_link l(:button_move), new_issue_move_path(:ids => @issues.collect(&:id)),
|
||||
:class => 'context_item', :disabled => !@can[:move] %></li>
|
||||
<li class="copy"><%= context_menu_link l(:button_copy), new_issue_move_path(:ids => @issues.collect(&:id), :copy_options => {:copy => 't'}),
|
||||
:class => 'context_item' %></li>
|
||||
<li class="delete"><%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :ids => @issues.collect(&:id)},
|
||||
:method => :post, :confirm => l(:text_issues_destroy_confirmation), :class => 'context_item', :disabled => !@can[:delete] %></li>
|
||||
|
||||
<%= call_hook(:view_issues_context_menu_end, {:issues => @issues, :can => @can, :back => @back }) %>
|
||||
</ul>
|
||||
|
@ -9,6 +9,15 @@
|
||||
|
||||
<p><label for="document_description"><%=l(:field_description)%></label>
|
||||
<%= text_area 'document', 'description', :cols => 60, :rows => 15, :class => 'wiki-edit' %></p>
|
||||
|
||||
<% if User.current.allowed_to?(:add_document_watchers, @project) -%>
|
||||
<p id="watchers_form"><label><%= l(:label_document_watchers) %></label>
|
||||
<% @document.project.users.sort.each do |user| -%>
|
||||
<label class="floating"><%= check_box_tag 'document[watcher_user_ids][]', user.id, @document.watched_by?(user) %> <%=h user %></label>
|
||||
<% end -%>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<!--[eoform:document]-->
|
||||
</div>
|
||||
|
||||
|
@ -27,6 +27,16 @@
|
||||
|
||||
<% html_title h(@document.title) -%>
|
||||
|
||||
<% content_for :sidebar do %>
|
||||
<% if User.current.allowed_to?(:add_document_watchers, @project) ||
|
||||
(@document.watchers.present? && User.current.allowed_to?(:view_document_watchers, @project)) %>
|
||||
<div id="watchers">
|
||||
<%= render :partial => 'watchers/watchers', :locals => {:watched => @document} %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% end %>
|
||||
|
||||
<% content_for :header_tags do %>
|
||||
<%= stylesheet_link_tag 'scm' %>
|
||||
<% end %>
|
||||
|
@ -41,17 +41,5 @@
|
||||
</div>
|
||||
|
||||
<div class="splitcontentright">
|
||||
<% if projects.any? %>
|
||||
<fieldset><legend><%=l(:label_project_new)%></legend>
|
||||
<% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => @group }) do %>
|
||||
<%= label_tag "membership_project_id", l(:description_choose_project), :class => "hidden-for-sighted" %>
|
||||
<%= select_tag 'membership[project_id]', options_for_membership_project_select(@group, projects) %>
|
||||
<p><%= l(:label_role_plural) %>:
|
||||
<% roles.each do |role| %>
|
||||
<label><%= check_box_tag 'membership[role_ids][]', role.id %> <%=h role %></label>
|
||||
<% end %></p>
|
||||
<p><%= submit_tag l(:button_add) %></p>
|
||||
<% end %>
|
||||
</fieldset>
|
||||
<% end %>
|
||||
<%= render :partial => 'members/membership_assignment', :locals => {:principal => @group, :projects => projects - @group.projects, :roles => roles } %>
|
||||
</div>
|
||||
|
@ -33,7 +33,7 @@
|
||||
<%= observe_field(:user_search,
|
||||
:frequency => 0.5,
|
||||
:update => :users,
|
||||
:url => { :controller => 'groups', :action => 'autocomplete_for_user', :id => @group },
|
||||
:url => auto_complete_users_path(:remove_group_members => @group),
|
||||
:with => 'q')
|
||||
%>
|
||||
|
||||
|
@ -13,20 +13,22 @@
|
||||
}
|
||||
a.new { color: #b73535; }
|
||||
|
||||
.CodeRay .c { color:#666; }
|
||||
.syntaxhl .line-numbers { padding: 2px 4px 2px 4px; background-color: #eee; margin:0 }
|
||||
.syntaxhl .comment { color:#666; }
|
||||
|
||||
.CodeRay .cl { color:#B06; font-weight:bold }
|
||||
.CodeRay .dl { color:black }
|
||||
.CodeRay .fu { color:#06B; font-weight:bold }
|
||||
.syntaxhl .class { color:#B06; font-weight:bold }
|
||||
.syntaxhl .delimiter { color:black }
|
||||
.syntaxhl .function { color:#06B; font-weight:bold }
|
||||
|
||||
.CodeRay .il { background: #eee }
|
||||
.CodeRay .il .idl { font-weight: bold; color: #888 }
|
||||
.syntaxhl .inline { background: #eee }
|
||||
.syntaxhl .inline .inline-delimiter { font-weight: bold; color: #888 }
|
||||
|
||||
.CodeRay .iv { color:#33B }
|
||||
.CodeRay .r { color:#080; font-weight:bold }
|
||||
.syntaxhl .instance-variable { color:#33B }
|
||||
.syntaxhl .reserved { color:#080; font-weight:bold }
|
||||
|
||||
.syntaxhl .string { background-color:#fff0f0; color: #D20; }
|
||||
.syntaxhl .string .delimiter { color:#710 }
|
||||
|
||||
.CodeRay .s { background-color:#fff0f0 }
|
||||
.CodeRay .s .dl { color:#710 }
|
||||
<% end %>
|
||||
|
||||
<% html_title "Wiki Formatting" %>
|
||||
@ -236,7 +238,7 @@ To go live, all you need to add is a database and a web server.
|
||||
|
||||
<h2><a name="13" class="wiki-page"></a>Code highlighting</h2>
|
||||
|
||||
<p>Code highlightment relies on <a href="http://coderay.rubychan.de/" class="external">CodeRay</a>, a fast syntax highlighting library written completely in Ruby. It currently supports c, cpp, css, delphi, groovy, html, java, javascript, json, php, python, rhtml, ruby, scheme, sql, xml and yaml languages.</p>
|
||||
<p>The default code highlighting relies on <a href="http://coderay.rubychan.de/" class="external">CodeRay</a>, a fast syntax highlighting library written completely in Ruby. It currently supports c, cpp, css, delphi, groovy, html, java, javascript, json, php, python, rhtml, ruby, scheme, sql, xml and yaml languages.</p>
|
||||
|
||||
<p>You can highlight code in your wiki page using this syntax:</p>
|
||||
|
||||
@ -248,15 +250,14 @@ To go live, all you need to add is a database and a web server.
|
||||
|
||||
<p>Example:</p>
|
||||
|
||||
<pre><code class="ruby CodeRay"><span class="no"> 1</span> <span class="c"># The Greeter class</span>
|
||||
<span class="no"> 2</span> <span class="r">class</span> <span class="cl">Greeter</span>
|
||||
<span class="no"> 3</span> <span class="r">def</span> <span class="fu">initialize</span>(name)
|
||||
<span class="no"> 4</span> <span class="iv">@name</span> = name.capitalize
|
||||
<span class="no"> 5</span> <span class="r">end</span>
|
||||
<span class="no"> 6</span>
|
||||
<span class="no"> 7</span> <span class="r">def</span> <span class="fu">salute</span>
|
||||
<span class="no"> 8</span> puts <span class="s"><span class="dl">"</span><span class="k">Hello </span><span class="il"><span class="idl">#{</span><span class="iv">@name</span><span class="idl">}</span></span><span class="k">!</span><span class="dl">"</span></span>
|
||||
<span class="no"> 9</span> <span class="r">end</span>
|
||||
<span class="no"><strong>10</strong></span> <span class="r">end</span>
|
||||
</code>
|
||||
<pre><code class="ruby syntaxhl"><span class="line-numbers"> 1</span> <span class="comment"># The Greeter class</span>
|
||||
<span class="line-numbers"> 2</span> <span class="reserved">class</span> <span class="class">Greeter</span>
|
||||
<span class="line-numbers"> 3</span> <span class="reserved">def</span> <span class="function">initialize</span>(name)
|
||||
<span class="line-numbers"> 4</span> <span class="instance-variable">@name</span> = name.capitalize
|
||||
<span class="line-numbers"> 5</span> <span class="reserved">end</span>
|
||||
<span class="line-numbers"> 6</span>
|
||||
<span class="line-numbers"> 7</span> <span class="reserved">def</span> <span class="function">salute</span>
|
||||
<span class="line-numbers"> 8</span> puts <span class="string"><span class="delimiter">"</span><span class="content">Hello </span><span class="inline"><span class="inline-delimiter">#{</span><span class="instance-variable">@name</span><span class="inline-delimiter">}</span></span><span class="content">!</span><span class="delimiter">"</span></span>
|
||||
<span class="line-numbers"> 9</span> <span class="reserved">end</span>
|
||||
<span class="line-numbers"><strong>10</strong></span> <span class="reserved">end</span></code>
|
||||
</pre>
|
||||
|
@ -38,7 +38,7 @@
|
||||
<%= call_hook(:view_issues_edit_notes_bottom, { :issue => @issue, :notes => @notes, :form => f }) %>
|
||||
</fieldset>
|
||||
|
||||
<fieldset id="attachments" class="collapsible collapsed borders"><legend onclick="toggleFieldset(this);"><%=l(:label_attachment_plural)%></legend>
|
||||
<fieldset id="attachments" class="header_collapsible collapsible collapsed"><legend onclick="toggleFieldset(this);"><%=l(:label_attachment_plural)%></legend>
|
||||
<div style="display: none;">
|
||||
<%= render :partial => 'attachments/form' %>
|
||||
</div>
|
||||
|
@ -1,10 +1,9 @@
|
||||
<div class="contextual">
|
||||
<% if authorize_for('issue_relations', 'new') %>
|
||||
<%= toggle_link l(:button_add), 'new-relation-form', {:focus => 'relation_issue_to_id'} %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<p><strong><%=l(:label_related_issues)%></strong></p>
|
||||
<p>
|
||||
<strong><%=l(:label_related_issues)%></strong>
|
||||
<% if authorize_for('issue_relations', 'new') %>
|
||||
(<%= toggle_link l(:button_add), 'new-relation-form', {:focus => 'relation_issue_to_id'} %>)
|
||||
<% end %>
|
||||
</p>
|
||||
|
||||
<% if @relations.present? %>
|
||||
<table style="width:100%">
|
||||
|
@ -1,16 +1,6 @@
|
||||
<h3><%= l(:label_issue_plural) %></h3>
|
||||
<%= link_to l(:label_issue_view_all), { :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 } %><br />
|
||||
<% if @project %>
|
||||
<%= link_to l(:field_summary), :controller => 'reports', :action => 'issue_report', :id => @project %><br />
|
||||
<% end %>
|
||||
<%= call_hook(:view_issues_sidebar_issues_bottom) %>
|
||||
|
||||
<% if User.current.allowed_to?(:view_calendar, @project, :global => true) %>
|
||||
<%= link_to(l(:label_calendar), :controller => 'calendars', :action => 'show', :project_id => @project) %><br />
|
||||
<% end %>
|
||||
<% if User.current.allowed_to?(:view_gantt, @project, :global => true) %>
|
||||
<%= link_to(l(:label_gantt), :controller => 'gantts', :action => 'show', :project_id => @project) %><br />
|
||||
<% end %>
|
||||
<%= call_hook(:view_issues_sidebar_planning_bottom) %>
|
||||
|
||||
<%= render_sidebar_queries %>
|
||||
|
@ -1,23 +1,29 @@
|
||||
<div class="title-bar">
|
||||
|
||||
<h2><%= @query.new_record? ? l(:label_issue_plural) : h(@query.name) %></h2>
|
||||
|
||||
<div class="title-bar-extras">
|
||||
|
||||
<div class="contextual">
|
||||
<% if !@query.new_record? && @query.editable_by?(User.current) %>
|
||||
<%= link_to l(:button_edit), {:controller => 'queries', :action => 'edit', :id => @query}, :class => 'icon icon-edit' %>
|
||||
<%= link_to l(:button_delete), {:controller => 'queries', :action => 'destroy', :id => @query}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
|
||||
<% end %>
|
||||
<%= render :partial => 'queries/new_issue_button' %>
|
||||
</div>
|
||||
|
||||
<h2><%= @query.new_record? ? l(:label_issue_plural) : h(@query.name) %></h2>
|
||||
<% html_title(@query.new_record? ? l(:label_issue_plural) : h(@query.name)) %>
|
||||
|
||||
<% form_tag({ :controller => 'queries', :action => 'new' }, :id => 'query_form') do %>
|
||||
<%= hidden_field_tag('project_id', @project.to_param) if @project %>
|
||||
<div id="query_form_content" class="hide-when-print">
|
||||
<fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>">
|
||||
<fieldset id="filters" class="header_collapsible collapsible <%= @query.new_record? ? "" : "collapsed" %>">
|
||||
<legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
|
||||
<div style="<%= @query.new_record? ? "" : "display: none;" %>">
|
||||
<div class="filter-fields" style="<%= @query.new_record? ? "" : "display: none;" %>">
|
||||
<%= render :partial => 'queries/filters', :locals => {:query => @query} %>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="collapsible collapsed">
|
||||
<fieldset id="column_options" class="header_collapsible collapsible collapsed">
|
||||
<legend onclick="toggleFieldset(this);"><%= l(:label_options) %></legend>
|
||||
<div style="display: none;">
|
||||
<table>
|
||||
@ -29,6 +35,20 @@
|
||||
<td><label for='group_by'><%= l(:field_group_by) %></label></td>
|
||||
<td><%= select_tag('group_by', options_for_select([[]] + @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, @query.group_by)) %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><%= l(:label_project_plural) %></td>
|
||||
<td>
|
||||
<label>
|
||||
<%= radio_button_tag('display_subprojects', '0', !@query.display_subprojects?) %>
|
||||
<%= l(:text_current_project) %>
|
||||
</label>
|
||||
<br />
|
||||
<label>
|
||||
<%= radio_button_tag('display_subprojects', '1', @query.display_subprojects?) %>
|
||||
<%= l(:label_and_its_subprojects, :value => l(:text_current_project)) %>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</fieldset>
|
||||
@ -55,6 +75,9 @@
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
</div><!-- .title-bar-extras -->
|
||||
</div><!-- .title-bar -->
|
||||
|
||||
<%= error_messages_for 'query' %>
|
||||
<% if @query.valid? %>
|
||||
<% if @issues.empty? %>
|
||||
|
@ -1,63 +1,75 @@
|
||||
<%= render :partial => 'action_menu' %>
|
||||
|
||||
<h2><%= h(@issue.tracker.name) %> #<%= h(@issue.id) %><%= call_hook(:view_issues_show_identifier, :issue => @issue) %></h2>
|
||||
<div class="title-bar" id="upper-title-bar">
|
||||
<div class="title-bar-actions">
|
||||
<%= render :partial => 'action_menu' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="<%= @issue.css_classes %> details">
|
||||
<%= avatar(@issue.author, :size => "50") %>
|
||||
|
||||
<div class="subject">
|
||||
<%= render_issue_subject_with_tree(@issue) %>
|
||||
</div>
|
||||
<p class="author">
|
||||
<%= authoring @issue.created_on, @issue.author %>.
|
||||
<% if @issue.created_on != @issue.updated_on %>
|
||||
<%= l(:label_updated_time, time_tag(@issue.updated_on)) %>.
|
||||
<h1 class="subject">
|
||||
<%=h(@issue.subject) %> (<%= h(@issue.tracker.name) + ' #' +@issue.id.to_s %>)
|
||||
</h1>
|
||||
<hr />
|
||||
|
||||
<p class="author">
|
||||
<%= avatar(@issue.author, :size => "14") %>
|
||||
<%= authoring @issue.created_on, @issue.author %>.
|
||||
<% if @issue.created_on != @issue.updated_on %>
|
||||
<%= l(:label_updated_time, time_tag(@issue.updated_on)) %>.
|
||||
<% end %>
|
||||
</p>
|
||||
<hr />
|
||||
|
||||
<div class="meta">
|
||||
<table class="attributes">
|
||||
<tr>
|
||||
<th class="status"><%=l(:field_status)%>:</th><td class="status"><%= h(@issue.status.name) %></td>
|
||||
<th class="start-date"><%=l(:field_start_date)%>:</th><td class="start-date"><%= format_date(@issue.start_date) %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="priority"><%=l(:field_priority)%>:</th><td class="priority"><%= h(@issue.priority.name) %></td>
|
||||
<th class="due-date"><%=l(:field_due_date)%>:</th><td class="due-date"><%= format_date(@issue.due_date) %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="assigned-to"><%=l(:field_assigned_to)%>:</th><td class="assigned-to"><%= avatar(@issue.assigned_to, :size => "14") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %></td>
|
||||
<th class="progress"><%=l(:field_done_ratio)%>:</th><td class="progress"><%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="category"><%=l(:field_category)%>:</th><td class="category"><%=h(@issue.category ? @issue.category.name : "-") %></td>
|
||||
<% if User.current.allowed_to?(:view_time_entries, @project) %>
|
||||
<th class="spent-time"><%=l(:label_spent_time)%>:</th>
|
||||
<td class="spent-time"><%= @issue.spent_hours > 0 ? (link_to l_hours(@issue.spent_hours), {:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}) : "-" %></td>
|
||||
<% end %>
|
||||
</p>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fixed-version"><%=l(:field_fixed_version)%>:</th><td class="fixed-version"><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td>
|
||||
<% if @issue.estimated_hours %>
|
||||
<th class="estimated-hours"><%=l(:field_estimated_hours)%>:</th><td class="estimated-hours"><%= l_hours(@issue.estimated_hours) %></td>
|
||||
<% end %>
|
||||
</tr>
|
||||
<%= render_custom_fields_rows(@issue) %>
|
||||
<%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %>
|
||||
</table>
|
||||
</div><!-- .meta -->
|
||||
|
||||
<table class="attributes">
|
||||
<tr>
|
||||
<th class="status"><%=l(:field_status)%>:</th><td class="status"><%= h(@issue.status.name) %></td>
|
||||
<th class="start-date"><%=l(:field_start_date)%>:</th><td class="start-date"><%= format_date(@issue.start_date) %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="priority"><%=l(:field_priority)%>:</th><td class="priority"><%= h(@issue.priority.name) %></td>
|
||||
<th class="due-date"><%=l(:field_due_date)%>:</th><td class="due-date"><%= format_date(@issue.due_date) %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="assigned-to"><%=l(:field_assigned_to)%>:</th><td class="assigned-to"><%= avatar(@issue.assigned_to, :size => "14") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %></td>
|
||||
<th class="progress"><%=l(:field_done_ratio)%>:</th><td class="progress"><%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="category"><%=l(:field_category)%>:</th><td class="category"><%=h(@issue.category ? @issue.category.name : "-") %></td>
|
||||
<% if User.current.allowed_to?(:view_time_entries, @project) %>
|
||||
<th class="spent-time"><%=l(:label_spent_time)%>:</th>
|
||||
<td class="spent-time"><%= @issue.spent_hours > 0 ? (link_to l_hours(@issue.spent_hours), {:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}) : "-" %></td>
|
||||
<% end %>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fixed-version"><%=l(:field_fixed_version)%>:</th><td class="fixed-version"><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td>
|
||||
<% if @issue.estimated_hours %>
|
||||
<th class="estimated-hours"><%=l(:field_estimated_hours)%>:</th><td class="estimated-hours"><%= l_hours(@issue.estimated_hours) %></td>
|
||||
<% end %>
|
||||
</tr>
|
||||
<%= render_custom_fields_rows(@issue) %>
|
||||
<%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %>
|
||||
</table>
|
||||
|
||||
<% if @issue.description? || @issue.attachments.any? -%>
|
||||
<hr />
|
||||
<% if @issue.description? %>
|
||||
<div class="contextual">
|
||||
<%= link_to_remote_if_authorized(l(:button_quote), { :url => {:controller => 'journals', :action => 'new', :id => @issue} }, :class => 'icon icon-comment') %>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<p><strong><%=l(:field_description)%></strong></p>
|
||||
<div class="wiki">
|
||||
<%= textilizable @issue, :description, :attachments => @issue.attachments %>
|
||||
</div>
|
||||
<div class="description">
|
||||
<div class="contextual">
|
||||
<%= link_to_remote_if_authorized(l(:button_quote), { :url => {:controller => 'journals', :action => 'new', :id => @issue} }, :class => 'icon icon-comment') %>
|
||||
</div>
|
||||
|
||||
<p><strong><%=l(:field_description)%></strong></p>
|
||||
<div class="wiki">
|
||||
<%= textilizable @issue, :description, :attachments => @issue.attachments %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= link_to_attachments @issue %>
|
||||
|
||||
<% if @issue.attachments.any? -%>
|
||||
<hr />
|
||||
<%= link_to_attachments @issue %>
|
||||
<% end -%>
|
||||
|
||||
<%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %>
|
||||
@ -65,10 +77,11 @@
|
||||
<% if !@issue.leaf? || User.current.allowed_to?(:manage_subtasks, @project) %>
|
||||
<hr />
|
||||
<div id="issue_tree">
|
||||
<div class="contextual">
|
||||
<%= link_to(l(:button_add), {:controller => 'issues', :action => 'new', :project_id => @project, :issue => {:parent_issue_id => @issue}}) if User.current.allowed_to?(:manage_subtasks, @project) %>
|
||||
</div>
|
||||
<p><strong><%=l(:label_subtask_plural)%></strong></p>
|
||||
<p>
|
||||
<strong><%=l(:label_subtask_plural)%></strong>
|
||||
(<%= link_to(l(:button_add), {:controller => 'issues', :action => 'new', :project_id => @project, :issue => {:parent_issue_id => @issue}}) if User.current.allowed_to?(:manage_subtasks, @project) %>)
|
||||
</p>
|
||||
|
||||
<%= render_descendants_tree(@issue) unless @issue.leaf? %>
|
||||
</div>
|
||||
<% end %>
|
||||
@ -78,6 +91,7 @@
|
||||
<div id="relations">
|
||||
<%= render :partial => 'relations' %>
|
||||
</div>
|
||||
<hr />
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
@ -91,14 +105,19 @@
|
||||
|
||||
<% if @journals.present? %>
|
||||
<div id="history">
|
||||
<h3><%=l(:label_history)%></h3>
|
||||
<h3 class="rounded-background"><%=l(:label_history)%></h3>
|
||||
<%= render :partial => 'history', :locals => { :issue => @issue, :journals => @journals } %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
||||
<div style="clear: both;"></div>
|
||||
<%= render :partial => 'action_menu' %>
|
||||
|
||||
<div class="title-bar" id="lower-title-bar">
|
||||
<div class="title-bar-actions">
|
||||
<%= render :partial => 'action_menu', :locals => {:replace_watcher => 'watcher2' } %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="clear: both;"></div>
|
||||
<% if authorize_for('issues', 'edit') %>
|
||||
|
9
app/views/journals/diff.html.erb
Normal file
9
app/views/journals/diff.html.erb
Normal file
@ -0,0 +1,9 @@
|
||||
<p><%= authoring @journal.created_at, @journal.user, :label => :label_updated_time_by %></p>
|
||||
|
||||
<div class="text-diff">
|
||||
<%= simple_format_without_paragraph @diff.to_html %>
|
||||
</div>
|
||||
|
||||
<p><%= link_to(l(:button_back), issue_path(@issue)) %></p>
|
||||
|
||||
<% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %>
|
@ -1,8 +1,6 @@
|
||||
<% unless controller_name == 'admin' && action_name == 'index' %>
|
||||
<% content_for :sidebar do %>
|
||||
<h3><%=l(:label_administration)%></h3>
|
||||
<%= render :partial => 'admin/menu' %>
|
||||
<% end %>
|
||||
<% @page_header_title = l(:label_administration) %>
|
||||
<% content_for :main_menu do %>
|
||||
<%= render :partial => 'admin/menu' %>
|
||||
<% end %>
|
||||
|
||||
<%= render :file => "layouts/base" %>
|
||||
|
@ -7,76 +7,149 @@
|
||||
<meta name="keywords" content="issue,bug,tracker" />
|
||||
<%= csrf_meta_tag %>
|
||||
<%= favicon %>
|
||||
<%= stylesheet_link_tag 'reset', :media => 'all' %>
|
||||
<%= stylesheet_link_tag 'smoothness/jquery-ui', :media => 'all' %>
|
||||
<%= stylesheet_link_tag 'application', :media => 'all' %>
|
||||
<%= stylesheet_link_tag 'print', :media => 'print' %>
|
||||
<%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %>
|
||||
<!--[if lte IE 6]><%= stylesheet_link_tag 'ie6', :media => 'all' %><![endif]-->
|
||||
<!--[if lte IE 7]><%= stylesheet_link_tag 'ie7', :media => 'all' %><![endif]-->
|
||||
<!--[if gte IE 8]><![endif]-->
|
||||
|
||||
<%= javascript_include_tag 'jquery.min.js' %>
|
||||
<%= javascript_include_tag 'jquery-ui.min.js' %>
|
||||
<%= javascript_include_tag 'jquery.menu_expand.js' %>
|
||||
<%= javascript_tag('jQuery.noConflict();') %>
|
||||
<%= javascript_heads %>
|
||||
<%= stylesheet_link_tag 'jstoolbar' %>
|
||||
<%= heads_for_theme %>
|
||||
<!--[if IE 6]>
|
||||
<style type="text/css">
|
||||
* html body{ width: expression( document.documentElement.clientWidth < 900 ? '900px' : '100%' ); }
|
||||
body {behavior: url(<%= stylesheet_path "csshover.htc" %>);}
|
||||
</style>
|
||||
<![endif]-->
|
||||
<% heads_for_wiki_formatter %>
|
||||
<%= call_hook :view_layouts_base_html_head %>
|
||||
<!-- page specific tags -->
|
||||
<%= yield :header_tags -%>
|
||||
</head>
|
||||
<body class="<%=h body_css_classes %>">
|
||||
<div id="wrapper">
|
||||
<div id="wrapper2">
|
||||
<div id="top-menu">
|
||||
<div id="account">
|
||||
<%= render_menu :account_menu -%>
|
||||
</div>
|
||||
<%= content_tag('div', "#{l(:label_logged_as)} #{link_to_user(User.current, :format => :username)}", :id => 'loggedas') if User.current.logged? %>
|
||||
<%= render_menu :top_menu if User.current.logged? || !Setting.login_required? -%>
|
||||
</div>
|
||||
<div id="top-menu">
|
||||
<div id="header">
|
||||
<div id="logo"><%= link_to(h(Setting.app_title), home_path) %></div>
|
||||
<div id="top-menu-items">
|
||||
<div id="search">
|
||||
<%= render :partial => 'search/quick_search', :locals => {:search_term => @question} %>
|
||||
</div>
|
||||
|
||||
<div id="header">
|
||||
<% if User.current.logged? || !Setting.login_required? %>
|
||||
<div id="quick-search">
|
||||
<% form_tag({:controller => 'search', :action => 'index', :id => @project}, :method => :get ) do %>
|
||||
<%= 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) %>:
|
||||
</label>
|
||||
<%= text_field_tag 'q', @question, :size => 20, :class => 'small', :accesskey => accesskey(:quick_search) %>
|
||||
<% if User.current.logged? || !Setting.login_required? %>
|
||||
<ul id="account-nav">
|
||||
<% main_top_menu_items.each do |item| %>
|
||||
<%= render_menu_node(item) %>
|
||||
<% end %>
|
||||
<%= render_project_jump_box %>
|
||||
<li class="drop-down">
|
||||
<%= link_to l(:label_project_plural), { :controller => 'projects', :action => 'index' }, :class => "projects" %>
|
||||
<ul style="display:none;">
|
||||
<li><%= link_to l(:label_project_all), { :controller => 'projects', :action => 'index' }, :class => "projects separator" %></li>
|
||||
<%
|
||||
project_content = ''
|
||||
project_tree(User.current.projects.all) do |project, level|
|
||||
name_prefix = (level > 0 ? (' ' * 2 * level + '» ') : '')
|
||||
project_content << content_tag(:li,
|
||||
link_to(name_prefix + h(project), {:controller => 'projects', :action => 'show', :id => project, :jump => current_menu_item}))
|
||||
end
|
||||
%>
|
||||
<%= project_content %>
|
||||
</ul>
|
||||
</li>
|
||||
<% if more_top_menu_items.present? || User.current.admin? %>
|
||||
<li class="drop-down" id="more-menu">
|
||||
<a class="more" href="#"><%= l(:label_more) %></a>
|
||||
<ul style="display:none;">
|
||||
<% more_top_menu_items.each do |item| %>
|
||||
<%= render_menu_node(item) %>
|
||||
<% end %>
|
||||
<%# TODO: Extract to helper %>
|
||||
<% if User.current.admin? %>
|
||||
<% menu_items_for(:admin_menu) do |item| -%>
|
||||
<li><%= link_to h(item.caption), item.url, item.html_options %></li>
|
||||
<% end -%>
|
||||
<% end %>
|
||||
</ul>
|
||||
</li>
|
||||
<% end %>
|
||||
<li>
|
||||
<%= render_menu_node(help_menu_item) %>
|
||||
<% unless User.current.logged? %>
|
||||
<% if Setting.self_registration? %>
|
||||
<li>
|
||||
<%= link_to l(:label_register), { :controller => 'account', :action => 'register' } %>
|
||||
</li>
|
||||
<% end %>
|
||||
<li id="login-menu" class="drop-down last-child">
|
||||
<%= link_to l(:label_login), {:controller => 'account', :action => 'login'}, :class => 'login' %>
|
||||
<div id="nav-login" style="display:none;">
|
||||
<%= render :partial => 'account/login' %>
|
||||
</div>
|
||||
</li>
|
||||
<% else %>
|
||||
<li class="drop-down last-child">
|
||||
<%= link_to_user(User.current) %>
|
||||
<ul style="display:none;">
|
||||
<% menu_items_for(:account_menu) do |item| %>
|
||||
<%= render_menu_node(item) %>
|
||||
<% end %>
|
||||
</ul>
|
||||
</li>
|
||||
<% end %>
|
||||
</li>
|
||||
</ul>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<div id="breadcrumb">
|
||||
<%= page_header_title %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% main_menu = render_main_menu(@project) %>
|
||||
<% if (side_displayed = has_content?(:sidebar) || has_content?(:main_menu) || !main_menu.blank?) %>
|
||||
<% display_sidebar = true %>
|
||||
<% else %>
|
||||
<% display_sidebar = false %>
|
||||
<% end %>
|
||||
<div id="main" class="<%= side_displayed ? '' : "nosidebar" %>">
|
||||
<% if (side_displayed) %>
|
||||
<div id="side-container">
|
||||
<div id="main-menu">
|
||||
<%= main_menu %>
|
||||
<%= yield :main_menu %>
|
||||
</div>
|
||||
|
||||
<% if display_sidebar %>
|
||||
<!-- Sidebar -->
|
||||
<div id="sidebar">
|
||||
<%= yield :sidebar %>
|
||||
<%= call_hook :view_layouts_base_sidebar %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<%= expand_current_menu %>
|
||||
<% end %>
|
||||
|
||||
<h1><%= page_header_title %></h1>
|
||||
|
||||
<% if display_main_menu?(@project) %>
|
||||
<div id="main-menu">
|
||||
<%= render_main_menu(@project) %>
|
||||
<div class="<%= side_displayed ? '' : "nosidebar" %>" id="content">
|
||||
<%= render_flash_messages %>
|
||||
<%= yield %>
|
||||
<%= call_hook :view_layouts_base_content %>
|
||||
<div style="clear:both;"> </div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= tag('div', {:id => 'main', :class => (has_content?(:sidebar) ? '' : 'nosidebar')}, true) %>
|
||||
<div id="sidebar">
|
||||
<%= yield :sidebar %>
|
||||
<%= call_hook :view_layouts_base_sidebar %>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div class="bgl"><div class="bgr">
|
||||
<%= l(:text_powered_by, :link => link_to(Redmine::Info.app_name, Redmine::Info.url)) %>
|
||||
</div></div>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<%= render_flash_messages %>
|
||||
<%= yield %>
|
||||
<%= call_hook :view_layouts_base_content %>
|
||||
<div style="clear:both;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ajax-indicator" style="display:none;"><span><%= l(:label_loading) %></span></div>
|
||||
<div id="dialog-window" style="display:none;"></div>
|
||||
|
||||
<div id="ajax-indicator" style="display:none;"><span><%= l(:label_loading) %></span></div>
|
||||
|
||||
<div id="footer">
|
||||
<div class="bgl"><div class="bgr">
|
||||
<%= l(:text_powered_by, :link => link_to(Redmine::Info.app_name, Redmine::Info.url)) %>
|
||||
</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%= call_hook :view_layouts_base_body_bottom %>
|
||||
</body>
|
||||
|
@ -0,0 +1,2 @@
|
||||
<p><%= l(:text_mail_handler_confirmation_successful) %><br />
|
||||
<%= auto_link(@url) %></p>
|
@ -0,0 +1,2 @@
|
||||
<%= l(:text_mail_handler_confirmation_successful) %>
|
||||
<%= @url %>
|
@ -0,0 +1,3 @@
|
||||
<p><%= l(:label_mail_handler_errors_with_submission) %></p>
|
||||
|
||||
<p><%= h(@errors) %></p>
|
@ -0,0 +1,3 @@
|
||||
<%= l(:label_mail_handler_errors_with_submission) %>
|
||||
|
||||
<%= h(@errors) %>
|
@ -0,0 +1 @@
|
||||
<%= l(:notice_not_authorized_action) %>
|
@ -0,0 +1 @@
|
||||
<%= l(:notice_not_authorized_action) %>
|
23
app/views/members/_membership_assignment.html.erb
Normal file
23
app/views/members/_membership_assignment.html.erb
Normal file
@ -0,0 +1,23 @@
|
||||
<% if projects.any? %>
|
||||
<fieldset><legend><%=l(:label_project_new)%></legend>
|
||||
<% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => principal }) do %>
|
||||
<p><%= text_field_tag 'project_search', nil, :size => "40" %></p>
|
||||
<%= observe_field(:project_search,
|
||||
:frequency => 0.5,
|
||||
:update => :projects,
|
||||
:url => { :controller => 'auto_completes', :action => 'projects', :id => principal },
|
||||
:with => 'q')
|
||||
%>
|
||||
|
||||
<div id="projects">
|
||||
<%= principals_check_box_tags 'project_ids[]', projects %>
|
||||
</div>
|
||||
|
||||
<p><%= l(:label_role_plural) %>:
|
||||
<% roles.each do |role| %>
|
||||
<label><%= check_box_tag 'membership[role_ids][]', role.id %> <%=h role %></label>
|
||||
<% end %></p>
|
||||
<p><%= submit_tag l(:button_add) %></p>
|
||||
<% end %>
|
||||
</fieldset>
|
||||
<% end %>
|
@ -63,4 +63,14 @@
|
||||
<%= stylesheet_link_tag 'scm' %>
|
||||
<% end %>
|
||||
|
||||
<% content_for :sidebar do %>
|
||||
<% if User.current.allowed_to?(:add_message_watchers, @project) ||
|
||||
(@topic.watchers.present? && User.current.allowed_to?(:view_message_watchers, @project)) %>
|
||||
<div id="watchers">
|
||||
<%= render :partial => 'watchers/watchers', :locals => {:watched => @topic} %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% end %>
|
||||
|
||||
<% html_title h(@topic.subject) %>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<%= auto_discovery_link_tag(:atom, {:action => 'index', :format => 'atom', :key => User.current.rss_key}) %>
|
||||
<% end %>
|
||||
|
||||
<div class="contextual">
|
||||
<div id="project-links" class="contextual">
|
||||
<%= link_to(l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add') + ' |' if User.current.allowed_to?(:add_project, nil, :global => true) %>
|
||||
<%= link_to(l(:label_issue_view_all), { :controller => 'issues' }) + ' |' if User.current.allowed_to?(:view_issues, nil, :global => true) %>
|
||||
<%= link_to(l(:label_overall_spent_time), { :controller => 'time_entries' }) + ' |' if User.current.allowed_to?(:view_time_entries, nil, :global => true) %>
|
||||
@ -13,6 +13,10 @@
|
||||
|
||||
<h2><%=l(:label_project_plural)%></h2>
|
||||
|
||||
<div class="wiki">
|
||||
<%= textilizable Setting.welcome_text %>
|
||||
</div>
|
||||
|
||||
<%= call_hook(:view_projects_show_top) %>
|
||||
|
||||
<%= render_project_hierarchy(@projects)%>
|
||||
|
@ -13,7 +13,7 @@
|
||||
<td><%=h(category.assigned_to.name) if category.assigned_to %></td>
|
||||
<td class="buttons">
|
||||
<%= link_to_if_authorized l(:button_edit), { :controller => 'issue_categories', :action => 'edit', :id => category }, :class => 'icon icon-edit' %>
|
||||
<%= link_to_if_authorized l(:button_delete), {:controller => 'issue_categories', :action => 'destroy', :id => category}, :method => :post, :class => 'icon icon-del' %>
|
||||
<%= link_to_if_authorized l(:button_delete), {:controller => 'issue_categories', :action => 'destroy', :id => category}, :method => :post, :class => 'icon icon-del', :confirm => l(:text_are_you_sure) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
@ -22,16 +22,33 @@ function toggle_filter(field) {
|
||||
if (check_box.checked) {
|
||||
Element.show("operators_" + field);
|
||||
Form.Element.enable("operators_" + field);
|
||||
Form.Element.enable("values_" + field);
|
||||
toggle_operator(field);
|
||||
} else {
|
||||
Element.hide("operators_" + field);
|
||||
Element.hide("div_values_" + field);
|
||||
Form.Element.disable("operators_" + field);
|
||||
Form.Element.disable("values_" + field);
|
||||
enableValues(field, []);
|
||||
}
|
||||
}
|
||||
|
||||
function enableValues(field, indexes) {
|
||||
var f = $$(".values_" + field);
|
||||
for(var i=0;i<f.length;i++) {
|
||||
if (indexes.include(i)) {
|
||||
Form.Element.enable(f[i]);
|
||||
f[i].up('span').show();
|
||||
} else {
|
||||
f[i].value = '';
|
||||
Form.Element.disable(f[i]);
|
||||
f[i].up('span').hide();
|
||||
}
|
||||
}
|
||||
if (indexes.length > 0) {
|
||||
Element.show("div_values_" + field);
|
||||
} else {
|
||||
Element.hide("div_values_" + field);
|
||||
}
|
||||
}
|
||||
|
||||
function toggle_operator(field) {
|
||||
operator = $("operators_" + field);
|
||||
switch (operator.value) {
|
||||
@ -41,21 +58,32 @@ function toggle_operator(field) {
|
||||
case "w":
|
||||
case "o":
|
||||
case "c":
|
||||
Element.hide("div_values_" + field);
|
||||
enableValues(field, []);
|
||||
break;
|
||||
case "><":
|
||||
enableValues(field, [0,1]);
|
||||
break;
|
||||
case "<t+":
|
||||
case ">t+":
|
||||
case "t+":
|
||||
case ">t-":
|
||||
case "<t-":
|
||||
case "t-":
|
||||
enableValues(field, [2]);
|
||||
break;
|
||||
default:
|
||||
Element.show("div_values_" + field);
|
||||
enableValues(field, [0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function toggle_multi_select(field) {
|
||||
select = $('values_' + field);
|
||||
if (select.multiple == true) {
|
||||
select.multiple = false;
|
||||
} else {
|
||||
select.multiple = true;
|
||||
}
|
||||
function toggle_multi_select(el) {
|
||||
var select = $(el);
|
||||
if (select.multiple == true) {
|
||||
select.multiple = false;
|
||||
} else {
|
||||
select.multiple = true;
|
||||
}
|
||||
}
|
||||
|
||||
function apply_filters_observer() {
|
||||
@ -92,16 +120,19 @@ Event.observe(document,"dom:loaded", apply_filters_observer);
|
||||
<div id="div_values_<%= field %>" style="display:none;">
|
||||
<% case options[:type]
|
||||
when :list, :list_optional, :list_status, :list_subprojects %>
|
||||
<select <%= "multiple=true" if query.values_for(field) and query.values_for(field).length > 1 %> name="v[<%= field %>][]" id="values_<%= field %>" class="select-small" style="vertical-align: top;">
|
||||
<%= options_for_select options[:values], query.values_for(field) %>
|
||||
</select>
|
||||
<%= link_to_function image_tag('bullet_toggle_plus.png'), "toggle_multi_select('#{field}');", :style => "vertical-align: bottom;" %>
|
||||
<span class="span_values_<%= field %>">
|
||||
<%= select_tag "v[#{field}][]", options_for_select(options[:values], query.values_for(field)), :class => "values_#{field}", :id => "values_#{field}_1", :multiple => (query.values_for(field) && query.values_for(field).length > 1) %>
|
||||
<%= link_to_function image_tag('bullet_toggle_plus.png'), "toggle_multi_select('values_#{field}_1');", :style => "vertical-align: bottom;" %>
|
||||
</span>
|
||||
<% when :date, :date_past %>
|
||||
<%= text_field_tag "v[#{field}][]", query.values_for(field).try(:first), :id => "values_#{field}", :size => 3, :class => "select-small" %> <%= l(:label_day_plural) %>
|
||||
<span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field), :size => 10, :class => "values_#{field}", :id => "values_#{field}_1" %> <%= calendar_for "values_#{field}_1" %></span>
|
||||
<span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field, 1), :size => 10, :class => "values_#{field}", :id => "values_#{field}_2" %> <%= calendar_for "values_#{field}_2" %></span>
|
||||
<span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field), :size => 3, :class => "values_#{field}" %> <%= l(:label_day_plural) %></span>
|
||||
<% when :string, :text %>
|
||||
<%= text_field_tag "v[#{field}][]", query.values_for(field).try(:first), :id => "values_#{field}", :size => 30, :class => "select-small" %>
|
||||
<span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field), :class => "values_#{field}", :id => "values_#{field}", :size => 30 %></span>
|
||||
<% when :integer %>
|
||||
<%= text_field_tag "v[#{field}][]", query.values_for(field).try(:first), :id => "values_#{field}", :size => 3, :class => "select-small" %>
|
||||
<span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field), :class => "values_#{field}", :id => "values_#{field}_1", :size => 3 %></span>
|
||||
<span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field, 1), :class => "values_#{field}", :id => "values_#{field}_2", :size => 3 %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<script type="text/javascript">toggle_filter('<%= field %>');</script>
|
||||
|
@ -16,6 +16,18 @@
|
||||
<%= check_box_tag 'query_is_for_all', 1, @query.project.nil?,
|
||||
:disabled => (!@query.new_record? && (@query.project.nil? || (@query.is_public? && !User.current.admin?))) %></p>
|
||||
|
||||
<p><label><%= l(:label_project_plural) %></label>
|
||||
<label style="text-align: left; float: none; margin-left: 0px;font-weight: normal">
|
||||
<%= radio_button_tag('display_subprojects', '0', !@query.display_subprojects?) %>
|
||||
<%= l(:text_current_project) %>
|
||||
</label>
|
||||
<br />
|
||||
<label style="text-align: left; float: none; margin-left: 0px;font-weight: normal">
|
||||
<%= radio_button_tag('display_subprojects', '1', @query.display_subprojects?) %>
|
||||
<%= l(:label_and_its_subprojects, :value => l(:text_current_project)) %>
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p><label for="query_default_columns"><%=l(:label_default_columns)%></label>
|
||||
<%= check_box_tag 'default_columns', 1, @query.has_default_columns?, :id => 'query_default_columns',
|
||||
:onclick => 'if (this.checked) {Element.hide("columns")} else {Element.show("columns")}' %></p>
|
||||
|
5
app/views/queries/_new_issue_button.html.erb
Normal file
5
app/views/queries/_new_issue_button.html.erb
Normal file
@ -0,0 +1,5 @@
|
||||
<% if @project %>
|
||||
<div class="new-issue button-large">
|
||||
<%= link_to_if_authorized(l(:label_issue_new), {:controller => 'issues', :action => 'new', :project_id => @project}, :title => l(:label_issue_new), :class => '') %>
|
||||
</div>
|
||||
<% end %>
|
5
app/views/search/_quick_search.html.erb
Normal file
5
app/views/search/_quick_search.html.erb
Normal file
@ -0,0 +1,5 @@
|
||||
<%= label_tag("q", l(:label_search), :class => "hidden-for-sighted") %>
|
||||
<% form_tag({:controller => 'search', :action => 'index', :id => @project}, :method => :get) do %>
|
||||
<%= hidden_field_tag(controller.default_search_scope, 1, :id => nil) if controller.default_search_scope %>
|
||||
<%= text_field_tag 'q', search_term, :size => 20, :class => 'search_field', :placeholder => l(:search_input_placeholder), :accesskey => accesskey(:quick_search) %>
|
||||
<% end %>
|
@ -5,6 +5,9 @@
|
||||
<%= setting_text_area :mail_handler_body_delimiters, :rows => 5 %>
|
||||
<br /><em><%= l(:text_line_separated) %></em>
|
||||
</p>
|
||||
|
||||
<p><%= setting_check_box :mail_handler_confirmation_on_success %></p>
|
||||
<p><%= setting_check_box :mail_handler_confirmation_on_failure %></p>
|
||||
</div>
|
||||
|
||||
<div class="box tabular settings">
|
||||
|
@ -4,8 +4,9 @@
|
||||
:onchange => 'if (this.value == "selected") {Element.show("notified-projects")} else {Element.hide("notified-projects")}' %>
|
||||
</p>
|
||||
<% content_tag 'div', :id => 'notified-projects', :style => (@user.mail_notification == 'selected' ? '' : 'display:none;') do %>
|
||||
<p><% @user.projects.each do |project| %>
|
||||
<label><%= check_box_tag 'notified_project_ids[]', project.id, @user.notified_projects_ids.include?(project.id) %> <%=h project.name %></label><br />
|
||||
<p><% project_tree(@user.projects.each) do |project,level| %>
|
||||
<% name_prefix = (level > 0 ? (' ' * 2 * level + '» ') : '') %>
|
||||
<label><%= check_box_tag 'notified_project_ids[]', project.id, @user.notified_projects_ids.include?(project.id) %> <%= name_prefix + h(project.name) %></label><br />
|
||||
<% end %></p>
|
||||
<p><em><%= l(:text_user_mail_option) %></em></p>
|
||||
<% end %>
|
||||
|
@ -47,16 +47,5 @@
|
||||
</div>
|
||||
|
||||
<div class="splitcontentright">
|
||||
<% if projects.any? %>
|
||||
<fieldset><legend><%=l(:label_project_new)%></legend>
|
||||
<% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => @user }) do %>
|
||||
<%= select_tag 'membership[project_id]', options_for_membership_project_select(@user, projects) %>
|
||||
<p><%= l(:label_role_plural) %>:
|
||||
<% roles.each do |role| %>
|
||||
<label><%= check_box_tag 'membership[role_ids][]', role.id %> <%=h role %></label>
|
||||
<% end %></p>
|
||||
<p><%= submit_tag l(:button_add) %></p>
|
||||
<% end %>
|
||||
</fieldset>
|
||||
<% end %>
|
||||
<%= render :partial => 'members/membership_assignment', :locals => {:principal => @user, :projects => projects - @user.projects, :roles => roles } %>
|
||||
</div>
|
||||
|
@ -47,6 +47,7 @@
|
||||
<% @versions.each do |version| %>
|
||||
<%= link_to format_version_name(version), "##{version.name}" %><br />
|
||||
<% end %>
|
||||
|
||||
<% end %>
|
||||
|
||||
<% html_title(l(:label_roadmap)) %>
|
||||
|
@ -1,24 +1,31 @@
|
||||
<div class="contextual">
|
||||
<%= link_to_remote l(:button_add),
|
||||
:url => {:controller => 'watchers',
|
||||
:action => 'new',
|
||||
:object_type => watched.class.name.underscore,
|
||||
:object_id => watched} if User.current.allowed_to?(:add_issue_watchers, @project) %>
|
||||
<%= link_to_function(l(:button_add), "$('new-watcher-form').toggle();") if User.current.allowed_to?("add_#{watched.class.name.underscore}_watchers".to_sym, @project) %>
|
||||
</div>
|
||||
|
||||
<h3><%= l(:label_issue_watchers) %> (<%= watched.watcher_users.size %>)</h3>
|
||||
|
||||
<% unless @watcher.nil? %>
|
||||
<% if User.current.allowed_to?("add_#{watched.class.name.underscore}_watchers".to_sym, @project) %>
|
||||
<% remote_form_for(:watcher, @watcher,
|
||||
:url => {:controller => 'watchers',
|
||||
:action => 'new',
|
||||
:object_type => watched.class.name.underscore,
|
||||
:object_id => watched},
|
||||
:method => :post,
|
||||
:html => {:id => 'new-watcher-form'}) do |f| %>
|
||||
<p><%= f.select :user_id, (watched.addable_watcher_users.collect {|m| [m.name, m.id]}), :prompt => "--- #{l(:actionview_instancetag_blank_option)} ---" %>
|
||||
:html => {:id => 'new-watcher-form', :style => 'display:none;'}) do |f| %>
|
||||
<% users = Principal.active.find(:all, :limit => 25) - watched.watcher_users %>
|
||||
<p><%= label_tag "user_search", l(:label_user_search) %><%= text_field_tag 'user_search', nil, :style => "width:98%;" %></p>
|
||||
<%= observe_field(:user_search,
|
||||
:frequency => 0.5,
|
||||
:update => :users,
|
||||
:url => auto_complete_users_path(:remove_watchers => watched.id, :klass => watched.class, :include_groups => true),
|
||||
:with => 'q')
|
||||
%>
|
||||
|
||||
<%= submit_tag l(:button_add) %>
|
||||
<div id="users">
|
||||
<%= principals_check_box_tags 'user_ids[]', users %>
|
||||
</div>
|
||||
|
||||
<p><%= submit_tag l(:button_add) %>
|
||||
<%= toggle_link l(:button_cancel), 'new-watcher-form'%></p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
@ -59,6 +59,14 @@
|
||||
|
||||
<% content_for :sidebar do %>
|
||||
<%= render :partial => 'wiki/sidebar' %>
|
||||
|
||||
<% if User.current.allowed_to?(:add_wiki_page_watchers, @project) ||
|
||||
(@page.watchers.present? && User.current.allowed_to?(:view_wiki_page_watchers, @project)) %>
|
||||
<div id="watchers">
|
||||
<%= render :partial => 'watchers/watchers', :locals => {:watched => @page} %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% end %>
|
||||
|
||||
<% html_title h(@page.pretty_title) %>
|
||||
|
@ -52,6 +52,9 @@ Rails::Initializer.run do |config|
|
||||
# (by default production uses :info, the others :debug)
|
||||
# config.log_level = :debug
|
||||
|
||||
# Liquid drops
|
||||
config.autoload_paths += %W( #{RAILS_ROOT}/app/drops )
|
||||
|
||||
# Enable page/fragment caching by setting a file-based store
|
||||
# (remember to create the caching directory and make it readable to the application)
|
||||
# config.action_controller.cache_store = :file_store, "#{RAILS_ROOT}/tmp/cache"
|
||||
|
@ -984,3 +984,16 @@ bg:
|
||||
description_date_from: Въведете начална дата
|
||||
label_deleted_custom_field: (изтрито потребителско поле)
|
||||
field_custom_filter: Custom LDAP filter
|
||||
text_display_subprojects: Display subprojects
|
||||
text_current_project: Current project
|
||||
label_toc: Contents
|
||||
search_input_placeholder: search ...
|
||||
setting_mail_handler_confirmation_on_success: Send confirmation email on successful incoming email
|
||||
label_mail_handler_confirmation: "Confirmation of email submission: %{subject}"
|
||||
label_mail_handler_errors_with_submission: "There were errors with your email submission:"
|
||||
label_document_watchers: Watchers
|
||||
setting_mail_handler_confirmation_on_failure: Send confirmation email on failed incoming email
|
||||
label_between: between
|
||||
label_mail_handler_failure: "Failed email submission: %{subject}"
|
||||
notice_not_authorized_action: You are not authorized to perform this action.
|
||||
text_mail_handler_confirmation_successful: Your email has been successful added at the following url
|
||||
|
@ -998,3 +998,16 @@ bs:
|
||||
description_date_from: Enter start date
|
||||
label_deleted_custom_field: (deleted custom field)
|
||||
field_custom_filter: Custom LDAP filter
|
||||
text_display_subprojects: Display subprojects
|
||||
text_current_project: Current project
|
||||
label_toc: Contents
|
||||
search_input_placeholder: search ...
|
||||
setting_mail_handler_confirmation_on_success: Send confirmation email on successful incoming email
|
||||
label_mail_handler_confirmation: "Confirmation of email submission: %{subject}"
|
||||
label_mail_handler_errors_with_submission: "There were errors with your email submission:"
|
||||
label_document_watchers: Watchers
|
||||
setting_mail_handler_confirmation_on_failure: Send confirmation email on failed incoming email
|
||||
label_between: between
|
||||
label_mail_handler_failure: "Failed email submission: %{subject}"
|
||||
notice_not_authorized_action: You are not authorized to perform this action.
|
||||
text_mail_handler_confirmation_successful: Your email has been successful added at the following url
|
||||
|
@ -987,3 +987,16 @@ ca:
|
||||
description_date_from: Enter start date
|
||||
label_deleted_custom_field: (deleted custom field)
|
||||
field_custom_filter: Custom LDAP filter
|
||||
text_display_subprojects: Display subprojects
|
||||
text_current_project: Current project
|
||||
label_toc: Contents
|
||||
search_input_placeholder: search ...
|
||||
setting_mail_handler_confirmation_on_success: Send confirmation email on successful incoming email
|
||||
label_mail_handler_confirmation: "Confirmation of email submission: %{subject}"
|
||||
label_mail_handler_errors_with_submission: "There were errors with your email submission:"
|
||||
label_document_watchers: Watchers
|
||||
setting_mail_handler_confirmation_on_failure: Send confirmation email on failed incoming email
|
||||
label_between: between
|
||||
label_mail_handler_failure: "Failed email submission: %{subject}"
|
||||
notice_not_authorized_action: You are not authorized to perform this action.
|
||||
text_mail_handler_confirmation_successful: Your email has been successful added at the following url
|
||||
|
@ -1208,3 +1208,16 @@ cs:
|
||||
description_date_from: Enter start date
|
||||
label_deleted_custom_field: (deleted custom field)
|
||||
field_custom_filter: Custom LDAP filter
|
||||
text_display_subprojects: Display subprojects
|
||||
text_current_project: Current project
|
||||
label_toc: Contents
|
||||
search_input_placeholder: search ...
|
||||
setting_mail_handler_confirmation_on_success: Send confirmation email on successful incoming email
|
||||
label_mail_handler_confirmation: "Confirmation of email submission: %{subject}"
|
||||
label_mail_handler_errors_with_submission: "There were errors with your email submission:"
|
||||
label_document_watchers: Watchers
|
||||
setting_mail_handler_confirmation_on_failure: Send confirmation email on failed incoming email
|
||||
label_between: between
|
||||
label_mail_handler_failure: "Failed email submission: %{subject}"
|
||||
notice_not_authorized_action: You are not authorized to perform this action.
|
||||
text_mail_handler_confirmation_successful: Your email has been successful added at the following url
|
||||
|
@ -1000,3 +1000,16 @@ da:
|
||||
description_date_from: Enter start date
|
||||
label_deleted_custom_field: (deleted custom field)
|
||||
field_custom_filter: Custom LDAP filter
|
||||
text_display_subprojects: Display subprojects
|
||||
text_current_project: Current project
|
||||
label_toc: Contents
|
||||
search_input_placeholder: search ...
|
||||
setting_mail_handler_confirmation_on_success: Send confirmation email on successful incoming email
|
||||
label_mail_handler_confirmation: "Confirmation of email submission: %{subject}"
|
||||
label_mail_handler_errors_with_submission: "There were errors with your email submission:"
|
||||
label_document_watchers: Watchers
|
||||
setting_mail_handler_confirmation_on_failure: Send confirmation email on failed incoming email
|
||||
label_between: between
|
||||
label_mail_handler_failure: "Failed email submission: %{subject}"
|
||||
notice_not_authorized_action: You are not authorized to perform this action.
|
||||
text_mail_handler_confirmation_successful: Your email has been successful added at the following url
|
||||
|
@ -658,6 +658,7 @@ de:
|
||||
label_roadmap_overdue: "%{value} verspätet"
|
||||
label_roadmap_no_issues: Keine Tickets für diese Version
|
||||
label_search: Suche
|
||||
search_input_placeholder: Suche ...
|
||||
label_result_plural: Resultate
|
||||
label_all_words: Alle Wörter
|
||||
label_wiki: Wiki
|
||||
@ -1001,3 +1002,15 @@ de:
|
||||
description_date_from: Startdatum eintragen
|
||||
description_date_to: Enddatum eintragen
|
||||
field_custom_filter: Custom LDAP filter
|
||||
label_toc: "Inhaltsverzeichnis"
|
||||
text_display_subprojects: Display subprojects
|
||||
text_current_project: Current project
|
||||
setting_mail_handler_confirmation_on_success: Send confirmation email on successful incoming email
|
||||
label_mail_handler_confirmation: "Confirmation of email submission: %{subject}"
|
||||
label_mail_handler_errors_with_submission: "There were errors with your email submission:"
|
||||
label_document_watchers: Watchers
|
||||
setting_mail_handler_confirmation_on_failure: Send confirmation email on failed incoming email
|
||||
label_between: between
|
||||
label_mail_handler_failure: "Failed email submission: %{subject}"
|
||||
notice_not_authorized_action: You are not authorized to perform this action.
|
||||
text_mail_handler_confirmation_successful: Your email has been successful added at the following url
|
||||
|
@ -984,3 +984,16 @@ el:
|
||||
description_date_from: Enter start date
|
||||
label_deleted_custom_field: (deleted custom field)
|
||||
field_custom_filter: Custom LDAP filter
|
||||
text_display_subprojects: Display subprojects
|
||||
text_current_project: Current project
|
||||
label_toc: Contents
|
||||
search_input_placeholder: search ...
|
||||
setting_mail_handler_confirmation_on_success: Send confirmation email on successful incoming email
|
||||
label_mail_handler_confirmation: "Confirmation of email submission: %{subject}"
|
||||
label_mail_handler_errors_with_submission: "There were errors with your email submission:"
|
||||
label_document_watchers: Watchers
|
||||
setting_mail_handler_confirmation_on_failure: Send confirmation email on failed incoming email
|
||||
label_between: between
|
||||
label_mail_handler_failure: "Failed email submission: %{subject}"
|
||||
notice_not_authorized_action: You are not authorized to perform this action.
|
||||
text_mail_handler_confirmation_successful: Your email has been successful added at the following url
|
||||
|
@ -988,3 +988,16 @@ en-GB:
|
||||
description_date_from: Enter start date
|
||||
label_deleted_custom_field: (deleted custom field)
|
||||
field_custom_filter: Custom LDAP filter
|
||||
text_display_subprojects: Display subprojects
|
||||
text_current_project: Current project
|
||||
label_toc: Contents
|
||||
search_input_placeholder: search ...
|
||||
setting_mail_handler_confirmation_on_success: Send confirmation email on successful incoming email
|
||||
label_mail_handler_confirmation: "Confirmation of email submission: %{subject}"
|
||||
label_mail_handler_errors_with_submission: "There were errors with your email submission:"
|
||||
label_document_watchers: Watchers
|
||||
setting_mail_handler_confirmation_on_failure: Send confirmation email on failed incoming email
|
||||
label_between: between
|
||||
label_mail_handler_failure: "Failed email submission: %{subject}"
|
||||
notice_not_authorized_action: You are not authorized to perform this action.
|
||||
text_mail_handler_confirmation_successful: Your email has been successful added at the following url
|
||||
|
@ -157,6 +157,7 @@ en:
|
||||
notice_file_not_found: The page you were trying to access doesn't exist or has been removed.
|
||||
notice_locking_conflict: Data has been updated by another user.
|
||||
notice_not_authorized: You are not authorized to access this page.
|
||||
notice_not_authorized_action: You are not authorized to perform this action.
|
||||
notice_not_authorized_archived_project: The project you're trying to access has been archived.
|
||||
notice_email_sent: "An email was sent to %{value}"
|
||||
notice_email_error: "An error occurred while sending mail (%{value})"
|
||||
@ -368,6 +369,8 @@ en:
|
||||
setting_commit_logtime_activity_id: Activity for logged time
|
||||
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart
|
||||
setting_issue_startdate_is_adddate: Use current date as start date for new issues
|
||||
setting_mail_handler_confirmation_on_success: "Send confirmation email on successful incoming email"
|
||||
setting_mail_handler_confirmation_on_failure: "Send confirmation email on failed incoming email"
|
||||
|
||||
permission_add_project: Create project
|
||||
permission_add_subprojects: Create subprojects
|
||||
@ -610,6 +613,7 @@ en:
|
||||
label_in_more_than: in more than
|
||||
label_greater_or_equal: '>='
|
||||
label_less_or_equal: '<='
|
||||
label_between: "between"
|
||||
label_in: in
|
||||
label_today: today
|
||||
label_all_time: all time
|
||||
@ -657,6 +661,7 @@ en:
|
||||
label_roadmap_overdue: "%{value} late"
|
||||
label_roadmap_no_issues: No issues for this version
|
||||
label_search: Search
|
||||
search_input_placeholder: search ...
|
||||
label_result_plural: Results
|
||||
label_all_words: All words
|
||||
label_wiki: Wiki
|
||||
@ -772,6 +777,7 @@ en:
|
||||
label_incoming_emails: Incoming emails
|
||||
label_generate_key: Generate a key
|
||||
label_issue_watchers: Watchers
|
||||
label_document_watchers: Watchers
|
||||
label_example: Example
|
||||
label_display: Display
|
||||
label_sort: Sort
|
||||
@ -814,6 +820,10 @@ en:
|
||||
label_notify_member_plural: Email issue updates
|
||||
label_path_encoding: Path encoding
|
||||
label_deleted_custom_field: '(deleted custom field)'
|
||||
label_toc: "Contents"
|
||||
label_mail_handler_confirmation: "Confirmation of email submission: %{subject}"
|
||||
label_mail_handler_failure: "Failed email submission: %{subject}"
|
||||
label_mail_handler_errors_with_submission: "There were errors with your email submission:"
|
||||
|
||||
button_login: Login
|
||||
button_submit: Submit
|
||||
@ -937,6 +947,9 @@ en:
|
||||
text_default_encoding: "Default: UTF-8"
|
||||
text_mercurial_repo_example: "local repository (e.g. /hgrepo, c:\\hgrepo)"
|
||||
text_git_repo_example: "a bare and local repository (e.g. /gitrepo, c:\\gitrepo)"
|
||||
text_display_subprojects: Display subprojects
|
||||
text_current_project: Current project
|
||||
text_mail_handler_confirmation_successful: "Your email has been successful added at the following url"
|
||||
|
||||
default_role_manager: Manager
|
||||
default_role_developer: Developer
|
||||
|
@ -1021,3 +1021,16 @@ es:
|
||||
description_date_from: Enter start date
|
||||
label_deleted_custom_field: (deleted custom field)
|
||||
field_custom_filter: Custom LDAP filter
|
||||
text_display_subprojects: Display subprojects
|
||||
text_current_project: Current project
|
||||
label_toc: Contents
|
||||
search_input_placeholder: search ...
|
||||
setting_mail_handler_confirmation_on_success: Send confirmation email on successful incoming email
|
||||
label_mail_handler_confirmation: "Confirmation of email submission: %{subject}"
|
||||
label_mail_handler_errors_with_submission: "There were errors with your email submission:"
|
||||
label_document_watchers: Watchers
|
||||
setting_mail_handler_confirmation_on_failure: Send confirmation email on failed incoming email
|
||||
label_between: between
|
||||
label_mail_handler_failure: "Failed email submission: %{subject}"
|
||||
notice_not_authorized_action: You are not authorized to perform this action.
|
||||
text_mail_handler_confirmation_successful: Your email has been successful added at the following url
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user