whimsical-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From curc...@apache.org
Subject [whimsy] branch master updated: Member private statistics about past board meetings
Date Fri, 23 Mar 2018 15:28:42 GMT
This is an automated email from the ASF dual-hosted git repository.

curcuru pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/whimsy.git


The following commit(s) were added to refs/heads/master by this push:
     new d97bd15  Member private statistics about past board meetings
d97bd15 is described below

commit d97bd15c8578443aa8d18aa35aa7c44ebb4e3422
Author: Shane Curcuru <asf@shanecurcuru.org>
AuthorDate: Fri Mar 23 11:27:30 2018 -0400

    Member private statistics about past board meetings
---
 www/members/board-attend.cgi | 176 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 176 insertions(+)

diff --git a/www/members/board-attend.cgi b/www/members/board-attend.cgi
new file mode 100644
index 0000000..f4a2d3f
--- /dev/null
+++ b/www/members/board-attend.cgi
@@ -0,0 +1,176 @@
+#!/usr/bin/env ruby
+PAGETITLE = "Board Meeting Attendance since 2013" # Wvisible:meeting
+$LOAD_PATH.unshift File.realpath(File.expand_path('../../../lib', __FILE__))
+
+require 'whimsy/asf'
+require 'whimsy/asf/agenda'
+require 'whimsy/public'
+require 'wunderbar/bootstrap'
+require 'json'
+require 'set'
+
+BOARD = ASF::SVN['private/foundation/board']
+IS_DIRECTOR = :director
+APPROVED = 'approved'
+
+# Map director ids->names and ids->initials
+# Only since 2013, once the preapp data in meetings is parseable
+INITIALS = 0
+FIRST_NAME = 1
+DISPLAY_NAME = 2
+DIRECTOR_MAP = {
+  'bdelacretaz' => ['bd', 'Bertrand', 'Bertrand Delacretaz'],
+  'brett' => ['bp', 'Brett', 'Brett Porter'],
+  'curcuru' => ['sc', 'Shane', 'Shane Curcuru'],
+  'cutting' => ['dc', 'Doug', 'Doug Cutting'],
+  'fielding' => ['rf', 'Roy', 'Roy T. Fielding'],
+  'gstein' => ['gs', 'Greg', 'Greg Stein'],
+  'isabel' => ['idf', 'Isabel', 'Isabel Drost-Fromm'],
+  'jim' => ['jj', 'Jim', 'Jim Jagielski'],
+  'ke4qqq' => ['dn', 'David', 'David Nalley'],
+  'markt' => ['mt', 'Mark', 'Mark Thomas'],
+  'marvin' => ['mh', 'Marvin', 'Marvin Humphrey'],
+  'mattmann' => ['cm', 'Chris', 'Chris Mattmann'],
+  'psteitz' => ['ps', 'Phil', 'Phil Steitz'],
+  'rbowen' => ['rb', 'Rich', 'Rich Bowen'],
+  'rgardler' => ['rg', 'Ross', 'Ross Gardler'],
+  'rubys' => ['sr', 'Sam', 'Sam Ruby'],
+  'rvs' => ['rs', 'Roman', 'Roman Shaposhnik'],
+  'tdunning' => ['td', 'Ted', 'Ted Dunning']
+}
+
+# Summarize director attendance and preapps at one meeting into dstats
+# @note that ASF::Board::Agenda has mix of symbols and strings for hash keys
+# @return string if error
+# Side effect: fills in dstats
+#   Each director gets one entry for each meeting they were a director
+def summarize(fname, dstats)
+  meeting = File.basename(fname, '.*')
+  begin
+    agenda = ASF::Board::Agenda.parse(File.read(fname.untaint))
+  rescue StandardError => e
+    return "summarize(#{fname}) Agenda parse error: #{e.message} #{e.backtrace[0]}"
+  end
+  begin
+    people = agenda[1]['people']
+  rescue StandardError => e
+    return "summarize(#{fname}) no attendance error: #{e.message} #{e.backtrace[0]}"
+  end
+  begin
+    people.each do |id, att|
+      if IS_DIRECTOR.eql?(att[:role])
+        dstats[id][meeting] = {'present' => att[:attending]}
+      end
+    end
+    reports = agenda.select{ |v| v.has_key?(APPROVED) && ! v.has_key?('missing')
}
+    numreports = reports.length.to_f
+    actions = agenda.select{ |v| v.has_key?(:index) && v[:index] == "Action Items"
}[0]['actions']
+    dstats.each do |id, dirmtg|
+      if dirmtg.has_key?(meeting)
+        dirmtg[meeting]['preapps'] = (reports.select {|v| v[APPROVED].include?(DIRECTOR_MAP[id][INITIALS])}.length
/ numreports).round(3)
+        dirmtg[meeting]['actions'] = actions.select{ |v| v[:owner] == DIRECTOR_MAP[id][FIRST_NAME]
}.length
+      end
+    end
+  rescue StandardError => e
+    return "summarize(#{fname}) process error: #{e.message} #{e.backtrace[0]}"
+  end
+  return nil
+end
+
+# Create summary of director attendance from board minutes (includes private data)
+# Note that prior to Dec 2012 and for F2F meetings, this won't parse
+# @param dir pointing to /foundation/board/archived_agendas
+# @return stats hash of each director's attendance & etc., error array
+def summarize_all(dir = BOARD)
+  summaries = Hash.new{|h,k| h[k] = {} }
+  errors = []
+  Dir[File.join(dir, 'archived_agendas', "board_agenda_201*.txt")].each do |f|
+    e = summarize(f, summaries)
+    errors << e if e
+  end
+  return summaries, errors
+end
+
+# If JSON requested, simply return the data hash
+_json do
+  summaries, errors = summarize_all
+  summaries
+end
+
+# produce HTML
+_html do
+  _whimsy_body(
+    title: PAGETITLE,
+    related: {
+      '/board/minutes' => 'Monthly Board Meeting Minutes (categorized)',
+      'https://www.apache.org/foundation/board/calendar.html' => 'Monthly Board Meeting
Minutes (by date)',
+      '/roster/group/board' => 'Current List of Directors'
+    },
+    helpblock: -> {
+      _ 'This lists statistics about director attendance and report preapprovals at monthly
board meetings since 2013.  Before 2013, the preapproval data isn\'t easily parseable.'
+    }
+  ) do
+    datums = JSON.parse(File.read(File.join(BOARD, 'scripts', 'board-attend.json')))
+    months = Set.new()
+    datums.each do |id, data|
+      data.keys.each do |m|
+        months << m
+      end
+    end
+    _whimsy_panel_table(
+      title: "Director attendance at monthly board meetings",
+      helpblock: -> {
+        _p do 
+          _ "Includes data from #{months.min} to #{months.max} regularly scheduled monthly
board meetings.  Key:"
+          _ul do
+            _li 'Mtgs Attended - # of meetings attended when they were a director'
+            _li 'Mtgs Missed - # of meetings missed when they were a director'
+            _li.text_muted '% Reports Preapp - average %age of reports they pre-approved
in Whimsy (member-private)'
+            _li 'Avg Action Items - average number of Action Items assigned per month'
+          end
+        end
+      }
+    ) do
+      _table.table.table_hover.table_striped do
+        _thead_ do
+          _tr do
+            _th 'Director'
+            _th 'Mtgs Attended'
+            _th 'Mtgs Missed'
+            _th do
+              _span.text_muted '% Reports Preapp'
+            end
+            _th 'Avg Action Items'
+          end
+          _tbody do
+            datums.each do | id, data |
+              totp = 0.0
+              tota = 0.0
+              data.each do |k,v|
+                totp += v['preapps']
+                tota += v['actions']
+              end
+              _tr_ do
+                _td do
+                  _ DIRECTOR_MAP[id][DISPLAY_NAME]
+                end
+                _td do
+                  _ data.select{|k,v| v['present']}.length
+                end
+                _td do
+                  _ data.select{|k,v| !v['present']}.length
+                end
+                _td do
+                  _span.text_muted "#{((totp / data.length)*100).round(0)}%"
+                end
+                _td do
+                  _ (tota / data.length).round(2)
+                end
+              end
+            end
+          end
+        end
+      end
+    end
+  end
+end

-- 
To stop receiving notification emails like this one, please contact
curcuru@apache.org.

Mime
View raw message