Compare commits
26 commits
9b165490e5
...
85af3fcff3
Author | SHA1 | Date | |
---|---|---|---|
85af3fcff3 | |||
8b6e1955ef | |||
2a7fb0d735 | |||
e1bb1885b2 | |||
0a762ccb1d | |||
6915cc0e21 | |||
6947dd37b3 | |||
d24b7c4136 | |||
fabb387ba1 | |||
708268d91d | |||
a9f5fc74e4 | |||
c458dc3900 | |||
dcf6d8937f | |||
15888b7e3e | |||
dc3044026c | |||
ed55660c80 | |||
d0771e130a | |||
6282a934c6 | |||
707bb1d61e | |||
ba2c753109 | |||
2674f08674 | |||
3629844743 | |||
65c7155ba3 | |||
939af54e87 | |||
a64ab232c6 | |||
2baffe570b |
14 changed files with 237 additions and 104 deletions
35
CHANGELOG.md
35
CHANGELOG.md
|
@ -1,14 +1,41 @@
|
||||||
ChangeLog
|
ChangeLog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
1.15
|
1.16.2 - released 2024-05-07
|
||||||
----
|
----------------------------
|
||||||
|
|
||||||
|
* fix rada-ml-pred? in -mlsync
|
||||||
|
|
||||||
|
1.16.1 - released 2024-04-02
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
* add EUR account for paying membership fees to member's page
|
||||||
|
|
||||||
|
1.16 - released 2024-02-09
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
* handle # character at weird positions in DokuWiki users.auth.php
|
||||||
|
* unify -mlsync and -mlcheck handling of member predicates
|
||||||
|
* handle unicode characters with 3-byte UTF-8 representation correctly
|
||||||
|
* calculate expected income with respect to discounts granted
|
||||||
|
* report soon-expiring members in the summary emails
|
||||||
|
* report mailing lists check status in summary emails
|
||||||
|
|
||||||
|
1.15.1 - released 2024-01-02
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
* fix calculating historical membership fee (was erroneously based on
|
||||||
|
current date)
|
||||||
|
* fix showing basic information without MLs loaded
|
||||||
|
|
||||||
|
1.15 - released 2024-12-24
|
||||||
|
--------------------------
|
||||||
|
|
||||||
* increase membership fees starting 2024-01 (specification.rkt)
|
* increase membership fees starting 2024-01 (specification.rkt)
|
||||||
* add support for explicit fee amounts for specified period
|
* add support for explicit fee amounts for specified period
|
||||||
|
|
||||||
1.14
|
1.14 - released 2024-12-06
|
||||||
----
|
--------------------------
|
||||||
|
|
||||||
* add support for dynamic terminal size
|
* add support for dynamic terminal size
|
||||||
* use table cell formatting instead of paragraph formatting everywhere
|
* use table cell formatting instead of paragraph formatting everywhere
|
||||||
|
|
17
src/Makefile
17
src/Makefile
|
@ -42,7 +42,7 @@ HACKERBASE-DEPS=hackerbase.scm cal-month.import.scm \
|
||||||
tests.import.scm notifications.import.scm logging.import.scm \
|
tests.import.scm notifications.import.scm logging.import.scm \
|
||||||
progress.import.scm cal-period.import.scm \
|
progress.import.scm cal-period.import.scm \
|
||||||
util-stdout.import.scm export-web-static.import.scm \
|
util-stdout.import.scm export-web-static.import.scm \
|
||||||
dokuwiki.import.scm
|
dokuwiki.import.scm mailinglist.import.scm
|
||||||
|
|
||||||
HACKERBASE-OBJS=hackerbase.o testing.o listing.o cal-month.o \
|
HACKERBASE-OBJS=hackerbase.o testing.o listing.o cal-month.o \
|
||||||
cal-period.o ansi.o util-bst-ldict.o command-line.o mbase.o \
|
cal-period.o ansi.o util-bst-ldict.o command-line.o mbase.o \
|
||||||
|
@ -59,7 +59,8 @@ HACKERBASE-OBJS=hackerbase.o testing.o listing.o cal-month.o \
|
||||||
template-list-expander.o box-drawing.o export-web-static.o \
|
template-list-expander.o box-drawing.o export-web-static.o \
|
||||||
util-dir.o dokuwiki.o racket-kwargs.o duck.o util-bst.o \
|
util-dir.o dokuwiki.o racket-kwargs.o duck.o util-bst.o \
|
||||||
util-bst-bdict.o util-bst-ldict.o util-bst-lset.o mailman2.o \
|
util-bst-bdict.o util-bst-ldict.o util-bst-lset.o mailman2.o \
|
||||||
mailman-common.o mailman3.o mailman3-sql.o tiocgwinsz.o
|
mailman-common.o mailman3.o mailman3-sql.o tiocgwinsz.o \
|
||||||
|
mailinglist.o
|
||||||
|
|
||||||
GENDOC-SOURCES=gendoc.scm duck-extract.import.scm \
|
GENDOC-SOURCES=gendoc.scm duck-extract.import.scm \
|
||||||
util-time.import.scm util-csv.import.scm util-git.import.scm \
|
util-time.import.scm util-csv.import.scm util-git.import.scm \
|
||||||
|
@ -291,7 +292,7 @@ util-io.o: util-io.import.scm
|
||||||
util-io.import.scm: $(UTIL-IO-SOURCES)
|
util-io.import.scm: $(UTIL-IO-SOURCES)
|
||||||
|
|
||||||
UTIL-PARSER-SOURCES=util-parser.scm testing.import.scm \
|
UTIL-PARSER-SOURCES=util-parser.scm testing.import.scm \
|
||||||
duck.import.scm
|
duck.import.scm racket-kwargs.import.scm
|
||||||
|
|
||||||
util-parser.o: util-parser.import.scm
|
util-parser.o: util-parser.import.scm
|
||||||
util-parser.import.scm: $(UTIL-PARSER-SOURCES)
|
util-parser.import.scm: $(UTIL-PARSER-SOURCES)
|
||||||
|
@ -332,7 +333,8 @@ NOTIFICATIONS-SOURCES=notifications.scm brmember.import.scm \
|
||||||
brmember-format.import.scm configuration.import.scm \
|
brmember-format.import.scm configuration.import.scm \
|
||||||
util-time.import.scm members-fees.import.scm mbase.import.scm \
|
util-time.import.scm members-fees.import.scm mbase.import.scm \
|
||||||
members-print.import.scm table.import.scm \
|
members-print.import.scm table.import.scm \
|
||||||
bank-account.import.scm logging.import.scm
|
bank-account.import.scm logging.import.scm \
|
||||||
|
mailinglist.import.scm
|
||||||
|
|
||||||
notifications.o: notifications.import.scm
|
notifications.o: notifications.import.scm
|
||||||
notifications.import.scm: $(NOTIFICATIONS-SOURCES)
|
notifications.import.scm: $(NOTIFICATIONS-SOURCES)
|
||||||
|
@ -550,3 +552,10 @@ TIOCGWINSZ-SOURCES=tiocgwinsz.scm duck.import.scm
|
||||||
|
|
||||||
tiocgwinsz.o: tiocgwinsz.import.scm
|
tiocgwinsz.o: tiocgwinsz.import.scm
|
||||||
tiocgwinsz.import.scm: $(TIOCGWINSZ-SOURCES)
|
tiocgwinsz.import.scm: $(TIOCGWINSZ-SOURCES)
|
||||||
|
|
||||||
|
MAILINGLIST-SOURCES=mailinglist.scm racket-kwargs.import.scm \
|
||||||
|
mailman.import.scm mbase.import.scm util-string.import.scm \
|
||||||
|
brmember.import.scm
|
||||||
|
|
||||||
|
mailinglist.o: mailinglist.import.scm
|
||||||
|
mailinglist.import.scm: $(MAILINGLIST-SOURCES)
|
||||||
|
|
|
@ -499,8 +499,8 @@
|
||||||
(ldict-equal?
|
(ldict-equal?
|
||||||
(make-brmember '|1234| "members/1234" '(|member|))
|
(make-brmember '|1234| "members/1234" '(|member|))
|
||||||
(make-ldict
|
(make-ldict
|
||||||
`((file-name . |1234|)
|
`((TAG . ,TAG-BRMEMBER)
|
||||||
(TAG . ,TAG-BRMEMBER)
|
(file-name . |1234|)
|
||||||
(file-path . "members/1234")
|
(file-path . "members/1234")
|
||||||
(symlinks |member|)
|
(symlinks |member|)
|
||||||
(id . 1234)))))
|
(id . 1234)))))
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
(users '()))
|
(users '()))
|
||||||
(if (null? lines)
|
(if (null? lines)
|
||||||
users
|
users
|
||||||
(let ((line (parser-preprocess-line (car lines))))
|
(let ((line (parser-preprocess-line (car lines) #:strip-comments? #f)))
|
||||||
(if (equal? line "")
|
(if (equal? line "")
|
||||||
(loop (cdr lines)
|
(loop (cdr lines)
|
||||||
users)
|
users)
|
||||||
|
@ -74,8 +74,8 @@
|
||||||
(handle-exceptions
|
(handle-exceptions
|
||||||
exn
|
exn
|
||||||
(let ()
|
(let ()
|
||||||
(log-warning "DokuWiki: cannot open ~A" fname)
|
(log-warning "DokuWiki (~A) exception ~A" fname (condition->list exn))
|
||||||
(stdout-printf "DokuWiki: cannot open ~A" fname)
|
(stdout-printf "DokuWiki (~A) exception ~A" fname (condition->list exn))
|
||||||
'())
|
'())
|
||||||
(with-input-from-file fname
|
(with-input-from-file fname
|
||||||
parse-dokuwiki-users-auth)))
|
parse-dokuwiki-users-auth)))
|
||||||
|
|
|
@ -101,7 +101,7 @@
|
||||||
(print "<dt>Member ID, Variable Symbol for Payments<br>(Členské číslo, variabilní symbol plateb)</dt><dd>"
|
(print "<dt>Member ID, Variable Symbol for Payments<br>(Členské číslo, variabilní symbol plateb)</dt><dd>"
|
||||||
(brmember-id mr) "</dd>")
|
(brmember-id mr) "</dd>")
|
||||||
(print "<dt>Balance in CZK<br>(Zůstatek v Kč)</dt><dd>" (caar (reverse bhs)) "</dd>")
|
(print "<dt>Balance in CZK<br>(Zůstatek v Kč)</dt><dd>" (caar (reverse bhs)) "</dd>")
|
||||||
(print "<dt>Account for Payments<br>(Účet pro platbu příspěvků)</dt><dd>2500079551/2010</dd>")
|
(print "<dt>Account for Payments<br>(Účet pro platbu příspěvků)</dt><dd>CZK: 2500079551/2010<br>EUR: CZ93 2010 0000 0021 0007 9552</dd>")
|
||||||
(print "</dl>")
|
(print "</dl>")
|
||||||
(print "</div>")
|
(print "</div>")
|
||||||
(print "<div class=\"bi\">")
|
(print "<div class=\"bi\">")
|
||||||
|
|
|
@ -50,7 +50,8 @@
|
||||||
export-web-static
|
export-web-static
|
||||||
dokuwiki
|
dokuwiki
|
||||||
racket-kwargs
|
racket-kwargs
|
||||||
util-string)
|
util-string
|
||||||
|
mailinglist)
|
||||||
|
|
||||||
;; Command-line options and configurable parameters
|
;; Command-line options and configurable parameters
|
||||||
(define -needs-bank- (make-parameter #f))
|
(define -needs-bank- (make-parameter #f))
|
||||||
|
@ -286,32 +287,6 @@
|
||||||
(print " " (car keys) ": " (length (ldict-ref status (car keys)))))
|
(print " " (car keys) ": " (length (ldict-ref status (car keys)))))
|
||||||
(loop (cdr keys)))))))
|
(loop (cdr keys)))))))
|
||||||
|
|
||||||
(define* (check-mailing-list mls name #:pred? (pred? #f))
|
|
||||||
(define ml (find-mailman-list mls name))
|
|
||||||
(when ml
|
|
||||||
(let-values (((missing surplus)
|
|
||||||
(mailman-compare-members ml
|
|
||||||
(mbase-active-emails MB
|
|
||||||
#:suspended #t
|
|
||||||
#:pred? pred?
|
|
||||||
))))
|
|
||||||
(if (null? (cdr ml))
|
|
||||||
(print "Skipping ML check - not loaded")
|
|
||||||
(if (and (null? missing)
|
|
||||||
(null? surplus))
|
|
||||||
(print (format "~a mailing list membership in sync." (string-capitalize name)))
|
|
||||||
(let ()
|
|
||||||
(print (format "~a mailing list:" (string-capitalize name)))
|
|
||||||
(when (not (null? missing))
|
|
||||||
(print " Missing: " missing))
|
|
||||||
(when (not (null? surplus))
|
|
||||||
(print " Outsiders: " surplus))))))))
|
|
||||||
|
|
||||||
(define (rada-ml-pred? mr)
|
|
||||||
(or (brmember-council? mr)
|
|
||||||
(brmember-chair? mr)
|
|
||||||
(brmember-revision? mr)))
|
|
||||||
|
|
||||||
;; Perform requested action
|
;; Perform requested action
|
||||||
(case (-action-)
|
(case (-action-)
|
||||||
((print-info)
|
((print-info)
|
||||||
|
@ -323,10 +298,7 @@
|
||||||
(let ()
|
(let ()
|
||||||
(print-members-base-table MB)
|
(print-members-base-table MB)
|
||||||
(newline)
|
(newline)
|
||||||
(check-mailing-list MLS "internal")
|
(print-mailing-list-checks MB MLS)
|
||||||
(check-mailing-list MLS "rada"
|
|
||||||
#:pred? rada-ml-pred?)
|
|
||||||
(check-mailing-list MLS "rk" #:pred? brmember-revision?)
|
|
||||||
(print-git-status)))
|
(print-git-status)))
|
||||||
(newline))
|
(newline))
|
||||||
((print-stats)
|
((print-stats)
|
||||||
|
@ -424,8 +396,8 @@
|
||||||
(print-git-status))
|
(print-git-status))
|
||||||
((summary)
|
((summary)
|
||||||
(if (-send-emails-)
|
(if (-send-emails-)
|
||||||
(make+send-summary-email MB)
|
(make+send-summary-email MB MLS)
|
||||||
(make+print-summary-email MB)))
|
(make+print-summary-email MB MLS)))
|
||||||
((list)
|
((list)
|
||||||
(for-each (lambda (mr)
|
(for-each (lambda (mr)
|
||||||
(print (brmember-nick mr)))
|
(print (brmember-nick mr)))
|
||||||
|
|
78
src/mailinglist.scm
Normal file
78
src/mailinglist.scm
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
;;
|
||||||
|
;; mailinglist.scm
|
||||||
|
;;
|
||||||
|
;; Common high-level mailinglist management procedures.
|
||||||
|
;;
|
||||||
|
;; ISC License
|
||||||
|
;;
|
||||||
|
;; Copyright 2023 Brmlab, z.s.
|
||||||
|
;; Dominik Pantůček <dominik.pantucek@trustica.cz>
|
||||||
|
;;
|
||||||
|
;; Permission to use, copy, modify, and/or distribute this software
|
||||||
|
;; for any purpose with or without fee is hereby granted, provided
|
||||||
|
;; that the above copyright notice and this permission notice appear
|
||||||
|
;; in all copies.
|
||||||
|
;;
|
||||||
|
;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
;; WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
;; WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||||
|
;; AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
||||||
|
;; CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||||
|
;; OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
;; NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
;; CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
;;
|
||||||
|
|
||||||
|
(declare (unit mailinglist))
|
||||||
|
|
||||||
|
(module
|
||||||
|
mailinglist
|
||||||
|
(
|
||||||
|
check-mailing-list
|
||||||
|
print-mailing-list-checks
|
||||||
|
|
||||||
|
rada-ml-pred?
|
||||||
|
)
|
||||||
|
|
||||||
|
(import scheme
|
||||||
|
(chicken base)
|
||||||
|
(chicken format)
|
||||||
|
racket-kwargs
|
||||||
|
mailman
|
||||||
|
mbase
|
||||||
|
util-string
|
||||||
|
brmember)
|
||||||
|
|
||||||
|
(define* (check-mailing-list MB mls name #:pred? (pred? #f) #:suspended (suspended #f))
|
||||||
|
(define ml (find-mailman-list mls name))
|
||||||
|
(when ml
|
||||||
|
(let-values (((missing surplus)
|
||||||
|
(mailman-compare-members ml
|
||||||
|
(mbase-active-emails MB
|
||||||
|
#:suspended suspended
|
||||||
|
#:pred? pred?
|
||||||
|
))))
|
||||||
|
(if (null? (cdr ml))
|
||||||
|
(print "Skipping ML check - not loaded")
|
||||||
|
(if (and (null? missing)
|
||||||
|
(null? surplus))
|
||||||
|
(print (format "~a mailing list membership in sync." (string-capitalize name)))
|
||||||
|
(let ()
|
||||||
|
(print (format "~a mailing list:" (string-capitalize name)))
|
||||||
|
(when (not (null? missing))
|
||||||
|
(print " Missing: " missing))
|
||||||
|
(when (not (null? surplus))
|
||||||
|
(print " Outsiders: " surplus))))))))
|
||||||
|
|
||||||
|
(define (print-mailing-list-checks MB MLS)
|
||||||
|
(check-mailing-list MB MLS "internal" #:suspended #t)
|
||||||
|
(check-mailing-list MB MLS "rada"
|
||||||
|
#:pred? rada-ml-pred?)
|
||||||
|
(check-mailing-list MB MLS "rk" #:pred? brmember-revision?))
|
||||||
|
|
||||||
|
(define (rada-ml-pred? mr)
|
||||||
|
(or (brmember-council? mr)
|
||||||
|
(brmember-chair? mr)
|
||||||
|
(brmember-revision? mr)))
|
||||||
|
|
||||||
|
)
|
|
@ -30,6 +30,7 @@
|
||||||
(
|
(
|
||||||
lookup-member-fee
|
lookup-member-fee
|
||||||
member-calendar
|
member-calendar
|
||||||
|
make-member-calendar-entry
|
||||||
member-calendar-first-month
|
member-calendar-first-month
|
||||||
member-calendar-last-month
|
member-calendar-last-month
|
||||||
member-calendar-query
|
member-calendar-query
|
||||||
|
@ -40,12 +41,14 @@
|
||||||
member-calendar->table
|
member-calendar->table
|
||||||
members-summary
|
members-summary
|
||||||
member-calendar-entry->fee
|
member-calendar-entry->fee
|
||||||
|
get-expected-income-string
|
||||||
)
|
)
|
||||||
|
|
||||||
(import scheme
|
(import scheme
|
||||||
(chicken base)
|
(chicken base)
|
||||||
(chicken format)
|
(chicken format)
|
||||||
(chicken sort)
|
(chicken sort)
|
||||||
|
(chicken string)
|
||||||
srfi-1
|
srfi-1
|
||||||
configuration
|
configuration
|
||||||
brmember
|
brmember
|
||||||
|
@ -82,15 +85,17 @@
|
||||||
(if (cal-month>? cm last-month)
|
(if (cal-month>? cm last-month)
|
||||||
(reverse cal)
|
(reverse cal)
|
||||||
(loop (cal-month-add cm)
|
(loop (cal-month-add cm)
|
||||||
(cons (list cm
|
(cons (with-current-month
|
||||||
(with-current-month
|
|
||||||
cm
|
cm
|
||||||
(brmember-flags mr))
|
(make-member-calendar-entry mr))
|
||||||
(with-current-month
|
|
||||||
cm
|
|
||||||
(brmember-spec-fee mr)))
|
|
||||||
cal))))))
|
cal))))))
|
||||||
|
|
||||||
|
;; Assumes current-month is specified correctly
|
||||||
|
(define (make-member-calendar-entry mr)
|
||||||
|
(list (*current-month*)
|
||||||
|
(brmember-flags mr)
|
||||||
|
(brmember-spec-fee mr)))
|
||||||
|
|
||||||
;; Returns the first month of the calendar
|
;; Returns the first month of the calendar
|
||||||
(define (member-calendar-first-month mc)
|
(define (member-calendar-first-month mc)
|
||||||
(caar mc))
|
(caar mc))
|
||||||
|
@ -203,4 +208,25 @@
|
||||||
(cons 0 0)
|
(cons 0 0)
|
||||||
members)))
|
members)))
|
||||||
|
|
||||||
|
(define (get-expected-income-string mb)
|
||||||
|
(let* ((flst
|
||||||
|
(map (compose member-calendar-entry->fee make-member-calendar-entry)
|
||||||
|
(find-members-by-predicate mb brmember-active?)))
|
||||||
|
(amts (sort (delete-duplicates flst) <))
|
||||||
|
(sums
|
||||||
|
(map
|
||||||
|
(lambda (amt)
|
||||||
|
(cons amt
|
||||||
|
(length (filter (lambda (v) (= v amt)) flst))))
|
||||||
|
amts)))
|
||||||
|
(string-append
|
||||||
|
"Expected income: "
|
||||||
|
(string-intersperse (map
|
||||||
|
(lambda (p)
|
||||||
|
(format "~A*~A" (cdr p) (car p)))
|
||||||
|
sums)
|
||||||
|
" + ")
|
||||||
|
" = "
|
||||||
|
(number->string (foldl + 0 (map (lambda (p) (* (car p) (cdr p))) sums))))))
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -500,7 +500,17 @@
|
||||||
(null? (cdr dsa)))
|
(null? (cdr dsa)))
|
||||||
#f
|
#f
|
||||||
(cadr dsa))))
|
(cadr dsa))))
|
||||||
(let* ((members ;; Pass 1
|
(let* ((raw-members
|
||||||
|
(sort
|
||||||
|
(if destroyed?
|
||||||
|
(find-members-by-predicate MB (lambda x #t))
|
||||||
|
(if only-active?
|
||||||
|
(find-members-by-predicate MB (lambda (mr)
|
||||||
|
(brmember-active? mr)))
|
||||||
|
(find-members-by-predicate MB (lambda (mr)
|
||||||
|
(not (brmember-destroyed? mr))))))
|
||||||
|
brmember<?))
|
||||||
|
(members ;; Pass 1
|
||||||
(map
|
(map
|
||||||
(lambda (mr)
|
(lambda (mr)
|
||||||
(let* ((balance (member-balance mr))
|
(let* ((balance (member-balance mr))
|
||||||
|
@ -522,15 +532,7 @@
|
||||||
total
|
total
|
||||||
balance
|
balance
|
||||||
)))
|
)))
|
||||||
(sort
|
raw-members))
|
||||||
(if destroyed?
|
|
||||||
(find-members-by-predicate MB (lambda x #t))
|
|
||||||
(if only-active?
|
|
||||||
(find-members-by-predicate MB (lambda (mr)
|
|
||||||
(brmember-active? mr)))
|
|
||||||
(find-members-by-predicate MB (lambda (mr)
|
|
||||||
(not (brmember-destroyed? mr))))))
|
|
||||||
brmember<?)))
|
|
||||||
(balances (map (lambda (m)
|
(balances (map (lambda (m)
|
||||||
(list-ref m 6))
|
(list-ref m 6))
|
||||||
members)))
|
members)))
|
||||||
|
@ -598,19 +600,7 @@
|
||||||
(map (lambda (member)
|
(map (lambda (member)
|
||||||
(min 0 (list-ref member 5)))
|
(min 0 (list-ref member 5)))
|
||||||
members)))
|
members)))
|
||||||
(let* ((ns (foldl (lambda (acc member)
|
(print (get-expected-income-string MB)))))
|
||||||
(cons (+ (car acc) (if (eq? 'student (cadr member)) 1 0))
|
|
||||||
(+ (cdr acc) (if (eq? 'active (cadr member)) 1 0))))
|
|
||||||
(cons 0 0)
|
|
||||||
members))
|
|
||||||
(students (car ns))
|
|
||||||
(full (cdr ns)))
|
|
||||||
(print "Expected income: "
|
|
||||||
(+ (* (lookup-member-fee 'normal) full)
|
|
||||||
(* (lookup-member-fee 'student) students))
|
|
||||||
" (" full " full members + " students " students)"))
|
|
||||||
)
|
|
||||||
))
|
|
||||||
|
|
||||||
(define (unpaired-table mb . args)
|
(define (unpaired-table mb . args)
|
||||||
(apply
|
(apply
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
(chicken format)
|
(chicken format)
|
||||||
(chicken string)
|
(chicken string)
|
||||||
(chicken sort)
|
(chicken sort)
|
||||||
|
(chicken port)
|
||||||
brmember
|
brmember
|
||||||
util-mail
|
util-mail
|
||||||
util-bst-ldict
|
util-bst-ldict
|
||||||
|
@ -54,7 +55,8 @@
|
||||||
table
|
table
|
||||||
bank-account
|
bank-account
|
||||||
logging
|
logging
|
||||||
srfi-1)
|
srfi-1
|
||||||
|
mailinglist)
|
||||||
|
|
||||||
;; Prints email to the console
|
;; Prints email to the console
|
||||||
(define (print-notification-email em)
|
(define (print-notification-email em)
|
||||||
|
@ -142,16 +144,14 @@
|
||||||
(send-notification-email em)))
|
(send-notification-email em)))
|
||||||
|
|
||||||
;; Summary email of membership fees payments
|
;; Summary email of membership fees payments
|
||||||
(define (summary-email-body mb)
|
(define (summary-email-body mb mls)
|
||||||
(let* ((mbs (members-summary mb))
|
(let* ((mbs (members-summary mb))
|
||||||
(students (car mbs))
|
(students (car mbs))
|
||||||
(full (cdr mbs))
|
(full (cdr mbs))
|
||||||
(income (+ (* (lookup-member-fee 'normal) full)
|
(income (+ (* (lookup-member-fee 'normal) full)
|
||||||
(* (lookup-member-fee 'student) students)))
|
(* (lookup-member-fee 'student) students)))
|
||||||
(income-lst
|
(income-lst
|
||||||
(list (format "Expected income: ~A CZK" income)
|
(list (get-expected-income-string mb)))
|
||||||
(format " ~A full members" full)
|
|
||||||
(format " ~A students" students)))
|
|
||||||
(unpaired (mbase-unpaired mb))
|
(unpaired (mbase-unpaired mb))
|
||||||
(unpaired-lst
|
(unpaired-lst
|
||||||
(if (null? unpaired)
|
(if (null? unpaired)
|
||||||
|
@ -160,6 +160,30 @@
|
||||||
(list ""
|
(list ""
|
||||||
"Unpaired transactions:")
|
"Unpaired transactions:")
|
||||||
(unpaired-table mb #:border-style 'ascii))))
|
(unpaired-table mb #:border-style 'ascii))))
|
||||||
|
(soonexps (sort
|
||||||
|
(find-members-by-predicate
|
||||||
|
mb
|
||||||
|
(brmember-suspended-for 21 24))
|
||||||
|
brmember<?))
|
||||||
|
(soonexps-lst
|
||||||
|
(if (null? soonexps)
|
||||||
|
#f
|
||||||
|
(list ""
|
||||||
|
(format "Expiring members (~A): ~A"
|
||||||
|
(length soonexps)
|
||||||
|
(string-intersperse
|
||||||
|
(map
|
||||||
|
(lambda (mr)
|
||||||
|
(brmember-format "~N (~S)" mr))
|
||||||
|
soonexps)
|
||||||
|
",")))))
|
||||||
|
(mlcheck-lst
|
||||||
|
(cons ""
|
||||||
|
(string-split
|
||||||
|
(with-output-to-string
|
||||||
|
(lambda ()
|
||||||
|
(print-mailing-list-checks mb mls)))
|
||||||
|
"\n")))
|
||||||
(debtors (sort
|
(debtors (sort
|
||||||
(members-to-notify mb 1)
|
(members-to-notify mb 1)
|
||||||
brmember<?))
|
brmember<?))
|
||||||
|
@ -256,6 +280,8 @@
|
||||||
", "))))))
|
", "))))))
|
||||||
(append income-lst
|
(append income-lst
|
||||||
unpaired-lst
|
unpaired-lst
|
||||||
|
soonexps-lst
|
||||||
|
mlcheck-lst
|
||||||
debtors-lst
|
debtors-lst
|
||||||
boring-lst
|
boring-lst
|
||||||
dw-lst
|
dw-lst
|
||||||
|
@ -266,21 +292,21 @@
|
||||||
))))
|
))))
|
||||||
|
|
||||||
;; Creates the summary email structure
|
;; Creates the summary email structure
|
||||||
(define (make-summary-email mb)
|
(define (make-summary-email mb mls)
|
||||||
(make-ldict
|
(make-ldict
|
||||||
`((to . ,(*summary-mailto*))
|
`((to . ,(*summary-mailto*))
|
||||||
(subject . ,(format "Členské příspěvky ~A"
|
(subject . ,(format "Členské příspěvky ~A"
|
||||||
(today/iso)))
|
(today/iso)))
|
||||||
(body . ,(summary-email-body mb)))))
|
(body . ,(summary-email-body mb mls)))))
|
||||||
|
|
||||||
;; Just print to standard output
|
;; Just print to standard output
|
||||||
(define (make+print-summary-email mb)
|
(define (make+print-summary-email mb mls)
|
||||||
(let ((em (make-summary-email mb)))
|
(let ((em (make-summary-email mb mls)))
|
||||||
(print-notification-email em)))
|
(print-notification-email em)))
|
||||||
|
|
||||||
;; Actually send emails
|
;; Actually send emails
|
||||||
(define (make+send-summary-email mr)
|
(define (make+send-summary-email mr mls)
|
||||||
(let ((em (make-summary-email mr)))
|
(let ((em (make-summary-email mr mls)))
|
||||||
(send-notification-email em)))
|
(send-notification-email em)))
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
(chicken format))
|
(chicken format))
|
||||||
|
|
||||||
;; Short banner
|
;; Short banner
|
||||||
(define banner-line "HackerBase 1.15.1 (c) 2023 Brmlab, z.s.")
|
(define banner-line "HackerBase 1.16.2 (c) 2023-2024 Brmlab, z.s.")
|
||||||
|
|
||||||
;; Banner source with numbers for ANSI CSI SGR
|
;; Banner source with numbers for ANSI CSI SGR
|
||||||
(define banner-source "
|
(define banner-source "
|
||||||
|
|
|
@ -286,10 +286,12 @@
|
||||||
(call/cc
|
(call/cc
|
||||||
(lambda (cc)
|
(lambda (cc)
|
||||||
(set! break cc)
|
(set! break cc)
|
||||||
(if resume
|
(cond (resume
|
||||||
(resume '())
|
(resume '())
|
||||||
(bst-iter-kv bst yield))
|
(break #f))
|
||||||
#f)))))
|
(else
|
||||||
|
(bst-iter-kv bst yield)
|
||||||
|
(break #f))))))))
|
||||||
|
|
||||||
(define/doc (bst-keys bst)
|
(define/doc (bst-keys bst)
|
||||||
("Returns all the keys contained in given dictionary.")
|
("Returns all the keys contained in given dictionary.")
|
||||||
|
|
|
@ -39,11 +39,12 @@ member file parsers. All functions are UTF-8 aware.")
|
||||||
|
|
||||||
(import scheme
|
(import scheme
|
||||||
(chicken base)
|
(chicken base)
|
||||||
|
racket-kwargs
|
||||||
testing)
|
testing)
|
||||||
|
|
||||||
;; Pass 0: Removes any comments and removes any leading and trailing
|
;; Pass 0: Removes any comments and removes any leading and trailing
|
||||||
;; whitespace.
|
;; whitespace.
|
||||||
(define/doc (parser-preprocess-line line)
|
(define*/doc (parser-preprocess-line line #:strip-comments? (strip-comments? #t))
|
||||||
("* ```line``` - a string with contents of one source line
|
("* ```line``` - a string with contents of one source line
|
||||||
|
|
||||||
If the input ```line``` contains the ```#``` character, the rest of
|
If the input ```line``` contains the ```#``` character, the rest of
|
||||||
|
@ -62,7 +63,9 @@ Returns a string representing the preprocessed line.")
|
||||||
(ploop (add1 pidx)))))
|
(ploop (add1 pidx)))))
|
||||||
(hpos (let hloop ((hidx ppos))
|
(hpos (let hloop ((hidx ppos))
|
||||||
(if (or (= hidx llen)
|
(if (or (= hidx llen)
|
||||||
(eq? (string-ref line hidx) #\#))
|
(and (or strip-comments?
|
||||||
|
(= hidx 0))
|
||||||
|
(eq? (string-ref line hidx) #\#)))
|
||||||
hidx
|
hidx
|
||||||
(hloop (add1 hidx)))))
|
(hloop (add1 hidx)))))
|
||||||
(spos (let sloop ((sidx (sub1 hpos)))
|
(spos (let sloop ((sidx (sub1 hpos)))
|
||||||
|
|
|
@ -120,13 +120,13 @@ of the string and a list of remaining bytes (as integers).")
|
||||||
(define/doc (utf8-bytes->lists chars)
|
(define/doc (utf8-bytes->lists chars)
|
||||||
("The same as above but accepts a list of bytes (as integers).")
|
("The same as above but accepts a list of bytes (as integers).")
|
||||||
(let loop ((bytes chars)
|
(let loop ((bytes chars)
|
||||||
(rpending '())
|
(rpending chars)
|
||||||
(pending 0)
|
(pending 0)
|
||||||
(expected #f)
|
(expected #f)
|
||||||
(res '()))
|
(res '()))
|
||||||
(if (null? bytes)
|
(if (null? bytes)
|
||||||
(values (reverse res)
|
(values (reverse res)
|
||||||
(reverse rpending))
|
rpending)
|
||||||
(let ((byte (car bytes)))
|
(let ((byte (car bytes)))
|
||||||
(cond (expected
|
(cond (expected
|
||||||
;; Decode UTF-8 sequence
|
;; Decode UTF-8 sequence
|
||||||
|
@ -135,14 +135,14 @@ of the string and a list of remaining bytes (as integers).")
|
||||||
(let ((char (integer->char (bitwise-ior pending
|
(let ((char (integer->char (bitwise-ior pending
|
||||||
(bitwise-and byte #b111111)))))
|
(bitwise-and byte #b111111)))))
|
||||||
(loop (cdr bytes)
|
(loop (cdr bytes)
|
||||||
'()
|
(cdr bytes)
|
||||||
0
|
0
|
||||||
#f
|
#f
|
||||||
(cons char res))))
|
(cons char res))))
|
||||||
(else
|
(else
|
||||||
;; Intermediate bytes
|
;; Intermediate bytes
|
||||||
(loop (cdr bytes)
|
(loop (cdr bytes)
|
||||||
(cons byte rpending)
|
rpending
|
||||||
(arithmetic-shift (bitwise-ior pending
|
(arithmetic-shift (bitwise-ior pending
|
||||||
(bitwise-and byte #b111111)) 6)
|
(bitwise-and byte #b111111)) 6)
|
||||||
(sub1 expected)
|
(sub1 expected)
|
||||||
|
@ -152,7 +152,7 @@ of the string and a list of remaining bytes (as integers).")
|
||||||
(cond ((= (bitwise-and byte #b10000000) 0)
|
(cond ((= (bitwise-and byte #b10000000) 0)
|
||||||
;; ASCII
|
;; ASCII
|
||||||
(loop (cdr bytes)
|
(loop (cdr bytes)
|
||||||
'()
|
(cdr bytes)
|
||||||
0
|
0
|
||||||
#f
|
#f
|
||||||
(cons (integer->char byte) res)))
|
(cons (integer->char byte) res)))
|
||||||
|
@ -160,20 +160,20 @@ of the string and a list of remaining bytes (as integers).")
|
||||||
;; First byte of UTF-8 sequence
|
;; First byte of UTF-8 sequence
|
||||||
(let-values
|
(let-values
|
||||||
(((first-byte char-bytes)
|
(((first-byte char-bytes)
|
||||||
(cond ((= (bitwise-and byte #b11000000) #b11000000)
|
(cond ((= (bitwise-and byte #b11100000) #b11000000)
|
||||||
(values (bitwise-and byte #b11111)
|
(values (bitwise-and byte #b11111)
|
||||||
2))
|
2))
|
||||||
((= (bitwise-and byte #b11100000) #b11100000)
|
((= (bitwise-and byte #b11110000) #b11100000)
|
||||||
(values (bitwise-and byte #b1111)
|
(values (bitwise-and byte #b1111)
|
||||||
3))
|
3))
|
||||||
((= (bitwise-and byte #b11110000) #b11110000)
|
((= (bitwise-and byte #b11111000) #b11110000)
|
||||||
(values (bitwise-and byte #b111)
|
(values (bitwise-and byte #b111)
|
||||||
4))
|
4))
|
||||||
(else
|
(else
|
||||||
;; Should not happen
|
;; Should not happen
|
||||||
(values 0 0)))))
|
(values 0 0)))))
|
||||||
(loop (cdr bytes)
|
(loop (cdr bytes)
|
||||||
(list byte)
|
bytes
|
||||||
(arithmetic-shift first-byte 6)
|
(arithmetic-shift first-byte 6)
|
||||||
(sub1 char-bytes)
|
(sub1 char-bytes)
|
||||||
res))))))))))
|
res))))))))))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue