# You should have received a copy of the GNU Affero General Public License
# along with Confetti. If not, see <http://www.gnu.org/licenses/>.
-mkdir -p "${_DATA}/lock"
+locktimeout=900
+. "$_EXEC"/session_lock.sh
card="$(GET card)"
-lock="$_DATA/lock/${card}/"
cardfile="$_DATA/vcard/$card"
-tempfile="$lock/temp.vcf"
-
filter="$(REF f)"
order="$(REF o)"
-if mkdir "$lock" 2>&-; then
- cp "$cardfile" "$tempfile"
+if tempfile="$(SLOCK "$cardfile" "$locktimeout")"; then
REDIRECT "/cards/?o=${order}&f=${filter}&e=${card}"
+elif [ -f "$tempfile" ]; then
+ SET_COOKIE session message="SESSLOCK"
+ REDIRECT "/cards/?o=${order}&f=${filter}#${card}"
else
SET_COOKIE session message="EDITLOCK"
REDIRECT "/cards/?o=${order}&f=${filter}#${card}"
edit_card(){
local cardfile="$_DATA/vcard/$1"
- local card="$(pdi_load "$cardfile")"
+ local tempfile card
- cat <<-EOF
- [form .card #${cardfile##*/} action="/cards/update_card.sh" method="POST"
- [div .section .basic $(
- edit_item "$card" N GENDER
- [ "$(pdi_count "$card" NICKNAME)" -gt 0 ] \
- && edit_item "$card" NICKNAME
- edit_item "$card" X-ZACK-JOINDATE
- [ "$(pdi_count "$card" X-ZACK-LEAVEDATE)" -gt 0 ] \
- && edit_item "$card" X-ZACK-LEAVEDATE
- card_item "$card" SOUND PHOTO LOGO
- )]
- [div .section .phone $(edit_item "$card" TEL)]
- [div .section .message $(
- edit_item "$card" EMAIL
- [ $(pdi_count "$card" IMPP) -gt 0 ] && edit_item "$card" IMPP
- [ $(pdi_count "$card" URL ) -gt 0 ] && edit_item "$card" URL
- )]
- [div .section .address $(edit_item "$card" ADR)]
- [div .section .note $(edit_item "$card" NOTE)]
- [div .section .attendance
- [h3 $(l10n course_attendance) ] $(
- for course in "$_DATA"/ical/*.ics; do
- printf '[label [input type="checkbox" name="attendance" value="%s" %s] %s]' \
- "${course##*/}" \
- "$(grep -qF "${course##*/} ${cardfile##*/}" "$_DATA/mappings/attendance" \
- && printf 'checked="checked"'
- )" \
- "$(pdi_value "$(pdi_load "$course")" SUMMARY |unescape |HTML)"
- done)
- [h3 $(l10n CATEGORIES) ] $(
- grep -xE '[^ ]+' "$_DATA"/mappings/categories |while read -r cat; do
- printf '[label [input type="checkbox" name="attendance" value="%s" %s] %s]' \
- "$(HTML "$cat")" \
- "$(seq 1 $(pdi_count "$card" CATEGORIES) |while read c; do
- pdi_value "$card" CATEGORIES $c |grep -qxF "$cat" \
- && printf 'checked="checked"' && break
- done)" \
- "$(HTML "$cat")"
- done)
- ]
- [div .control
- [select .item name="newfield"
- [option value="" disabled="disabled" selected="selected" $(l10n edit_addfieldtext)]
- $(for f in ; do
- printf '[option value="%s" %s] ' "$f" "$(l10n "$f")"
- done)
- ]
- [button .item type="submit" name="action" value="addfield" $(l10n edit_addfield)]
- [button .item type="submit" name="action" value="update" $(l10n edit_update)]
- [input type="checkbox" #delete] [label .item for="delete" $(l10n edit_delete)]
- [button .item type="submit" name="action" value="delete"]
- [button .item type="submit" name="action" value="cancel" $(l10n edit_cancel)]
- ]
- [input type="hidden" name="UID" value="$(pdi_value "$card" UID |HTML)"]
- [input type="hidden" name="card" value="${cardfile##*/}"]
- ]
+ . $_EXEC/session_lock.sh
+
+ if ! tempfile="$(CHECK_SLOCK "$cardfile")"; then
+ printf '[div .message %s]' "$(l10n "This card is not set up for editing within this session.")"
+ else
+ card="$(pdi_load "$tempfile")"
+ cat <<-EOF
+ [form .card #${cardfile##*/} action="/cards/update_card.sh" method="POST"
+ [input type="hidden" name="tid" value="$(transid ${tempfile})"]
+ [div .section .basic $(
+ edit_item "$card" N GENDER
+ [ "$(pdi_count "$card" NICKNAME)" -gt 0 ] \
+ && edit_item "$card" NICKNAME
+ edit_item "$card" X-ZACK-JOINDATE
+ [ "$(pdi_count "$card" X-ZACK-LEAVEDATE)" -gt 0 ] \
+ && edit_item "$card" X-ZACK-LEAVEDATE
+ card_item "$card" SOUND PHOTO LOGO
+ )]
+ [div .section .phone $(edit_item "$card" TEL)]
+ [div .section .message $(
+ edit_item "$card" EMAIL
+ [ $(pdi_count "$card" IMPP) -gt 0 ] && edit_item "$card" IMPP
+ [ $(pdi_count "$card" URL ) -gt 0 ] && edit_item "$card" URL
+ )]
+ [div .section .address $(edit_item "$card" ADR)]
+ [div .section .note $(edit_item "$card" NOTE)]
+ [div .section .attendance
+ [h3 $(l10n course_attendance) ] $(
+ for course in "$_DATA"/ical/*.ics; do
+ printf '[label [input type="checkbox" name="attendance" value="%s" %s] %s]' \
+ "${course##*/}" \
+ "$(grep -qF "${course##*/} ${cardfile##*/}" "$_DATA/mappings/attendance" \
+ && printf 'checked="checked"'
+ )" \
+ "$(pdi_value "$(pdi_load "$course")" SUMMARY |unescape |HTML)"
+ done)
+ [h3 $(l10n CATEGORIES) ] $(
+ grep -xE '[^ ]+' "$_DATA"/mappings/categories |while read -r cat; do
+ printf '[label [input type="checkbox" name="attendance" value="%s" %s] %s]' \
+ "$(HTML "$cat")" \
+ "$(seq 1 $(pdi_count "$card" CATEGORIES) |while read c; do
+ pdi_value "$card" CATEGORIES $c |grep -qxF "$cat" \
+ && printf 'checked="checked"' && break
+ done)" \
+ "$(HTML "$cat")"
+ done)
+ ]
+ [div .control
+ [select .item name="newfield"
+ [option value="" disabled="disabled" selected="selected" $(l10n edit_addfieldtext)]
+ $(for f in ; do
+ printf '[option value="%s" %s] ' "$f" "$(l10n "$f")"
+ done)
+ ]
+ [button .item type="submit" name="action" value="addfield" $(l10n edit_addfield)]
+ [button .item type="submit" name="action" value="update" $(l10n edit_update)]
+ [input type="checkbox" #delete] [label .item for="delete" $(l10n edit_delete)]
+ [button .item type="submit" name="action" value="delete"]
+ [button .item type="submit" name="action" value="cancel" $(l10n edit_cancel)]
+ ]
+ [input type="hidden" name="UID" value="$(pdi_value "$card" UID |HTML)"]
+ [input type="hidden" name="card" value="${cardfile##*/}"]
+ ]
EOF
+ fi
}
print_card(){
$(card_item "$card" CATEGORIES)
]
[div .control
- [a .item href="/cards/?e=${cardfile##*/}" $(l10n edit)]
+ [a .item href="/cards/edit_card.sh?card=${cardfile##*/}" $(l10n edit)]
[a .item href="/cards/?x=${cardfile##*/}" $(l10n vcf_export)]
]
]
#!/bin/zsh
-# Copyright 2014, 2016 Paul Hänsch
+# Copyright 2014, 2016, 2019 Paul Hänsch
#
# This file is part of Confetti.
#
# You should have received a copy of the GNU Affero General Public License
# along with Confetti. If not, see <http://www.gnu.org/licenses/>.
-cgi_refdata
+. "$_EXEC/pdiread.sh"
+. "$_EXEC/session_lock.sh"
-filter="&filter=${_REF[filter]}"
-filtertype="&filtertype=${_REF[filtertype]}"
-order="&order=${_REF[order]}"
+filter="$(REF f)"
+order="$(REF o)"
-card="${_POST[card]}"
-tempfile="$_DATA/temp/$card"
+card="$(POST card)"
cardfile="$_DATA/vcard/$card"
attfile="$_DATA/mappings/attendance"
+if ! tempfile=$(CHECK_SLOCK "$cardfile"); then
+ SET_COOKIE 0 message="NO VALID FILE LOCK"
+ REDIRECT "/cards/?o=${order}&f=${filter}&e=${card}"
+ exit 0
+elif [ "$(POST tid)" != "$(transid "$tempfile")" ]; then
+ SET_COOKIE 0 message="INVALID TRANSACTION ID"
+ REDIRECT "/cards/?o=${order}&f=${filter}&e=${card}"
+ exit 0
+fi
+
vcf_escape(){
for each in "$@"; do
printf %s\\n "$each" \
- | sed -r ':X;$!{N;bX}; s;\r\n;\n;g; s;([;,\\]);\\\1;g; s;\n;\\n;g;'
+ | sed -E ':X;$!{N;bX}; s;\r\n;\n;g; s;([;,\\]);\\\1;g; s;\n;\\n;g;'
done \
- | sed -r ':X;$!{N;bX}; s;\n;\;;g'
+ | sed -E ':X;$!{N;bX}; s;\n;\;;g'
}
-[ "${_POST[hi_select]}" = "list" ] || _POST[hi_company]="${_POST[hi_other]}"
-[ -n "${_POST[hi_company]}${_POST[hi_number]}${_POST[hi_status]}" ] \
-&& _POST[X-HEALTH-INSURANCE]="$(vcf_escape "${_POST[hi_company]}" "${_POST[hi_number]}" "${_POST[hi_status]}")"
+# [ "${_POST[hi_select]}" = "list" ] || _POST[hi_company]="${_POST[hi_other]}"
+# [ -n "${_POST[hi_company]}${_POST[hi_number]}${_POST[hi_status]}" ] \
+# && _POST[X-HEALTH-INSURANCE]="$(vcf_escape "${_POST[hi_company]}" "${_POST[hi_number]}" "${_POST[hi_status]}")"
-sed -r 's;$;\r;' >"$tempfile" <<EOF
-BEGIN:VCARD
-VERSION:4.0
-N:$(vcf_escape "${_POST[0N]}" "${_POST[1N]}" "${_POST[2N]}" "${_POST[3N]}" "${_POST[4N]}")
-UID:${_POST[UID]}
-$(
- for field in $VCF_FIELDS; do for key in $field $field{0..100}; do
- [ -z "${_POST[$key]+x}" ] && break
- [ -z "${_POST[$key]}" ] && continue
- case "$key" in
- (TEL[0-9]*)
- printf '%s;TYPE=%s:%s\r\n' "${field}" "${_POST[phonetype${key#TEL}]}" "$(vcf_escape "${_POST[$key]}")"
- ;;
- (X-HEALTH-INSURANCE)
- printf '%s:%s\r\n' "${field}" "${_POST[$key]}"
- ;;
+vcf="$(pdi_load "$cardfile")"
+
+vcf="$(pdi_update_value "$vcf" N 1 "$(vcf_escape "$(POST 1N)" "$(POST 2N)" "$(POST 3N)" "$(POST 4N)" "$(POST 5N)")")"
+
+for field in $(POST_KEYS |grep -xE '[A-Z][A-Z0-9-]*'); do
+ for cnt in $(seq 1 $(POST_COUNT "$field")); do
+ case "$field" in
+ # (TEL)
+ # printf '%s;TYPE=%s:%s\r\n' "${field}" "${_POST[phonetype${key#TEL}]}" "$(vcf_escape "$(POST "$field" "$cnt")")"
+ # ;;
(*)
- printf '%s:%s\r\n' "${field}" "$(vcf_escape "${_POST[$key]}")"
+ vcf="$(pdi_update_value "$vcf" "$field" "$cnt" "$(POST "$field" "$cnt")")"
;;
esac
- done; done
- [ "${_POST[action]}" = addfield ] && printf '%s:\r\n' "${_POST[newfield]}"
-)
-END:VCARD
-EOF
+done; done
+[ "$(POST action)" = addfield ] && vcf="$(vcf_update_field "$vcf" "$(POST newfield)" $(($(pdi_count $(POST newfield)) + 1)) '')"
+
+printf '%s' "$vcf" >"$tempfile"
-case "${_POST[action]}" in
+case "$(POST action)" in
addfield)
- redirect "?p=cards${filter}${filtertype}${order}&edit=$card"
+ REDIRECT "/cards/?o=${order}&f=${filter}&e=${card}"
;;
update)
- attendance=()
- for att in attendance attendance{0..100}; do
- [ -n "${_POST[$att]}" ] && attendance+=("${_POST[$att]}")
- done
- sed -rn 's:^(.+)'$card'$:\1:p' "$attfile" |while read course; do
- touch "$_DATA/ical/$course"
- done
- sed -i -r '/^(.+)\t'$card'$/d' "$attfile"
- for each in $attendance; do
- echo "$each\t$card"
- done >>"$attfile"
- sed -rn 's:^(.+)'$card'$:\1:p' "$attfile" |while read course; do
- touch "$_DATA/ical/$course"
- done
+ # attendance=()
+ # for att in attendance attendance{0..100}; do
+ # [ -n "${_POST[$att]}" ] && attendance+=("${_POST[$att]}")
+ # done
+ # sed -rn 's:^(.+)'$card'$:\1:p' "$attfile" |while read course; do
+ # touch "$_DATA/ical/$course"
+ # done
+ # sed -i -r '/^(.+)\t'$card'$/d' "$attfile"
+ # for each in $attendance; do
+ # echo "$each\t$card"
+ # done >>"$attfile"
+ # sed -rn 's:^(.+)'$card'$:\1:p' "$attfile" |while read course; do
+ # touch "$_DATA/ical/$course"
+ # done
- mv "$tempfile" "$cardfile"
- redirect "?p=cards${filter}${filtertype}${order}#$card"
+ cp "$tempfile" "$cardfile"
+ RELEASE_SLOCK "$cardfile"
+ REDIRECT "/cards/?o=${order}&f=${filter}#${card}"
;;
cancel)
- rm "$tempfile"
+ RELEASE_SLOCK "$cardfile"
[ -f "$cardfile" ] \
- && redirect "?p=cards${filter}${filtertype}${order}#$card" \
- || redirect "?p=cards${filter}${filtertype}${order}"
+ && REDIRECT "/cards/?o=${order}&f=${filter}#${card}" \
+ || REDIRECT "/cards/?o=${order}&f=${filter}"
;;
delete)
- rm "$tempfile" "$cardfile"
- redirect "?p=cards${filter}${filtertype}${order}"
+ rm "$cardfile"
+ RELEASE_SLOCK "$cardfile"
+ REDIRECT "/cards/?o=${order}&f=${filter}"
;;
esac
--- /dev/null
+#!/bin/sh
+
+[ "$include_session_lock" ] && return 0
+include_session_lock="$0"
+
+SLOCK(){
+ local file="$1";
+ local timeout="${2-900}"
+ local lockdir="$_DATA/lock/${file#$_DATA}"; lockdir="${lockdir%/}"
+ local ovlock="${lockdir%/*}/delete.${lockdir##*/}"
+ local tempfile="$lockdir/${SESSION_ID}"
+ local lockexpire=$(( $(date +%s) - timeout ))
+
+ mkdir -p "$_DATA/lock/${file%/*}"
+
+ if [ -e "$lockdir" ] \
+ && [ "$(stat -c %Y "$lockdir")" -lt "$lockexpire" ] \
+ && mkdir "$ovlock"; then
+ [ "$(stat -c %Y "$lockdir")" -lt "$lockexpire" ] \
+ && rm -r "$lockdir"
+ rmdir "$ovlock"
+ fi
+
+ printf '%s\n' "$tempfile"
+ if mkdir "$lockdir" 2>&-; then
+ cp "$file" "$tempfile"
+ return 0
+ else
+ return 1
+ fi
+}
+
+CHECK_SLOCK(){
+ local file="$1";
+ local lockdir="$_DATA/lock/${file#$_DATA}"; lockdir="${lockdir%/}"
+ local tempfile="$lockdir/${SESSION_ID}"
+
+ printf '%s\n' "$tempfile"
+ if [ -f "$tempfile" ]; then
+ touch "$lockdir"
+ return 0
+ else
+ return 1
+ fi
+}
+
+RELEASE_SLOCK(){
+ local file="$1";
+ local lockdir="$_DATA/lock/${file#$_DATA}"; lockdir="${lockdir%/}"
+ local ovlock="${lockdir%/*}/delete.${lockdir##*/}"
+ local tempfile="$lockdir/${SESSION_ID}"
+
+ if [ -f "$tempfile" ] && mkdir "$ovlock"; then
+ [ -f "$tempfile" ] && rm -r "$lockdir"
+ rmdir "$ovlock"
+ return 0
+ else
+ return 1
+ fi
+}