Revision 1298:4f746d8966dd .svn/pristine/35

View differences:

.svn/pristine/35/3512f0a7e8a0b7dd8c33b6309137ca6b0f893a68.svn-base
1
<%= TestHelper.view_path_for __FILE__ %> (from a_view)
.svn/pristine/35/35159d7789b8fbcfc57c58eacb8fb9632b6c69c9.svn-base
1
api.issue do
2
  api.id @issue.id
3
  api.project(:id => @issue.project_id, :name => @issue.project.name) unless @issue.project.nil?
4
  api.tracker(:id => @issue.tracker_id, :name => @issue.tracker.name) unless @issue.tracker.nil?
5
  api.status(:id => @issue.status_id, :name => @issue.status.name) unless @issue.status.nil?
6
  api.priority(:id => @issue.priority_id, :name => @issue.priority.name) unless @issue.priority.nil?
7
  api.author(:id => @issue.author_id, :name => @issue.author.name) unless @issue.author.nil?
8
  api.assigned_to(:id => @issue.assigned_to_id, :name => @issue.assigned_to.name) unless @issue.assigned_to.nil?
9
  api.category(:id => @issue.category_id, :name => @issue.category.name) unless @issue.category.nil?
10
  api.fixed_version(:id => @issue.fixed_version_id, :name => @issue.fixed_version.name) unless @issue.fixed_version.nil?
11
  api.parent(:id => @issue.parent_id) unless @issue.parent.nil?
12

  
13
  api.subject @issue.subject
14
  api.description @issue.description
15
  api.start_date @issue.start_date
16
  api.due_date @issue.due_date
17
  api.done_ratio @issue.done_ratio
18
  api.estimated_hours @issue.estimated_hours
19
  api.spent_hours(@issue.spent_hours) if User.current.allowed_to?(:view_time_entries, @project)
20

  
21
  render_api_custom_values @issue.custom_field_values, api
22

  
23
  api.created_on @issue.created_on
24
  api.updated_on @issue.updated_on
25

  
26
  render_api_issue_children(@issue, api) if include_in_api_response?('children')
27

  
28
  api.array :attachments do
29
    @issue.attachments.each do |attachment|
30
      render_api_attachment(attachment, api)
31
    end
32
  end if include_in_api_response?('attachments')
33

  
34
  api.array :relations do
35
    @relations.each do |relation|
36
      api.relation(:id => relation.id, :issue_id => relation.issue_from_id, :issue_to_id => relation.issue_to_id, :relation_type => relation.relation_type, :delay => relation.delay)
37
    end
38
  end if include_in_api_response?('relations') && @relations.present?
39

  
40
  api.array :changesets do
41
    @issue.changesets.each do |changeset|
42
      api.changeset :revision => changeset.revision do
43
        api.user(:id => changeset.user_id, :name => changeset.user.name) unless changeset.user.nil?
44
        api.comments changeset.comments
45
        api.committed_on changeset.committed_on
46
      end
47
    end
48
  end if include_in_api_response?('changesets') && User.current.allowed_to?(:view_changesets, @project)
49

  
50
  api.array :journals do
51
    @issue.journals.each do |journal|
52
      api.journal :id => journal.id do
53
        api.user(:id => journal.user_id, :name => journal.user.name) unless journal.user.nil?
54
        api.notes journal.notes
55
        api.created_on journal.created_on
56
        api.array :details do
57
          journal.details.each do |detail|
58
            api.detail :property => detail.property, :name => detail.prop_key do
59
              api.old_value detail.old_value
60
              api.new_value detail.value
61
            end
62
          end
63
        end
64
      end
65
    end
66
  end if include_in_api_response?('journals')
