You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

407 lines
13 KiB
Ruby

2 years ago
# Copyright © Emilio González Montaña
# Licence: Attribution & no derivatives
# * Attribution to the plugin web page URL should be done if you want to use it.
# https://redmine.ociotec.com/projects/redmine-plugin-scrum
# * No derivatives of this plugin (or partial) are allowed.
# Take a look to licence.txt file at plugin root folder for further details.
class ScrumController < ApplicationController
menu_item :product_backlog, :except => [:stats]
menu_item :overview, :only => [:stats]
before_action :find_issue,
:only => [:change_story_points, :change_remaining_story_points,
:change_pending_effort,
:change_assigned_to, :new_time_entry,
:create_time_entry, :edit_task, :update_task,
:change_pending_efforts]
before_action :find_sprint,
:only => [:new_pbi, :create_pbi,
:move_not_closed_pbis_to_last_sprint]
before_action :find_pbi,
:only => [:new_task, :create_task, :edit_pbi, :update_pbi,
:move_pbi, :move_to_last_sprint,
:move_to_product_backlog]
before_action :find_project_by_project_id,
:only => [:stats]
before_action :authorize,
:except => [:new_pbi, :create_pbi, :new_task, :create_task,
:move_to_last_sprint,
:move_not_closed_pbis_to_last_sprint,
:move_to_product_backlog,
:new_time_entry, :create_time_entry]
before_action :authorize_add_issues,
:only => [:new_pbi, :create_pbi, :new_task, :create_task]
before_action :authorize_edit_issues,
:only => [:move_to_last_sprint,
:move_not_closed_pbis_to_last_sprint,
:move_to_product_backlog]
before_action :authorize_log_time,
:only => [:new_time_entry, :create_time_entry]
helper :custom_fields
helper :projects
helper :scrum
helper :timelog
def change_story_points
begin
@issue.story_points = params[:value]
status = 200
rescue
status = 503
end
render :body => nil, :status => status
end
def change_remaining_story_points
@issue.remaining_story_points = params[:value]
render :body => nil, :status => status
end
def change_pending_effort
@issue.pending_effort = params[:value]
render :body => nil, :status => 200
end
def change_pending_efforts
params['pending_efforts'].each_pair do |id, value|
pending_effort = PendingEffort.find(id)
raise "Invalid pending effort ID #{id}" if pending_effort.nil?
raise "Pending effort ID #{id} is not owned by this issue" if pending_effort.issue_id != @issue.id
if value.blank?
pending_effort.delete
else
pending_effort.effort = value.to_f
pending_effort.save!
end
end
redirect_to issue_path(@issue)
end
def change_assigned_to
@issue.init_journal(User.current)
@issue.assigned_to = params[:value].blank? ? nil : User.find(params[:value].to_i)
@issue.save!
render_task(@project, @issue, params)
end
def new_time_entry
@pbi_status_id = params[:pbi_status_id]
@other_pbi_status_ids = params[:other_pbi_status_ids]
@issue_id = params[:issue_id]
respond_to do |format|
format.js
end
end
def create_time_entry
begin
time_entry = TimeEntry.new(params.require(:time_entry).permit(:hours, :spent_on, :comments, :activity_id, :user_id))
time_entry.project_id = @project.id
time_entry.issue_id = @issue.id
time_entry.user_id = params[:time_entry][:user_id]
call_hook(:controller_timelog_edit_before_save, {:params => params, :time_entry => time_entry})
time_entry.save!
rescue Exception => @exception
logger.error("Exception: #{@exception.inspect}")
end
respond_to do |format|
format.js
end
end
def new_pbi
@pbi = Issue.new
@pbi.project = @project
@pbi.tracker = @project.trackers.find(params[:tracker_id])
@pbi.status = @pbi.default_status
@pbi.author = User.current
@pbi.sprint = @sprint
@top = true unless params[:top].nil? or (params[:top] == 'false')
respond_to do |format|
format.html
format.js
end
end
def create_pbi
begin
@continue = !(params[:create_and_continue].nil?)
@top = !(params[:top].nil?)
@pbi = Issue.new
if params[:issue][:project_id]
@pbi.project_id = params[:issue][:project_id]
else
@pbi.project = @project
end
@pbi.author = User.current
@pbi.tracker_id = params[:issue][:tracker_id]
@pbi.set_on_top if @top
@pbi.sprint = @sprint
update_attributes(@pbi, params)
@pbi.save!
rescue Exception => @exception
logger.error("Exception: #{@exception.inspect}")
end
respond_to do |format|
format.js
end
end
def edit_pbi
respond_to do |format|
format.js
end
end
def update_pbi
begin
@pbi.init_journal(User.current, params[:issue][:notes])
update_attributes(@pbi, params)
@pbi.save!
rescue Exception => @exception
logger.error("Exception: #{@exception.inspect}")
end
respond_to do |format|
format.js
end
end
def move_pbi
begin
@position = params[:position]
case params[:position]
when 'top', 'bottom'
@pbi.move_pbi_to(@position)
when 'before'
@other_pbi = params[:before_other_pbi]
@pbi.move_pbi_to(@position, @other_pbi)
when 'after'
@other_pbi = params[:after_other_pbi]
@pbi.move_pbi_to(@position, @other_pbi)
else
raise "Invalid position: #{@position.inspect}"
end
rescue Exception => @exception
logger.error("Exception: #{@exception.inspect}")
end
end
def move_to_last_sprint
begin
raise "The project hasn't defined any Sprint yet" unless @project.last_sprint
@previous_sprint = @pbi.sprint
move_issue_to_sprint(@pbi, @project.last_sprint)
rescue Exception => @exception
logger.error("Exception: #{@exception.inspect}")
end
respond_to do |format|
format.js
end
end
def move_not_closed_pbis_to_last_sprint
begin
last_sprint = @project.last_sprint
raise "The project hasn't defined any Sprint yet" unless last_sprint
not_closed_pbis = @sprint.not_closed_pbis
if not_closed_pbis.empty?
flash[:notice] = l(:label_nothing_to_move)
else
not_closed_pbis_links = []
not_closed_pbis.each do |pbi|
link = view_context.link_to_issue(pbi,
:project => pbi.project != @project,
:tracker => true)
not_closed_pbis_links << link
move_issue_to_sprint(pbi, last_sprint)
end
flash[:notice] = l(:label_pbis_moved,
:pbis => not_closed_pbis_links.join(', '))
end
rescue Exception => exception
logger.error("Exception: #{exception.inspect}")
flash[:error] = exception
end
redirect_to sprint_path(@sprint)
end
def move_to_product_backlog
begin
product_backlog = @project.product_backlogs.find(params[:id])
move_issue_to_sprint(@pbi, product_backlog)
rescue Exception => @exception
logger.error("Exception: #{@exception.inspect}")
end
respond_to do |format|
format.js
end
end
def new_task
@task = Issue.new
@task.project = @pbi.project
@task.tracker = Tracker.find(params[:tracker_id])
@task.status = @task.default_status
@task.parent = @pbi
@task.author = User.current
@task.sprint = @sprint
if Scrum::Setting.inherit_pbi_attributes
@task.inherit_from_issue(@pbi)
end
respond_to do |format|
format.html
format.js
end
rescue Exception => e
logger.error("Exception: #{e.inspect}")
render_404
end
def create_task
begin
@continue = !(params[:create_and_continue].nil?)
@task = Issue.new
if params[:issue][:project_id]
@task.project_id = params[:issue][:project_id]
else
@task.project = @pbi.project
end
@task.parent_issue_id = @pbi.id
@task.author = User.current
@task.sprint = @sprint
@task.tracker_id = params[:issue][:tracker_id]
update_attributes(@task, params)
@task.save!
@task.pending_effort = params[:issue][:pending_effort]
rescue Exception => @exception
end
respond_to do |format|
format.js
end
end
def edit_task
respond_to do |format|
format.js
end
end
def update_task
begin
@issue.init_journal(User.current, params[:issue][:notes])
@old_status = @issue.status
update_attributes(@issue, params)
@issue.save!
@issue.pending_effort = params[:issue][:pending_effort]
rescue Exception => @exception
logger.error("Exception: #{@exception.inspect}")
end
respond_to do |format|
format.js do
render "scrum/update_issue"
end
end
end
def stats
if User.current.allowed_to?(:view_time_entries, @project)
cond = @project.project_condition(Setting.display_subprojects_issues?)
@total_hours = TimeEntry.visible.where(cond).sum(:hours).to_f
end
@closed_story_points_per_sprint = @project.closed_story_points_per_sprint
@closed_story_points_per_sprint_chart = {:id => 'closed_story_points_per_sprint', :height => 400}
@hours_per_story_point = @project.hours_per_story_point
@hours_per_story_point_chart = {:id => 'hours_per_story_point', :height => 400}
@sps_by_pbi_category, @sps_by_pbi_category_total = @project.sps_by_category
@sps_by_pbi_type, @sps_by_pbi_type_total = @project.sps_by_pbi_type
@effort_by_activity, @effort_by_activity_total = @project.effort_by_activity
end
private
def render_task(project, task, params)
render :partial => "post_its/sprint_board/task",
:status => 200,
:locals => {:project => project,
:task => task,
:pbi_status_id => params[:pbi_status_id],
:other_pbi_status_ids => params[:other_pbi_status_ids].split(","),
:task_id => params[:task_id],
:read_only => false}
end
def find_sprint
@sprint = Sprint.find(params[:sprint_id])
@project = @sprint.project
rescue
logger.error("Sprint #{params[:sprint_id]} not found")
render_404
end
def find_pbi
@pbi = Issue.find(params[:pbi_id])
@sprint = @pbi.sprint
@project = @sprint.project
rescue
logger.error("PBI #{params[:pbi_id]} not found")
render_404
end
def authorize_action_on_current_project(action)
if User.current.allowed_to?(action, @project)
return true
else
render_403
return false
end
end
def authorize_add_issues
authorize_action_on_current_project(:add_issues)
end
def authorize_log_time
authorize_action_on_current_project(:log_time)
end
def authorize_edit_issues
authorize_action_on_current_project(:edit_issues)
end
def update_attributes(issue, params)
issue.status_id = params[:issue][:status_id] unless params[:issue][:status_id].nil?
raise 'New status is not allowed' unless issue.new_statuses_allowed_to.include?(issue.status)
issue.project_id = params[:issue][:project_id] unless params[:issue][:project_id].nil?
issue.assigned_to_id = params[:issue][:assigned_to_id] unless params[:issue][:assigned_to_id].nil?
issue.subject = params[:issue][:subject] unless params[:issue][:subject].nil?
issue.priority_id = params[:issue][:priority_id] unless params[:issue][:priority_id].nil?
issue.estimated_hours = params[:issue][:estimated_hours].gsub(',', '.') if issue.safe_attribute?(:estimated_hours) and (!(params[:issue][:estimated_hours].nil?))
issue.done_ratio = params[:issue][:done_ratio] unless params[:issue][:done_ratio].nil?
issue.description = params[:issue][:description] unless params[:issue][:description].nil?
issue.category_id = params[:issue][:category_id] if issue.safe_attribute?(:category_id) and (!(params[:issue][:category_id].nil?))
issue.fixed_version_id = params[:issue][:fixed_version_id] if issue.safe_attribute?(:fixed_version_id) and (!(params[:issue][:fixed_version_id].nil?))
issue.start_date = params[:issue][:start_date] if issue.safe_attribute?(:start_date) and (!(params[:issue][:start_date].nil?))
issue.due_date = params[:issue][:due_date] if issue.safe_attribute?(:due_date) and (!(params[:issue][:due_date].nil?))
issue.custom_field_values = params[:issue][:custom_field_values] unless params[:issue][:custom_field_values].nil?
end
def move_issue_to_sprint(issue, sprint)
issue.init_journal(User.current)
issue.sprint = sprint
issue.save!
issue.children.each do |child|
unless child.closed?
move_issue_to_sprint(child, sprint)
end
end
end
end