class PeriodsController < ApplicationController skip_before_filter :populate_layout, :only => [:index, :show_nolayout, :destroy, :burn_down_chart_thumbnail, :burn_down_chart] skip_before_filter :authenticate_user, :only => [:burn_down_chart, :burn_down_chart_thumbnail, :burn_down_chart_large] def index active_periods = Period.find(:all).select {|period| period.active?(true)} my_active_periods = active_periods.select {|period| period.party.includes?(current_user)} unless my_active_periods.empty? most_urgent_period = my_active_periods.sort_by {|p| p.required_speed}.last else most_urgent_period = active_periods.sort_by {|p| p.required_speed}.last end redirect_to :action => 'show', :id => most_urgent_period end # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) verify :method => :post, :only => [ :destroy, :create, :update ], :redirect_to => { :action => :index } def show if params[:task_id] @selected_task = Task.find(params[:task_id]) end if @selected_task @period = @selected_task.period elsif params[:id] && @period = Period.find_by_id(params[:id]) elsif @period = Period.find(:first) else redirect_to :action => :new return end if @selected_task.nil? @selected_task = Task.find(:first, :conditions => "position = 1 AND period_id = #{@period.id}") end @tasks = @period.open_tasks @completed_tasks = @period.completed_tasks.reverse end def show_no_layout show render :partial => 'show_active', :layout => false, :locals => {:i => 0} end def new @period = Period.new if params[:period] && params[:period][:party_id] @period.party_id = params[:period][:party_id] previous = @period.party.periods.last if previous @period.start_on = previous.end_on + 1 @period.end_on = previous.end_on + (1 + (previous.end_on - previous.start_on)) else @period.start_on = Date.today end end @parties = Party.find(:all) end def create @period = Period.new(params[:period]) if @period.save @period.reload flash[:notice] = 'Period was successfully created.' back_or_redirect_to :action => 'show', :id => @period.higher_item ? @period.higher_item : @period else render :action => 'new' end end def edit @period = Period.find(params[:id]) end def update @period = Period.find(params[:id]) if @period.update_attributes(params[:period]) flash[:notice] = 'Period was successfully updated.' redirect_to :action => 'show', :id => @period else render :action => 'edit' end end def destroy Period.find(params[:id]).destroy flash[:notice] = 'Period was successfully deleted.' redirect_to :action => 'index' end def burn_down_chart_thumbnail send_burn_down_chart 270 end def burn_down_chart send_burn_down_chart 640 end def burn_down_chart_large send_burn_down_chart '1440x900' end def list_work @period = Period.find(params[:id]) @works = Work.find_by_sql("SELECT w.* FROM works w LEFT OUTER JOIN tasks t ON t.id = w.task_id WHERE t.period_id = #{@period.id} ORDER BY w.completed_at") render :template => '/works/list' end private def send_burn_down_chart(size) period = Period.find(params[:id]) g = Gruff::Line.new(size) g.theme_37signals g.title = l(:burn_down_chart) + " " + period.to_s g.font = '/usr/share/fonts/bitstream-vera/Vera.ttf' g.legend_font_size = 14 g.hide_dots = true g.colors = %w{blue orange} if period.track_work? g.colors += %w{green} end if previous_period = period.higher_item g.colors += %w{grey grey} end if period.active? g.colors += %w{lightblue #d7a790} end recorded_dates = period.recorded_dates observed_todo_data = get_todo_data(recorded_dates, period) actual_todo_data = get_todo_data(recorded_dates, period, true) g.data("#{l :todo} (#{l :obs})", observed_todo_data) g.data("#{l :calc}", actual_todo_data) g.data(l(:done), get_work_data(recorded_dates, period)) if period.track_work? if previous_period = period.higher_item g.data("#{l :previous} #{l :obs}", get_todo_data(previous_period.dates, previous_period)) g.data("#{l :calc}", get_todo_data(previous_period.dates, previous_period, true)) end if period.active? g.data(l(:projection), projection_data(observed_todo_data, period)) g.data(l(:projection), projection_data(actual_todo_data, period)) end g.minimum_value = 0 all_dates = period.dates labels = {0 => all_dates.first.to_s, all_dates.length-1 => all_dates.last.to_s} labels.merge({all_dates.index(Date.today) => Date.today.to_s}) if all_dates.index(Date.today) && (all_dates.index(Date.today) / all_dates.length) > 0.10 g.labels = labels # g.draw_vertical_legend g.maximum_value = g.maximum_value.to_i send_data(g.to_blob, :disposition => 'inline', :type => 'image/png', :filename => "burn_down_chart.png") end def get_todo_data(dates, period, actual=false) dates.map { |date| period.estimate_data(date, actual) } end def get_work_data(dates, period) dates.map { |date| period.work_data(date) } end def projection_data(observed_todo_data, period) if observed_todo_data.length <= 1 velocity = 0 else velocity = (observed_todo_data[-1] - observed_todo_data[0]).to_f / (observed_todo_data.length-1) end projection_data = period.dates.map do |date| if date < Date.today nil else if observed_todo_data.length == 1 observed_todo_data[0] else value = observed_todo_data[0] + (date-period.start_on).to_f*velocity value >= 0 ? value : 0 end end end end end