kanbanworkflowstimelinescrumrubyroadmapproject-planningproject-managementopenprojectangularissue-trackerifcgantt-chartganttbug-trackerboardsbcf
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
321 lines
11 KiB
321 lines
11 KiB
#-- encoding: UTF-8
|
|
#-- copyright
|
|
# OpenProject is a project management system.
|
|
# Copyright (C) 2011-2013 the OpenProject Foundation (OPF)
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License version 3.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
# See doc/COPYRIGHT.md for more details.
|
|
#++
|
|
|
|
class MyProjectsOverviewsController < ApplicationController
|
|
|
|
menu_item :overview
|
|
|
|
unloadable
|
|
|
|
before_filter :find_project, :find_user
|
|
before_filter :authorize
|
|
before_filter :jump_to_project_menu_item, :only => :index
|
|
|
|
verify :xhr => true,
|
|
:only => [:add_block, :remove_block, :order_blocks]
|
|
|
|
def self.available_blocks
|
|
@available_blocks ||= OpenProject::MyProjectPage.plugin_blocks
|
|
end
|
|
|
|
def index
|
|
render
|
|
end
|
|
|
|
# User's page layout configuration
|
|
def page_layout
|
|
end
|
|
|
|
def update_custom_element
|
|
block_name = params["block_name"]
|
|
block_title = params["block_title_#{block_name}"]
|
|
textile = params["textile_#{block_name}"]
|
|
|
|
if params["attachments"]
|
|
# Attach files and save them
|
|
attachments = Attachment.attach_files(overview, params["attachments"])
|
|
unless attachments[:unsaved].blank?
|
|
flash[:error] = l(:warning_attachments_not_saved, attachments[:unsaved].size)
|
|
end
|
|
end
|
|
|
|
overview.save_custom_element(block_name, block_title, textile)
|
|
|
|
redirect_to :back
|
|
end
|
|
|
|
# Add a block to user's page
|
|
# The block is added on top of the page
|
|
# params[:block] : id of the block to add
|
|
def add_block
|
|
block = params[:block].to_s.underscore
|
|
if (MyProjectsOverviewsController.available_blocks.keys.include? block)
|
|
# remove if already present in a group
|
|
%w(top left right hidden).each {|f| overview.send(f).delete block }
|
|
# add it hidden
|
|
overview.hidden.unshift block
|
|
overview.save!
|
|
render :partial => "block",
|
|
:locals => { :block_name => block }
|
|
elsif block == "custom_element"
|
|
overview.hidden.unshift overview.new_custom_element
|
|
overview.save!
|
|
render(:partial => "block_textilizable",
|
|
:locals => { :user => user,
|
|
:project => project,
|
|
:block_title => l(:label_custom_element),
|
|
:block_name => overview.hidden.first.first,
|
|
:textile => overview.hidden.first.last})
|
|
else
|
|
render :nothing => true
|
|
end
|
|
end
|
|
|
|
# Remove a block to user's page
|
|
# params[:block] : id of the block to remove
|
|
def remove_block
|
|
block = param_to_block(params[:block])
|
|
%w(top left right hidden).each {|f| overview.send(f).delete block }
|
|
overview.save!
|
|
render :nothing => true
|
|
end
|
|
|
|
# Change blocks order on user's page
|
|
# params[:group] : group to order (top, left or right)
|
|
# params[:list-(top|left|right)] : array of block ids of the group
|
|
def order_blocks
|
|
group = params[:group]
|
|
if group.is_a?(String)
|
|
group_items = (params["list-#{group}"] || []).collect {|x| param_to_block(x) }
|
|
unless group_items.size < overview.send(group).size
|
|
# We are adding or re-ordering, not removing
|
|
# Remove group blocks if they are presents in other groups
|
|
overview.update_attributes('top' => (overview.top - group_items),
|
|
'left' => (overview.left - group_items),
|
|
'right' => (overview.right - group_items),
|
|
'hidden' => (overview.hidden - group_items))
|
|
overview.update_attribute(group, group_items)
|
|
end
|
|
end
|
|
render :nothing => true
|
|
end
|
|
|
|
def param_to_block(param)
|
|
block = param.to_s.underscore
|
|
unless (MyProjectsOverviewsController.available_blocks.keys.include? block)
|
|
block = overview.custom_elements.detect {|ary| ary.first == block}
|
|
end
|
|
block
|
|
end
|
|
|
|
def destroy_attachment
|
|
if user.allowed_to?(:edit_project, project)
|
|
begin
|
|
att = Attachment.find(params[:attachment_id].to_i)
|
|
overview.attachments.delete(att)
|
|
overview.save
|
|
rescue ActiveRecord::RecordNotFound
|
|
end
|
|
end
|
|
|
|
render :partial => 'page_layout_attachments'
|
|
end
|
|
|
|
def show_all_members
|
|
respond_to do |format|
|
|
format.js { render :partial => "members",
|
|
:locals => { :users_by_role => users_by_role(0),
|
|
:count_users_by_role => count_users_by_role } }
|
|
end
|
|
end
|
|
|
|
helper_method :users_by_role,
|
|
:count_users_by_role,
|
|
:childprojects,
|
|
:recent_news,
|
|
:types,
|
|
:open_work_packages_by_type,
|
|
:total_work_packages_by_type,
|
|
:assigned_work_packages,
|
|
:total_hours,
|
|
:project,
|
|
:user,
|
|
:blocks,
|
|
:block_options,
|
|
:overview,
|
|
:attachments,
|
|
:render_block,
|
|
:object_callback
|
|
|
|
def childprojects
|
|
@childprojects ||= project.children.visible.all
|
|
end
|
|
|
|
def recent_news
|
|
@news ||= project.news.all :limit => 5,
|
|
:include => [ :author, :project ],
|
|
:order => "#{News.table_name}.created_on DESC"
|
|
|
|
end
|
|
|
|
def types
|
|
@types ||= project.rolled_up_types
|
|
end
|
|
|
|
def open_work_packages_by_type
|
|
@open_work_packages_by_tracker ||= WorkPackage.visible.count(:group => :type,
|
|
:include => [:project, :status, :type],
|
|
:conditions => ["(#{subproject_condition}) AND #{Status.table_name}.is_closed=?", false])
|
|
end
|
|
|
|
def total_work_packages_by_type
|
|
@total_work_packages_by_tracker ||= WorkPackage.visible.count(:group => :type,
|
|
:include => [:project, :status, :type],
|
|
:conditions => subproject_condition)
|
|
|
|
end
|
|
|
|
def assigned_work_packages
|
|
@assigned_issues ||= WorkPackage.visible.open.find(:all,
|
|
:conditions => { :assigned_to_id => User.current.id },
|
|
:limit => 10,
|
|
:include => [ :status, :project, :type, :priority ],
|
|
:order => "#{IssuePriority.table_name}.position DESC, #{WorkPackage.table_name}.updated_on DESC")
|
|
end
|
|
|
|
def users_by_role(limit = 100)
|
|
@users_by_role = Hash.new do |h, size|
|
|
h[size] = if size > 0
|
|
sql_string = all_roles.map do |r|
|
|
%Q{ (Select users.*, member_roles.role_id from users
|
|
JOIN members on users.id = members.user_id
|
|
JOIN member_roles on member_roles.member_id = members.id
|
|
WHERE members.project_id = #{ project.id } AND member_roles.role_id = #{ r.id }
|
|
LIMIT #{ size } ) }
|
|
end.join(" UNION ALL ")
|
|
|
|
User.find_by_sql(sql_string).group_by(&:role_id).inject({}) do |hash, (role_id, users)|
|
|
hash[all_roles.detect{ |r| r.id == role_id.to_i }] = users
|
|
hash
|
|
end
|
|
else
|
|
project.users_by_role
|
|
end
|
|
|
|
end
|
|
|
|
@users_by_role[limit]
|
|
end
|
|
|
|
def count_users_by_role
|
|
@count_users_per_role ||= begin
|
|
sql_string = all_roles.map do |r|
|
|
%Q{ (Select COUNT(users.id) AS count, member_roles.role_id AS role_id from users
|
|
JOIN members on users.id = members.user_id
|
|
JOIN member_roles on member_roles.member_id = members.id
|
|
WHERE members.project_id = #{ project.id } AND member_roles.role_id = #{ r.id }
|
|
GROUP BY (member_roles.role_id)) }
|
|
end.join(" UNION ALL ")
|
|
|
|
role_count = {}
|
|
|
|
ActiveRecord::Base.connection.execute(sql_string).each do |entry|
|
|
if entry.is_a?(Hash)
|
|
# MySql
|
|
count = entry['count'].to_i
|
|
role_id = entry['role_id'].to_i
|
|
else
|
|
# Postgresql
|
|
count = entry.first.to_i
|
|
role_id = entry.last.to_i
|
|
end
|
|
|
|
role_count[all_roles.detect{ |r| r.id == role_id }] = count if count > 0
|
|
end
|
|
|
|
role_count
|
|
end
|
|
end
|
|
|
|
def all_roles
|
|
@all_roles = Role.all
|
|
end
|
|
|
|
def total_hours
|
|
if User.current.allowed_to?(:view_time_entries, project) ||
|
|
# granted, this is a dirty hack
|
|
Redmine::Plugin.installed?(:openproject_costs) && User.current.allowed_to?(:view_own_time_entries, project)
|
|
|
|
@total_hours ||= TimeEntry.visible.sum(:hours, :include => :project, :conditions => subproject_condition).to_f
|
|
end
|
|
end
|
|
|
|
def project
|
|
@project
|
|
end
|
|
|
|
def user
|
|
@user
|
|
end
|
|
|
|
def blocks
|
|
@blocks ||= {
|
|
'top' => overview.top,
|
|
'left' => overview.left,
|
|
'right' => overview.right,
|
|
'hidden' => overview.hidden
|
|
}
|
|
end
|
|
|
|
def block_options
|
|
@block_options = []
|
|
MyProjectsOverviewsController.available_blocks.each {|k, v| @block_options << [l("my.blocks.#{v}", :default => [v, v.to_s.humanize]), k.dasherize]}
|
|
@block_options << [l(:label_custom_element), :custom_element]
|
|
end
|
|
|
|
def overview
|
|
@overview ||= MyProjectsOverview.find_or_create_by_project_id(project.id)
|
|
end
|
|
|
|
def attachments
|
|
@attachments = overview.attachments || []
|
|
end
|
|
|
|
private
|
|
|
|
def subproject_condition
|
|
@subproject_condition ||= project.project_condition(Setting.display_subprojects_work_packages?)
|
|
end
|
|
|
|
def find_user
|
|
@user = User.current
|
|
end
|
|
|
|
def default_breadcrumb
|
|
l(:label_overview)
|
|
end
|
|
|
|
def jump_to_project_menu_item
|
|
if params[:jump]
|
|
# try to redirect to the requested menu item
|
|
redirect_to_project_menu_item(project, params[:jump]) && return
|
|
end
|
|
end
|
|
end
|
|
|