Ben Ashton
2 years ago
commit
bcf3b8dd7f
1 changed files with 236 additions and 0 deletions
@ -0,0 +1,236 @@
|
||||
#!/usr/bin/env n0m |
||||
$ #!/bin/bash |
||||
Content-Type: text/html |
||||
|
||||
# Constants |
||||
# ========= |
||||
$ true=1; |
||||
$ false=0; |
||||
# |
||||
$ restaurant_file="restaurants.txt"; |
||||
$ title="FeedMe"; |
||||
# |
||||
# Components |
||||
# ========== |
||||
# |
||||
# $1: string: input value |
||||
# $2: number: 0=existing restaurant, 1=new restaurant |
||||
$ restaurant_form () { |
||||
$ enforce_arguments "${FUNCNAME[0]}" "$#" 2; |
||||
$ local icon_class; |
||||
$ if [ "$2" -eq 0 ]; then |
||||
$ icon_class="ri-save-2-fill"; |
||||
$ else |
||||
$ icon_class="ri-add-line"; |
||||
$ fi |
||||
<form class="restaurant-form" method="POST" action=""> |
||||
<input type="hidden" name="old" value="<% $1 %>" /> |
||||
<input type="text" placeholder="Restaurant" name="new" value="<% $1 %>" /> |
||||
<label class="button <% $icon_class %>"> |
||||
$ local action; |
||||
$ if [ "$2" -eq 0 ]; then |
||||
$ action="save"; |
||||
$ else |
||||
$ action="add"; |
||||
$ fi; |
||||
<input type="submit" name="action" value="<% $action %>" /> |
||||
</label> |
||||
$ if [ "$2" -eq 0 ]; then |
||||
<label class="button ri-delete-bin-2-fill"> |
||||
<input type="submit" name="action" value="delete" /> |
||||
</label> |
||||
$ fi |
||||
</form> |
||||
$ } |
||||
# |
||||
# Utility Functions |
||||
# ================= |
||||
# |
||||
# $1: string: function name |
||||
# $2: number: $# |
||||
# $3: number: expected number of arguments |
||||
$ enforce_arguments () { |
||||
$ if [ "$2" -lt "$3" ]; then |
||||
$ printf '%s %s %s\n' 'Function:' "$1" 'called with too few arguments'; |
||||
$ exit 1; |
||||
$ elif [ "$2" -gt "$3" ]; then |
||||
$ printf '%s %s %s\n' 'Function:' "$1" 'called with too many arguments'; |
||||
$ exit 1; |
||||
$ fi; |
||||
$ } |
||||
# |
||||
$ decode_uri () { |
||||
$ local i="${*//+/ }"; |
||||
$ echo -e "${i//%/\\x}"; |
||||
$ } |
||||
# |
||||
# |
||||
# Restaurant List Functions |
||||
# ========================= |
||||
# |
||||
# $1: string: restaurant to remove |
||||
$ remove_restaurant () { |
||||
$ enforce_arguments "${FUNCNAME[0]}" "$#" 1; |
||||
$ cat "$restaurant_file" | grep -Fxv "$1" | tee "$restaurant_file" >/dev/null; |
||||
$ } |
||||
# |
||||
# $1: string: restuarant to add |
||||
$ add_restaurant () { |
||||
$ enforce_arguments "${FUNCNAME[0]}" "$#" 1; |
||||
$ cat "$restaurant_file" |\ |
||||
$ (grep -Fxv "$1"; printf '%s\n' "$1") |\ |
||||
$ tee "$restaurant_file" >/dev/null; |
||||
$ } |
||||
# |
||||
# $1 (optional): number: 0=don't overwrite, 1=overwrite |
||||
$ todays_restaurant () { |
||||
$ local today="$(date +'%Y%m%d')"; |
||||
$ local filename="$today.pick"; |
||||
$ if [ -n "$1" ] && [ "$1" -ne 0 ]; then |
||||
$ rm "$filename"; |
||||
$ fi; |
||||
$ if [ ! -f "$filename" ]; then |
||||
$ shuf -n 1 "$restaurant_file" > "$filename"; |
||||
$ fi; |
||||
$ cat "$filename"; |
||||
$ } |
||||
# |
||||
# Initialization |
||||
# ============== |
||||
# |
||||
# Make sure restaurant file eixsts |
||||
$ touch -a "$restaurant_file"; |
||||
# |
||||
# Parse body |
||||
# ---------- |
||||
$ declare -A body; |
||||
$ while IFS= read -d '&' -r pair || [ "$pair" ]; do |
||||
$ name=$(decode_uri "${pair%%=*}"); |
||||
$ value=$(decode_uri "${pair#*=}"); |
||||
$ if [ -n "$name" ]; then |
||||
$ body["$name"]="$value"; |
||||
$ fi; |
||||
$ done #> |
||||
# |
||||
# Perform requested action |
||||
# ------------------------ |
||||
$ case "${body['action']}" in |
||||
$ add) |
||||
$ add_restaurant "${body['new']}"; |
||||
$ ;; |
||||
$ delete) |
||||
$ remove_restaurant "${body['old']}"; |
||||
$ ;; |
||||
$ save) |
||||
$ remove_restaurant "${body['old']}"; |
||||
$ add_restaurant "${body['new']}"; |
||||
$ ;; |
||||
$ new_restaurant) |
||||
$ todays_restaurant $true >/dev/null; |
||||
$ ;; |
||||
$ esac |
||||
# |
||||
# |
||||
<!doctype html> |
||||
<html> |
||||
<head> |
||||
<title><% $title %></title> |
||||
<style> |
||||
:root { |
||||
--border-color: gray; |
||||
} |
||||
|
||||
html, body { |
||||
margin: 0; |
||||
padding: 0; |
||||
} |
||||
|
||||
html { |
||||
font-family: sans-serif; |
||||
} |
||||
|
||||
body { |
||||
background-color: #f5f5f5; |
||||
} |
||||
|
||||
\#title { |
||||
color: rgba(0, 0, 0, 0.15); |
||||
text-align: center; |
||||
} |
||||
|
||||
\#content { |
||||
margin: 0 auto; |
||||
width: fit-content; |
||||
min-width: 400px; |
||||
} |
||||
|
||||
\#todays-restaurant { |
||||
text-align: center; |
||||
font-size: 1.3em; |
||||
} |
||||
|
||||
\#restaurant-list { |
||||
list-style-type: none; |
||||
padding: 0; |
||||
} |
||||
|
||||
.restaurant-form { |
||||
display: flex; |
||||
} |
||||
.restaurant-form input[type='text'] { |
||||
flex-grow: 1; |
||||
border: 1px solid var(--border-color); |
||||
padding: 0.4em 0.7em; |
||||
} |
||||
.restaurant-form label.button { |
||||
border-radius: 0; |
||||
} |
||||
.restaurant-form > :not(:first-child) { |
||||
border-left: 0; |
||||
} |
||||
\#restaurant-list > li:not(:last-child) .restaurant-form > * { |
||||
border-bottom: 0; |
||||
} |
||||
|
||||
label.button { |
||||
display: flex; |
||||
border: 1px solid var(--border-color); |
||||
border-radius: 0.3em; |
||||
padding: 0.2em 0.5em; |
||||
background: #FDFDFD; |
||||
align-items: center; |
||||
} |
||||
label.button > span:first-of-type { |
||||
flex-grow: 1; |
||||
text-align: center; |
||||
} |
||||
label.button > input { |
||||
display: none; |
||||
} |
||||
</style> |
||||
<link |
||||
href="https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css" |
||||
rel="stylesheet" |
||||
> |
||||
</head> |
||||
<body> |
||||
<div id="content"> |
||||
<h1 id="title"><% $title %></h1> |
||||
<p id="todays-restaurant"> |
||||
Today's Restaurant: <strong><$% todays_restaurant %></strong> |
||||
<form method="POST" action=""> |
||||
<label class="button"> |
||||
<span>I want to go somewhere else</span> |
||||
<input type="submit" name="action" value="new_restaurant" /> |
||||
</label> |
||||
</form> |
||||
</p> |
||||
<ul id="restaurant-list"> |
||||
$ while IFS= read -r line || [ "$line" ]; do |
||||
<li><$!% restaurant_form "$line" $false %></li> |
||||
$ done <restaurants.txt #> |
||||
<li><$!% restaurant_form "" $true %></li> |
||||
</ul> |
||||
</div> |
||||
</body> |
||||
</html> |
Loading…
Reference in new issue