67
end
.svn/pristine/35/35a0a9f6553f729051c01dc102ed98a7a0151c3f.svn-base
1
# encoding: utf-8
2
#
3
# Helpers to sort tables using clickable column headers.
4
#
5
# Author:  Stuart Rackham <srackham@methods.co.nz>, March 2005.
6
#          Jean-Philippe Lang, 2009
7
# License: This source code is released under the MIT license.
8
#
9
# - Consecutive clicks toggle the column's sort order.
10
# - Sort state is maintained by a session hash entry.
11
# - CSS classes identify sort column and state.
12
# - Typically used in conjunction with the Pagination module.
13
#
14
# Example code snippets:
15
#
16
# Controller:
17
#
18
#   helper :sort
19
#   include SortHelper
20
#
21
#   def list
22
#     sort_init 'last_name'
23
#     sort_update %w(first_name last_name)
24
#     @items = Contact.find_all nil, sort_clause
25
#   end
26
#
27
# Controller (using Pagination module):
28
#
29
#   helper :sort
30
#   include SortHelper
31
#
32
#   def list
33
#     sort_init 'last_name'
34
#     sort_update %w(first_name last_name)
35
#     @contact_pages, @items = paginate :contacts,
36
#       :order_by => sort_clause,
37
#       :per_page => 10
38
#   end
39
#
40
# View (table header in list.rhtml):
41
#
42
#   <thead>
43
#     <tr>
44
#       <%= sort_header_tag('id', :title => 'Sort by contact ID') %>
45
#       <%= sort_header_tag('last_name', :caption => 'Name') %>
46
#       <%= sort_header_tag('phone') %>
47
#       <%= sort_header_tag('address', :width => 200) %>
48
#     </tr>
49
#   </thead>
50
#
51
# - Introduces instance variables: @sort_default, @sort_criteria
52
# - Introduces param :sort
53
#
54

  
55
module SortHelper
56
  class SortCriteria
57

  
58
    def initialize
59
      @criteria = []
60
    end
61

  
62
    def available_criteria=(criteria)
63
      unless criteria.is_a?(Hash)
64
        criteria = criteria.inject({}) {|h,k| h[k] = k; h}
65
      end
66
      @available_criteria = criteria
67
    end
68

  
69
    def from_param(param)
70
      @criteria = param.to_s.split(',').collect {|s| s.split(':')[0..1]}
71
      normalize!
72
    end
73

  
74
    def criteria=(arg)
75
      @criteria = arg
76
      normalize!
77
    end
78

  
79
    def to_param
80
      @criteria.collect {|k,o| k + (o ? '' : ':desc')}.join(',')
81
    end
82

  
83
    # Returns an array of SQL fragments used to sort the list
84
    def to_sql
85
      sql = @criteria.collect do |k,o|
86
        if s = @available_criteria[k]
87
          (o ? s.to_a : s.to_a.collect {|c| append_desc(c)})
88
        end
89
      end.flatten.compact
90
      sql.blank? ? nil : sql
91
    end
92

  
93
    def to_a
94
      @criteria.dup
95
    end
96

  
97
    def add!(key, asc)
98
      @criteria.delete_if {|k,o| k == key}
99
      @criteria = [[key, asc]] + @criteria
100
      normalize!
101
    end
102

  
103
    def add(*args)
104
      r = self.class.new.from_param(to_param)
105
      r.add!(*args)
106
      r
107
    end
108

  
109
    def first_key
110
      @criteria.first && @criteria.first.first
111
    end
112

  
113
    def first_asc?
114
      @criteria.first && @criteria.first.last
115
    end
116

  
117
    def empty?
118
      @criteria.empty?
119
    end
120

  
121
    private
122

  
123
    def normalize!
124
      @criteria ||= []
125
      @criteria = @criteria.collect {|s| s = s.to_a; [s.first, (s.last == false || s.last == 'desc') ? false : true]}
126
      @criteria = @criteria.select {|k,o| @available_criteria.has_key?(k)} if @available_criteria
127
      @criteria.slice!(3)
128
      self
129
    end
130

  
131
    # Appends DESC to the sort criterion unless it has a fixed order
