#-- encoding: UTF-8 #-- copyright # OpenProject My Project Page Plugin # # Copyright (C) 2011-2014 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 before_action :find_project, :find_user before_action :authorize before_action :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 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? render text: t(:warning_attachments_not_saved, attachments[:unsaved].size), status: 400 end end overview.save_custom_element(block_name, block_title, textile) render(partial: "block_textilizable", locals: { user: user, project: project, block_title: block_title, block_name: block_name, textile: textile }) 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] if MyProjectsOverviewsController.available_blocks.keys.include? block render partial: "block", locals: { block_name: block, editing: true } elsif block == "custom_element" new_block = overview.new_custom_element overview.hidden << new_block overview.save! render(partial: "block_textilizable", locals: { user: user, project: project, block_title: l(:label_custom_element), new_block: true, block_name: new_block.first, textile: new_block.last }) else render nothing: true end end ## # Handle saving the changes def save_changes # Save block states %w(top left right hidden).each do |group| active_blocks = param_to_blocks(params[group]) overview.send("#{group}=", active_blocks) end if overview.save flash[:notice] = I18n.t(:notice_successful_update) redirect_to action: :page_layout else render :page_layout end end def param_to_blocks(block_str) blocks = [] block_str.split(',').select do |name| if MyProjectsOverviewsController.available_blocks.keys.include?(name) blocks << name else custom = overview.custom_elements.detect {|ary| ary.first == name } blocks << custom unless custom.nil? end end blocks 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 end def recent_news @news ||= project .news .includes([:author, :project]) .order("#{News.table_name}.created_on DESC") .limit(5) end def types @types ||= project.rolled_up_types end def open_work_packages_by_type @open_work_packages_by_tracker ||= work_packages_by_type .where(statuses: { is_closed: false }) .count end def total_work_packages_by_type @total_work_packages_by_tracker ||= work_packages_by_type.count end def work_packages_by_type WorkPackage .visible .group(:type) .includes([:project, :status, :type]) .where(subproject_condition) end def assigned_work_packages @assigned_issues ||= WorkPackage .visible .open .where(assigned_to: User.current.id) .limit(10) .includes([: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.uniq {|user| user.id} 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(DISTINCT 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 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 = [default_selected_option] MyProjectsOverviewsController.available_blocks.each do |k, v| @block_options << [l("my.blocks.#{v}", default: [v, v.to_s.humanize]), k] end @block_options << [l(:label_custom_element), :custom_element] end def default_selected_option [ "--- #{t(:actionview_instancetag_blank_option)} ---", '', { disabled: true, selected: true } ] 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