www/committers/subscribe.cgi (286 lines of code) (raw):

#!/usr/bin/env ruby PAGETITLE = "ASF Mailing List Subscription Helper" # Wvisible:mail subscribe $LOAD_PATH.unshift '/srv/whimsy/lib' require 'wunderbar' require 'wunderbar/bootstrap' require 'whimsy/asf' require 'whimsy/asf/mlist' FORMAT_NUMBER = 3 # json format number user = ASF::Person.new($USER) # authz handled by httpd # get the possible names of the current, graduated and retired podlings current = [] retired = [] graduated = [] # if no longer a PMC then this is the same as retired ASF::Podling.list.each {|p| names = p['resourceAliases'] # array, may be empty names.push p['resource'] # single string, always present status = p['status'] if status == 'current' current.concat(names) elsif status == 'retired' retired.concat(names) elsif status == 'graduated' graduated.concat(names) end } pmcs = ASF::Committee.pmcs.map(&:mail_list) # hack to get access to pmcs etc define_method(:gettype) do |dom| return :ASF if dom == 'apache.org' host = dom.sub('.apache.org', '') # get the host name return :TLP if pmcs.include? host return :PPMC if current.include? host return :TLP if dom.end_with? '.apache.org' return nil if retired.include? host or graduated.include? host return :ASF end ldap_pmcs = [] # No need to get the info for ASF members ldap_pmcs = user.committees.map(&:mail_list) unless user.asf_member? # Also allow podling private lists to be subscribed by podling owners ldap_pmcs += user.podlings.map(&:mail_list) unless user.asf_member? addrs = user.all_mail listtype = {} # key: list@dom, value: list type: ASF|TLP|PPMC lists = ASF::Mail.cansub(user.asf_member?, ASF.pmc_chairs.include?(user), ldap_pmcs, false) .map { |dom, lname, _list| listid = lname + '@' + dom type = gettype(dom) listtype[listid] = type if type [dom, lname] }.sort.map {|d, l| "#{l}@#{d}"} _html do # better system output styling (errors in red) _style :system _script src: '/assets/bootstrap-select.js' _link rel: 'stylesheet', href: '/assets/bootstrap-select.css' _body? do _whimsy_body( title: PAGETITLE, subtitle: 'Mailing List Subscriptions', related: { 'https://www.apache.org/foundation/mailinglists.html' => 'Apache Mailing List Info Page (How-to Subscribe Manually)', 'https://lists.apache.org' => 'Apache Mailing List Archives', '/committers/moderationhelper.cgi' => 'Mailing List Moderation Helper', '/roster/committer/__self__' => 'Your Committer Details (and subscriptions)' }, helpblock: -> { _p 'The below form allows Apache committers to automatically subscribe to, or unsubscribe from, most ASF mailing lists.' _p do _span.text_info 'Note:' _ 'Only email address(es) associated with your Apache ID are listed here. To' _span.strong 'change your associated email addresses' _ ', login to ' _a 'your Whimsy personal details page', href: "https://whimsy.apache.org/roster/committer/__self__" _ 'where you can change your Forwarding Address(es) and alternate email addresses you may use.' end _p 'ASF members can use this form to subscribe to most private lists. PMC chairs can subscribe to board lists. (P)PMC members can subscribe to their private@ list.' _p 'The subscription request will be queued and should be processed within about an hour.' _p do _ 'To subscribe to other private lists, send an email to the list-subscribe@ address and wait for the request to be manually approved.' _ 'This might take a day or two.' end _p do _ 'To view all your existing subscriptions (and email addresses), see your' _a 'committer details', href: '/roster/committer/__self__' _ '.' end } ) do _form method: 'post' do _input type: 'hidden', name: 'request', value: 'sub' _fieldset do _legend 'Subscribe To A List' _label 'Select a mailing list first, then select the email address to subscribe to that list.' _ '(The dropdown only shows lists to which you can automatically subscribe)' _br _label 'List name:' _select name: 'list', data_live_search: 'true' do _optgroup label: 'Foundation lists' do lists.find_all { |list| listtype[list] == :ASF }.each do |list| _option list end end _optgroup label: 'Top-Level Projects' do lists.find_all { |list| listtype[list] == :TLP }.each do |list| _option list end end _optgroup label: 'Podlings' do lists.find_all { |list| listtype[list] == :PPMC }.each do |list| _option list end end end _label 'Email:' _select name: 'addr' do addrs.each do |addr| _option addr end end _input type: 'submit', value: 'Submit Request' end end _p do _br _b 'WARNING' _ 'Some providers are known to block our emails as SPAM.' _br _ 'Please see the following for details: ' _a 'email provider issues', href: 'emailissues', target: '_blank' _ ' (opens in new page)' end _p _hr _p _form method: 'post' do _input type: 'hidden', name: 'request', value: 'unsub' _fieldset do _legend 'Unsubscribe From A List' _label 'Select the mailing list first, then select the email address to unsubscribe.' _ '(The dropdown only shows lists to which you are subscribed)' _br # collect subscriptions subscriptions = ASF::MLIST.subscriptions(user.all_mail)[:subscriptions]. select { |listid, _| ASF::Mail.unsubbable? listid}. # can we unsubscribe from this list? group_by {|listid, _mail| listid}. # allow for multiple subs to single list transform_values {|v| v.map(&:last)} # pick out the emails # fill in any missing types subscriptions.each_key do |list| listtype[list] ||= gettype(list.split('@')[-1]) || :ASF end _label 'List name:' _select.ulist! name: 'list', data_live_search: 'true' do _optgroup label: 'Foundation lists' do subscriptions.select { |list, _| listtype[list] == :ASF }.each do |list, emails| _option list, data_emails: emails.join(' ') end end _optgroup label: 'Top-Level Projects' do subscriptions.select { |list, _| listtype[list] == :TLP }.each do |list, emails| _option list, data_emails: emails.join(' ') end end _optgroup label: 'Podlings' do subscriptions.select { |list, _| listtype[list] == :PPMC }.each do |list, emails| _option list, data_emails: emails.join(' ') end end end _label 'Email:' _select.uaddr! name: 'addr' do addrs.each do |addr| _option addr end end _input type: 'submit', value: 'Submit Request' end end _p if _.post? _hr unless addrs.include? @addr and lists.include? @list _h2_.text_danger {_span.label.label_danger 'Invalid Input'} _p 'Both email and list to subscribe to are required!' break end # subreq/unsubreq now accept name@dom # Keep the key for the file name listkey = ASF::Mail.listdom2listkey(@list) # Each user can only subscribe once to each list in each timeslot fn = "#{$USER}-#{listkey}.json" vars = { version: FORMAT_NUMBER, availid: $USER, addr: @addr, listkey: @list, # f3 member_p: user.asf_member?, chair_p: ASF.pmc_chairs.include?(user), } request = JSON.pretty_generate(vars) + "\n" _div.well do if @request == 'unsub' _p 'Submitting unsubscribe request:' else _p 'Submitting subscribe request:' end _pre request end SUBREQ = ASF::SVN.svnpath!('subreq') SUBREQ.sub! '/subreq', '/unsubreq' if @request == 'unsub' rc = 999 Dir.mktmpdir do |tmpdir| # commit using user's credentials if possible, otherwise use whisysvn if not $PASSWORD # should not happen raise ArgumentError.new "Missing credentials" elsif user.asf_member? credentials = {user: $USER, password: $PASSWORD} else # committer has insufficient karma, use the proxy credentials = {user: 'whimsysvn'} end ASF::SVN.svn_('checkout', [SUBREQ, tmpdir], _, credentials) Dir.chdir tmpdir do if File.exist? fn File.write(fn, request + "\n") ASF::SVN.svn('status', '.') else File.write(fn, request + "\n") ASF::SVN.svn('add', fn) end if @request == 'unsub' message = "#{@list} -= #{$USER}" else message = "#{@list} += #{$USER}" end options = credentials.merge({msg: message}) rc = ASF::SVN.svn_('commit', fn, _, options) end end if rc == 0 _div.alert.alert_success role: 'alert' do _p do _span.strong 'Request successfully submitted.' if @request == 'unsub' _ 'You will be unsubscribed within the hour.' else _ 'You will be subscribed within the hour.' end end end else _div.alert.alert_danger role: 'alert' do _p do _span.strong 'Request Failed, see above for details' end end end end end _script %{ $('select').selectpicker({}); function select_emails() { var emails = $('#ulist option:selected').attr('data-emails').split(' '); var oldval = $('#addr').val(); var newval = null; $('#uaddr option').each(function() { if (emails.indexOf($(this).text()) == -1) { this.disabled = true; if (this.textContent == oldval) oldval = null; } else { this.disabled = false; newval = newval || this.textContent; }; }); if (newval && !oldval) { $('#uaddr').val(newval); $('button[data-id=uaddr] .filter-option').text(newval); } $('#uaddr').selectpicker('render'); } select_emails(); $('#ulist').change(function() { select_emails(); }); } end end