From d87e28c811b76a4f9bdcc5b8478f7e7b0db37c8f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Paul=20H=C3=A4nsch?= Date: Thu, 21 Jan 2021 00:37:58 +0100 Subject: [PATCH 1/1] pdf export of course lists --- courses/course_print.sh | 63 ----------------- courses/export_pdf.sh | 123 +++++++++++++++++++++++++++++++++ courses/generate_courselist.sh | 109 ----------------------------- index.cgi | 38 ++++++---- 4 files changed, 147 insertions(+), 186 deletions(-) delete mode 100755 courses/course_print.sh create mode 100755 courses/export_pdf.sh delete mode 100755 courses/generate_courselist.sh diff --git a/courses/course_print.sh b/courses/course_print.sh deleted file mode 100755 index 72ab8b8..0000000 --- a/courses/course_print.sh +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2014 - 2016 Paul Hänsch -# -# This file is part of Confetti. -# -# Confetti is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Confetti is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Confetti. If not, see . - -. ${_EXEC}/templates/text_cards.sh - -echo -E ' -\documentclass[landscape,10pt]{article} -\usepackage[utf8x]{inputenc} -\usepackage{ngerman} -\usepackage{eurosym} -\usepackage[landscape,margin=0.25in]{geometry} -\usepackage{longtable} - -\begin{document} - -\section*{Teilnehmende} -\begin{longtable}{|p{60mm}|l|p{50mm}|p{80mm}|} -\hline - \textbf{'"$(l10n N)"'} & - \textbf{'"$(l10n BDAY)"'} & - \textbf{'"$(l10n TEL)"'} & - \textbf{'"$(l10n NOTE)"'} \\ -\hline -\hline -\endhead -'"$( -list_attendance "$course" |sort -k 2 |while read line; do - cardfile="$(echo "$line" |cut -d\ -f1)" - list_attendee "$cardfile" |sed -r 's:$:\\\\[3ex] \\hline:' -done -)"' -\end{longtable} - -\newpage - -\section*{Termine} -\begin{longtable}{|p{60mm}|c|c|c|c|c|c|c|c|c|c|} -\hline - '"$(get_dates)"' \\ -\hline -\hline -\endhead -'"$( -tex_clean "$(list_attendance "$course")" |sort -k 2 | debug |sed -r 's:^[0-9a-z\.]+ (.+) \(\*[0-9]{4}\)$:\1:;s:$: \& \& \& \& \& \& \& \& \& \& \\\\[3ex] \\hline:' -)"' -\end{longtable} - -\end{document} -' diff --git a/courses/export_pdf.sh b/courses/export_pdf.sh new file mode 100755 index 0000000..7a9a9dd --- /dev/null +++ b/courses/export_pdf.sh @@ -0,0 +1,123 @@ +#!/bin/sh + +. "${_EXEC}/pdiread.sh" +. "$_EXEC/cards/l10n.sh" + +coursefile="${_DATA}/ical/$(GET course)" + +if [ ! -r "$coursefile" ]; then + SET_COOKIE 0 message="Cannot read course file" + REDIRECT /courses/ + return 0 +elif ! mkdir -p "$_DATA/export"; then + SET_COOKIE 0 message="Cannot create export directory" + REDIRECT /courses/ + return 0 +fi + +ics="$(pdi_load "$coursefile")" +htmlfile="${_DATA}/export/$(pdi_value "$ics" SUMMARY |URL |tr / _).html" +pdffile=${htmlfile%.html}.pdf + +pdi_date() { + local pdt y m d H M S Z + [ $# -eq 0 ] && read pdt || pdt="$*" + + case $pdt in + *T*Z) + Z=UTC; pdt="${pdt%Z}";; + TZID=*:*T*) + Z="${pdt%%:*}"; Z=${Z#TZID=}; pdt=${pdt#TZID=*:};; + esac + + y="${pdt%%????T*}" pdt=${pdt#????} + m="${pdt%%??T*}" pdt=${pdt#??} + d="${pdt%%T*}" pdt=${pdt#??T} + H="${pdt%%????}" pdt=${pdt#??} + M="${pdt%%??}" pdt=${pdt#??} + S="${pdt}" pdt='' + + case Z in + UTC) date -d "${y}-${m}-${d} ${H}:${M}:${S} UTC" +%s;; + '') date -d "${y}-${m}-${d} ${H}:${M}:${S}" +%s;; + *) date -d "TZ=\"${Z}\" ${y}-${m}-${d} ${H}:${M}:${S}" +%s;; + esac +} + +get_dates() { + local dts_date rrule rr_int rr_freq rec today="$(date +%Y%m%d)" + + dts_date="$(pdi_value "$ics" DTSTART || printf %s "$today")" + dts_date="${dts_date#TZID=*:}" dts_date="${dts_date%%T*}" + rrule="$(pdi_value "$ics" RRULE)" + rr_int="${rrule##*INTERVAL=}" rr_int="${rr_int%%;*}" + rr_freq="${rrule##*FREQ=}" rr_freq="${rr_freq%%;*}" + + [ "$rr_int" -ge 0 ] || rr_int=1 2>/dev/null + case "$rr_freq" in + YEARLY) rec="$rr_int year";; + MONTHLY) rec="$rr_int month";; + DAILY) rec="$rr_int day";; + WEEKLY) rec="$rr_int week";; + *) rec="$rr_int week";; + esac + + while [ "$dts_date" -lt "$today" ]; do dts_date="$(date -d "${dts_date} + ${rec}" +%Y%m%d)"; done + for n in 1 2 3 4 5 6 7 8 9 10; do + LANG=de_DE.UTF-8 date -d "$dts_date" +"%A, %d. %b." + dts_date="$(date -d "${dts_date} + ${rec}" +%Y%m%d)" + done +} + +"$_EXEC/cgilite/html-sh.sed" <<-EOF |sed -E 's;<(td|th)([^>]*)>;<\1 \2 style="border: 1pt solid\; padding: 1mm 2mm\;">;g' >"$htmlfile" + +[html [head + [meta http-equiv="content-type" content="text/html; charset=utf-8"] + [title] + [meta name="generator" content="Confetti"] + [meta name="created" content="$(date +%FT%T)"] + [meta name="changed" content="$(date +%FT%T)"] + [style type="text/css" + @page { size: 29.7cm 21cm; margin: 1.5cm; } + * { background: inherit; } + body { background: transparent; font-family: Liberation Sans, Sans-Serif; } + + th { white-space: pre; } + th, td { text-align: left; } + ] +][body lang="de_DE" + [table width="100%" + [col width=10*] [col width=5*] [col width=10*] [col width=15*] + [thead + [tr [th . $(l10n N)] [th . $(l10n BDAY)] [th . $(l10n TEL)] [th . $(l10n NOTE)]] + ][tbody + $(grep -F "${coursefile##*/} " "$_DATA/mappings/attendance" |while read discard each; do + vcf="$(pdi_load "$_DATA/vcard/$each")" + tel="$( seq 1 $(pdi_count "$vcf" TEL) |while read n; do + type="$(pdi_attrib "$vcf" TEL $n TYPE)" + [ "$type" ] && type="$(l10n "TYPE=$type"):" + printf '%s %s
' "$type" "$(pdi_value "$vcf" TEL $n)" + done )" + printf '[tr [td .N . %s] [td .BDAY . %s] [td .TEL . %s] [td .NOTE . %s]]\n' \ + "$(pdi_value "$vcf" FN |unescape |HTML)" \ + "$(pdi_value "$vcf" BDAY |unescape |HTML)" \ + "$tel" \ + "$(pdi_value "$vcf" NOTE |unescape |HTML)" + done |sort -k4)] + ] + [table width="100%" style="page-break-before: always;" + [col width=30*] [col width=10*] [col width=10*] [col width=10*] [col width=10*] [col width=10*] [col width=10*] [col width=10*] [col width=10*] [col width=10*] [col width=10*] + [thead + [tr [th ] $(get_dates |xargs -d\\n printf '[th . %s]')] + ][tbody + $(grep -F "${coursefile##*/} " "$_DATA/mappings/attendance" |while read discard each; do + vcf="$(pdi_load "$_DATA/vcard/$each")" + printf '[tr [td .N . %s] [td] [td] [td] [td] [td] [td] [td] [td] [td] [td]]\n' \ + "$(pdi_value "$vcf" FN |unescape |HTML)" + done |sort -k4)] + ] +]] +EOF + +lowriter --convert-to pdf --outdir "$_DATA/export/" "$htmlfile" +REDIRECT "/export/${pdffile##*/}" diff --git a/courses/generate_courselist.sh b/courses/generate_courselist.sh deleted file mode 100755 index d777536..0000000 --- a/courses/generate_courselist.sh +++ /dev/null @@ -1,109 +0,0 @@ -#!/bin/zsh - -# Copyright 2014, 2016, 2017 Paul Hänsch -# -# This file is part of Confetti. -# -# Confetti is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Confetti is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Confetti. If not, see . - -pdflatex="$(where pdflatex |head -n1 || echo false)" -course="${_GET[course]}" -fromdate="${_GET[fromdate]}" -fromdate="$(date -d "$fromdate" +%s)" 2>/dev/null -[ -z "$fromdate" ] && fromdate=$(date +%s) - -. ${_EXEC}/pages/courses.sh -. ${_EXEC}/pages/cards.sh - -tex_clean() { #in dire need for improvement - printf %s "$*" |tr -d '{&}\\"' -} - - -list_attendee() { #Parameter: Cardfile - id="$1" - cardfile="$_DATA/vcard/${id}" - - declare -A values - - if [ -r "$cardfile" ]; then - vcf_parse "$cardfile" - - n=$(printf %s "$values[N]" \ - | sed -rn 's:^([^;]*)(;[^;]*)(;[^;]*)?(;[^;]*)?(;[^;]*)?$:\4 \2 \3 \1 \5:gp' \ - | sed -r 's:,: :;s:;: :g;s: +: :g;s:^ $::;' - ) - fullname="${n:-${values[FN]:-${values[NICKNAME]}}}" - - tel='' - for n in TEL TEL{0..10}; do if (echo "$values[$n]" |grep -Eq '[0-9]'); then - [ -n "$tel" ] && tel="$tel\\newline $(tex_clean "$values[$n]")" || tel="$(tex_clean "$values[$n]")" - fi; done - - note='' - for n in NOTE NOTE{0..10}; do if [ -n "$values[$n]" ]; then - [ -n "$note" ] && note="$note\\newline $(tex_clean "$values[$n]")" || note="$(tex_clean "$values[$n]")" - fi; done - printf '%s & %s & %s & %s\n' \ - "$(tex_clean $fullname)" "$(tex_clean $values[BDAY])" "$tel" "$note" \ - | sed -r ':X;N;$!bX; s;\n;\\newline ;g' - fi -} - -get_dates() { #Parameter: Calendarfile - calendarfile="$_DATA/ical/$course" - - declare -A values - ics_parse "$calendarfile" - - dtstart="$values[DTSTART]" - [ -z "$dtstart" ] && dtstart=$(date +%Y%m%dT%H%M%S) - echo "$dtstart" |case "$dtstart" in - *Z) sed -rn 's:^([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2})([0-9]{2})([0-9]{2})Z$:\1-\2-\3 \4\:\5\:\6 UTC:p';; - TZID*) sed -rn 's:^TZID=(.+)\:([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2})([0-9]{2})([0-9]{2})$:TZ="\1" \2-\3-\4 \5\:\6\:\7:p';; - *) sed -rn 's:^([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2})([0-9]{2})([0-9]{2})$:\1-\2-\3 \4\:\5\:\6:p';; - esac |read dts_date - rrule="$values[RRULE]" - rr_int="$(echo $rrule |sed -rn 's:^.*INTERVAL=([0-9]+)(;.*)?$:\1:p')" - rr_freq="$(echo $rrule |sed -rn 's:^.*FREQ=(YEARLY|MONTHLY|WEEKLY|DAILY)(;.*)?$:\1:p')" - case "$rr_freq" in - YEARLY) rec="$rr_int year";; - MONTHLY) rec="$rr_int month";; - DAILY) rec="$rr_int day";; - *) rec="$rr_int week";; - esac - - next_date="$dts_date" - n=10 - while [ $n -gt 0 ]; do - if [ "$(date -d "$next_date" +%s)" -gt "$(date +%s)" ]; then - dtlist="$dtlist & $(date -d "$next_date" +"%d. %b.")" - n=$(($n - 1)) - fi - next_date="$(date -d "$next_date + $rec" +%Y-%m-%d)" - done - - echo "$dtlist" -} - -if [ -r "${_DATA}/ical/${course}" ]; then - . ${_EXEC}/templates/course_print.sh >"${_DATA}/temp/courselist_${course}.tex" - [ -e "${_DATA}/temp/courselist_${course}.pdf" ] && rm "${_DATA}/temp/courselist_${course}.pdf" - "$pdflatex" -halt-on-error -output-directory "${_DATA}/temp/" "${_DATA}/temp/courselist_${course}.tex" |debug >/dev/null - "$pdflatex" -halt-on-error -output-directory "${_DATA}/temp/" "${_DATA}/temp/courselist_${course}.tex" |debug >/dev/null -fi -if [ -r "${_DATA}/temp/courselist_${course}.pdf" ]; then - echo 'Content-Type: application/x-pdf\n' - cat "${_DATA}/temp/courselist_${course}.pdf" -fi diff --git a/index.cgi b/index.cgi index 5dc55be..0cfa8a3 100755 --- a/index.cgi +++ b/index.cgi @@ -65,17 +65,27 @@ yield_page() { topdir="${_PATH#/}" topdir="/${topdir%%/*}" -if [ "${_PATH}" = / ]; then - REDIRECT /cards/ -elif [ -d "${_EXEC}/${_PATH}" -a -x "${_EXEC}/${_PATH}/index.cgi" ]; then - . "${_EXEC}/${_PATH}/index.cgi" -elif [ ! -d "${_EXEC}/${_PATH}" -a -x "${_EXEC}/${_PATH}" ]; then - . "${_EXEC}/${_PATH}" -elif [ ! -x "${_EXEC}/${_PATH}" -a -r "${_EXEC}/${_PATH}" ]; then - . "$_EXEC/cgilite/file.sh" - FILE "${_EXEC}/${_PATH}" -elif [ -d "${_EXEC}/${topdir}" -a -x "${_EXEC}/${topdir}/index.cgi" ]; then - . "${_EXEC}/${topdir}/index.cgi" -else - printf 'Status: 404 Not Found\r\nContent-Length: 0\r\n\r\n' -fi +case ${_PATH} in + /) REDIRECT /cards/ + ;; + /export/*.pdf) . "$_EXEC/cgilite/file.sh" + FILE "${_DATA}/${_PATH}" "application/pdf" + ;; + /export/*) . "$_EXEC/cgilite/file.sh" + FILE "${_DATA}/${_PATH}" + ;; + *) + if [ -d "${_EXEC}/${_PATH}" -a -x "${_EXEC}/${_PATH}/index.cgi" ]; then + . "${_EXEC}/${_PATH}/index.cgi" + elif [ -f "${_EXEC}/${_PATH}" -a -x "${_EXEC}/${_PATH}" ]; then + . "${_EXEC}/${_PATH}" + elif [ -f "${_EXEC}/${_PATH}" -a -r "${_EXEC}/${_PATH}" ]; then + . "$_EXEC/cgilite/file.sh" + FILE "${_EXEC}/${_PATH}" + elif [ -d "${_EXEC}/${topdir}" -a -x "${_EXEC}/${topdir}/index.cgi" ]; then + . "${_EXEC}/${topdir}/index.cgi" + else + printf '%s\r\n' 'Status: 404 Not Found' 'Content-Length: 0' '' + fi + ;; +esac -- 2.39.2