132
    def append_desc(criterion)
133
      if criterion =~ / (asc|desc)$/i
134
        criterion
135
      else
136
        "#{criterion} DESC"
137
      end
138
    end
139
  end
140

  
141
  def sort_name
142
    controller_name + '_' + action_name + '_sort'
143
  end
144

  
145
  # Initializes the default sort.
146
  # Examples:
147
  #
148
  #   sort_init 'name'
149
  #   sort_init 'id', 'desc'
150
  #   sort_init ['name', ['id', 'desc']]
151
  #   sort_init [['name', 'desc'], ['id', 'desc']]
152
  #
153
  def sort_init(*args)
154
    case args.size
155
    when 1
156
      @sort_default = args.first.is_a?(Array) ? args.first : [[args.first]]
157
    when 2
158
      @sort_default = [[args.first, args.last]]
159
    else
160
      raise ArgumentError
161
    end
162
  end
163

  
164
  # Updates the sort state. Call this in the controller prior to calling
165
  # sort_clause.
166
  # - criteria can be either an array or a hash of allowed keys
167
  #
168
  def sort_update(criteria, sort_name=nil)
169
    sort_name ||= self.sort_name
170
    @sort_criteria = SortCriteria.new
171
    @sort_criteria.available_criteria = criteria
172
    @sort_criteria.from_param(params[:sort] || session[sort_name])
173
    @sort_criteria.criteria = @sort_default if @sort_criteria.empty?
174
    session[sort_name] = @sort_criteria.to_param
175
  end
176

  
177
  # Clears the sort criteria session data
178
  #
179
  def sort_clear
180
    session[sort_name] = nil
181
  end
182

  
183
  # Returns an SQL sort clause corresponding to the current sort state.
184
  # Use this to sort the controller's table items collection.
185
  #
186
  def sort_clause()
187
    @sort_criteria.to_sql
188
  end
189

  
190
  def sort_criteria
191
    @sort_criteria
192
  end
193

  
194
  # Returns a link which sorts by the named column.
195
  #
196
  # - column is the name of an attribute in the sorted record collection.
197
  # - the optional caption explicitly specifies the displayed link text.
198
  # - 2 CSS classes reflect the state of the link: sort and asc or desc
199
  #
200
  def sort_link(column, caption, default_order)
201
    css, order = nil, default_order
202

  
203
    if column.to_s == @sort_criteria.first_key
204
      if @sort_criteria.first_asc?
205
        css = 'sort asc'
206
        order = 'desc'
207
      else
208
        css = 'sort desc'
209
        order = 'asc'
210
      end
211
    end
212
    caption = column.to_s.humanize unless caption
213

  
214
    sort_options = { :sort => @sort_criteria.add(column.to_s, order).to_param }
215
    url_options = params.merge(sort_options)
216

  
217
     # Add project_id to url_options
218
    url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id)
219

  
220
    link_to_content_update(h(caption), url_options, :class => css)
221
  end
222

  
223
  # Returns a table header <th> tag with a sort link for the named column
224
  # attribute.
225
  #
226
  # Options:
227
  #   :caption     The displayed link name (defaults to titleized column name).
228
  #   :title       The tag's 'title' attribute (defaults to 'Sort by :caption').
229
  #
230
  # Other options hash entries generate additional table header tag attributes.
231
  #
232
  # Example:
233
  #
234
  #   <%= sort_header_tag('id', :title => 'Sort by contact ID', :width => 40) %>
235
  #
236
  def sort_header_tag(column, options = {})
237
    caption = options.delete(:caption) || column.to_s.humanize
238
    default_order = options.delete(:default_order) || 'asc'
239
    options[:title] = l(:label_sort_by, "\"#{caption}\"") unless options[:title]
240
    content_tag('th', sort_link(column, caption, default_order), options)
241
  end
