Chris@1464: # encoding: utf-8 Chris@1464: # Chris@1464: # Redmine - project management software Chris@1494: # Copyright (C) 2006-2014 Jean-Philippe Lang Chris@1464: # Chris@1464: # This program is free software; you can redistribute it and/or Chris@1464: # modify it under the terms of the GNU General Public License Chris@1464: # as published by the Free Software Foundation; either version 2 Chris@1464: # of the License, or (at your option) any later version. Chris@1464: # Chris@1464: # This program is distributed in the hope that it will be useful, Chris@1464: # but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@1464: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@1464: # GNU General Public License for more details. Chris@1464: # Chris@1464: # You should have received a copy of the GNU General Public License Chris@1464: # along with this program; if not, write to the Free Software Chris@1464: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. chris@1011: chris@1011: module ActivitiesHelper chris@1011: Chris@1464: def sort_activity_events(events) Chris@1464: events_by_group = events.group_by(&:event_group) Chris@1464: sorted_events = [] Chris@1464: events.sort {|x, y| y.event_datetime <=> x.event_datetime}.each do |event| Chris@1464: if group_events = events_by_group.delete(event.event_group) Chris@1464: group_events.sort {|x, y| y.event_datetime <=> x.event_datetime}.each_with_index do |e, i| Chris@1464: sorted_events << [e, i > 0] Chris@1464: end Chris@1464: end Chris@1464: end Chris@1464: sorted_events Chris@1464: end Chris@1484: chris@1205: def date_of_event(e) chris@1205: if e.respond_to? :updated_at chris@1205: e.updated_at chris@1205: elsif e.respond_to? :updated_on chris@1205: e.updated_on chris@1205: elsif e.respond_to? :created_on chris@1205: e.created_on chris@1205: elsif e.respond_to? :committed_on chris@1205: e.committed_on chris@1205: else chris@1205: nil chris@1205: end chris@1205: end chris@1205: chris@1217: def project_activity_on_events(events) chris@1186: chris@1186: # Score each project for which there are any events, by giving chris@1186: # each event a score based on how long ago it was (the more recent chris@1217: # the better). Return a hash mapping project id to score. chris@1186: chris@1186: projhash = Hash.new chris@1186: chris@1186: events.each do |e| chris@1186: if e.respond_to?(:project) chris@1186: p = e.project chris@1205: d = date_of_event e chris@1205: if !d.nil? chris@1205: dd = Date.parse d.to_s chris@1205: age = Date.today - dd chris@1205: score = (age < 14 ? 15-age : 1) chris@1205: if projhash.key? p chris@1205: projhash[p] += score chris@1205: else chris@1205: projhash[p] = score chris@1205: end chris@1186: end chris@1186: end chris@1186: end chris@1217: projhash chris@1217: end chris@1217: chris@1217: def projects_by_activity(user, count) chris@1217: Chris@1227: # Return up to count of the user's project ids ordered by that user's chris@1217: # recent activity, omitting any projects for which no activity Chris@1219: # occurred in the recent past and any projects not visible to Chris@1219: # the current user chris@1217: Chris@1219: activity = Redmine::Activity::Fetcher.new(User.current, :author => user) chris@1224: chris@1224: # Limit scope so as to exclude issues (which non-members can add) chris@1224: activity.scope = [ "changesets", "files", "documents", "news", "wiki_edits", "messages", "time_entries", "publications" ] chris@1224: chris@1217: days = Setting.activity_days_default.to_i chris@1217: events = activity.events(Date.today - days, Date.today + 1) chris@1217: projhash = project_activity_on_events(events) chris@1217: projhash.keys.sort_by { |k| -projhash[k] }.first(count) chris@1217: end chris@1217: chris@1217: def render_active_colleagues(colleagues) chris@1217: chris@1217: s = "" chris@1217: chris@1222: start = Time.now chris@1222: Chris@1226: my_inst = "" Chris@1226: if ! User.current.ssamr_user_detail.nil? Chris@1226: my_inst = User.current.ssamr_user_detail.institution_name Chris@1226: end Chris@1226: Chris@1227: actives = Hash.new chris@1217: for c in colleagues chris@1217: u = User.find_by_id(c) chris@1217: active_projects = projects_by_activity(u, 3) chris@1217: if !active_projects.empty? Chris@1227: actives[c] = active_projects Chris@1227: end Chris@1227: end Chris@1227: Chris@1227: if actives.empty? Chris@1227: l(:label_no_active_colleagues) Chris@1227: else Chris@1227: Chris@1227: s << "
" Chris@1227: for c in actives.keys.sample(10) Chris@1227: u = User.find_by_id(c) chris@1224: s << "
" Chris@1219: s << avatar(u, :size => '24') Chris@1219: s << "" Chris@1219: s << h(u.name) chris@1217: s << "" Chris@1219: if !u.ssamr_user_detail.nil? Chris@1226: inst = u.ssamr_user_detail.institution_name Chris@1226: if inst != "" and inst != my_inst Chris@1226: s << " - " Chris@1226: s << h(u.ssamr_user_detail.institution_name) Chris@1226: s << "" Chris@1226: end Chris@1219: end chris@1224: s << "
" chris@1224: s << "
" Chris@1219: s << "" Chris@1227: s << (actives[c].map { |p| link_to_project(p) }.join ", ") Chris@1219: s << "" chris@1217: end Chris@1227: s << "
" chris@1222: Chris@1227: finish = Time.now Chris@1227: logger.info "render_active_colleagues: took #{finish-start}" chris@1217: Chris@1330: s.html_safe chris@1217: end chris@1217: end chris@1217: chris@1217: def busy_projects(events, count) chris@1217: chris@1217: # Return a list of count projects randomly selected from amongst chris@1217: # the busiest projects represented by the given activity events chris@1217: chris@1217: projhash = project_activity_on_events(events) chris@1217: chris@1186: # pick N highest values and use cutoff value as selection threshold chris@1186: threshold = projhash.values.sort.last(count).first chris@1186: chris@1186: # select projects above threshold and pick N from them randomly chris@1186: busy = projhash.keys.select { |k| projhash[k] >= threshold }.sample(count) chris@1186: chris@1186: # return projects rather than just ids chris@1011: busy.map { |pid| Project.find(pid) } chris@1011: end chris@1011: chris@1011: def busy_institutions(events, count) Chris@1013: authors = events.map do |e| Chris@1013: e.event_author unless !e.respond_to?(:event_author) Chris@1013: end.compact Chris@1013: institutions = authors.map do |a| Chris@1499: if a.respond_to?(:ssamr_user_detail) and !a.ssamr_user_detail.nil? and a.ssamr_user_detail.institution_name != "none" Chris@1013: a.ssamr_user_detail.institution_name Chris@1013: end Chris@1013: end chris@1011: insthash = institutions.compact.sort.group_by { |i| i } chris@1011: insthash = insthash.merge(insthash) { |k,v| v.length } chris@1011: threshold = insthash.values.sort.last(count).first chris@1011: insthash.keys.select { |k| insthash[k] >= threshold }.sample(count) chris@1011: end chris@1011: chris@1011: end