]> git.plutz.net Git - webpoll/commitdiff
added polling page
authorPaul Hänsch <paul@plutz.net>
Mon, 26 Jul 2021 22:52:14 +0000 (00:52 +0200)
committerPaul Hänsch <paul@plutz.net>
Mon, 26 Jul 2021 22:52:14 +0000 (00:52 +0200)
index.cgi
newdate.sh
poll.sh [new file with mode: 0644]
webpoll.css

index 9037c330099f6bc876743d39888543912bf3058c..0694c6e4d9b5f8c9c9ea8fa3c744149d8a2ece86 100755 (executable)
--- a/index.cgi
+++ b/index.cgi
@@ -11,6 +11,13 @@ _BASE="${_BASE%/}"
 #. "$_EXEC"/session_lock.sh
 . "$_EXEC"/widgets.sh
 
+export MD_HTML="false"
+if [ "$(which awk)" ]; then
+  markdown() { awk -f "$_EXEC/cgilite/markdown.awk"; }
+else
+  markdown() { busybox awk -f "$_EXEC/cgilite/markdown.awk"; }
+fi
+
 PATH_INFO="$(PATH "/${PATH_INFO#${_BASE}}")"
 
 #git init "$_DATA" >/dev/null &
@@ -28,7 +35,7 @@ yield_page(){
       [link rel="stylesheet" type="text/css" href="%s/webpoll.css"]
       [title %s]
     ] [body class="%s"
-  ' "$_BASE" "$_BASE" "$_BASE" "$title" "$page"
+  ' "$_BASE" "$_BASE" "$_BASE" "$(HTML "$title")" "$page"
   cat
   printf '] ]'
   } |"$_EXEC/cgilite/html-sh.sed" -u
@@ -77,6 +84,7 @@ page_home() {
   fi
 }
 page_newdate() { . "$_EXEC"/newdate.sh; }
+page_poll() { . "$_EXEC/poll.sh"; }
 
 case ${PATH_INFO} in
   /favicon.ico) printf '%s\r\n' 'Content-Length: 0' '';;
@@ -85,7 +93,7 @@ case ${PATH_INFO} in
   /) page_home;;
   /*/newdate) page_newdate;;
   /*/newoptions);;
-  *);;
+  /[0-9a-zA-Z:=]???????????????) page_poll;;
 esac
 
 exit 0
index b71bdef063fb6679681cebd533222e7ab4e55e73..b2e35a6b5144c94b602640628a86897cdacc8c5a 100755 (executable)
@@ -116,6 +116,8 @@ if [ "$REQUEST_METHOD" = POST ]; then
   if [ "$(POST cancel)" = cancel ]; then
     rm -- "$file"
     REDIRECT "$_BASE/"
+  elif [ "$(POST post)" = post ]; then
+    REDIRECT "$_BASE${PATH_INFO%/*}"
   else
     REDIRECT "$_BASE$PATH_INFO${month:+?month=}${month}"
   fi