242
end
243

  
.svn/pristine/35/35c1cd09fb09a0095fc148484431ad643d188dd6.svn-base
1
# Redmine - project management software
2
# Copyright (C) 2006-2013  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
class CommentObserver < ActiveRecord::Observer
19
  def after_create(comment)
20
    if comment.commented.is_a?(News) && Setting.notified_events.include?('news_comment_added')
21
      Mailer.news_comment_added(comment).deliver
22
    end
23
  end
24
end
.svn/pristine/35/35d2a8dc4a5a8983e7bc3e63a00a706b7e3bfb4c.svn-base
1
# encoding: utf-8
2
#
3
# Redmine - project management software
4
# Copyright (C) 2006-2013  Jean-Philippe Lang
5
#
6
# This program is free software; you can redistribute it and/or
7
# modify it under the terms of the GNU General Public License
8
# as published by the Free Software Foundation; either version 2
9
# of the License, or (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19

  
20
module QueriesHelper
21
  def filters_options_for_select(query)
22
    options_for_select(filters_options(query))
23
  end
24

  
25
  def filters_options(query)
26
    options = [[]]
27
    options += query.available_filters.map do |field, field_options|
28
      [field_options[:name], field]
29
    end
30
  end
31

  
32
  def query_filters_hidden_tags(query)
33
    tags = ''.html_safe
34
    query.filters.each do |field, options|
35
      tags << hidden_field_tag("f[]", field, :id => nil)
36
      tags << hidden_field_tag("op[#{field}]", options[:operator], :id => nil)
37
      options[:values].each do |value|
38
        tags << hidden_field_tag("v[#{field}][]", value, :id => nil)
39
      end
40
    end
41
    tags
42
  end
43

  
44
  def query_columns_hidden_tags(query)
45
    tags = ''.html_safe
46
    query.columns.each do |column|
47
      tags << hidden_field_tag("c[]", column.name, :id => nil)
48
    end
49
    tags
50
  end
51

  
52
  def query_hidden_tags(query)
53
    query_filters_hidden_tags(query) + query_columns_hidden_tags(query)
54
  end
55

  
56
  def available_block_columns_tags(query)
57
    tags = ''.html_safe
58
    query.available_block_columns.each do |column|
59
      tags << content_tag('label', check_box_tag('c[]', column.name.to_s, query.has_column?(column)) + " #{column.caption}", :class => 'inline')
60
    end
61
    tags
62
  end
63

  
64
  def query_available_inline_columns_options(query)
