Index: test/unit/helpers/issue_schedules_helper_test.rb =================================================================== --- test/unit/helpers/issue_schedules_helper_test.rb (revision 0) +++ test/unit/helpers/issue_schedules_helper_test.rb (revision 0) @@ -0,0 +1,4 @@ +require 'test_helper' + +class IssueSchedulesHelperTest < ActionView::TestCase +end Index: test/unit/issue_schedule_test.rb =================================================================== --- test/unit/issue_schedule_test.rb (revision 0) +++ test/unit/issue_schedule_test.rb (revision 0) @@ -0,0 +1,8 @@ +require 'test_helper' + +class IssueScheduleTest < ActiveSupport::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end Index: test/functional/issue_schedules_controller_test.rb =================================================================== --- test/functional/issue_schedules_controller_test.rb (revision 0) +++ test/functional/issue_schedules_controller_test.rb (revision 0) @@ -0,0 +1,8 @@ +require 'test_helper' + +class IssueSchedulesControllerTest < ActionController::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end Index: test/fixtures/issue_schedules.yml =================================================================== --- test/fixtures/issue_schedules.yml (revision 0) +++ test/fixtures/issue_schedules.yml (revision 0) @@ -0,0 +1,23 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +one: + project_id: 1 + issue_id: 1 + assigned_to_id: 1 + author_id: 1 + subject: MyString + interval_number: 1 + interval_units: MyString + last_assigned_date: 2012-02-14 14:26:40 + next_run_date: 2012-02-14 14:26:40 + +two: + project_id: 1 + issue_id: 1 + assigned_to_id: 1 + author_id: 1 + subject: MyString + interval_number: 1 + interval_units: MyString + last_assigned_date: 2012-02-14 14:26:40 + next_run_date: 2012-02-14 14:26:40 Index: app/helpers/issue_schedules_helper.rb =================================================================== --- app/helpers/issue_schedules_helper.rb (revision 0) +++ app/helpers/issue_schedules_helper.rb (revision 0) @@ -0,0 +1,2 @@ +module IssueSchedulesHelper +end Index: app/models/journal.rb =================================================================== --- app/models/journal.rb (revision 8667) +++ app/models/journal.rb (working copy) @@ -85,4 +85,16 @@ def notify=(arg) @notify = arg end + # copies a set of journal notes from one object to another + def self.copy_notes(objToId, objFromId) + transaction do + connection.insert "INSERT INTO #{Journal.table_name} (journalized_id,journalized_type,user_id,notes,created_on)" + + " SELECT #{objToId}, journalized_type,user_id,notes,created_on" + + " FROM #{Journal.table_name}" + + " WHERE journalized_id = #{objFromId}" + + + end + true + end end Index: app/models/issue_schedule.rb =================================================================== --- app/models/issue_schedule.rb (revision 0) +++ app/models/issue_schedule.rb (revision 0) @@ -0,0 +1,4 @@ +class IssueSchedule < ActiveRecord::Base + belongs_to :issue + +end Index: app/models/issue.rb =================================================================== --- app/models/issue.rb (revision 8667) +++ app/models/issue.rb (working copy) @@ -29,6 +29,7 @@ has_many :journals, :as => :journalized, :dependent => :destroy has_many :time_entries, :dependent => :delete_all + has_many :issue_schedules, :dependent=> :delete_all has_and_belongs_to_many :changesets, :order => "#{Changeset.table_name}.committed_on ASC, #{Changeset.table_name}.id ASC" has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all @@ -50,6 +51,7 @@ :author_key => :author_id DONE_RATIO_OPTIONS = %w(issue_field issue_status) + INTERVAL_UNITS = ['day','week', 'month'] attr_reader :current_journal @@ -86,7 +88,7 @@ before_save :close_duplicates, :update_done_ratio_from_issue_status after_save :reschedule_following_issues, :update_nested_set_attributes, :update_parent_attributes, :create_journal after_destroy :update_parent_attributes - + # Returns a SQL conditions string used to find all issues visible by the specified user def self.visible_condition(user, options={}) Project.allowed_to_condition(user, :view_issues, options) do |role, user| @@ -141,7 +143,50 @@ self.status = issue.status self end - + def copy_attachment(arg) + + issue = arg.is_a?(Issue) ? arg : Issue.visible.find(arg) + + if issue.attachments.any? + Attachment.copy_files(id,issue.id) + end + + end + + def copy_notes(arg) + issue = arg.is_a?(Issue) ? arg : Issue.visible.find(arg) + + if issue.journals.present? + Journal.copy_notes(id,issue.id) + end + + end + + # repeats and schedule issues + def repeat_issue(params) + + Issue.transaction do + #if User.current.allowed_to?(:schedule_issue, project) + @schedule_entry = IssueSchedule.new + @schedule_entry.project_id = project + @schedule_entry.tracker_id = self.tracker_id + @schedule_entry.issue_id = self.id + @schedule_entry.assigned_to_id = self.assigned_to_id + @schedule_entry.author_id = self.author_id + @schedule_entry.subject = self.subject + @schedule_entry.interval_number = params[:issue][:issue_schedules][:interval_number] + @schedule_entry.interval_units = params[:issue][:issue_schedules][:interval_units] + @schedule_entry.last_assigned_date = User.current.today + @schedule_entry.next_run_date = params[:issue][:issue_schedules][:next_run_date] + self.issue_schedules << @schedule_entry + #end + end + true + + end + + + # Moves/copies an issue to a new project and tracker # Returns the moved/copied issue on success, false on failure def move_to_project(*args) Index: app/models/attachment.rb =================================================================== --- app/models/attachment.rb (revision 8667) +++ app/models/attachment.rb (working copy) @@ -58,6 +58,7 @@ def file=(incoming_file) unless incoming_file.nil? @temp_file = incoming_file + if @temp_file.size > 0 self.filename = sanitize_filename(@temp_file.original_filename) self.disk_filename = Attachment.disk_filename(filename) @@ -149,6 +150,7 @@ if attachments && attachments.is_a?(Hash) attachments.each_value do |attachment| file = attachment['file'] + logger.info("filename '#{file}'") next unless file && file.size > 0 a = Attachment.create(:container => obj, :file => file, @@ -172,12 +174,24 @@ |att| att.filename.downcase == filename.downcase } end + + # copies a set of files attached from one object to another + def self.copy_files(objToId, objFromId) + transaction do + connection.insert "INSERT INTO #{Attachment.table_name} (container_id,container_type,filename,disk_filename,filesize,content_type,digest,downloads,author_id,created_on,description)" + + " SELECT #{objToId}, container_type,filename,disk_filename,filesize,content_type,digest,downloads,author_id,created_on,description" + + " FROM #{Attachment.table_name}" + + " WHERE container_id = #{objFromId}" + end + true + end private def sanitize_filename(value) # get only the filename, not the whole path + just_filename = value.gsub(/^.*(\\|\/)/, '') - + # Finally, replace invalid characters with underscore @filename = just_filename.gsub(/[\/\?\%\*\:\|\"\'<>]+/, '_') end Index: app/controllers/issues_controller.rb =================================================================== --- app/controllers/issues_controller.rb (revision 8667) +++ app/controllers/issues_controller.rb (working copy) @@ -123,6 +123,7 @@ @edit_allowed = User.current.allowed_to?(:edit_issues, @project) @priorities = IssuePriority.active @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project) + respond_to do |format| format.html { render :template => 'issues/show' } format.api @@ -143,6 +144,7 @@ def create call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue }) if @issue.save + attachments = Attachment.attach_files(@issue, params[:attachments]) call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue}) respond_to do |format| @@ -175,10 +177,12 @@ end def update + @issue.repeat_issue(params) if params[:repeat] update_issue_from_params if @issue.save_issue_with_child_records(params, @time_entry) render_attachment_warning_if_needed(@issue) + flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record? respond_to do |format| @@ -195,6 +199,7 @@ format.api { render_validation_errors(@issue) } end end + end # Bulk edit a set of issues @@ -293,6 +298,7 @@ @notes = params[:notes] || (params[:issue].present? ? params[:issue][:notes] : nil) @issue.init_journal(User.current, @notes) @issue.safe_attributes = params[:issue] + end # TODO: Refactor, lots of extra code in here Index: app/controllers/issue_schedules_controller.rb =================================================================== --- app/controllers/issue_schedules_controller.rb (revision 0) +++ app/controllers/issue_schedules_controller.rb (revision 0) @@ -0,0 +1,84 @@ +class IssueSchedulesController < ApplicationController + unloadable + + + before_filter :find_project + before_filter :find_issueschedule, :except => [:new, :index] + before_filter :load_users, :except => [:destroy] + + def index + if !params[:project_id] then return end + @project_identifier = params[:project_id] + @project = Project.find(params[:project_id]) + @issue_schedule = IssueSchedule.find_all_by_project_id(@project[:id]) + end + def update + if !params[:project_id] then return end + @issue_schedule = IssueSchedule.find(params[:id]) + @issue_schedule.update_attributes(params[:issue_schedules]) + + if @issue_schedule.save + flash[:notice] = "Issue Schedule is saved" + redirect_to :controller => 'issue_schedules', :action => 'index', :project_id=>params[:project_id] + end + end + def new + if !params[:project_id] then return end + @project = Project.find(params[:project_id]) + @issue_schedule = IssueSchedule.new(:project=>@project, :author_id=>User.current.id) + if request.post? + params[:issue_schedules][:project_id] = @project[:id] + @issue_schedule.attributes = params[:issue_schedules] + if @issue_schedule.save + flash[:notice] = "Issue Schedule is saved" + redirect_to :controller => 'issue_schedules', :action => 'index', :project_id=>params[:project_id] + end + end + + end + + def edit + if request.post? + @issue_schedule = IssueSchedule.find(params[:id]) + params[:issue_schedules][:project_id] = params[:project_id] + if request.post? + if @issue_schedule.update_attributes(params[:issue_schedules]) + flash[:notice] = "saved issue schedule" + redirect_to :action => 'index', :project_id => params[:project_id] + end + end + end + end + + def destroy + @issue_schedule = IssueSchedule.find(params[:id]) + @issue_schedule.destroy + redirect_to :action => 'index', :project_id => params[:project_id] + end +private + def find_issueschedule + @issue_schedule = IssueSchedule.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + end + def find_project + @project = Project.find(params[:project_id]) + end + + def load_users + # Get the users that are members in the project + # + #@users = User.find_by_sql('SELECT users.id, CONCAT(users.firstname, \' \', users.lastname) fullname FROM members INNER JOIN users + # ON members.user_id = users.id + # WHERE project_id = ' + @project[:id].to_s + ' + # AND status = 1 + # ORDER BY firstname ASC') + @users = [] + @project.members.each do |m| + @users << m.user + end + + end + + +end Index: app/views/issue_schedules/edit.html.erb =================================================================== --- app/views/issue_schedules/edit.html.erb (revision 0) +++ app/views/issue_schedules/edit.html.erb (revision 0) @@ -0,0 +1,9 @@ +
Use this form to edit this task.
+<% labelled_tabular_form_for :issue_schedules, @issue_schedule, + :url => { :controller => 'issue_schedules', :action => 'update', :id=>@issue_schedule.id, :project_id => @project }, + :html => { :id => 'task-form' } do |f| %> +<%= render :partial => 'issue_schedules/form', :locals => { :f => f } %> +<%= submit_tag l(:button_update) %> +<%= link_to l(:button_cancel), :controller => 'issue_schedules',:action => 'index', :project_id => @project%> +<% end if @project %> Index: app/views/issue_schedules/index.html.erb =================================================================== --- app/views/issue_schedules/index.html.erb (revision 0) +++ app/views/issue_schedules/index.html.erb (revision 0) @@ -0,0 +1,34 @@ + +<% if @project_identifier %> + +These are the currently scheduled issues
+| <%= l(:label_subject) %> | <%= l(:label_next_run_date) %> |   |   | +
|---|---|---|---|
| <%= a.subject %> | +<%= a.next_run_date %> | ++ <%= link_to l(:button_edit), + {:controller => 'issue_schedules', :action => 'edit', :id => a.id, :project_id => @project}, + :class => 'icon icon-edit', + :accesskey => accesskey(:edit), + :onclick => 'Element.show("edit-task"); return false;' %> + | ++ <%= link_to l(:button_delete), {:controller => 'issue_schedules', :action => 'destroy', :id => a.id, :project_id => @project}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> + | +
No project ID supplied
+<% end %> Index: app/views/issue_schedules/destroy.html.erb =================================================================== --- app/views/issue_schedules/destroy.html.erb (revision 0) +++ app/views/issue_schedules/destroy.html.erb (revision 0) @@ -0,0 +1 @@ +<%= f.text_field :subject, :required => true, :size => 60 %>
++ + <% if @users.length > 0 %> +
<%= f.select :assigned_to_id, @users.collect {|t| [t.name, t.id]}, :required => true %>
+ + <% else %> + <%= l(:no_members_in_project) %> + <% end %> + +<%= f.text_field :interval_number, :required=> true, :size => 3 %>
+<%= f.select :interval_units, Issue::INTERVAL_UNITS %>
+<%= f.select :tracker_id, @project.trackers.collect {|t| [t.name, t.id]}, :required => true %>
+ +<%= f.text_field :next_run_date %><%=calendar_for('issue_schedules_next_run_date')%>
+