diff --git a/poll.sh b/poll.sh
new file mode 100644 (file)
index 0000000..74fa3e1
--- /dev/null
+++ b/poll.sh
@@ -0,0 +1,160 @@
+#!/bin/sh
+
+id="$(checkid "${PATH_INFO#/}")"
+file="${_DATA}/${id}"
+
+#cancel if poll is invalid
+[ "$id" -a -f "$file" ] || REDIRECT "$_BASE/"
+
+tkey() {
+  # convert time stamps for use in POST keys
+  local str="$1" out
+  while [ "$str" ]; do
+    case $str in
+      :*) out="${out}.";;
+      *) out="${out}${str%"${str#?}"}";;
+    esac
+    str="${str#?}"
+  done
+  printf %s "$out"
+}
+
+timelist() {
+  local dates todall splittimes
+  local date tod todsplit
+
+  if [ "$splittimes" = no -a "$dates" -a "$todall" ]; then
+    for date in $dates; do for tod in $todall; do
+      printf %s\\n "${date}_${tod%-}"
+    done ;done
+
+  elif [ "$splittimes" = no -a "$dates" ]; then
+    for date in $dates; do
+      printf %s\\n "${date}"
+    done
+
+  elif [ "$splittimes" = no -a "$todall" ]; then
+    for tod in $todall; do
+      printf %s\\n "${tod%-}"
+    done
+
+  elif [ "$splittimes" = yes ]; then
+    for date in $dates; do
+      todsplit="$(DBM "$file" get "tod_$date")"
+      [ "$todsplit" ] \
+      && for tod in $todsplit; do printf %s\\n "${date}_${tod%-}"; done \
+      || printf %s\\n "${date}"
+    done
+
+  else
+    return 1
+
+  fi
+}
+
+table_poll() {
+  local splittimes="$(DBM "$file" get splittimes || printf no)"
+  local dates="$(DBM "$file" get dates)"
+  local todall="$(DBM "$file" get todall)"
+  local timelist="$(timelist)"
+  local time date span name
+
+  [ "$timelist" ] || return 1
+
+  printf '[table .poll [thead\n'
+  # date header
+  if [ "$dates" ]; then
+    printf '[tr .dates [th]'
+    for date in $dates; do
+      span=0; for time in $timelist; do case $time in
+        ${date}*) span=$((span + 1));;
+      esac; done
+      date -d "$date" +"[th colspan=\"${span}\" . %A <br/> %B %_d, %Y]";
+    done
+    printf '[th]]\n'
+  fi
+  
+  # tod header
+  if [ "$splittimes" = yes -o "$todall" ]; then
+    printf '[tr .tod [th]'
+    for time in $timelist; do
+      [ "${time#*_}" = "${time}" ] && time="${time}_"
+      printf '[th . %s]' "${time#*_}"
+    done
+    printf '[th]]\n'
+  fi
+
+  printf '][tbody\n'
+
+  { DBM "$file" get participants; printf \\n; } |while read -r name; do
+      yes="$(DBM "$file" get "reply_yes_${name}")"
+       no="$(DBM "$file" get "reply_no_${name}")"
+    maybe="$(DBM "$file" get "reply_maybe_${name}")"
+
+    printf '[tr [th .name . %s]' "$(HTML "$name")"
+    for time in $timelist; do
+      printf %s   "$yes" |grep -qwF "$time" && printf '[td   .yes   Yes]' && continue
+      printf %s    "$no" |grep -qwF "$time" && printf '[td    .no    No]' && continue
+      printf %s "$maybe" |grep -qwF "$time" && printf '[td .maybe Maybe]' && continue
+      printf '[td .missing . ?]'
+    done
+    printf '[td]]'
+  done
+
+  # Submit line
+  printf '[tr .new [td [input name="name" value="" placeholder="Your Name" autocomplete=off]]'
+  for time in $timelist; do
+    time="$(tkey "$time")"
+    printf '[td  [radio "%s"   "yes"   #yes_%s][label   for="yes_%s"   Yes]
+                 [radio "%s"    "no"    #no_%s][label    for="no_%s"    No]
+                 [radio "%s" "maybe" #maybe_%s][label for="maybe_%s" Maybe]
+            ]' "${time}" "${time}" "${time}" \
+               "${time}" "${time}" "${time}" \
+               "${time}" "${time}" "${time}"
+  done
+  printf '[td [submit "new" "new" Submit]]]\n'
+
+  printf ']]'
+}
+
+if [ "$REQUEST_METHOD" = POST ]; then
+  local name="$(POST name |grep -m 1 -xE '.*[^         ].*')"
+  local splittimes="$(DBM "$file" get splittimes || printf no)"
+  local dates="$(DBM "$file" get dates)"
+  local todall="$(DBM "$file" get todall)"
+  local timelist="$(timelist)"
+  local time yes no maybe reply
+
+  if [ "$(POST new)" = new ]; then
+    if [ ! "$name" ]; then
+      REDIRECT "${_BASE}${PATH_INFO}#ERROR_NONAME"
+    elif DBM "$file" get participants |grep -qxF "$name"; then
+      REDIRECT "${_BASE}${PATH_INFO}#ERROR_NAMEEXISTS"
+    fi
+    DBM "$file" append participants "${BR}${name}" || DBM "$file" insert participants "${name}" \
+    || REDIRECT "${_BASE}${PATH_INFO}#ERROR_DBACCESS"
+
+    for time in $timelist; do reply="$(POST "$(tkey "$time")")"; case $reply in
+        yes)   yes="${yes}${yes:+ }${time}";;
+         no)    no="${no}${no:+ }${time}";;
+      maybe) maybe="${maybe}${maybe:+ }${time}";;
+    esac; done
+    DBM "$file" set "reply_yes_${name}" "$yes"
+    DBM "$file" set "reply_no_${name}" "$no"
+    DBM "$file" set "reply_maybe_${name}" "$maybe"
+    REDIRECT "${_BASE}${PATH_INFO}"
+  fi
+  
+else
+  pagename="$(pagename "$id")"
+
+  yield_page "$pagename" poll <<-EOF
+       [form method=POST
+         [section .description
+           [h1 .title $(HTML "$pagename")]
+           $(DBM "$file" get description |markdown)
+         ]
+         $(table_poll || printf '[p Poll parameters are invalid]')
+       ]
+       EOF
+fi
index fafb9f4e5dcf593b4e08b7c3e246c118feb9c618..cfc363be9808115da33df6b412c45539b6fddc82 100644 (file)
@@ -18,6 +18,76 @@ body.home form {
   transform: translate(-50%, -50%);
 }
 