65
    (query.available_inline_columns - query.columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
66
  end
67

  
68
  def query_selected_inline_columns_options(query)
69
    (query.inline_columns & query.available_inline_columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
70
  end
71

  
72
  def render_query_columns_selection(query, options={})
73
    tag_name = (options[:name] || 'c') + '[]'
74
    render :partial => 'queries/columns', :locals => {:query => query, :tag_name => tag_name}
75
  end
76

  
77
  def column_header(column)
78
    column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
79
                                                        :default_order => column.default_order) :
80
                      content_tag('th', h(column.caption))
81
  end
82

  
83
  def column_content(column, issue)
84
    value = column.value(issue)
85
    if value.is_a?(Array)
86
      value.collect {|v| column_value(column, issue, v)}.compact.join(', ').html_safe
87
    else
88
      column_value(column, issue, value)
89
    end
90
  end
91
  
92
  def column_value(column, issue, value)
93
    case value.class.name
94
    when 'String'
95
      if column.name == :subject
96
        link_to(h(value), :controller => 'issues', :action => 'show', :id => issue)
97
      elsif column.name == :description
98
        issue.description? ? content_tag('div', textilizable(issue, :description), :class => "wiki") : ''
99
      else
100
        h(value)
101
      end
102
    when 'Time'
103
      format_time(value)
104
    when 'Date'
105
      format_date(value)
106
    when 'Fixnum'
107
      if column.name == :id
108
        link_to value, issue_path(issue)
109
      elsif column.name == :done_ratio
110
        progress_bar(value, :width => '80px')
111
      else
112
        value.to_s
113
      end
114
    when 'Float'
115
      sprintf "%.2f", value
116
    when 'User'
117
      link_to_user value
118
    when 'Project'
119
      link_to_project value
120
    when 'Version'
121
      link_to(h(value), :controller => 'versions', :action => 'show', :id => value)
122
    when 'TrueClass'
123
      l(:general_text_Yes)
124
    when 'FalseClass'
125
      l(:general_text_No)
126
    when 'Issue'
127
      value.visible? ? link_to_issue(value) : "##{value.id}"
128
    when 'IssueRelation'
129
      other = value.other_issue(issue)
130
      content_tag('span',
131
        (l(value.label_for(issue)) + " " + link_to_issue(other, :subject => false, :tracker => false)).html_safe,
132
        :class => value.css_classes_for(issue))
133
    else
134
      h(value)
135
    end
136
  end
137

  
138
  def csv_content(column, issue)
139
    value = column.value(issue)
140
    if value.is_a?(Array)
141
      value.collect {|v| csv_value(column, issue, v)}.compact.join(', ')
142
    else
143
      csv_value(column, issue, value)
144
    end
145
  end
146

  
147
  def csv_value(column, issue, value)
148
    case value.class.name
149
    when 'Time'
150
      format_time(value)
151
    when 'Date'
152
      format_date(value)
153
    when 'Float'
154
      sprintf("%.2f", value).gsub('.', l(:general_csv_decimal_separator))
155
    when 'IssueRelation'
156
      other = value.other_issue(issue)
157
      l(value.label_for(issue)) + " ##{other.id}"
158
    else
159
      value.to_s
160
    end
161
  end
162

  
163
  def query_to_csv(items, query, options={})
164
    encoding = l(:general_csv_encoding)
165
    columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns)
166
    query.available_block_columns.each do |column|
167
      if options[column.name].present?
168
        columns << column
169
      end
170
    end
171

  
172
    export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
173
      # csv header fields
174
      csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) }
175
      # csv lines
176
      items.each do |item|
177
        csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(csv_content(c, item), encoding) }
178
      end
179
    end
180
    export
181
  end
182

  
183
  # Retrieve query from session or build a new query
184
  def retrieve_query
185
    if !params[:query_id].blank?
186
      cond = "project_id IS NULL"
187
      cond << " OR project_id = #{@project.id}" if @project
188
      @query = IssueQuery.find(params[:query_id], :conditions => cond)
189
      raise ::Unauthorized unless @query.visible?
190
      @query.project = @project
191
      session[:query] = {:id => @query.id, :project_id => @query.project_id}
192
      sort_clear
193
    elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
194
      # Give it a name, required to be valid
195
      @query = IssueQuery.new(:name => "_")
196
      @query.project = @project
197
      @query.build_from_params(params)
198
      session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
199
    else
200
      # retrieve from session
201
      @query = IssueQuery.find_by_id(session[:query][:id]) if session[:query][:id]
202
      @query ||= IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
203
      @query.project = @project
204
    end
205
  end
206

  
207
  def retrieve_query_from_session
208
    if session[:query]
209
      if session[:query][:id]
210
        @query = IssueQuery.find_by_id(session[:query][:id])
211
        return unless @query
212
      else
213
        @query = IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
214
      end
215
      if session[:query].has_key?(:project_id)
216
        @query.project_id = session[:query][:project_id]
217
      else
218
        @query.project = @project
219
      end
220
      @query
221
    end
222
  end
223
end
.svn/pristine/35/35f7ce114c4047a04259024e5c563af98880d0e2.svn-base
1
# Add new mime types for use in respond_to blocks:
2

  
3
Mime::SET << Mime::CSV unless Mime::SET.include?(Mime::CSV)
4
Mime::Type.register 'application/pdf', :pdf
5
Mime::Type.register 'image/png', :png

Also available in: Unified diff