www/members/mailing_lists.cgi (171 lines of code) (raw):
#!/usr/bin/env ruby
PAGETITLE = "Apache Mailing List Info" # Wvisible:members mail
$LOAD_PATH.unshift '/srv/whimsy/lib'
# parse mailing list flags and try to interpret them
require 'wunderbar'
require 'whimsy/asf'
require 'whimsy/asf/mlist'
require 'wunderbar/bootstrap'
require 'wunderbar/jquery/stupidtable'
FLAGS = %{
-m message moderation (see also -u)
-u user posts (i.e. subscribed or allowed)
-mu allow subscribers to post, moderate all others (submod)
-mU moderate all posts (modall)
-Mu allow subscribers to post, reject all others (subonly)
-MU allow anyone to post (open)
-mz reject if it is not from an apache.org address, then moderate
-Mz reject if sender is not an apache.org address or in LDAP
-s subscriptions are moderated (usually means the list is private)
-x check mime-type, size etc
-y send copy to security@apache.org
-z sender/from address checking: see above
}
# announce@a.o: mUxYz
def type(mu)
{
mu: 'submod',
mU: 'modall',
Mu: 'subonly',
MU: 'open',
}[mu.to_sym]
end
query = ENV['QUERY_STRING'] || ''
params = CGI.parse(query)
filter = nil
# Only allow letters in the query string so it is safe to use
if params['filter'].last =~ %r{^([a-zA-Z]+)$}
# Convert xmU into m.......U..x
sorted = $1.split('').sort_by(&:upcase)
letters = []
letters << sorted[0,1] # first letter needed to start off
sorted.each_cons(2).with_index do |(a, b), i|
gap = (b.upcase.ord - a.upcase.ord - 1)
if gap > 0
gap.times {letters << '.'}
else
raise ArgumentError,"Repeated letters #{[a, b]} not allowed"
end
letters << b
end
filter = Regexp.new(letters.join)
end
listfilter = params['match'].last
mod_counts = ASF::MLIST.list_moderators(nil).first.map {|x,y| [x, y.length]}.to_h
list_types = {}
ASF::MLIST.list_types(true) {|d,l,t| list_types["#{l}@#{d}"] = t}
_html do
_body? do
_whimsy_body(
title: PAGETITLE,
related: {
'https://svn.apache.org/repos/infra/infrastructure/apmail/trunk/bin/EZMLM_FLAGS.txt' =>
'Description of all flags',
'https://svn.apache.org/repos/infra/infrastructure/apmail/trunk/.ezmlmrc' =>
'.ezmlmrc file which interprets the flags',
'http://untroubled.org/ezmlm/man/man1/ezmlm-make.1.html' => 'ezmlm-make(1)',
'https://svn.apache.org/repos/infra/infrastructure/apmail/trunk/bin/makelist-apache.sh' =>
'makelist-apache.sh - script tp create an ASF list; sets up options for ezmlm-make(1)',
'https://svn.apache.org/repos/infra/infrastructure/apmail/trunk/bin' =>
'Location of tools',
},
helpblock: -> {
_h2 'DRAFT - treat information with caution'
_p do
_ "This script shows the flag settings for all mailing lists, and attempts to interpret them."
end
_p %{
'mod count' is the number of moderators for the list.
Lists should ideally have at least 3 moderators to ensure timely responses.
The count is enclosed in [] if the list is 'open' or 'subonly' (and not private(s)),
because posts (and subscriptions) don't need to be moderated in that case.
}
_p %{
Note that there are other settings which affect the behaviour, and the initial behaviour defined
by the flags can be modified by local changes to the editor script.
}
_p do
_ 'The following query attributes can be added to the URL to filter the output:'
_dl do
_dt 'match'
_dd 'Regex match against the full list name, e.g. dev@ or @apache\.'
_dt 'filter'
_dd 'Filter flags; must only contain characters A-Za-z, checks if the provided letters are in flags'
end
_ 'For example:'
_pre '?filter=S&match=private@'
_ 'This should not produce any output as private@ lists should require subscription moderation (s)'
end
_ 'Sample flag meanings'
_pre FLAGS
}
) do
_table.table.table_striped do
_thead_ do
_tr do
_th 'list', data_sort: 'string'
_th 'domain', data_sort: 'string'
_th "flags #{filter}", data_sort: 'string'
_th 'Type (mu)', data_sort: 'string'
_th 'mod count', data_sort: 'int'
_th 'Known (z)', data_sort: 'string'
_th 'Moderate subs(s)', data_sort: 'string'
_th 'Archiver type', data_sort: 'string'
_th 'Filter (x)', data_sort: 'string'
_th 'cc.Security (y)', data_sort: 'string'
end
end
_tbody do
ASF::Mail.parse_flags(filter) do |domain, list, flags|
lad = "#{list}@#{domain}"
next if listfilter and ! lad.include? listfilter
mu = flags.tr('^muMU', '')
_tr do
_td data_sort_value: "#{list}-#{domain}" do
_a list, href: "https://lists.apache.org/list.html?#{lad}", target: '_blank'
end
_td data_sort_value: "#{domain}-#{list}" do
_a domain, href: "https://lists.apache.org/list.html?#{lad}", target: '_blank'
end
_td flags
_td do
_ mu
_ type(mu)
end
count = mod_counts[lad]
if !flags.include?('s') and %w{subonly open}.include? type(mu)
# ensure unmoderated lists are not penalised for having few moderators
_td data_sort_value: count+100 do
_ "[#{count}]"
end
else
if count.to_i < 3
_td class: 'bg-danger' do
_ count
end
else
_td count
end
end
_td flags.include? 'z'
_td flags.include? 's'
_td list_types[lad]
_td flags.include? 'x'
_td flags.include? 'y'
end
end
end
end
_script %{
var table = $(".table").stupidtable();
table.on("aftertablesort", function (event, data) {
var th = $(this).find("th");
th.find(".arrow").remove();
var dir = $.fn.stupidtable.dir;
var arrow = data.direction === dir.ASC ? "↑" : "↓";
th.eq(data.column).append('<span class="arrow">' + arrow +'</span>');
});
}
end
end
end