+body.poll form {
+  text-align: center;
+  max-width: 95%;
+}
+body.poll .description {
+  text-align: left;
+  max-width: 50em;
+  padding: 1pt 1em 1em 1em;
+  margin: auto;
+  margin-bottom: 1em;
+  background-color: rgba(255,255,255,.5);
+}
+body.poll .description .title {
+  text-align: center;
+}
+body.poll table {
+  background-color: rgba(255,255,255,.5);
+  border-collapse: collapse;
+  margin: auto;
+  -border: .5pt solid;
+  box-shadow: #000 .25em .25em .5em;
+  border-radius: 2pt;
+}
+body.poll table thead tr.dates th {
+  padding: .25em;
+}
+body.poll table thead tr.tod th {
+  border-width: .5pt;
+  border-style: none solid none solid;
+  padding: .25em;
+}
+body.poll table tbody tr td {
+  text-align: center;
+  border: .5pt solid;
+  padding: 0 .25em;
+}
+body.poll table tbody tr td:first-child,
+body.poll table tbody tr td:last-child,
+body.poll table thead tr th:first-child,
+body.poll table thead tr th:last-child { border: none; }
+
+body.poll table tbody tr th.name  { padding: .25em .5em; text-align: right; }
+body.poll table tbody tr td.yes   { background-color: #AFA; }
+body.poll table tbody tr td.no    { background-color: #FAA; }
+body.poll table tbody tr td.maybe { background-color: #FFA; }
+
+body.poll table td input[type=radio] { display: none; }
+body.poll table td input[type=radio] + label {
+  font-size: .875em;
+  text-decoration: underline;
+  color: #066;
+  padding: .25em;
+  margin: 0;
+}
+body.poll table td input[type=radio]:checked + label {
+  font-weight: bold;
+}
+body.poll table td input[type=radio][value=yes]:checked + label {
+  background-color: #AFA;
+  margin: 0 -1.5pt;
+}
+body.poll table td input[type=radio][value=no]:checked + label {
+  background-color: #FAA;
+  margin: 0 -.75pt;
+}
+body.poll table td input[type=radio][value=maybe]:checked + label {
+  background-color: #FFA;
+  margin: 0 -1.75pt;
+}
+
 body.newdate form {
   text-align: center;
   max-width: 100%;