Command - diff
diff --git a/.exec b/.exec
deleted file mode 100644
index ffc5783..0000000
--- a/.exec
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/ksh
-
-if [[ ! -z "$1" ]]; then
- case "$1" in
- cgit.cgi) exec ./e/cgit.cgi;;
- poem) _see_other /poem/$poem_id;;
- *) NotAllowed;;
- esac
-fi
-
-NotAllowed
diff --git a/components/menu.html b/components/menu.html
index 8448fad..3174a34 100644
--- a/components/menu.html
+++ b/components/menu.html
@@ -1,4 +1,4 @@
-<div class="_ f fic mkn">
- <a class="$RB" href="/e/index">🏠</a>
+<div class="h f fic mt0">
+ <a class="$RB" href="/"><span role="img" aria-label="home">🏠</span></a>
$USER_ICON
</div>
diff --git a/e/cart b/e/cart
deleted file mode 100755
index 148118f..0000000
--- a/e/cart
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/bin/ksh
-
-. $ROOT/lib/auth.sh
-. $ROOT/lib/common.sh
-. $ROOT/lib/shop.sh
-
-EmptyContents() {
- _EMPTY="`_ "Empty"`"
- echo "<div class=\"tsxl tac\">$_EMPTY</div>"
-}
-
-Contents() {
- TOTAL_CART_EXP="`process_cart $CART_PATH`"
- TOTAL="`echo "$TOTAL_CART_EXP" | bc -l`"
- _SUBMIT="`_ Submit`"
- PRODUCTS="`ProductsFromCart -rcart $CART_PATH`"
- PRODUCTS="`Wrap "$PRODUCTS"`"
-
- cat <<!
-<div class="v">
- $PRODUCTS
-</div>
-<div class="tcv fic v">
- <div class="tsxl">$TOTAL€</div>
- <form action="/e/order" method="POST">
- <input type="hidden" name="shop_id" value="$shop_id"></input>
- <button>$_SUBMIT</Button>
- </form>
-</div>
-!
-}
-
-if [[ -z "$shop_id" ]] || [[ ! -d $SHOP_PATH ]]; then
- Fatal 404 Shop not found
-fi
-
-case "$REQUEST_METHOD" in
- POST)
- PRODUCT_PATH=$SHOP_PATH/$product_id
-
- if [[ -z "$product_id" ]] || [[ ! -d "$PRODUCT_PATH" ]]; then
- Fatal 404 Product not found
- fi
-
- if [[ $quantity -lt 0 ]]; then
- Fatal 400 Invalid quantity
- fi
-
- SHOP_OWNER="`cat $SHOP_PATH/.owner`"
- fmkdir $USER_SHOP_PATH
- STOCK="`cat $PRODUCT_PATH/stock`"
- if [[ -f $CART_PATH ]] && cat $CART_PATH | grep -q $product_id; then
- OLD_QUANTITY="`cat $CART_PATH | grep $product_id | awk '{ print $2 }'`"
- else
- OLD_QUANTITY=0
- fi
- AVAILABLE_EXP="$STOCK - ($quantity - $OLD_QUANTITY) >= 0"
- AVAILABLE="`echo $AVAILABLE_EXP | bc`"
-
- [[ "$AVAILABLE" != "0" ]] || Fatal 400 Not enough stock
-
- if [[ "$quantity" == "0" ]]; then
- sed -i "/^$product_id /d" $CART_PATH
- else
- fappend $CART_PATH echo $product_id $quantity
- cat $CART_PATH | awk \
- '{a[$1]=$2} END{for (i in a) print i FS a[i]}' \
- > $ROOT/tmp/cart
- mv $ROOT/tmp/cart $CART_PATH
- fi
-
- case "$return" in
- cart)
- see_other cart ?shop_id=$shop_id
- ;;
- shop)
- see_other shop ?shop_id=$shop_id
- ;;
- product)
- see_other product ?shop_id=$shop_id\&product_id=$product_id
- ;;
- *)
- Fatal 400 "Invalid return"
- ;;
- esac
-
- ;;
-
- GET)
- if [[ -f "$CART_PATH" ]] && [[ ! -z `cat $CART_PATH` ]]; then
- CONTENTS="`Contents`"
- else
- CONTENTS="`EmptyContents`"
- fi
- export CONTENTS
-
- export _TITLE="`_ $shop_id` - `_ Cart`"
-
- NormalCat
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
- ;;
-esac
diff --git a/e/cgit.cgi b/e/cgit.cgi
deleted file mode 100755
index 96ea1c3..0000000
Binary files a/e/cgit.cgi and /dev/null differ
diff --git a/e/class b/e/class
new file mode 100755
index 0000000..3d6b3f3
--- /dev/null
+++ b/e/class
@@ -0,0 +1,70 @@
+#!/bin/ksh
+
+. $ROOT/lib/optional-auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+Courses() {
+ for_each_in "$SCHOOL_PATH/courses" classes "$class_id" \
+ | SmallButtons course \&school_id=$school_id | cond || {
+ echo "<h2>`_ Courses`</h2>"
+ cat $contents | fw 8
+ }
+}
+
+Teacher() {
+ _TEACHER="`_ Teacher`"
+ LabeledIDEdit "$_TEACHER" teacher $teacher_id class $class_id \&school_id=$school_id
+}
+
+AssignGrades() {
+ if im $SCHOOL_OWNER $teacher_id; then
+ ls $SCHOOL_PATH/students | while read student_id; do
+ STUDENT_PATH=$SCHOOL_PATH/students/$student_id
+
+ if grep -q "^$class_id " $STUDENT_PATH/grades; then
+ continue
+ fi
+
+ cat $STUDENT_PATH/courses | while read course_id; do
+ COURSE_PATH=$SCHOOL_PATH/courses/$course_id
+
+ if grep -q $class_id $COURSE_PATH/classes; then
+ echo $student_id
+ fi
+ done
+ done | sort -u | while read student_id; do
+ cat <<!
+<a class="btn c0 ps rs" href="/e/class-grading?school_id=$school_id&class_id=$class_id&student_id=$student_id">
+ $student_id
+</a>
+!
+ done | cond || {
+ echo "<h2>`_ "Assign grades"`</h2>"
+ cat $contents | fw 8
+ }
+ fi
+}
+
+case "$REQUEST_METHOD" in
+ GET)
+ export class_id
+ CLASS_PATH=$SCHOOL_PATH/classes/$class_id
+ teacher_id="`cat $CLASS_PATH/.teacher`"
+ export class_title="`cat $CLASS_PATH/title`"
+ export _SEMESTER="`_ Semester`"
+ export COURSES="`Courses`"
+ export TEACHER="`Teacher`"
+ export ASSIGN_GRADES="`AssignGrades`"
+ export class_semester="`cat $CLASS_PATH/semester`"
+
+ NormalCat ?school_id=$school_id\&class_id=$class_id
+
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
+
+
diff --git a/e/class-add b/e/class-add
new file mode 100755
index 0000000..be6f2f4
--- /dev/null
+++ b/e/class-add
@@ -0,0 +1,39 @@
+#!/bin/ksh
+
+. $ROOT/lib/auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+im $SCHOOL_OWNER || Forbidden
+
+case "$REQUEST_METHOD" in
+ POST)
+ if invalid_id $class_id; then
+ Fatal 400 Not a valid ID
+ fi
+
+ CLASS_PATH="$SCHOOL_PATH/classes/$class_id"
+
+ fmkdir $CLASS_PATH
+ urldecode $teacher | fwrite $CLASS_PATH/.teacher
+ urldecode $class_title | fwrite $CLASS_PATH/title
+ urldecode $semester | fwrite $CLASS_PATH/semester
+
+ see_other class ?school_id=$school_id\&class_id=$class_id
+ ;;
+
+ GET)
+ export _TITLE="`_ "Add class to school"`"
+ export _CLASS_ID="`_ "Class ID"`"
+ export _CLASS_TITLE="`_ "Class Title"`"
+ export _TEACHER="`_ "Teacher"`"
+ export _SEMESTER="`_ "Semester"`"
+ export _SUBMIT="`_ Submit`"
+
+ NormalCat
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/class-grading b/e/class-grading
new file mode 100755
index 0000000..7b6bb99
--- /dev/null
+++ b/e/class-grading
@@ -0,0 +1,34 @@
+#!/bin/ksh
+
+. $ROOT/lib/auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+CLASS_PATH="$SCHOOL_PATH/classes/$class_id"
+teacher_id="`cat $CLASS_PATH/.teacher`"
+
+im $SCHOOL_OWNER $teacher_id || Forbidden
+
+case "$REQUEST_METHOD" in
+ POST)
+ STUDENT_PATH="$SCHOOL_PATH/students/$student_id"
+
+ echo $class_id `urldecode $grade` | fappend $STUDENT_PATH/grades
+
+ see_other class ?school_id=$school_id\&class_id=$class_id
+ ;;
+
+ GET)
+ export _TITLE="`_ "Assign grade to student"`"
+ export _SUBMIT="`_ Submit`"
+ export class_id
+ export student_id
+
+ NormalCat
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
+
diff --git a/e/class-teacher-associate b/e/class-teacher-associate
new file mode 100755
index 0000000..56268b3
--- /dev/null
+++ b/e/class-teacher-associate
@@ -0,0 +1,35 @@
+#!/bin/ksh
+
+. $ROOT/lib/auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+im $SCHOOL_OWNER || Forbidden
+
+case "$REQUEST_METHOD" in
+ POST)
+ CLASS_PATH="$SCHOOL_PATH/classes/$class_id"
+
+ if invalid_s teachers $teacher_id; then
+ Fatal 400 Not a valid ID
+ fi
+
+ echo $teacher_id | fwrite $CLASS_PATH/.teacher
+
+ see_other class ?school_id=$school_id\&class_id=$class_id
+ ;;
+
+ GET)
+ export _TITLE="`_ "Assign teacher to class"`"
+ export _TEACHER_ID="`_ "Teacher ID"`"
+ export _CLASS_ID="`_ "Class ID"`"
+ export _SUBMIT="`_ Submit`"
+ export class_id
+
+ NormalCat
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/classes b/e/classes
new file mode 100755
index 0000000..2ef8983
--- /dev/null
+++ b/e/classes
@@ -0,0 +1,22 @@
+#!/bin/ksh
+
+. $ROOT/lib/optional-auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+case "$REQUEST_METHOD" in
+ GET)
+ export _TITLE="`_ Classes`"
+
+ if im $SCHOOL_OWNER; then
+ export CLASS_ADD="<a class=\"$RB\" href=\"/e/class-add?school_id=$school_id\">+</a>"
+ fi
+
+ export CLASSES="`ls $SCHOOL_PATH/classes | BigButtons class \&school_id=$school_id`"
+ NormalCat
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/course b/e/course
new file mode 100755
index 0000000..c1c6374
--- /dev/null
+++ b/e/course
@@ -0,0 +1,50 @@
+#!/bin/ksh
+
+. $ROOT/lib/optional-auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+COURSE_PATH=$SCHOOL_PATH/courses/$course_id
+
+Classes() {
+ {
+ cat $COURSE_PATH/classes | SmallButtons class \&school_id=$school_id
+ if im $SCHOOL_OWNER; then
+ echo "<a class=\"$RBS\" href=\"/e/course-class-associate?school_id=$school_id&course_id=$course_id\">+</a>"
+ fi
+ } | cond || {
+ echo "<h2>`_ Classes`</h2>"
+ cat $contents | fw 8
+ }
+}
+
+Students() {
+ for_each_in "$SCHOOL_PATH/students" courses "$course_id" \
+ | SmallButtons student \&school_id=$school_id | cond || {
+ echo "<h2>`_ Students`</h2>"
+ cat $contents | fw 8
+ }
+}
+
+Regent() {
+ teacher_id="`cat $COURSE_PATH/.teacher`"
+ _REGENT="`_ Regent`"
+ LabeledIDEdit "$_REGENT" teacher $teacher_id course $course_id \&school_id=$school_id
+}
+
+case "$REQUEST_METHOD" in
+ GET)
+ export course_id
+ export course_title="`cat $COURSE_PATH/title`"
+ export CLASSES="`Classes`"
+ export STUDENTS="`Students`"
+ export REGENT="`Regent`"
+
+ NormalCat ?school_id=$school_id\&course_id=$course_id
+
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/course-add b/e/course-add
new file mode 100755
index 0000000..d793bd1
--- /dev/null
+++ b/e/course-add
@@ -0,0 +1,37 @@
+#!/bin/ksh
+
+. $ROOT/lib/auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+im $SCHOOL_OWNER || Forbidden
+
+case "$REQUEST_METHOD" in
+ POST)
+ if invalid_id $course_id; then
+ Fatal 400 Not a valid ID
+ fi
+
+ COURSE_PATH="$SCHOOL_PATH/courses/$course_id"
+
+ fmkdir $COURSE_PATH
+ echo $teacher_id | fwrite $COURSE_PATH/.teacher
+ urldecode $course_title | fwrite $COURSE_PATH/title
+
+ see_other course ?school_id=$school_id\&course_id=$course_id
+ ;;
+
+ GET)
+ export _TITLE="`_ "Add course to school"`"
+ export _COURSE_ID="`_ "Course ID"`"
+ export _COURSE_TITLE="`_ "Course Title"`"
+ export _REGENT="`_ Regent`"
+ export _SUBMIT="`_ Submit`"
+
+ NormalCat
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/course-class-associate b/e/course-class-associate
new file mode 100755
index 0000000..7c8039a
--- /dev/null
+++ b/e/course-class-associate
@@ -0,0 +1,40 @@
+#!/bin/ksh
+
+. $ROOT/lib/auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+COURSE_PATH="$SCHOOL_PATH/courses/$course_id"
+COURSE_REGENT="`cat $COURSE_PATH/.teacher`"
+
+im $SCHOOL_OWNER $COURSE_REGENT || Forbidden
+
+case "$REQUEST_METHOD" in
+ POST)
+ if invalid_s classes $class_id; then
+ Fatal 400 That class does not exist
+ fi
+
+ if grep -q "$class_id" $COURSE_PATH/classes; then
+ Fatal 400 That class is already assigned to this course
+ fi
+
+ echo $class_id | fappend $COURSE_PATH/classes
+
+ see_other course ?school_id=$school_id\&course_id=$course_id
+ ;;
+
+ GET)
+ export _TITLE="`_ "Assign class to course"`"
+ export _COURSE_ID="`_ "Course ID"`"
+ export _CLASS_ID="`_ "Class ID"`"
+ export _SUBMIT="`_ Submit`"
+ export course_id
+
+ NormalCat
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/course-teacher-associate b/e/course-teacher-associate
new file mode 100755
index 0000000..4847bc5
--- /dev/null
+++ b/e/course-teacher-associate
@@ -0,0 +1,34 @@
+#!/bin/ksh
+
+. $ROOT/lib/auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+im $SCHOOL_OWNER || Forbidden
+
+case "$REQUEST_METHOD" in
+ POST)
+ COURSE_PATH="$SCHOOL_PATH/courses/$course_id"
+
+ if invalid_s teachers $teacher_id; then
+ Fatal 400 Not a valid ID
+ fi
+
+ echo $teacher_id | fwrite $COURSE_PATH/.teacher
+
+ see_other course ?school_id=$school_id\&course_id=$course_id
+ ;;
+
+ GET)
+ export _TITLE="`_ "Assign teacher to course"`"
+ export _TEACHER_ID="`_ "Teacher ID"`"
+ export _SUBMIT="`_ Submit`"
+ export course_id
+
+ NormalCat
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/courses b/e/courses
new file mode 100755
index 0000000..15dc46d
--- /dev/null
+++ b/e/courses
@@ -0,0 +1,23 @@
+#!/bin/ksh
+
+. $ROOT/lib/optional-auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+case "$REQUEST_METHOD" in
+ GET)
+ export _TITLE="`_ Courses`"
+
+ if im $SCHOOL_OWNER; then
+ export COURSE_ADD="<a class=\"$RB\" href=\"/e/course-add?school_id=$school_id\">+</a>"
+ fi
+
+ export COURSES="`ls $SCHOOL_PATH/courses | BigButtons course \&school_id=$school_id`"
+
+ NormalCat
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/image-add b/e/image-add
index 436e46d..b66b9f8 100755
--- a/e/image-add
+++ b/e/image-add
@@ -12,6 +12,8 @@ case "$REQUEST_METHOD" in
fmkdir $USER_IMAGES_PATH
+ [[ ! -f $ROOT/tmp/images ]] || rm $ROOT/tmp/images
+
file_count="`cat $ROOT/tmp/mpfd/file-count`"
for i in `seq 0 $file_count`; do
FILE_PATH=$ROOT/tmp/mpfd/file$i
@@ -19,8 +21,20 @@ case "$REQUEST_METHOD" in
IMAGE_ID="`counter_inc $ROOT/public/img-counter`"
ext="`file -i $FILE_PATH | awk '{print $2}' | tr '/' ' ' | awk '{print $2}'`"
mv $FILE_PATH $USER_IMAGES_PATH/$IMAGE_ID.$ext
+ cd $USER_IMAGES_PATH
+ convert -resize x128 $IMAGE_ID.$ext small-$IMAGE_ID.$ext 2>&1
+ cd - > $ROOT/tmp/null
+ echo /img/$REMOTE_USER/$IMAGE_ID.$ext >> $ROOT/tmp/images
done
+ if [[ "$HTTP_ACCEPT" == "text/plain" ]]; then
+ RESP_CONTENT_TYPE="text/plain"
+ NormalHead 200
+ echo
+ cat $ROOT/tmp/images
+ exit
+ fi
+
see_other images
;;
diff --git a/e/images b/e/images
index 4b51bc1..3fbfd97 100755
--- a/e/images
+++ b/e/images
@@ -5,7 +5,7 @@
Image() {
cat <<!
-<img height="128" class="ofc s_k256 b0" src="http://$HTTP_HOST/img/$1" />
+<img height="128" class="ofc s_k256 b0" src="http://$HTTP_HOST/img/$REMOTE_USER/small-$1" />
!
}
@@ -15,16 +15,14 @@ Images() {
done
}
-find_images() {
- find $1 -type f | sed "s|$1/||"
+ls_images() {
+ ls $ROOT/htdocs/img/$REMOTE_USER | sed '/^small-.*$/d'
}
case "$REQUEST_METHOD" in
GET)
export _TITLE="`_ Images`"
- IMAGES="`find_images $ROOT/htdocs/img | Images`"
- IMAGES="`Wrap $IMAGES`"
- export IMAGES
+ export IMAGES="`ls_images | Images | fw`"
NormalCat
;;
*)
diff --git a/e/images-edit b/e/images-edit
new file mode 100755
index 0000000..98ec1fe
--- /dev/null
+++ b/e/images-edit
@@ -0,0 +1,31 @@
+#!/bin/ksh
+
+. $ROOT/lib/auth.sh
+. $ROOT/lib/common.sh
+
+ls_images() {
+ ls $ROOT/htdocs/img/$REMOTE_USER | sed '/^small-.*$/d'
+}
+
+case "$REQUEST_METHOD" in
+ POST)
+ USER_IMAGES_PATH=$ROOT/htdocs/img/$REMOTE_USER
+
+ ls_images | while read noext; do
+ local qname=delete_$noext
+ eval echo $noext \$$qname
+ done | while read noext state; do
+ [[ "$state" != "on" ]] || rm $USER_IMAGES_PATH/$noext.*
+ done
+
+ RESP_CONTENT_TYPE="text/plain"
+ NormalHead 200
+ echo
+ exit
+
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/index b/e/index
index 5c02e7d..717355f 100755
--- a/e/index
+++ b/e/index
@@ -8,9 +8,12 @@ case "$REQUEST_METHOD" in
export _TITLE="tty.pt"
export _POEMS="`_ Poems`"
export _NEVERDARK="`_ "Never Dark"`"
+ export _SCHOOLS="`_ "Schools"`"
export _SHOPS="`_ "Shops"`"
export _SEM="`_ "Shared Expenses Manager"`"
+ export _SOURCE_CODE="`_ "Source Code"`"
export _TERMINAL="`_ "Terminal"`"
+ export _COMMANDS="`_ "Commands"`"
NormalCat
;;
*)
diff --git a/e/login b/e/login
deleted file mode 100755
index 4bb5914..0000000
--- a/e/login
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/ksh
-
-. $ROOT/lib/optional-auth.sh
-. $ROOT/lib/common.sh
-
-error() {
- echo 'Status: 303 See Other'
- echo "Location: login?error=$1"
- echo
- exit
-}
-
-case "$REQUEST_METHOD" in
- POST)
- username="`urldecode $username`"
- password="`urldecode $password`"
-
- hash="`grep "^$username:" $ROOT/.htpasswd | awk 'BEGIN{FS=":"} {print $2}'`"
- [[ -z "$REMOTE_USER" ]] || rm $ROOT/sessions/$cookie
- [[ ! -z "$hash" ]] || Fatal 400 No such user
-
- if crypt_checkpass "$password" "$hash"; then
- Unauthorized
- fi
-
- [[ ! -f $ROOT/users/$username/rcode ]] \
- || Fatal 400 The account was not activated
-
- TOKEN="`rand_str_1`"
- #[[ -d $ROOT/sessions ]] || mkdir $ROOT/sessions
- echo $username > $ROOT/sessions/$TOKEN
- echo 'Status: 303 See Other'
- echo "Set-Cookie: QSESSION=$TOKEN; SameSite=Lax"
- echo "Location: /e/user"
- #echo "Location: http://$username:$password@$HTTP_HOST/e/user"
- echo
- ;;
- GET)
- export _TITLE="`_ Login`"
- export _REGISTER="`_ "Register"`"
- export _USERNAME="`_ "Username"`"
- export _PASSWORD="`_ "Password"`"
- export _SUBMIT="`_ "Submit"`"
-
- NormalCat
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
- ;;
-esac
diff --git a/e/logout b/e/logout
deleted file mode 100755
index d3b844b..0000000
--- a/e/logout
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/ksh
-
-. $ROOT/lib/auth.sh
-. $ROOT/lib/common.sh
-
-case "$REQUEST_METHOD" in
- GET)
- rm $ROOT/sessions/$cookie
-
- echo 'Status: 303 See Other'
- echo "Set-Cookie: QSESSION=; SameSite=Lax; expires=Thu, 01 Jan 1970 00:00:00 GMT"
- echo "Location: /e/index"
- echo
- exit
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
- ;;
-esac
-
diff --git a/e/order b/e/order
deleted file mode 100755
index e14a7d3..0000000
--- a/e/order
+++ /dev/null
@@ -1,186 +0,0 @@
-#!/bin/ksh
-
-. $ROOT/lib/auth.sh
-. $ROOT/lib/common.sh
-. $ROOT/lib/shop.sh
-. $ROOT/lib/order.sh
-
-AccountInfo() {
- ACCOUNT_IBAN="`zcat $ROOT/users/$SHOP_OWNER/iban`"
-
- if [[ -z "$ACCOUNT_IBAN" ]]; then
- return
- fi
-
- cat <<!
-<div>
- <div>`_ "Account IBAN"`</div>
- <div>$ACCOUNT_IBAN</div>
-</div>
-!
-}
-
-MBWayInfo() {
- PHONE_NUMBER="`zcat $ROOT/users/$SHOP_OWNER/phone_number`"
-
- if [[ -z $PHONE_NUMBER ]]; then
- return
- fi
-
- cat <<!
-<div>
- <span>`_ "Phone number"` (MBWay): </span>
- <a href="tel:$PHONE_NUMBER">$PHONE_NUMBER</a>
-</div>
-!
-}
-
-TransferData() {
- OWNER_PATH=$ROOT/users/$SHOP_OWNER
- OWNER_EMAIL="`cat $OWNER_PATH/email`"
- cat <<!
-<div>`_ "Please refer to the order number in the credit description."` (#$order_id)</div>
-<div>`_ "You can send an e-mail to"` <a href="mailto:$OWNER_EMAIL">$OWNER_EMAIL</a> `_ "to speed up shipment."`</div>
-`AccountInfo`
-`MBWayInfo`
-!
-}
-
-AddressInfo() {
- if [[ "$ORDER_STATE_TEXT" != "Pending_shipment" ]] \
- || [[ "$REMOTE_USER" != "$SHOP_OWNER" ]]; then
- return;
- fi
-
- cat <<!
-<pre>
-`cat $ORDER_PATH/address_line_1`
-`cat $ORDER_PATH/address_line_2`
-`cat $ORDER_PATH/zip`
-</pre>
-
-!
-}
-
-if [[ -z "$shop_id" ]] || [[ ! -d "$SHOP_PATH" ]]; then
- Fatal 404 Shop not found
-fi
-
-SHOP_OWNER="`cat $SHOP_PATH/.owner`"
-DF_USER=$SHOP_OWNER
-
-case "$REQUEST_METHOD" in
- POST)
- if [[ -z "$order_id" ]]; then
- if [[ -z "`zcat $CART_PATH`" ]]; then
- Fatal 404 Cart not found
- fi
-
- if [[ -z "`zcat $USER_PATH/address_line_1`" ]] \
- || [[ -z "`zcat $USER_PATH/address_line_2`" ]] \
- || [[ -z "`zcat $USER_PATH/zip`" ]]; then
- Fatal 400 Invalid shipping address
- fi
-
- ORDERS_PATH=$SHOP_PATH/.orders
- ORDER_ID_PATH=$SHOP_PATH/.orders/.count
- ORDER_ID="`counter_inc $ORDER_ID_PATH`"
- ORDER_PATH=$SHOP_PATH/.orders/$ORDER_ID
-
- fmkdir $ORDERS_PATH
- fmkdir $ORDER_PATH
- fwrite $ORDER_PATH/raw cat $CART_PATH
- fwrite $ORDER_PATH/owner echo $REMOTE_USER
- fwrite $ORDER_PATH/state echo Pending_payment
- fwrite $ORDER_PATH/address_line_1 cat $USER_PATH/address_line_1
- fwrite $ORDER_PATH/address_line_2 cat $USER_PATH/address_line_2
- fwrite $ORDER_PATH/zip cat $USER_PATH/zip
-
- cat $ORDER_PATH/raw | while read product_id quantity; do
- counter_dec $SHOP_PATH/$product_id/stock $quantity
- done >/tmp/null
-
- rm $CART_PATH # TODO also remove unneeded directories?
-
- see_other order ?shop_id=$shop_id\&order_id=$ORDER_ID
- else
- ORDER_PATH=$SHOP_PATH/.orders/$order_id
-
- if [[ "$SHOP_OWNER" != "$REMOTE_USER" ]]; then
- Fatal 401 "You can not do that"
- fi
-
- ORDER_STATE_TEXT="`cat $ORDER_PATH/state`"
- case "$ORDER_STATE_TEXT" in
- Pending_payment)
- ORDER_STATE_TEXT=Pending_shipment
- ;;
- Pending_shipment)
- ORDER_STATE_TEXT=Shipped
- ;;
- Shipped)
- ORDER_STATE_TEXT=Delivered
- ;;
- Delivered)
- rm -rf $ORDER_PATH
- see_other orders ?shop_id=$shop_id
- exit
- ;;
- esac
-
- fwrite $ORDER_PATH/state echo $ORDER_STATE_TEXT
-
- case "$return" in
- order)
- see_other order ?shop_id=$shop_id\&order_id=$order_id
- ;;
- orders)
- see_other orders ?shop_id=$shop_id
- ;;
- esac
- fi
-
- ;;
-
- GET)
- ORDER_PATH=$SHOP_PATH/.orders/$order_id
- if [[ -z "$order_id" ]] || [[ ! -d "$ORDER_PATH" ]]; then
- Fatal 404 Order not found
- fi
-
- SHOP_OWNER="`cat $SHOP_PATH/.owner`"
- ORDER_OWNER="`cat $ORDER_PATH/owner`"
-
- if [[ "$REMOTE_USER" != "$ORDER_OWNER" ]] \
- && [[ "$REMOTE_USER" != "$SHOP_OWNER" ]]; then
-
- Fatal 401 "You can not do that"
- fi
-
- export order_id
-
- export _TITLE="`_ $shop_id` - `_ Order` #$order_id"
-
- TOTAL_EXP="`process_cart $ORDER_PATH/raw`"
- export TOTAL="`echo "$TOTAL_EXP" | bc -l`"
- export PRODUCTS="`ProductsFromCart $ORDER_PATH/raw`"
- ORDER_STATE_TEXT="`cat $ORDER_PATH/state`"
- export ADDRESS_INFO="`AddressInfo`"
- export ORDER_STATE="`OrderState -rorder "$ORDER_STATE_TEXT" $order_id`"
- if [[ "$REMOTE_USER" == "$ORDER_OWNER" ]]; then
- case "$ORDER_STATE_TEXT" in
- Pending_payment)
- TRANSFER_DATA=`TransferData`
- export TRANSFER_DATA
- ;;
- esac
- fi
- NormalCat ?shop_id=$shop_id
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
- ;;
-esac
-
-
diff --git a/e/orders b/e/orders
deleted file mode 100755
index ec689d2..0000000
--- a/e/orders
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/bin/ksh
-
-. $ROOT/lib/auth.sh
-. $ROOT/lib/common.sh
-. $ROOT/lib/shop.sh
-. $ROOT/lib/order.sh
-
-Order() {
- ORDER_PATH=$SHOP_PATH/.orders/$1
- ORDER_OWNER="`cat $ORDER_PATH/owner`"
- TOTAL_EXP="`process_cart $ORDER_PATH/raw`"
- TOTAL="`echo "$TOTAL_EXP" | bc -l`"
- ORDER_STATE_TEXT="`cat $ORDER_PATH/state`"
- ORDER_STATE="`OrderState -rorders "$ORDER_STATE_TEXT" $1`"
-
- cat <<!
-<a href="/e/order?shop_id=$shop_id&order_id=$1" class="b0 p v">
- <span>
- $_ORDER #$1 - $ORDER_OWNER $TOTAL€
- </span>
-
- $ORDER_STATE
-</a>
-!
-}
-
-VendorOrders() {
- ls $SHOP_PATH/.orders | while read line; do
- Order $line
- done
-}
-
-UserOrders() {
- ls $SHOP_PATH/.orders | while read line; do
- ORDER_PATH=$SHOP_PATH/.orders/$line
- ORDER_OWNER="`cat $ORDER_PATH/owner`"
- [[ "$ORDER_OWNER" == "$REMOTE_USER" ]] && Order $line || true
- done
-}
-
-if [[ -z "$shop_id" ]] || [[ ! -d "$SHOP_PATH" ]]; then
- Fatal 404 Shop not found
-fi
-
-case "$REQUEST_METHOD" in
- GET)
- SHOP_OWNER="`cat $SHOP_PATH/.owner`"
-
- ORDERS_PATH=$SHOP_PATH/.orders
-
- export _TITLE="`_ $shop_id` - `_ Orders`"
-
- _ORDER="`_ Order`"
-
- if [[ "$REMOTE_USER" == "$SHOP_OWNER" ]]; then
- ORDERS="`VendorOrders`"
- else
- ORDERS="`UserOrders`"
- fi
-
- ORDERS="`Wrap $ORDERS`"
-
- export ORDERS
- NormalCat ?shop_id=$shop_id
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
- ;;
-esac
-
-
-
diff --git a/e/poem b/e/poem
index eb36e1b..d515eff 100755
--- a/e/poem
+++ b/e/poem
@@ -3,17 +3,13 @@
. $ROOT/lib/optional-auth.sh
. $ROOT/lib/common.sh
-noslash() {
- sed -e 's:/:\\/:g' $1
-}
-
POEM_PATH=$ROOT/poems/$poem_id
COMMENTS_PATH="$POEM_PATH/comments.txt"
case "$REQUEST_METHOD" in
POST)
[[ ! -z "$REMOTE_USER" ]] || Unauthorized
- fappend $COMMENTS_PATH echo $REMOTE_USER: "`urldecode "$comment"`" 2>&1
+ echo $REMOTE_USER: "`urldecode "$comment"`" | fappend $COMMENTS_PATH
see_other poem ?poem_id=$poem_id
;;
GET)
diff --git a/e/poem-add b/e/poem-add
index 0ec79f3..341c423 100755
--- a/e/poem-add
+++ b/e/poem-add
@@ -7,26 +7,30 @@ case "$REQUEST_METHOD" in
POST)
poem_id="`cat $ROOT/tmp/mpfd/poem_id`"
- if not_valid_id $poem_id; then
+ if invalid_id $poem_id; then
Fatal 400 Not a valid ID
fi
POEM_PATH="$ROOT/poems/$poem_id"
fmkdir $POEM_PATH
- fwrite $POEM_PATH/.owner echo $REMOTE_USER
- file_count="`cat $ROOT/tmp/mpfd/file-count`"
- for i in `seq 0 $file_count`; do
- FILE_PATH=$ROOT/tmp/mpfd/file$i
- fbytes $FILE_PATH
- filename="`cat $FILE_PATH-name`"
+ echo $REMOTE_USER | fwrite $POEM_PATH/.owner
+
+ mpfd-ls | while read FILE_PATH filename ; do
file_lang="`echo $filename | sed 's/\.[^.]*$//'`"
- if not_valid_lang "$file_lang"; then
+ if invalid_lang "$file_lang"; then
Fatal 400 Not a valid locale
fi
- mv $FILE_PATH $POEM_PATH/$file_lang.html
+ fbytes $FILE_PATH
+ cat $FILE_PATH | cslash > $POEM_PATH/$file_lang.html
+ rm $FILE_PATH
done
+ if [[ ! -f $POEM_PATH/$lang.html ]]; then
+ rm -rf $POEM_PATH
+ Fatal 400 You must submit a poem in your language
+ fi
+
see_other poem ?poem_id=$poem_id
;;
diff --git a/e/product b/e/product
deleted file mode 100755
index ae264db..0000000
--- a/e/product
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/ksh
-
-. $ROOT/lib/optional-auth.sh
-. $ROOT/lib/common.sh
-. $ROOT/lib/shop.sh
-. $ROOT/lib/order.sh
-
-if [[ -z "$shop_id" ]] || [[ ! -d "$SHOP_PATH" ]]; then
- Fatal 404 Shop not found
-fi
-
-PRODUCT_PATH=$SHOP_PATH/$product_id
-if [[ -z "$product_id" ]] || [[ ! -d "$PRODUCT_PATH" ]]; then
- Fatal 404 Product not found
-fi
-
-case "$REQUEST_METHOD" in
- GET)
-
- export _TITLE="`_ $shop_id` - `_ Product` #$product_id"
-
- export PRODUCT="`Product -rproduct $CART_PATH $product_id`"
- NormalCat ?shop_id=$shop_id\&product_id=$product_id
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
- ;;
-esac
-
-
-
-
diff --git a/e/product-add b/e/product-add
deleted file mode 100755
index 1a335a3..0000000
--- a/e/product-add
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/bin/ksh
-
-. $ROOT/lib/auth.sh
-. $ROOT/lib/common.sh
-. $ROOT/lib/shop.sh
-
-if [[ -z "$shop_id" ]] || [[ ! -d "$SHOP_PATH" ]]; then
- fatal 404 Shop not found
-fi
-
-case "$REQUEST_METHOD" in
- POST)
- SHOP_OWNER="`cat $SHOP_PATH/.owner`"
-
- if [[ "$REMOTE_USER" != "$SHOP_OWNER" ]]; then
- Fatal 401 "You cannot do that"
- fi
-
- PRODUCT_ID_PATH=$SHOP_PATH/.count
- PRODUCT_ID="`counter_inc $PRODUCT_ID_PATH`"
- PRODUCT_PATH=$SHOP_PATH/$PRODUCT_ID
- DF_USER=$SHOP_OWNER
-
- fmkdir $PRODUCT_PATH
- fwrite $PRODUCT_PATH/title urldecode $title
- fwrite $PRODUCT_PATH/description urldecode $description
- fwrite $PRODUCT_PATH/images urldecode $images
- fwrite $PRODUCT_PATH/price echo $price
- fwrite $PRODUCT_PATH/stock echo $stock
-
- see_other shop ?shop_id=$shop_id
- ;;
-
- GET)
- export _TITLE="`_ $shop_id` - `_ "Add product"`"
- export __TITLE="`_ Title`"
- export _DESCRIPTION="`_ Description`"
- export _IMAGES="`_ Images`"
- export _STOCK="`_ Stock`"
- export _PRICE="`_ Price`"
- export _SUBMIT="`_ Submit`"
-
- NormalCat ?shop_id=$shop_id
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
- ;;
-esac
diff --git a/e/register b/e/register
deleted file mode 100755
index ad1e0e3..0000000
--- a/e/register
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/bin/ksh
-
-. $ROOT/lib/common.sh
-
-error() {
- see_other register ?error=$1
- exit
-}
-
-case "$REQUEST_METHOD" in
- POST)
- username="`urldecode $username`"
- password="`urldecode $password`"
- password2="`urldecode $password2`"
- email="`urldecode $email`"
-
- if not_valid_password $password; then
- Fatal 400 Not a valid password
- fi
-
- if [[ "$password" != "$password2" ]]; then
- Fatal 400 The passwords don\'t match
- fi
-
- if grep -q "^$username:" $ROOT/.htpasswd; then
- Fatal 400 User already exists
- fi
-
- USER_DIR=$ROOT/users/$username
- DF_USER=$username
- fmkdir $USER_DIR
- fwrite $USER_DIR/email echo $email
- echo $username:$password | htpasswd -I $ROOT/.htpasswd
- rand_str="`rand_str_1`"
- fwrite $USER_DIR/rcode echo "$rand_str"
- femail -f noreply@tty.pt $email <<!
-Subject: `_ "Registration on tty.pt"`
-
-`_ "Welcome to tty.pt!"`
-
-`_ "To confirm that this e-mail address belongs to you, go to the page at:"`
-https://tty.pt/e/registration-confirm?username=$username&rcode=$rand_str
-
-`_ "You will then be able to use your account."`
-
-`_ "Thank you!"`
-!
- see_other registration-complete
- ;;
- GET)
- export _REGISTER="`_ "Register"`"
- export _USERNAME="`_ "Username"`"
- export _PASSWORD="`_ "Password"`"
- export _REPEAT_PASSWORD="`_ "Repeat password"`"
- export _EMAIL="`_ "Email"`"
- export _SUBMIT="`_ "Submit"`"
- export _LOGIN="`_ Login`"
- export _COOKIE_POLICY="`_ "Cookie policy"`"
-
- NormalCat
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
- ;;
-esac
diff --git a/e/registration-complete b/e/registration-complete
deleted file mode 100755
index 5d9ef6b..0000000
--- a/e/registration-complete
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/ksh
-
-. $ROOT/lib/common.sh
-
-case "$REQUEST_METHOD" in
- GET)
- export _REGISTRATION_COMPLETE="`_ "Registration complete"`"
- export _ACCOUNT_CREATED="`_ "Please click the link sent to your e-mail to activate your account."`"
- NormalCat
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
- ;;
-esac
-
diff --git a/e/registration-confirm b/e/registration-confirm
deleted file mode 100755
index cf7f57c..0000000
--- a/e/registration-confirm
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/ksh
-
-. $ROOT/lib/common.sh
-
-case "$REQUEST_METHOD" in
- GET)
- USER_PATH=$ROOT/users/$username
- USER_RCODE="`cat $USER_PATH/rcode`"
-
- if [[ "$rcode" != "$USER_RCODE" ]]; then
- Fatal 401 "You can not do that"
- fi
-
- rm $USER_PATH/rcode
- see_other login
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
- ;;
-esac
-
diff --git a/e/school b/e/school
new file mode 100755
index 0000000..f163b4b
--- /dev/null
+++ b/e/school
@@ -0,0 +1,24 @@
+#!/bin/ksh
+
+. $ROOT/lib/optional-auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+case "$REQUEST_METHOD" in
+ GET)
+ # export SCHOOL_MENU="`SchoolMenu`"
+ export _TEACHERS="`_ Teachers`"
+ export _STUDENTS="`_ Students`"
+ export _COURSES="`_ Courses`"
+ export _CLASSES="`_ Classes`"
+ export school_title="`cat $SCHOOL_PATH/title`"
+
+ NormalCat ?school_id=$school_id
+
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
+
diff --git a/e/school-add b/e/school-add
new file mode 100755
index 0000000..220ad79
--- /dev/null
+++ b/e/school-add
@@ -0,0 +1,35 @@
+#!/bin/ksh
+
+. $ROOT/lib/auth.sh
+. $ROOT/lib/common.sh
+
+case "$REQUEST_METHOD" in
+ POST)
+ school_id="`urldecode $school_id`"
+
+ if invalid_id $school_id; then
+ Fatal 400 Not a valid ID
+ fi
+
+ SCHOOL_PATH="$ROOT/schools/$school_id"
+
+ fmkdir $SCHOOL_PATH
+ echo $REMOTE_USER | fwrite $SCHOOL_PATH/.owner
+ echo $school_title | fwrite $SCHOOL_PATH/title
+
+ see_other school ?school_id=$school_id
+ ;;
+
+ GET)
+ export _TITLE="`_ "Add school"`"
+ export _SCHOOL_ID="`_ "School ID"`"
+ export _SCHOOL_TITLE="`_ "School Title"`"
+ export _SUBMIT="`_ Submit`"
+
+ NormalCat
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/poems b/e/schools
similarity index 58%
rename from e/poems
rename to e/schools
index 56a60d6..a33d4f3 100755
--- a/e/poems
+++ b/e/schools
@@ -5,13 +5,13 @@
case "$REQUEST_METHOD" in
GET)
- export _TITLE="`_ Poems`"
+ export _TITLE="`_ Schools`"
if [[ ! -z "$REMOTE_USER" ]]; then
- export POEM_ADD="<a class=\"$RB\" href=\"/e/poem-add\">+</p>"
+ export SCHOOL_ADD="<a class=\"$RB\" href=\"/e/school-add\">+</a>"
fi
- export POEMS="`ls $ROOT/poems | BigButtons poem`"
+ export SCHOOLS="`ls $ROOT/schools | BigButtons school`"
NormalCat
;;
*)
@@ -19,3 +19,5 @@ case "$REQUEST_METHOD" in
echo
;;
esac
+
+
diff --git a/e/sem b/e/sem
deleted file mode 100755
index aa8ae6f..0000000
--- a/e/sem
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/ksh
-
-case "$REQUEST_METHOD" in
- POST)
- echo 'Status: 200 OK'
- echo 'Content-Type: text/plain; charset=utf-8'
- echo
- (
- read && read && read && read &&
- read line1 &&
- read line2 &&
- while read nextline ; do
- echo "$line1"
- line1="$line2"
- line2="$nextline"
- done
- ) | sem
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
-esac
diff --git a/e/shop b/e/shop
deleted file mode 100755
index 34a0eca..0000000
--- a/e/shop
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/bin/ksh
-
-. $ROOT/lib/optional-auth.sh
-. $ROOT/lib/common.sh
-. $ROOT/lib/shop.sh
-
-lsshown() {
- find $1 -type d -mindepth 1 -maxdepth 1 -name "[!.]*" | sed "s|$1||"
-}
-
-Category() {
- CATEGORY_ID="$1"
- CATEGORY_NAME="`_ $CATEGORY_ID`"
- cat <<!
-<option value="$CATEGORY_ID">$CATEGORY_NAME</option>
-!
-}
-
-Products() {
- while read line; do
- if [[ "`cat $SHOP_PATH/$line/stock`" -gt 0 ]]; then
- Product -rshop $CART_PATH $line;
- fi
- done
-}
-
-ShopButtons() {
- [[ ! -z "$REMOTE_USER" ]] || return
-
- cat <<!
-<a class="$RB" href="/e/orders?shop_id=$shop_id">🚚</a>
-<a class="$RB" href="/e/cart?shop_id=$shop_id">🛒</a>
-!
-}
-
-if [[ -z "$shop_id" ]] || [[ ! -d "$SHOP_PATH" ]]; then
- Fatal 404 Shop not found
-fi
-
-case "$REQUEST_METHOD" in
- POST)
- case "$action" in
- delete)
- PRODUCT_PATH=$SHOP_PATH/$product_id
- if [[ -z "$product_id" ]] || [[ ! -d "$PRODUCT_PATH" ]]; then
- Fatal 404 Product not found
- fi
-
- SHOP_OWNER="`cat $SHOP_PATH/.owner`"
-
- [[ "$SHOP_OWNER" != "$REMOTE_USER" ]] \
- && Fatal 401 "You can not do that"
-
- rm -rf $SHOP_PATH/$product_id
-
- see_other shop ?shop_id=$shop_id
- ;;
- *)
- Fatal 400 Invalid action
- ;;
- esac
-
- ;;
- GET)
- export _TITLE="`_ $shop_id`"
-
- export SHOP_CATEGORIES="`lsshown $SHOP_PATH/.categories/ | while read line; do Category $line; done`"
- PRODUCTS="`lsshown $SHOP_PATH/ | Products`"
- export PRODUCTS="`Wrap $PRODUCTS`"
- SHOP_OWNER="`cat $SHOP_PATH/.owner`"
- export SHOP_BUTTONS="`ShopButtons`"
- if [[ "$REMOTE_USER" == "$SHOP_OWNER" ]]; then
- ADD_PRODUCT_BUTTON="<div class=\"tar\"><a class=\"tsxl round ps btn\" href=\"/e/product-add?shop_id=$shop_id\">+</a></div>"
- fi
- export ADD_PRODUCT_BUTTON
-
- NormalCat ?shop_id=$shop_id
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
- ;;
-esac
diff --git a/e/shop-add b/e/shop-add
deleted file mode 100755
index e1c3372..0000000
--- a/e/shop-add
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/ksh
-
-. $ROOT/lib/auth.sh
-. $ROOT/lib/common.sh
-
-case "$REQUEST_METHOD" in
- POST)
- shop_id="`urldecode $shop_id`"
-
- if not_valid_id $shop_id; then
- Fatal 400 Not a valid ID
- fi
-
- SHOP_PATH="$ROOT/shops/$shop_id"
-
- fmkdir $SHOP_PATH
- fwrite $SHOP_PATH/.owner echo $REMOTE_USER
- fmkdir $SHOP_PATH/.orders
-
- see_other shop ?shop_id=$shop_id
- ;;
-
- GET)
- export _TITLE="`_ "Add shop"`"
- export _SHOP_ID="`_ "Shop ID"`"
- export _SUBMIT="`_ Submit`"
-
- NormalCat
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
- ;;
-esac
-
diff --git a/e/shop-edit b/e/shop-edit
new file mode 100755
index 0000000..9321000
--- /dev/null
+++ b/e/shop-edit
@@ -0,0 +1,65 @@
+#!/bin/ksh
+
+. $ROOT/lib/optional-auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/shop.sh
+
+lsshown() {
+ find $1 -type d -mindepth 1 -maxdepth 1 -name "[!.]*" | sed "s|$1||" | sed "s/\/$//"
+}
+
+Products() {
+ local product_id
+ while read product_id; do
+ if [[ "`cat $SHOP_PATH/$product_id/stock`" -gt 0 ]]; then
+ product_env $product_id
+ cat <<!
+<label class="card f v8 b0 fic p">
+ `PImage $product_image_path`
+ <div class="tsl">$product_price€</div>
+ <a class="tsxl" href="/e/product?shop_id=$shop_id&product_id=$product_id">$product_title</a>
+ `echo "$product_description" | csurround p`
+ <input name="delete_$product_id" type="checkbox"></input>
+</label>
+!
+ fi
+ done
+}
+
+if [[ -z "$shop_id" ]] || [[ ! -d "$SHOP_PATH" ]]; then
+ Fatal 404 Shop not found
+fi
+
+case "$REQUEST_METHOD" in
+ POST)
+ im $SHOP_OWNER || Forbidden
+
+ lsshown $SHOP_PATH/ | while read product_id; do
+ local qname=delete_$product_id
+ eval echo $product_id \$$qname
+ done | while read product_id state; do
+ [[ "$state" != "on" ]] || product_rm $product_id
+ done
+
+ see_other shop ?shop_id=$shop_id
+
+ ;;
+ GET)
+ export _TITLE="`_ $shop_id` - `_ "Edit shop"`"
+ export _DELETE_PRODUCTS="`_ "Delete products"`"
+
+ export PRODUCTS="`lsshown $SHOP_PATH/ | Products | fw`"
+ SHOP_OWNER="`cat $SHOP_PATH/.owner`"
+ export SHOP_BUTTONS="`ShopButtons`"
+ if im $SHOP_OWNER; then
+ export ADD_PRODUCT_BUTTON="<div class=\"tar\"><a class=\"tsxl round p8 btn\" href=\"/e/product-add?shop_id=$shop_id\">+</a></div>"
+ export EDIT_BTN="`EditBtn "/e/shop-edit?shop_id=$shop_id"`"
+ fi
+
+ NormalCat ?shop_id=$shop_id
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/shops b/e/shops
deleted file mode 100755
index 1b2ad77..0000000
--- a/e/shops
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/ksh
-
-. $ROOT/lib/optional-auth.sh
-. $ROOT/lib/common.sh
-
-case "$REQUEST_METHOD" in
- GET)
- export _TITLE="`_ Shops`"
- if [[ ! -z "$REMOTE_USER" ]]; then
- export SHOP_ADD="<a class=\"$RB\" href=\"/e/shop-add\">+</a>"
- fi
-
- export SHOPS="`ls $ROOT/shops | BigButtons shop`"
- NormalCat
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
- ;;
-esac
diff --git a/e/student b/e/student
new file mode 100755
index 0000000..91ed993
--- /dev/null
+++ b/e/student
@@ -0,0 +1,70 @@
+#!/bin/ksh
+
+. $ROOT/lib/optional-auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+invalid_s students $student_id && Fatal 400 Invalid student
+
+STUDENT_PATH=$SCHOOL_PATH/students/$student_id
+
+Courses() {
+ {
+ cat $STUDENT_PATH/courses | SmallButtons course \&school_id=$school_id
+ if im $SCHOOL_OWNER $student_id; then
+ echo "<a class=\"$RBS\" href=\"/e/student-course-associate?school_id=$school_id&student_id=$student_id\">+</a>"
+ fi
+ } | cond || {
+ echo "<h2>`_ Courses`</h2>"
+ cat $contents | fw 8
+ }
+}
+
+Grades() {
+ cat $STUDENT_PATH/grades | while read class_id grade; do
+ cat <<!
+<div class="ps c0 _">
+ <a href="/e/class?school_id=$school_id&class_id=$class_id">$class_id</a>
+ <span>$grade</span>
+</div>
+!
+ done | cond || {
+ echo "<h2>`_ Grades`</h2>"
+ cat $contents | fw 8
+ }
+}
+
+RNField() {
+ Field "`_ "Registration Number"`" "`cat $STUDENT_PATH/required_number`"
+}
+
+NameField() {
+ Field "`_ Name`" "`cat $STUDENT_PATH/name`"
+}
+
+DobField() {
+ Field "`_ "Date of birth"`" "`cat $STUDENT_PATH/dob`"
+}
+
+case "$REQUEST_METHOD" in
+ GET)
+ export student_id
+ export _STUDENT="`_ Student`"
+ export COURSES="`Courses`"
+ export RN="`RNField`"
+ export NAME="`NameField`"
+ export DOB="`DobField`"
+ export GRADES="`Grades`"
+
+ if im $SCHOOL_OWNER $student_id; then
+ export EDIT_BTN="`EditBtn "/e/student-edit?school_id=$school_id&student_id=$student_id"`"
+ fi
+
+ NormalCat ?school_id=$school_id\&student_id=$student_id
+
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/student-add b/e/student-add
new file mode 100755
index 0000000..851767a
--- /dev/null
+++ b/e/student-add
@@ -0,0 +1,38 @@
+#!/bin/ksh
+
+. $ROOT/lib/auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+im $SCHOOL_OWNER || Forbidden
+
+case "$REQUEST_METHOD" in
+ POST)
+ if invalid_id $student_id; then
+ Fatal 400 Not a valid ID
+ fi
+
+ STUDENT_PATH="$SCHOOL_PATH/students/$student_id"
+
+ fmkdir $STUDENT_PATH
+ urldecode $name | fwrite $STUDENT_PATH/name
+ urldecode $dob | fwrite $STUDENT_PATH/dob
+ counter_inc $SCHOOL_PATH/students/.count | fwrite $STUDENT_PATH/required_number
+
+ see_other student ?school_id=$school_id\&student_id=$student_id
+ ;;
+
+ GET)
+ export _TITLE="`_ "Add student to school"`"
+ export _STUDENT_ID="`_ "Student ID"`"
+ export _NAME="`_ Name`"
+ export _DOB="`_ "Date of birth"`"
+ export _SUBMIT="`_ Submit`"
+
+ NormalCat
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/student-course-associate b/e/student-course-associate
new file mode 100755
index 0000000..a3a72a7
--- /dev/null
+++ b/e/student-course-associate
@@ -0,0 +1,38 @@
+#!/bin/ksh
+
+. $ROOT/lib/auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+im $SCHOOL_OWNER $student_id || Forbidden
+
+case "$REQUEST_METHOD" in
+ POST)
+ if invalid_s courses $course_id; then
+ Fatal 400 That course does not exist
+ fi
+
+ STUDENT_PATH="$SCHOOL_PATH/students/$student_id"
+
+ if grep -q "$course_id_id" "$STUDENT_PATH/courses"; then
+ Fatal 400 That course is already assigned to this student
+ fi
+
+ echo $course_id | fappend "$STUDENT_PATH/courses"
+
+ see_other student ?school_id=$school_id\&student_id=$student_id
+ ;;
+
+ GET)
+ export _TITLE="`_ "Assign course to student"`"
+ export _CLASS_ID="`_ "Course ID"`"
+ export _SUBMIT="`_ Submit`"
+ export student_id
+
+ NormalCat
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/student-edit b/e/student-edit
new file mode 100755
index 0000000..26def23
--- /dev/null
+++ b/e/student-edit
@@ -0,0 +1,44 @@
+#!/bin/ksh
+
+. $ROOT/lib/auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+im $SCHOOL_OWNER $student_id || Forbidden
+
+STUDENT_PATH=$SCHOOL_PATH/students/$student_id
+
+case "$REQUEST_METHOD" in
+ POST)
+ if invalid_id $student_id; then
+ Fatal 400 Not a valid ID
+ fi
+
+ urldecode $name | fwrite $STUDENT_PATH/name
+ urldecode $dob | fwrite $STUDENT_PATH/dob
+
+ see_other student ?school_id=$school_id\&student_id=$student_id
+ ;;
+
+ GET)
+ export student_id
+ export _EDIT="`_ Edit`"
+ export _STUDENT="`_ Student`"
+ export _NAME="`_ Name`"
+ export name="`cat $STUDENT_PATH/name`"
+ export _DOB="`_ "Date of birth"`"
+ export dob="`cat $STUDENT_PATH/dob`"
+ export _SUBMIT="`_ Submit`"
+
+ if im $SCHOOL_OWNER $student_id; then
+ export EDIT_BTN="`EditBtn "/e/student-edit?school_id=$school_id&student_id=$student_id"`"
+ fi
+
+ NormalCat ?school_id=$school_id\&student_id=$student_id
+
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/students b/e/students
new file mode 100755
index 0000000..4efdc77
--- /dev/null
+++ b/e/students
@@ -0,0 +1,22 @@
+#!/bin/ksh
+
+. $ROOT/lib/optional-auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+case "$REQUEST_METHOD" in
+ GET)
+ export _TITLE="`_ Students`"
+
+ if im $SCHOOL_OWNER; then
+ export STUDENT_ADD="<a class=\"$RB\" href=\"/e/student-add?school_id=$school_id\">+</a>"
+ fi
+
+ export STUDENTS="`ls $SCHOOL_PATH/students | BigButtons student \&school_id=$school_id`"
+ NormalCat
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/teacher b/e/teacher
new file mode 100755
index 0000000..492cdd9
--- /dev/null
+++ b/e/teacher
@@ -0,0 +1,75 @@
+#!/bin/ksh
+
+. $ROOT/lib/optional-auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+teacher_things() {
+ for_each_in "$SCHOOL_PATH/$1" .teacher "$teacher_id"
+}
+
+Classes() {
+ teacher_things classes | SmallButtons class \&school_id=$school_id | cond || {
+ echo "<h2>`_ Classes`</h2>"
+ cat $contents | fw 8
+ }
+}
+
+Courses() {
+ teacher_things courses | SmallButtons course \&school_id=$school_id | cond || {
+ echo "<h2>`_ Courses` (`_ Regent`)</h2>"
+ cat $contents | fw 8
+ }
+}
+
+salary_exp() {
+ pay_per_class=750
+ pay_per_course=2500
+
+ teacher_things classes | while read ignored; do
+ echo $pay_per_class
+ done | sum_lines_exp
+
+ echo -n " + "
+
+ teacher_things courses | while read ignored; do
+ echo $pay_per_course
+ done | sum_lines_exp
+}
+
+NameField() {
+ Field "`_ Name`" "`cat $TEACHER_PATH/name`"
+}
+
+DobField() {
+ Field "`_ "Date of birth"`" "`cat $TEACHER_PATH/dob`"
+}
+
+SalaryField() {
+ salary_exp="`salary_exp`"
+ Field "`_ Salary`" "`echo "$salary_exp" | bc`€"
+}
+
+case "$REQUEST_METHOD" in
+ GET)
+ export teacher_id
+ export _TEACHER="`_ Teacher`"
+ export CLASSES="`Classes`"
+ export COURSES="`Courses`"
+ TEACHER_PATH=$SCHOOL_PATH/teachers/$teacher_id
+ export NAME="`NameField`"
+ export DOB="`DobField`"
+ export SALARY="`SalaryField`"
+
+ if im $SCHOOL_OWNER $teacher_id; then
+ export EDIT_BTN="`EditBtn "/e/teacher-edit?school_id=$school_id&teacher_id=$teacher_id"`"
+ fi
+
+ NormalCat ?school_id=$school_id\&teacher_id=$teacher_id
+
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/teacher-add b/e/teacher-add
new file mode 100755
index 0000000..06896e6
--- /dev/null
+++ b/e/teacher-add
@@ -0,0 +1,37 @@
+#!/bin/ksh
+
+. $ROOT/lib/auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+im $SCHOOL_OWNER || Forbidden
+
+case "$REQUEST_METHOD" in
+ POST)
+ if invalid_id $teacher_id; then
+ Fatal 400 Not a valid ID
+ fi
+
+ TEACHER_PATH="$SCHOOL_PATH/students/$teacher_id"
+
+ fmkdir $TEACHER_PATH
+ urldecode $name | fwrite $TEACHER_PATH/name
+ urldecode $dob | fwrite $TEACHER_PATH/dob
+
+ see_other student ?school_id=$school_id\&student_id=$student_id
+ ;;
+
+ GET)
+ export _TITLE="`_ "Add teacher to school"`"
+ export _TEACHER_ID="`_ "Teacher ID"`"
+ export _NAME="`_ Name`"
+ export _DOB="`_ "Date of birth"`"
+ export _SUBMIT="`_ Submit`"
+
+ NormalCat
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/teacher-edit b/e/teacher-edit
new file mode 100755
index 0000000..93d9018
--- /dev/null
+++ b/e/teacher-edit
@@ -0,0 +1,46 @@
+#!/bin/ksh
+
+. $ROOT/lib/auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+im $SCHOOL_OWNER $teacher_id || Forbidden
+
+TEACHER_PATH=$SCHOOL_PATH/teachers/$teacher_id
+
+case "$REQUEST_METHOD" in
+ POST)
+ if invalid_id $teacher_id; then
+ Fatal 400 Not a valid ID
+ fi
+
+ urldecode $name | fwrite $TEACHER_PATH/name
+ urldecode $dob | fwrite $TEACHER_PATH/dob
+
+ see_other teacher ?school_id=$school_id\&teacher_id=$teacher_id
+ ;;
+
+ GET)
+ TEACHER_PATH=$SCHOOL_PATH/teachers/$teacher_id
+
+ export teacher_id
+ export _EDIT="`_ Edit`"
+ export _TEACHER="`_ Teacher`"
+ export _NAME="`_ Name`"
+ export name="`cat $TEACHER_PATH/name`"
+ export _DOB="`_ "Date of birth"`"
+ export dob="`cat $TEACHER_PATH/dob`"
+ export _SUBMIT="`_ Submit`"
+
+ if im $SCHOOL_OWNER $teacher_id; then
+ export EDIT_BTN="`EditBtn "/e/teacher-edit?school_id=$school_id&teacher_id=$teacher_id"`"
+ fi
+
+ NormalCat ?school_id=$school_id\&teacher_id=$teacher_id
+
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/teachers b/e/teachers
new file mode 100755
index 0000000..f868490
--- /dev/null
+++ b/e/teachers
@@ -0,0 +1,22 @@
+#!/bin/ksh
+
+. $ROOT/lib/optional-auth.sh
+. $ROOT/lib/common.sh
+. $ROOT/lib/school.sh
+
+case "$REQUEST_METHOD" in
+ GET)
+ export _TITLE="`_ Teachers`"
+
+ if im $SCHOOL_OWNER; then
+ export TEACHER_ADD="<a class=\"$RB\" href=\"/e/teacher-add?school_id=$school_id\">+</a>"
+ fi
+
+ export TEACHERS="`ls $SCHOOL_PATH/teachers | BigButtons teacher \&school_id=$school_id`"
+ NormalCat
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/e/tty b/e/tty
deleted file mode 100755
index 36e5eac..0000000
--- a/e/tty
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/ksh
-
-. $ROOT/lib/auth.sh
-. $ROOT/lib/common.sh
-
-USER_PATH="$ROOT/users/$REMOTE_USER"
-WHISPER_PATH="$USER_PATH/.whisper"
-
-case "$REQUEST_METHOD" in
- POST)
- cmd="`urldecode $cmd`"
- echo "$REMOTE_USER$ $cmd" >> $WHISPER_PATH
-
- case "$cmd" in
- help)
- echo Welcome to the terminal
- echo Beware - the values might not be correct
- echo commands: df quota whisper
- ;;
- df)
- df
- ;;
- quota)
- echo "`df_total`/`free_space`"
- ;;
- whisper*)
- set -- $cmd
- shift
- username=$1
- shift
- message=$@
-
- [[ -d $ROOT/users/$username ]] || Fatal 400 No such user
-
- DF_USER=$username
- fappend $ROOT/users/$username/.whisper \
- echo "$REMOTE_USER": "$message"
- echo "Sent whisper."
- ;;
- *)
- ;;
- esac >> $WHISPER_PATH
-
- ;;
- GET)
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
- exit
- ;;
-esac
-
-export _TITLE="`_ "Terminal"`"
-
-NormalCat
diff --git a/e/user b/e/user
deleted file mode 100755
index ea688cd..0000000
--- a/e/user
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/bin/ksh
-
-. $ROOT/lib/auth.sh
-. $ROOT/lib/common.sh
-
-USER_PATH=$ROOT/users/$REMOTE_USER
-
-case "$REQUEST_METHOD" in
- POST)
- case "$action" in
- personal_data)
- address_line_1="`urldecode $address_line_1`"
- address_line_2="`urldecode $address_line_2`"
- zip="`urldecode $zip`"
- phone_number="`urldecode $phone_number`"
- fwrite $USER_PATH/address_line_1 echo $address_line_1
- fwrite $USER_PATH/address_line_2 echo $address_line_2
- fwrite $USER_PATH/zip echo $zip
- fwrite $USER_PATH/phone_number echo $phone_number
- ;;
- vendor_data)
- iban="`urldecode $iban`"
- bicswift="`urldecode $bicswift`"
- fwrite $USER_PATH/iban echo $iban
- fwrite $USER_PATH/bicswift echo $bicswift
- ;;
- *)
- Fatal 400 Invalid action
- esac
- see_other user
- ;;
- GET)
- export _TITLE="`_ User` - $REMOTE_USER"
- export _WELCOME="`_ Welcome`"
- export _LOGOUT="`_ Logout`"
- export _CHANGE_PERSONAL_DATA="`_ change_personal_data`"
- export _ADDRESS_LINE_1="`_ "Address line 1"`"
- export _ADDRESS_LINE_2="`_ "Address line 2"`"
- export _ZIP_CODE="`_ "Zip code"`"
- export _PHONE_NUMBER="`_ "Phone number"`"
- export _CHANGE_VENDOR_DATA="`_ change_vendor_data`"
- export _ACCOUNT_IBAN="`_ "Account IBAN"`"
- export _ACCOUNT_BICSWIFT="`_ "Account BICSWIFT"`"
- export _SUBMIT="`_ Submit`"
-
- export address_line_1="`zcat $USER_PATH/address_line_1`"
- export address_line_2="`zcat $USER_PATH/address_line_2`"
- export zip="`zcat $USER_PATH/zip`"
- export phone_number="`zcat $USER_PATH/phone_number`"
-
- export iban="`zcat $USER_PATH/iban`"
- export bicswift="`zcat $USER_PATH/bicswift`"
-
- NormalCat
- ;;
- *)
- echo "Status: 405 Method Not Allowed"
- echo
- ;;
-esac
diff --git a/e/user-edit b/e/user-edit
new file mode 100755
index 0000000..e1badf0
--- /dev/null
+++ b/e/user-edit
@@ -0,0 +1,45 @@
+#!/bin/ksh
+
+. $ROOT/lib/auth.sh
+. $ROOT/lib/common.sh
+
+USER_PATH=$ROOT/users/$REMOTE_USER
+
+case "$REQUEST_METHOD" in
+ POST)
+ urldecode $name | fwrite $USER_PATH/name
+ urldecode $address_line_1 | fwrite $USER_PATH/address_line_1
+ urldecode $address_line_2 | fwrite $USER_PATH/address_line_2
+ urldecode $zip | fwrite $USER_PATH/zip
+ urldecode $phone_number | fwrite $USER_PATH/phone_number
+ urldecode $iban | fwrite $USER_PATH/iban
+ urldecode $bicswift | fwrite $USER_PATH/bicswift
+
+ see_other user
+ ;;
+ GET)
+ export _TITLE="`_ "Edit user"` - $REMOTE_USER"
+ export _NAME="`_ Name`"
+ export _ADDRESS_LINE_1="`_ "Address line 1"`"
+ export _ADDRESS_LINE_2="`_ "Address line 2"`"
+ export _ZIP_CODE="`_ "Zip code"`"
+ export _PHONE_NUMBER="`_ "Phone number"`"
+ export _ACCOUNT_IBAN="`_ "Account IBAN"`"
+ export _ACCOUNT_BICSWIFT="`_ "Account BICSWIFT"`"
+ export _SUBMIT="`_ Submit`"
+
+ export name="`zcat $USER_PATH/name`"
+ export address_line_1="`zcat $USER_PATH/address_line_1`"
+ export address_line_2="`zcat $USER_PATH/address_line_2`"
+ export zip="`zcat $USER_PATH/zip`"
+ export phone_number="`zcat $USER_PATH/phone_number`"
+ export iban="`zcat $USER_PATH/iban`"
+ export bicswift="`zcat $USER_PATH/bicswift`"
+
+ NormalCat
+ ;;
+ *)
+ echo "Status: 405 Method Not Allowed"
+ echo
+ ;;
+esac
diff --git a/htdocs/vss/color.h b/htdocs/vss/color.h
new file mode 100644
index 0000000..e242ce3
--- /dev/null
+++ b/htdocs/vss/color.h
@@ -0,0 +1,20 @@
+#ifndef COLORS_N
+#define COLORS_N
+#define VAL_COLOR_0 #2c2c2c
+#define VAL_COLOR_1 #bd4a6a
+#define VAL_COLOR_2 #3a5e46
+#define VAL_COLOR_3 #a3975a
+#define VAL_COLOR_4 #7389bd
+#define VAL_COLOR_5 #8a77ac
+#define VAL_COLOR_6 #415c5f
+#define VAL_COLOR_7 #8b85a5
+#define VAL_COLOR_8 #b4aac1
+#define VAL_COLOR_9 #bd4a87
+#define VAL_COLOR_10 #53d38a
+#define VAL_COLOR_11 #b8cd2e
+#define VAL_COLOR_12 #739cbd
+#define VAL_COLOR_13 #9589c5
+#define VAL_COLOR_14 #16d0ba
+#define VAL_COLOR_15 #f5f5f5
+#define ALL_COLORS 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+#endif
diff --git a/htdocs/vss/c.txt b/htdocs/vss/color.txt
similarity index 100%
rename from htdocs/vss/c.txt
rename to htdocs/vss/color.txt
diff --git a/htdocs/vss/text-size.h b/htdocs/vss/text-size.h
new file mode 100644
index 0000000..ea0c090
--- /dev/null
+++ b/htdocs/vss/text-size.h
@@ -0,0 +1,18 @@
+/* x = i * 0.880; f(x) = 0.112 * x ^ 3 + -0.610 * x ^ 2 + 3.900 * x + 6.100 */
+#ifndef TEXT_SIZES_H
+#define TEXT_SIZES_H
+#define VAL_TEXT_SIZE_9 9px
+#define VAL_TEXT_SIZE_11 11px
+#define VAL_TEXT_SIZE_14 14px
+#define VAL_TEXT_SIZE_17 17px
+#define VAL_TEXT_SIZE_20 20px
+#define VAL_TEXT_SIZE_26 26px
+#define VAL_TEXT_SIZE_33 33px
+#define VAL_TEXT_SIZE_42 42px
+#define VAL_TEXT_SIZE_54 54px
+#define VAL_TEXT_SIZE_69 69px
+#define VAL_TEXT_SIZE_88 88px
+#define VAL_TEXT_SIZE_111 111px
+#define VAL_TEXT_SIZE_138 138px
+#define ALL_TEXT_SIZES 9, 11, 14, 17, 20, 26, 33, 42, 54, 69, 88, 111, 138
+#endif
diff --git a/htdocs/vss/vss.config.h b/htdocs/vss/vss.config.h
index 50c5ef4..bb33263 100644
--- a/htdocs/vss/vss.config.h
+++ b/htdocs/vss/vss.config.h
@@ -2,26 +2,31 @@
#define CONFIG_ROUND
#define CONFIG_VARS
#include "vss/vss.h"
+#define CF #c1c3da
+#define CM VAL(COLOR, 13)
-CALL(TEXT_SIZE, TS)
-CALL(BG_COLOR, CS)
-CALL(COLOR, CS)
-CALL(BO_COLOR, CS)
+ROUND
+ALL_FLEX
+CALL(TEXT_SIZE, ALL_TEXT_SIZES)
+CALL(BACKGROUND_COLOR, ALL_COLORS)
+CALL(COLOR, ALL_COLORS)
+CALL(BORDER, ALL_COLORS)
CALL(SIZE, SS)
-CALL(PADDING, SS)
-CALL(DIR_PADDING, SS)
-CALL(ABS_PADDING, SS)
-CALL(CENTER_ABS_V, SS)
-CALL(HORIZONTAL, SS)
-CALL(VERTICAL, SS)
-CALL(MARGIN, SS)
-CALL(FLEX_VERTICAL, SS)
-CALL(ROUND_T, TS)
-CALL(ROUND_EDGE, SS)
-ROUND_PADDING( , l)
-ROUND_PADDING( s, l)
-ROUND_PADDING( s, xl)
+CALL(SIZE, ALL_SIZES)
+CALL(PADDING, ALL_SIZES)
+CALL(AXIS_horizontal, ALL_SIZES)
+CALL(AXIS_vertical, ALL_SIZES)
+AXIS_0
+FULL_SIZE
+/* CALL(FLEX_VERTICAL, SS) */
+CALL(ROUND_T, ALL_TEXT_SIZES)
+CALL(ROUND_EDGE, ALL_SIZES)
+ROUND_PADDING( 4, 14)
+ROUND_PADDING( 8, 17)
+ROUND_PADDING( 8, 20)
+ROUND_PADDING( 8, 26)
+.dn { display: none; }
.cf { background: #3c403c; }
.cb { color: #c1c3da; }
body {
@@ -42,6 +47,8 @@ input:focus {
border: solid thin #9589c5;
outline: #9589c5;
}
+.abs { position: absolute; }
+.rel { position: relative; }
a { color: #c1c3da; }
style { display: none !important; }
.oav { overflow: auto; }
@@ -57,14 +64,20 @@ pre { font-family: monospace; }
.wn { white-space: nowrap; }
button, .btn {
font-size: inherit;
- padding: var(--S);
- background-color: var(--C0);
+ padding: VAL(SIZE, );
+ background-color: VAL(COLOR, 0);
color: var(--C15);
border: none;
//border: solid thin black;
box-shadow: 0 3px 3px rgba(0, 0, 0, 0.5);
text-decoration: none;
}
+
+button > a, .btn > a, a.btn {
+ display: block;
+ text-decoration: none;
+}
+
button:hover, .btn:hover, .card:hover {
box-shadow: 0 5px 5px rgba(0, 0, 0, 0.5);
}
@@ -87,3 +100,23 @@ pre {
.card a {
//color: var(--C0);
}
+
+.menu:not(.js) > div { display: none; }
+.menu input[type="checkbox"] { display: none; }
+.menu :checked + div { display: block; }
+.menu a { text-decoration: none; }
+.menu a:hover { color: white; }
+
+.pn { padding: 0; }
+.fix { position: fixed; }
+
+.j { bottom: var(--S); }
+.l { right: var(--S); }
+.cp { cursor: pointer; }
+.ttc { text-transform: capitalize; }
+
+input.c0 { border: solid thin VAL(COLOR, 0); color: CF; }
+input.c0:focus {
+ border: solid thin CM;
+ outline: CM;
+}
diff --git a/init.sh b/init.sh
deleted file mode 100644
index e039b0f..0000000
--- a/init.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/ksh
-mkdir dev 2>/dev/null || true
-cd dev
-mknod zero c 13 12
-mknod null c 13 2
-mknod tty c 1 0
-chmod 666 zero null tty
-cd -
-# copy www and root users to etc/master.passwd
-# and run the following inside the chroot
-# pwd_mkdb /etc/master.passwd
diff --git a/js/menu.js b/js/menu.js
new file mode 100644
index 0000000..c4364ea
--- /dev/null
+++ b/js/menu.js
@@ -0,0 +1,14 @@
+function menu(cont_el) {
+ let menu_el = cont_el.querySelector('div');
+ cont_el.classList.add("js");
+ cont_el.removeChild(cont_el.querySelector("input"));
+ menu_el.classList.add("dn");
+ let sem_menu_visible = false;
+ cont_el.onclick = function (ev) {
+ sem_menu_visible = !sem_menu_visible;
+ if (sem_menu_visible)
+ menu_el.classList.remove("dn");
+ else
+ menu_el.classList.add("dn");
+ };
+}
diff --git a/js/nfiles.js b/js/nfiles.js
new file mode 100644
index 0000000..82e1dab
--- /dev/null
+++ b/js/nfiles.js
@@ -0,0 +1,148 @@
+function basename(str) {
+ return str.substr(str.lastIndexOf('/') + 1);
+}
+
+function nfiles(nfiles_name, nfiles_el, submit_el, submit_label, file_name, add_ep, edit_ep) {
+ let loading = 0;
+
+ function load_start() {
+ submit_el.innerText = i_wait;
+ submit_el.disabled = true;
+ loading++;
+ }
+
+ function load_end() {
+ loading--;
+ if (!loading) {
+ submit_el.innerText = _submit;
+ submit_el.disabled = false;
+ }
+ }
+
+ let search = nfiles_el.querySelector('a');
+ let textarea = nfiles_el.querySelector('textarea');
+
+ nfiles_el.removeChild(search);
+ nfiles_el.removeChild(textarea);
+
+ let nfiles_cont = document.createElement('div');
+ nfiles_cont.classList.add('fw', 'f', 'h8', 'v8', 'fic');
+ nfiles_el.appendChild(nfiles_cont);
+
+ let upload_image = document.createElement('button');
+ upload_image.innerText = '📁';
+ upload_image.classList.add('btn', 'round', 'p8', 'tsxl');
+ upload_image.type = "button";
+ nfiles_el.appendChild(upload_image);
+
+ let file_input = document.createElement('input');
+ file_input.type = 'file';
+ file_input.name = file_name;
+ file_input.classList.add('dn');
+ file_input.multiple = true;
+ nfiles_el.appendChild(file_input);
+
+ let hidden_input = document.createElement('input');
+ hidden_input.type = 'hidden';
+ hidden_input.name = nfiles_name;
+ nfiles_el.appendChild(hidden_input);
+
+ let nfiles_map = {};
+
+ const body = document.querySelector('body');
+
+ function nfiles_insert(url) {
+ let image = document.createElement('div');
+ image.classList.add('tss', 'p4', 'c0', 'rxs', 'h8', 'f', 'fic');
+
+ let image_link = document.createElement('a');
+ const bname = basename(url);
+ image_link.innerText = bname;
+ image_link.href = url;
+ image.appendChild(image_link);
+
+ nfiles_map[url] = true;
+
+ let btn = document.createElement('button');
+ btn.classList.add('btn', 'round', 'p4', 'tss', 'c15', 'cf0');
+ btn.innerText = '×';
+ btn.type = 'button';
+ btn.onclick = function (ev) {
+ const formData = new FormData();
+ const noext = bname.substr(0, bname.indexOf('.'));
+
+ formData.set('delete_' + noext, 'on');
+
+ nfiles_cont.removeChild(image);
+ delete nfiles_map[bname];
+
+ fetch(edit_ep, {
+ method: 'POST',
+ data: formData,
+ });
+ };
+ image.appendChild(btn);
+
+ nfiles_cont.appendChild(image);
+ }
+
+ textarea.value.split('\n').filter(url => !!url).map(nfiles_insert);
+
+ let main_form = document.querySelector('form');
+
+ main_form.onsubmit = function() {
+ file_input.disabled = true;
+ hidden_input.value = Object.keys(nfiles_map).join('\n');
+ console.log('final value', hidden_input.value);
+ }
+
+ upload_image.onclick = function (ev) {
+ file_input.click(ev);
+ };
+
+ const _submit = submit_label;
+ const i_wait = "⏱";
+
+ file_input.onchange = function (ev) {
+ let files = file_input.files;
+ let formData = new FormData();
+
+ for (const file of files)
+ formData.append(file_input.name, file, file.name);
+
+ load_start();
+
+ fetch(add_ep, {
+ method: 'POST',
+ headers: {
+ 'Accept': 'text/plain',
+ },
+ body: formData,
+ })
+ .then(response => {
+ return response.text().then(data => {
+ const san = data.replaceAll('\r', '');
+ if (response.ok) {
+ console.log('received', data);
+ // TODO might have multiple images
+ san.split('\n')
+ .filter(url => !!url)
+ .map(nfiles_insert);
+ load_end();
+ } else {
+ load_end();
+ const notif = document.createElement('div');
+ notif.classList.add('tsxs', 'cf9', 'cp');
+ notif.innerText = san;
+ notif.onclick = function (ev) {
+ body.removeChild(notif);
+
+ };
+ body.prepend(notif);
+ }
+ });
+ });
+
+ return false;
+ };
+}
diff --git a/lib/auth.sh b/lib/auth.sh
index e73b090..beb2069 100644
--- a/lib/auth.sh
+++ b/lib/auth.sh
@@ -1,10 +1,10 @@
#!/bin/ksh
-. $ROOT/lib/very-common.sh
+. $DOCUMENT_ROOT/lib/very-common.sh
-if [[ -z "$cookie" ]] || [[ ! -f "$ROOT/sessions/$cookie" ]]; then
+if [[ -z "$cookie" ]] || [[ ! -f "$DOCUMENT_ROOT/sessions/$cookie" ]]; then
Unauthorized
fi
-user="`cat $ROOT/sessions/$cookie`"
+user="`cat $DOCUMENT_ROOT/sessions/$cookie`"
REMOTE_USER=$user
diff --git a/lib/command.sh b/lib/command.sh
new file mode 100644
index 0000000..30d446b
--- /dev/null
+++ b/lib/command.sh
@@ -0,0 +1,26 @@
+. $DOCUMENT_ROOT/lib/common.sh
+
+if [[ "$REQUEST_METHOD" != "GET" ]]; then
+ echo "Status: 405 Method Not Allowed"
+ echo
+ exit
+fi
+
+Command() {
+ local args="$@"
+ if [[ -z "$args" ]]; then
+ args=$SCRIPT
+ fi
+
+ if [[ "$HTTP_ACCEPT" == "text/plain" ]]; then
+ NormalHead 200
+ echo
+ else
+ Normal 200
+ echo
+ export _TITLE="`_ Command` - $args"
+ export MENU="`Menu`"
+ export OUTPUT="`literal`"
+ Cat command
+ fi
+}
diff --git a/lib/common.sh b/lib/common.sh
index 4f4b663..0905283 100644
--- a/lib/common.sh
+++ b/lib/common.sh
@@ -1,10 +1,42 @@
#!/bin/ksh
-. $ROOT/lib/very-common.sh
+. $DOCUMENT_ROOT/lib/very-common.sh
Forbidden() {
NormalHead 403
_TITLE="`_ Forbidden`"
+ if [[ $# -ge 1 ]]; then
+ _TITLE="$_TITLE - $@"
+ fi
+ export _TITLE
+ echo
+ Head
+ export MENU="`Menu`"
+ Cat fatal
+ exit
+}
+
+NotAllowed() {
+ NormalHead 405 Method Not Allowed
+ _TITLE="`_ Method Not Allowed`"
+ if [[ $# -ge 1 ]]; then
+ _TITLE="$_TITLE - $@"
+ fi
+ export _TITLE
+ echo
+ Head
+ export MENU="`Menu`"
+ Cat fatal
+ exit
+}
+
+NotFound() {
+ NormalHead 404 Not Found
+ _TITLE="`_ Not Found`"
+ if [[ $# -ge 1 ]]; then
+ _TITLE="$_TITLE - $@"
+ fi
+ export _TITLE
echo
Head
export MENU="`Menu`"
@@ -15,11 +47,15 @@ Forbidden() {
bc() {
read exp
#echo "BC='$exp'" >&2
- echo "$exp" | $ROOT/usr/bin/bc "$@"
+ echo "$exp" | $DOCUMENT_ROOT/usr/bin/bc "$@"
+}
+
+_urldecode() {
+ sed 's@+@ @g;s@%@\\x@g' | xargs -0 printf "%b"
}
urldecode() {
- echo $@ | sed 's@+@ @g;s@%@\\x@g' | xargs -0 printf "%b"
+ echo $@ | _urldecode
}
url2vars() {
@@ -29,16 +65,13 @@ url2vars() {
eval "$exp"
}
-zcat() {
- [[ -f "$@" ]] && cat $@ || true
-}
-
case "$REQUEST_METHOD" in
POST)
case "$CONTENT_TYPE" in
multipart/form-data*)
+ grep -q "^$REMOTE_USER$" $DOCUMENT_ROOT/.uploaders || Forbidden "`_ "You don't have upload permissions"`"
boundary="`echo $CONTENT_TYPE | sed 's/.*=//'`"
- mpfd "$boundary" 2>&1
+ $DOCUMENT_ROOT/usr/bin/mpfd "$boundary" 2>&1
;;
application/x-www-form-urlencoded*)
read line1 || true
@@ -83,7 +116,7 @@ counter_dec() {
}
sum_lines_exp() {
- echo -n '('
+ echo -n '(0'
sed 's/$/ +/' | tr '\n' ' ' | sed 's/ + $//'
echo -n ')'
}
@@ -92,10 +125,18 @@ revlines() {
rev | tr '\n' '~' | rev | tr '~' '\n'
}
+_see_other() {
+ echo 'Status: 303 See Other'
+ echo "Location: $1"
+ echo
+ exit
+}
+
see_other() {
echo 'Status: 303 See Other'
echo "Location: /e/$1$2"
echo
+ exit
}
no_html() {
@@ -108,17 +149,17 @@ format_df() {
}
df_dir() {
- if [[ ! -d $ROOT/$1 ]]; then
+ if [[ ! -d $DOCUMENT_ROOT/$1 ]]; then
return
fi
- du_user="`du -c $ROOT/$1 | tail -1 | awk '{print $1}'`"
+ du_user="`du -c $DOCUMENT_ROOT/$1 | tail -1 | awk '{print $1}'`"
format_df $1 `calcround "$du_user * 1024"`
}
dir_df() {
- ls $ROOT/$1 | \
+ ls $DOCUMENT_ROOT/$1 | \
while read line; do
- path=$ROOT/$1/$line
+ path=$DOCUMENT_ROOT/$1/$line
OWNER="`cat $path/.owner`"
[[ "$OWNER" != "$DF_USER" ]] || df_dir $1/$line
done
@@ -129,6 +170,8 @@ df() {
df_dir htdocs/img/$DF_USER
dir_df shops
dir_df poems
+ dir_df sems
+ dir_df schools
}
df_total_exp() {
@@ -147,21 +190,23 @@ calcround() {
}
free_space() {
- N_USERS="`cat $ROOT/.htpasswd | wc -l | sed 's/ //g'`"
+ N_USERS="`cat $DOCUMENT_ROOT/.htpasswd | wc -l | sed 's/ //g'`"
FREE_SPACE_EXP="(20000000000 / $N_USERS)"
calcround "$FREE_SPACE_EXP"
}
FREE_SPACE="`free_space`"
-_fbytes() {
+__fbytes() {
[[ -z "$DF_USER" ]] && Fatal 400 Checking bytes of unknown user
- # echo exp="`df_total_exp`" >&2
OCCUPIED_SPACE="`df_total`"
CAN_EXP="($FREE_SPACE - $OCCUPIED_SPACE) >= $1"
- # echo CAN_EXP="$CAN_EXP" >&2
CAN="`echo $CAN_EXP | bc -l`"
- if [[ "$CAN" == "0" ]]; then
+ [[ "$CAN" == "0" ]]
+}
+
+_fbytes() {
+ if __fbytes $1; then
Fatal 400 No available space
fi
}
@@ -173,37 +218,36 @@ fbytes() {
fmkdir() {
if [[ ! -d "$1" ]]; then
- fbytes /empty
+ fbytes $DOCUMENT_ROOT/empty
mkdir -p "$1"
fi
}
fwrite() {
- TARGET=$1
- shift
- count="`$@ | wc | awk '{print $3}'`"
- _fbytes $count
- $@ > $TARGET
+ cat - > $1
+ local count="`cat $1 | wc | awk '{print $3}'`"
+ if __fbytes $count; then
+ rm $1
+ Fatal 400 No available space
+ fi
}
fappend() {
- TARGET=$1
- shift
- count="`$@ | wc | awk '{print $3}'`"
- _fbytes $count
- $@ >> $TARGET
-}
-
-rand_str_1() {
- # TODO maybe remove lowercase conversion
- xxd -l32 -ps $ROOT/dev/urandom | xxd -r -ps | openssl base64 \
- | tr -d = | tr + - | tr / _ | tr '[A-Z]' '[a-z]'
+ cat - > $DOCUMENT_ROOT/tmp/append
+ local count="`cat $DOCUMENT_ROOT/tmp/append | wc | awk '{print $3}'`"
+ if __fbytes $count; then
+ rm $DOCUMENT_ROOT/tmp/append
+ Fatal 400 No available space
+ else
+ cat $DOCUMENT_ROOT/tmp/append >> $1
+ rm $DOCUMENT_ROOT/tmp/append
+ fi
}
## COMPONENTS
Whisper() {
- WHISPER_PATH=$ROOT/users/$REMOTE_USER/.whisper
+ WHISPER_PATH=$DOCUMENT_ROOT/users/$REMOTE_USER/.whisper
WHISPER="`zcat $WHISPER_PATH | no_html`"
if [[ -z "$WHISPER" ]]; then
return
@@ -213,16 +257,34 @@ Whisper() {
rm $WHISPER_PATH
}
+NotNormal() {
+ NormalHead "$1"
+ shift
+ echo "Link: <http://$HTTP_HOST$@>; rel=\"alternate\"; hreflang=\"x-default\""
+ echo
+ Head
+ Whisper
+ export MENU="`Menu`"
+}
+
Normal() {
NormalHead "$1"
echo "Link: <http://$HTTP_HOST/e/$2$3>; rel=\"alternate\"; hreflang=\"x-default\""
echo
Head
-
Whisper
export MENU="`Menu`"
}
+UserNormal() {
+ NormalHead "$1"
+ echo "Link: <http://$HTTP_HOST/e/$2$3>; rel=\"alternate\"; hreflang=\"x-default\""
+ echo
+ export HEAD="`Head`"
+ export WHISPER="`Whisper`"
+ export MENU="`Menu`"
+}
+
NormalCat() {
Normal 200 $SCRIPT $1
Cat $SCRIPT
@@ -233,46 +295,197 @@ Fatal() {
shift
allargs="$@"
export _TITLE="`_ "$allargs"`"
- export _HEAD_TITLE="tty.pt - $SC - $_TITLE"
- Normal $SC
- Cat fatal
- exit 1
+
+ if [[ "$HTTP_ACCEPT" == "text/plain" ]]; then
+ NormalHead $SC
+ echo
+ echo $_TITLE
+ exit 1
+ else
+ export _HEAD_TITLE="tty.pt - $SC - $_TITLE"
+ Normal $SC
+ Cat fatal
+ exit 1
+ fi
}
DF_USER=$REMOTE_USER
-SCRIPT="`basename $SCRIPT_NAME | cut -f1 -d'.'`"
-Wrap() {
- if [[ ! -z "$@" ]]; then
- echo "<div class=\"_ v f fw fcc fic\">$@</div>"
- fi
+SCRIPT="`echo $DOCUMENT_URI | awk -F '/' '{print $2}'`"
+ARG="`echo $DOCUMENT_URI | awk -F '/' '{print $3}'`"
+set -- `echo $DOCUMENT_URI | tr '/' ' '`
+if [[ "$SCRIPT" == "e" ]]; then
+ SCRIPT="`echo $DOCUMENT_URI | awk -F '/' '{print $3}'`"
+ ARG="`echo $DOCUMENT_URI | awk -F '/' '{print $4}'`"
+ e_mode=1
+fi
+
+fw() {
+ csurround div "class=\"h$1 v$1 f fw fcc fic\""
}
-not_valid_id() {
+invalid_id() {
valid="`echo $@ | tr -cd '[a-zA-Z0-9]_'`"
- [[ "$valid" != "$@" ]]
+ count="`echo $@ | wc -c`"
+ [[ "$valid" != "$@" ]] || [[ "$count" -le 0 ]]
}
-not_valid_password() {
+invalid_password() {
count="`echo $@ | wc -c`"
[[ "$count" -le 8 ]]
}
-not_valid_lang() {
+invalid_lang() {
lang="$@"
- ! grep -q "$lang" $ROOT/locale/langs
+ ! grep -q "$lang" $DOCUMENT_ROOT/locale/langs
}
-BigButton() {
- ID="$1"
- _TITLE="`_ $1`"
- WHERE="$2"
- cat <<!
-<a class="btn tsxl" href="/e/$WHERE?${WHERE}_id=$ID">
+Buttons() {
+ if [[ $e_mode == 1 ]]; then
+ while read id; do
+ _TITLE="`_ $id`"
+ where="$2"
+ extra="$3"
+ cat <<!
+<div><a class="btn $1" href="/e/$where?${where}_id=$id$extra">
$_TITLE
-</a>
+</a></div>
!
+ done
+ else
+ while read id; do
+ _TITLE="`_ $id`"
+ where="$2"
+ extra="$3"
+ cat <<!
+<div><a class="btn $1" href="/$where/$id$extra">
+ $_TITLE
+</a></div>
+!
+ done
+ fi
}
BigButtons() {
- while read line; do BigButton $line $1; done
+ Buttons "tsxl" "$1" "$2"
+}
+
+SmallButtons() {
+ Buttons "c0 ps rs" "$1" "$2"
+}
+
+for_each_in() {
+ path="$1"
+ target="$2"
+ find_id="$3"
+
+ ls $path | while read id; do
+ if grep -q "$find_id" "$path/$id/$target"; then
+ echo $id
+ fi
+ done
+}
+
+im() {
+ ret=""
+ while [[ $# -ge 1 ]]; do
+ if [[ "$REMOTE_USER" == "$1" ]]; then
+ ret="1"
+ break;
+ fi
+ shift
+ done
+
+ [[ "$ret" == "1" ]]
+}
+
+contents=$DOCUMENT_ROOT/tmp/contents
+
+cond() {
+ # tee $contents$1
+ cat - > $contents$1
+ [[ -z "`cat $contents$1`" ]]
+}
+
+surround() {
+ echo "<$@>"
+ cat -
+ echo "</$1>"
+}
+
+csurround() {
+ local contents="`cat -`"
+
+ [[ -z "$contents" ]] || {
+ echo $contents | surround $@
+ }
+
+}
+
+Field() {
+ cat <<!
+<div class="_">
+ <span class="tsxs">$1</span>
+ <span>$2</span>
+</div>
+!
+}
+
+EditBtn() {
+ local i_edit="✎"
+ echo $i_edit | surround a "href=\"$1\"" "class=\"$RB\""
+}
+
+nfiles() {
+ urldecode "$@" | sed '/^$/d' | tr -d '\r'
+}
+
+a2l() {
+ while [[ $# -ge 1 ]]; do
+ echo $1
+ shift;
+ done
+}
+
+noslash() {
+ sed -e 's:/:\\/:g' $1
+}
+
+cslash() {
+ if grep -q "^$REMOTE_USER$" $DOCUMENT_ROOT/.slash; then
+ cat -
+ else
+ noslash -
+ fi
+}
+
+mpfd-ls() {
+ local file_count="`cat $DOCUMENT_ROOT/tmp/mpfd/file-count`"
+ for i in `seq 0 $file_count`; do
+ local FILE_PATH=$DOCUMENT_ROOT/tmp/mpfd/file$i
+ filename="`cat $FILE_PATH-name`"
+ echo $FILE_PATH $filename
+ done
+}
+
+literal() {
+ sed 's/</\<\;/g'
+}
+
+ls_shown() {
+ ls $1 | while read line; do
+ if [[ ! -f "$1/$line/.hidden" ]]; then
+ echo $line
+ fi
+ done
+}
+
+export GIT_HTTP_EXPORT_ALL=1
+export REQUEST_METHOD
+
+git_backend() {
+ export GIT_PROJECT_ROOT="/"
+ export PATH_INFO="`echo $DOCUMENT_URI | sed 's|^/~|/home/|'`"
+ # echo PATH_INFO$PATH_INFO
+ $DOCUMENT_ROOT/usr/local/libexec/git/git-http-backend 2>&1
+ exit
}
diff --git a/lib/optional-auth.sh b/lib/optional-auth.sh
index 34c5e0c..84081dd 100644
--- a/lib/optional-auth.sh
+++ b/lib/optional-auth.sh
@@ -1,8 +1,14 @@
#!/bin/ksh
-. $ROOT/lib/very-common.sh
+. $DOCUMENT_ROOT/lib/very-common.sh
-if [[ -f "$ROOT/sessions/$cookie" ]]; then
- user="`cat $ROOT/sessions/$cookie`"
+if [[ -f "$DOCUMENT_ROOT/sessions/$cookie" ]]; then
+ user="`cat $DOCUMENT_ROOT/sessions/$cookie`"
REMOTE_USER=$user
+elif [[ ! -z "$HTTP_AUTHORIZATION" ]]; then
+ AUTH="`echo $HTTP_AUTHORIZATION | awk '{print $2}' | openssl base64 -d | tr ':' ' '`"
+ username="`echo $AUTH | awk '{print $1}'`"
+ password="`echo $AUTH | awk '{print $2}'`"
+ auth $username $password 2>&1
+ REMOTE_USER=$username
fi
diff --git a/lib/order.sh b/lib/order.sh
index bb063fc..5732f62 100644
--- a/lib/order.sh
+++ b/lib/order.sh
@@ -1,28 +1,12 @@
#!/bin/ksh
OrderStateVendor() {
- TEMP="`getopt r: $*`"
- if [ $? -ne 0 ]; then
- exit 1;
- fi
- set -- $TEMP
- while [ $# -ne 0 ]; do
- case "$1" in
- -r)
- return_str="<input name=\"return\" type=\"hidden\" value=\"$2\"></input>"
- shift 2
- ;;
- --)
- shift
- break;
- ;;
- esac
- done
+ return_str="<input name=\"return\" type=\"hidden\" value=\"$1\"></input>"
cat <<!
-<form action="/e/order" method="POST" class="tac">
+<form action="/shop/$shop_id/order/$2" method="POST" class="tac">
<input type="hidden" name="shop_id" value="$shop_id"></input>
- <input type="hidden" name="order_id" value="$1"></input>
+ <input type="hidden" name="order_id" value="$2"></input>
$return_str
<button class="dib ps c$ORDER_STATE_COLOR">
$_ORDER_STATE
@@ -59,29 +43,11 @@ order_state_color() {
}
OrderState() {
- TEMP="`getopt r: $*`"
- if [ $? -ne 0 ]; then
- exit 1;
- fi
- set -- $TEMP
- while [ $# -ne 0 ]; do
- case "$1" in
- -r)
- ret=$1$2
- shift 2
- ;;
- --)
- shift
- break;
- ;;
- esac
- done
-
- _ORDER_STATE="`_ "$1"`"
- ORDER_STATE_COLOR="`order_state_color "$1"`"
+ _ORDER_STATE="`_ "$2"`"
+ ORDER_STATE_COLOR="`order_state_color "$2"`"
- if [[ "$REMOTE_USER" == "$SHOP_OWNER" ]]; then
- OrderStateVendor $ret $2
+ if im $SHOP_OWNER; then
+ OrderStateVendor $1 $3
else
OrderStateUser
fi
diff --git a/lib/school.sh b/lib/school.sh
new file mode 100644
index 0000000..fffbe53
--- /dev/null
+++ b/lib/school.sh
@@ -0,0 +1,34 @@
+SCHOOL_PATH="$DOCUMENT_ROOT/schools/$school_id"
+
+if [[ -z "$school_id" ]] || [[ ! -d "$SCHOOL_PATH" ]]; then
+ Fatal 404 School not found
+fi
+
+SCHOOL_OWNER="`cat $SCHOOL_PATH/.owner`"
+SCHOOL_BTN="<a class=\"$RB\" href=\"/e/school?school_id=$school_id\">🏫</a>"
+DF_USER="$SCHOOL_OWNER"
+
+export school_id
+export SCHOOL_BTN
+
+LabeledIDEdit() {
+ label=$1
+ typ=$2
+ typ_id=$3
+ assoc=$4
+ assoc_id=$5
+ extra=$6
+ cat <<!
+<div class="c0 ps rs _s">
+ <a class="tdn _s" href="/e/$typ?${typ}_id=$typ_id$extra">
+ <small>$label</small>
+ <span>$typ_id</span>
+ </a>
+ <a class="$RBXS cf0 c15" href="/e/$assoc-${typ}-associate?${assoc}_id=$assoc_id$extra">🖉</a>
+</div>
+!
+}
+
+invalid_s() {
+ invalid_id $2 || [[ ! -d "$SCHOOL_PATH/$1/$2" ]]
+}
diff --git a/lib/sem.sh b/lib/sem.sh
new file mode 100644
index 0000000..4e45d2e
--- /dev/null
+++ b/lib/sem.sh
@@ -0,0 +1,155 @@
+SemMenuOption() {
+ if [[ $e_mode == 1 ]]; then
+ echo "<div><a href=\"/e/sem-$1?sem_id=$sem_id\">`_ "$1"`</a></div>"
+ else
+ echo "<div><a href=\"/sem/$sem_id/$1\">`_ "$1"`</a></div>"
+ fi
+}
+
+js() {
+ cat <<!
+`cat $DOCUMENT_ROOT/js/menu.js`
+menu(document.getElementById("sem_menu_cont"));
+!
+}
+
+access() {
+ $SEM -p < $SEM_FILE
+}
+
+export JS="`js`"
+
+SemMenu() {
+ current="$1"
+ options=""
+ present="`echo $PRESENT | awk '{ print $1 }'`"
+
+ if im $SEM_OWNER; then
+ if [[ "$current" != "start" ]]; then
+ options="$options`SemMenuOption start`"
+ fi
+
+ if [[ "$current" != "pause" ]] && $SEM -p < $SEM_FILE | grep -q '^P '; then
+ options="$options`SemMenuOption pause`"
+ fi
+
+ if [[ "$current" != "resume" ]] && $SEM -p < $SEM_FILE | grep -q '^A '; then
+ options="$options`SemMenuOption resume`"
+ fi
+ else
+ case "$present" in
+ P)
+ if [[ "$current" != "pause" ]]; then
+ options="$options`SemMenuOption pause`"
+ fi
+
+ if [[ "$current" != "stop" ]]; then
+ options="$options`SemMenuOption stop`"
+ fi
+
+ ;;
+ A)
+ if [[ "$current" != "resume" ]]; then
+ options="$options`SemMenuOption resume`"
+ fi
+
+ if [[ "$current" != "stop" ]]; then
+ options="$options`SemMenuOption stop`"
+ fi
+
+ ;;
+ esac
+ fi
+
+ if [[ "$current" != "pay" ]]; then
+ options="$options`SemMenuOption pay`"
+ fi
+
+ if [[ "$current" != "transfer" ]]; then
+ options="$options`SemMenuOption transfer`"
+ fi
+
+ if [[ "$current" != "buy" ]]; then
+ options="$options`SemMenuOption buy`"
+ fi
+
+ cat <<!
+<label id="sem_menu_cont" class="$RB rel c15 cf0 menu">
+ +
+ <input type="checkbox" />
+ <div class="abs v0 f ah ak p c0 ts btn ttc">
+ $options
+ </div>
+</label>
+!
+}
+
+IdOptions() {
+ while read value sel; do
+ if test "$sel" == "y"; then
+ echo "<option selected value=\"$value\">$value</option>"
+ else
+ echo "<option value=\"$value\">$value</option>"
+ fi
+ done
+}
+
+SourceIdOptions() {
+ if im $SEM_OWNER; then
+ cat $SEM_PATH/.owner $SEM_PATH/.members
+ else
+ echo $REMOTE_USER
+ fi | IdOptions
+}
+
+sem_op() {
+ $DOCUMENT_ROOT/usr/bin/sem-echo "`echo $@`" < $SEM_FILE > $DOCUMENT_ROOT/tmp/data.txt
+
+ if $SEM -q 2>&1 < $DOCUMENT_ROOT/tmp/data.txt; then
+ DF_USER=$SEM_OWNER
+ cat $DOCUMENT_ROOT/tmp/data.txt | fwrite $SEM_FILE
+ rm $DOCUMENT_ROOT/tmp/data.txt
+ git -C $DOCUMENT_ROOT/sem/$sem_id add data.txt
+ git -C $DOCUMENT_ROOT/sem/$sem_id commit -m "$@"
+ if [[ $e_mode == 1 ]]; then
+ _see_other e/sem?sem_id=$sem_id
+ else
+ _see_other .
+ fi
+ else
+ rm $DOCUMENT_ROOT/tmp/data.txt
+ Fatal 409 We can not have that
+ fi
+}
+
+sem_source() {
+ if [[ $e_mode == 1 ]]; then
+ SEM_PATH="$DOCUMENT_ROOT/sems/$sem_id"
+ else
+ SEM_PATH="$DOCUMENT_ROOT/sem/$sem_id"
+ fi
+ if [[ -z "$sem_id" ]]; then
+ sem_id="`echo $SCRIPT_NAME | awk -F'/' '{print $3}'`"
+ SEM_PATH="$DOCUMENT_ROOT/sem/$sem_id"
+ sem_script=1
+ fi
+ SEM_FILE="$SEM_PATH/data.txt"
+
+ if [[ -z "$sem_id" ]] ; then
+ Fatal 404 Sem not found
+ fi
+
+ SEM_OWNER="`cat $SEM_PATH/.owner`"
+ SEM="$DOCUMENT_ROOT/usr/bin/sem"
+
+ if [[ ! -d "$SEM_PATH" ]]; then
+ Fatal 404 Sem not found
+ fi
+
+ PRESENT="`access | grep $REMOTE_USER || echo`"
+ if [[ -z "$PRESENT" ]] && ! test $REMOTE_USER == quirinpa; then
+ Unauthorized
+ fi
+
+ export sem_id
+}
diff --git a/lib/shop.sh b/lib/shop.sh
index cf06e21..526cfc1 100644
--- a/lib/shop.sh
+++ b/lib/shop.sh
@@ -1,178 +1,55 @@
get_product_path() {
- echo $ROOT/shops/$shop_id/$1
+ echo $DOCUMENT_ROOT/shop/$shop_id/$1
}
-ProductSummary() {
- if [[ ! -z "$REMOTE_USER" ]]; then
- qntstr=" x $quantity"
- fi
- cat <<!
-<div class="tsl">$product_price€$qntstr</div>
-!
-}
-
-ProductForm() {
- PRODUCT_STOCK="`cat $PRODUCT_PATH/stock`"
- cat <<!
-<div class="tsl">$product_price€</div>
-<div class="_ f fic">
- <form action="./cart" method="post" class="_ f fic wn">
- <input name="product_id" type="hidden" value="$PRODUCT_ID"></input>
- <input name="shop_id" type="hidden" value="$shop_id"></input>
- <input name="quantity" type="number" min="0" max="$PRODUCT_STOCK" value="$quantity" class="s_4_5"></input>
- $return_str
- <button class="$SRB">🛒</button>
- </form>
- $delete_form
-</div>
-!
-}
-
-DeleteProductForm() {
- cat <<!
-<form action="./shop" method="post">
- <input name="action" type="hidden" value="delete"></input>
- <input name="product_id" type="hidden" value="$PRODUCT_ID"></input>
- <input name="shop_id" type="hidden" value="$shop_id"></input>
- <button class="$SRB">×</button>
-</form>
-!
+product_env() {
+ local product_id=$1
+ product_path="`get_product_path $product_id`"
+ product_images="`zcat $product_path/images`"
+ [[ ! -z "$product_images" ]] || product_images=/img/no-image.png
+ product_image_path="`echo "$product_images" | head -n 1`"
+ product_title="`cat $product_path/title`"
+ product_description="`cat $product_path/description`"
+ product_price="`cat $product_path/price`"
+ product_stock="`cat $product_path/stock`"
}
-ProductImage() {
- cat <<!
-<a href="$1"><img height="128" class="ofc" src="$1" /></a>
-!
-}
-
-Product() {
- TEMP="`getopt r: $*`"
- if [ $? -ne 0 ]; then
- exit 1;
- fi
- set -- $TEMP
- while [ $# -ne 0 ]; do
- case "$1" in
- -r)
- if [[ -z "$REMOTE_USER" ]]; then
- shift 2
- continue
- fi
- return_str="<input name=\"return\" type=\"hidden\" value=\"$2\"></input>"
- SHOP_OWNER="`cat $SHOP_PATH/.owner`"
- if [[ "$2" == "shop" ]] && [[ "$SHOP_OWNER" == "$REMOTE_USER" ]]; then
- delete_form=y
- else
- if [[ "$2" == "product" ]]; then
- multiple_images=y
- fi
- fi
-
- shift 2
- ;;
- --)
- shift
- break;
- ;;
- esac
- done
-
- CART_PATH=$1
- PRODUCT_ID=$2
-
- if [[ ! -z "$delete_form" ]]; then
- delete_form="`DeleteProductForm`"
- fi
-
- PRODUCT_PATH="`get_product_path $PRODUCT_ID`"
-
- PRODUCT_IMAGES_CONTENT="`cat $PRODUCT_PATH/images`"
- if [[ -z "$PRODUCT_IMAGES_CONTENT" ]]; then
- PRODUCT_IMAGES_CONTENT=/img/no-image.png
- fi
-
- if [[ -z "$multiple_images" ]]; then
- PRODUCT_IMAGES="`echo "$PRODUCT_IMAGES_CONTENT" | head -n 1 | while read image_path; do ProductImage $image_path; done`"
- else
- PRODUCT_IMAGES="`echo "$PRODUCT_IMAGES_CONTENT" | while read image_path; do ProductImage $image_path; done`"
- if [[ ! -z $PRODUCT_IMAGES ]]; then
- PRODUCT_IMAGES="<div class=\"f fw _ v fic fcc\">$PRODUCT_IMAGES</div>"
- fi
- fi
-
- PRODUCT_TITLE="`cat $PRODUCT_PATH/title`"
- PRODUCT_DESCRIPTION="`cat $PRODUCT_PATH/description`"
- if [[ ! -z "$PRODUCT_DESCRIPTION" ]]; then
- PRODUCT_DESCRIPTION="<p>$PRODUCT_DESCRIPTION</p>"
- fi
-
- product_price="`cat $PRODUCT_PATH/price`"
-
- if [[ -f $CART_PATH ]]; then
- quantity="`cat $CART_PATH | grep $PRODUCT_ID | awk '{print $2}'`"
- if [[ -z "$quantity" ]]; then
- quantity=0
- fi
- else
- quantity=0
- fi
-
-
- if [[ -z "$return_str" ]]; then
- summary="`ProductSummary`"
- else
- summary="`ProductForm`"
- fi
-
+PImage() {
cat <<!
-<div class="card f v b0 fic p">
- $PRODUCT_IMAGES
- <a class="tsxl" href="/e/product?shop_id=$shop_id&product_id=$PRODUCT_ID">
- $PRODUCT_TITLE
- </a>
- $PRODUCT_DESCRIPTION
- $summary
-</div>
+<img height="128" class="ofc" src="`dirname $1`/small-`basename $1`" />
!
}
process_cart() {
+ local product_id
+ local quantity
cat $1 | while read product_id quantity; do
- PRODUCT_PATH="`get_product_path $product_id`"
- PRODUCT_PRICE="`cat $PRODUCT_PATH/price`"
- echo $quantity \* $PRODUCT_PRICE
+ local product_path="`get_product_path $product_id`"
+ local product_price="`cat $product_path/price`"
+ echo $quantity \* $product_price
done | sum_lines_exp
}
-ProductsFromCart() {
- TEMP="`getopt r: $*`"
- if [ $? -ne 0 ]; then
- exit 1;
- fi
- set -- $TEMP
- while [ $# -ne 0 ]; do
- case "$1" in
- -r)
- ret=$1$2
- shift 2
- ;;
- --)
- shift
- break;
- ;;
- esac
- done
-
-
- cat $1 | while read product_id quantity; do
- Product $ret $1 $product_id
+product_rm() {
+ local product_id=$1
+ cat $SHOP_PATH/$product_id/images | while read line; do
+ [[ ! -f "$DOCUMENT_ROOT$line" ]] || rm $DOCUMENT_ROOT$line
done
+ rm -rf $SHOP_PATH/$product_id
}
-SHOP_PATH=$ROOT/shops/$shop_id
-USER_PATH=$ROOT/users/$REMOTE_USER
-USER_SHOPS_PATH=$USER_PATH/shops
-USER_SHOP_PATH=$USER_SHOPS_PATH/$shop_id
-CART_PATH=$USER_SHOP_PATH/cart
-
-export shop_id
+shop_source() {
+ if [[ -z "$shop_id" ]]; then
+ shop_id="$ARG"
+ fi
+ SHOP_PATH=$DOCUMENT_ROOT/shop/$shop_id
+ if [[ -z "$shop_id" ]] || [[ ! -d "$SHOP_PATH" ]]; then
+ Fatal 404 Shop not found
+ fi
+ USER_PATH=$DOCUMENT_ROOT/users/$REMOTE_USER
+ USER_SHOPS_PATH=$USER_PATH/shops
+ USER_SHOP_PATH=$USER_SHOPS_PATH/$shop_id
+ CART_PATH=$USER_SHOP_PATH/cart
+ SHOP_OWNER="`cat $SHOP_PATH/.owner`"
+ export shop_id
+}
diff --git a/lib/very-common.sh b/lib/very-common.sh
index dc4116b..23cd447 100644
--- a/lib/very-common.sh
+++ b/lib/very-common.sh
@@ -5,6 +5,7 @@ set -e
[[ -z "$VERY_COMMON" ]] || return 0
VERY_COMMON=y
+RES_CONTENT_TYPE="text/html; charset=utf-8"
debug() {
echo Status: 500 Internal Error
@@ -12,17 +13,23 @@ debug() {
echo Sorry, I\'m currently debugging. Please wait.
}
+zcat() {
+ [[ -f "$@" ]] && cat $@ || true
+}
+
NormalHead() {
case "$1" in
200) STATUS_TEXT="OK";;
400) STATUS_TEXT="Bad Request";;
401) STATUS_TEXT="Unauthorized";;
404) STATUS_TEXT="Not Found";;
+ 409) STATUS_TEXT="Conflict";;
esac
export STATUS_TEXT
export STATUS_CODE=$1
echo "Status: $1 $STATUS_TEXT"
- echo 'Content-Type: text/html; charset=utf-8'
+ echo "Content-Type: $RES_CONTENT_TYPE"
+ [[ -z "$HEADERS" ]] || echo -n $HEADERS
}
Head() {
@@ -37,11 +44,17 @@ Head() {
!
}
+Scat() {
+ cat $1.html | envsubst
+ echo "</html>"
+ exit
+}
+
Cat() {
if [[ $# -lt 1 ]]; then
envsubst
else
- cat $ROOT/templates/$1.html | envsubst
+ cat $DOCUMENT_ROOT/templates/$1.html | envsubst
fi
echo "</html>"
}
@@ -50,7 +63,7 @@ Cat() {
get_lang() {
echo $HTTP_ACCEPT_LANGUAGE | tr ',' '\n' | tr '-' '_' | tr ';' ' ' | \
while read alang qlang; do \
- if grep "$alang" $ROOT/locale/langs; then
+ if grep "$alang" $DOCUMENT_ROOT/locale/langs; then
break
fi
done
@@ -63,33 +76,35 @@ if [[ -z "$LANG" ]]; then
LANG=pt_PT
fi
ILANG=$LANG
-# debug
-# echo $HTTP_ACCEPT_LANGUAGE
-# echo lang=$lang
_() {
+ arg="$@"
IFS='$'
TEXTDOMAIN=site
- value="`cat $ROOT/locale/$TEXTDOMAIN-$lang.txt | sed -n "s|^$@\|||p"`"
- [[ -z "$value" ]] && echo $@ || echo $value
+ value="`cat $DOCUMENT_ROOT/locale/$TEXTDOMAIN-$lang.txt | sed -n "s|^$arg\|||p"`"
+ [[ -z "$value" ]] && echo $arg || echo $value
}
-export RB="btn round ps tsxl"
+export RB="btn round p8 ts64"
+export RBS="btn round p8 ts"
+export RBXS="btn round p4 tss"
export SRB="btn round ps tsl"
Menu() {
if [[ ! -z "$REMOTE_USER" ]]; then
USER_NAME="<span class=\"ts\">$REMOTE_USER</span>"
- USER_ICON="<a class=\"tsxl f _ fic btn ps\" href=\"/e/user\"><span>🔑 </span><span> $USER_NAME</span></a>"
+ USER_ICON="<a class=\"tsxl f h fic btn p8\" href=\"/user\"><span role=\"img\" aria-label=\"user\">🔑 </span><span> $USER_NAME</span></a>"
else
- USER_ICON="<a class=\"$RB\" href=\"/e/login\">🔑 </a>"
+ USER_ICON="<a class=\"$RB\" href=\"/login\"><span role=\"img\" aria-label=\"login\">🔑 </span></a>"
fi
export USER_ICON
- cat $ROOT/components/menu.html | envsubst
+ cat $DOCUMENT_ROOT/components/menu.html | envsubst
}
Unauthorized() {
NormalHead 401
+ echo "Date: `TZ=GMT date '+%a, %d %b %Y %T %Z'`"
+ echo WWW-Authenticate: Basic realm="tty-pt"
export _TITLE="`_ Unauthorized`"
echo
Head
@@ -101,3 +116,25 @@ Unauthorized() {
cookie=$HTTP_COOKIE
cookie="`echo $cookie | tr ' ' '\n' | head -n 1`"
cookie="`echo $cookie | awk 'BEGIN { FS = "=" } { print $2 }'`"
+
+rand_str_1() {
+ # TODO maybe remove lowercase conversion
+ xxd -l32 -ps $DOCUMENT_ROOT/dev/urandom | xxd -r -ps | openssl base64 \
+ | tr -d = | tr + - | tr / _ | tr '[A-Z]' '[a-z]'
+}
+
+auth() {
+ username=$1
+ password=$2
+ hash="`grep "^$username:" $DOCUMENT_ROOT/.htpasswd | awk 'BEGIN{FS=":"} {print $2}'`"
+ [[ ! -z "$hash" ]] || Fatal 400 No such user
+ if crypt_checkpass "$password" "$hash"; then
+ Unauthorized
+ fi
+ [[ ! -f $ROOT/users/$username/rcode ]] || Fatal 400 The account was not activated
+
+ TOKEN="`rand_str_1`"
+ #[[ -d $ROOT/sessions ]] || mkdir $ROOT/sessions
+ echo $username > $DOCUMENT_ROOT/sessions/$TOKEN
+ HEADERS=$HEADERS"Set-Cookie: QSESSION=$TOKEN; SameSite=Lax\n"
+}
diff --git a/poem/.add b/poem/.add
new file mode 100644
index 0000000..54385d8
--- /dev/null
+++ b/poem/.add
@@ -0,0 +1,51 @@
+#!/bin/ksh
+
+[[ ! -z "$REMOTE_USER" ]] || Forbidden
+
+case "$REQUEST_METHOD" in
+ POST)
+ poem_id="`cat $ROOT/tmp/mpfd/poem_id`"
+
+ if invalid_id $poem_id; then
+ Fatal 400 Not a valid ID
+ fi
+
+ POEM_PATH="$ROOT/poem/$poem_id"
+
+ fmkdir $POEM_PATH
+ echo $REMOTE_USER | fwrite $POEM_PATH/.owner
+
+ mpfd-ls | while read FILE_PATH filename ; do
+ file_lang="`echo $filename | sed 's/\.[^.]*$//'`"
+ if invalid_lang "$file_lang"; then
+ Fatal 400 Not a valid locale
+ fi
+ fbytes $FILE_PATH
+ cat $FILE_PATH | cslash > $POEM_PATH/$file_lang.html
+ rm $FILE_PATH
+ touch $POEM_PATH/comments.txt
+ done
+
+ if [[ ! -f $POEM_PATH/$lang.html ]]; then
+ rm -rf $POEM_PATH
+ Fatal 400 You must submit a poem in your language
+ fi
+
+ _see_other /poem/$poem_id
+ ;;
+
+ GET)
+ export _TITLE="`_ "Add poem"`"
+ export _POEM_ID="`_ "Poem ID"`"
+ export _FILES="`_ Files`"
+ export _ADD_POEM_NOTE="`_ add_poem_note` $lang.html"
+ export _SUBMIT="`_ Submit`"
+
+ Normal 200 poem/add
+ Scat .template/add
+ ;;
+ *) NotAllowed ;;
+esac
+
+
+
diff --git a/poem/.index b/poem/.index
new file mode 100644
index 0000000..4c86d16
--- /dev/null
+++ b/poem/.index
@@ -0,0 +1,19 @@
+#!/bin/ksh
+
+if [[ ! -z "$1" ]]; then
+ case "$1" in
+ add) shift; . ./.add $@ ; exit 0;;
+ *) . ./.sub-index $@ ; exit 0;;
+ esac
+fi
+
+[[ "$REQUEST_METHOD" == "GET" ]] || NotAllowed
+export _TITLE="`_ Poems`"
+
+if [[ ! -z "$REMOTE_USER" ]]; then
+ export POEM_ADD="<a class=\"$RB\" href=\"/poem/add\">+</p>"
+fi
+
+export POEMS="`ls_shown $ROOT/poem | BigButtons poem`"
+Normal 200 poem
+Scat .template/index
diff --git a/poem/.sub-index b/poem/.sub-index
new file mode 100644
index 0000000..c4a4b85
--- /dev/null
+++ b/poem/.sub-index
@@ -0,0 +1,43 @@
+#!/bin/ksh
+
+poem_id=$1
+POEM_PATH=$ROOT/poem/$poem_id
+COMMENTS_PATH="$POEM_PATH/comments.txt"
+
+case "$REQUEST_METHOD" in
+ POST)
+ [[ ! -z "$REMOTE_USER" ]] || Unauthorized
+ echo $REMOTE_USER: "`urldecode "$comment"`" | fappend $COMMENTS_PATH
+ _see_other $poem_id\#comments
+ ;;
+ GET)
+ if [[ -z "$poem_id" ]]; then
+ Fatal 404 Poem not found
+ fi
+
+ POEM_HTML_PATH="$POEM_PATH/pt_PT.html"
+
+ if [[ ! -f "$POEM_HTML_PATH" ]] || [[ ! -d "$POEM_PATH" ]]; then
+ Fatal 404 Poem not found
+ fi
+
+ NEW_POEM_HTML_PATH="$POEM_PATH/$lang.html"
+ if [[ -f $NEW_POEM_HTML_PATH ]]; then
+ POEM_HTML_PATH=$NEW_POEM_HTML_PATH
+ fi
+
+ export poem_id
+
+ export _POEM="`cat $POEM_HTML_PATH`"
+ export _COMMENTS="`cat $COMMENTS_PATH | revlines | no_html`"
+
+ COUNTER_PATH=$POEM_PATH/counter.txt
+ export COUNTER="`counter_inc $COUNTER_PATH`"
+
+ export _TITLE="`_ "$poem_id"`"
+
+ Normal 200 poem/$poem_id
+ Scat .template/sub-index
+ ;;
+ *) NotAllowed ;;
+esac
diff --git a/poem/.template/add.html b/poem/.template/add.html
new file mode 100644
index 0000000..77a9d56
--- /dev/null
+++ b/poem/.template/add.html
@@ -0,0 +1,18 @@
+<body class="f fic v">
+ $MENU
+
+ <h1 class="tac">$_TITLE</h1>
+
+ <form action="add" method="POST" class="v f fic" enctype="multipart/form-data">
+ <label>
+ $_POEM_ID
+ <input required name="poem_id"></input>
+ </label>
+ <label>
+ $_FILES
+ <input required type="file" name="file[]" multiple></input>
+ </label>
+ <div>$_ADD_POEM_NOTE</div>
+ <button>$_SUBMIT</button>
+ </form>
+</body>
diff --git a/templates/poems.html b/poem/.template/index.html
similarity index 100%
rename from templates/poems.html
rename to poem/.template/index.html
diff --git a/poem/.template/sub-index.html b/poem/.template/sub-index.html
new file mode 100644
index 0000000..b7d6be1
--- /dev/null
+++ b/poem/.template/sub-index.html
@@ -0,0 +1,34 @@
+<style>
+pre,form { margin: 0 }
+pre {
+ display: inline-block;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+.s_k9 {
+ max-width: 512px;
+}
+</style>
+
+<body class="v">
+ <header class="h f fw v fic fcc">
+ <a href="#comments" class="$RB">💬</a>
+ $MENU
+ <div class="cf15 tsxl">$COUNTER</div>
+ </header>
+
+ <h1 class="tac">$_TITLE</h1>
+
+ <pre>
+$_POEM
+ </pre>
+
+ <form action="$poem_id" method="post" class="h f fic">
+ <input type="hidden" name="poem_id" value="$poem_id"></input>
+ <input class="fg" name="comment"></input>
+ </form>
+
+ <pre id="comments">
+$_COMMENTS
+ </pre>
+</body>
diff --git a/sem/.add b/sem/.add
new file mode 100644
index 0000000..58f396e
--- /dev/null
+++ b/sem/.add
@@ -0,0 +1,50 @@
+#!/bin/ksh
+
+ginit() {
+ mkdir $SEM_PATH/.git
+ git -C $SEM_PATH/.git init --bare
+ git --git-dir=$SEM_PATH/.git --work-tree=$SEM_PATH/. add $SEM_PATH/data.txt
+ git --git-dir=$SEM_PATH/.git --work-tree=$SEM_PATH/. commit -m "First commit"
+ cat - >> $SEM_PATH/.git/config <<!
+[http]
+ receivepack = true
+!
+ mkdir $SEM_PATH/.git/hooks
+ cp $DOCUMENT_ROOT/etc/skel/hooks/user-post-update .git/hooks/post-update
+ chmod +x $SEM_PATH/.git/hooks/post-update
+}
+
+case "$REQUEST_METHOD" in
+ POST)
+ sem_id="`cat $ROOT/tmp/mpfd/sem_id`"
+ sem_id="`urldecode $sem_id`"
+
+ if invalid_id $sem_id; then
+ Fatal 400 Not a valid ID
+ fi
+
+ SEM_PATH="$ROOT/sem/$sem_id"
+
+ fmkdir $SEM_PATH
+ echo $REMOTE_USER | fwrite $SEM_PATH/.owner
+
+ FILE_PATH=$ROOT/tmp/mpfd/file
+ if [[ -f $FILE_PATH ]]; then
+ fbytes $FILE_PATH
+ mv $FILE_PATH $SEM_PATH/data.txt
+ fi
+ ginit >/dev/null
+
+ see_other sem ?sem_id=$sem_id
+ ;;
+
+ GET)
+ export _TITLE="`_ "Add sem"`"
+ export _SEM_ID="`_ "Sem ID"`"
+ export _SUBMIT="`_ Submit`"
+
+ Normal 200 sem/add
+ Scat .template/add
+ ;;
+ *) NotAllowed ;;
+esac
diff --git a/sem/.buy b/sem/.buy
new file mode 100644
index 0000000..2429ce3
--- /dev/null
+++ b/sem/.buy
@@ -0,0 +1,32 @@
+#!/bin/ksh
+
+sem_source
+
+buy_options() {
+ if im $SEM_OWNER; then
+ $SEM -p < $SEM_FILE | awk '{ print $2 }'
+ else
+ echo $REMOTE_USER
+ fi
+}
+
+case "$REQUEST_METHOD" in
+ POST)
+ sem_op BUY `urldecode $ts` $id `urldecode $value` `urldecode $rest`
+
+ ;;
+ GET)
+ export _TITLE="`_ buy`"
+ export _DATE_TIME="`_ "Date / Time"`"
+ export _VALUE="`_ Value`"
+ export _MORE_INFO="`_ "More information"`"
+ export _SUBMIT="`_ Submit`"
+ export SEM_MENU="`SemMenu buy`"
+ export NOW="`date -u +"%Y-%m-%dT%H:%M:%S"`"
+ export ID_OPTIONS="`buy_options | IdOptions`"
+ Normal 200 sem/$sem_id/buy
+ Scat .template/buy
+
+ ;;
+ *) NotAllowed ;;
+esac
diff --git a/sem/.diff b/sem/.diff
new file mode 100755
index 0000000..8313678
--- /dev/null
+++ b/sem/.diff
@@ -0,0 +1,4 @@
+#!/bin/ksh
+
+. $DOCUMENT_ROOT/lib/command.sh
+git -C $DOCUMENT_ROOT/sem/$sem_id diff | Command sem diff
diff --git a/sem/.download b/sem/.download
new file mode 100644
index 0000000..9f11693
--- /dev/null
+++ b/sem/.download
@@ -0,0 +1,6 @@
+#!/bin/ksh
+
+echo Status 200: Ok
+echo Content-Type: text
+echo
+cat $SEM_FILE
diff --git a/sem/.index b/sem/.index
new file mode 100755
index 0000000..c43f7b8
--- /dev/null
+++ b/sem/.index
@@ -0,0 +1,21 @@
+#!/bin/ksh
+
+. $DOCUMENT_ROOT/lib/sem.sh
+
+if [[ ! -z "$ARG" ]]; then
+ case "$ARG" in
+ add) . ./.add ; exit 0;;
+ *) . ./.sub-index $@ ; exit 0;;
+ esac
+fi
+
+[[ "$REQUEST_METHOD" == "GET" ]] || NotAllowed
+
+export _TITLE="`_ Sems`"
+if [[ ! -z "$REMOTE_USER" ]]; then
+export SEM_ADD="<a class=\"$RB\" href=\"/sem/add\">+</a>"
+fi
+
+export SEMS="`ls $DOCUMENT_ROOT/sem | BigButtons sem`"
+Normal 200 sem
+Scat .template/index
diff --git a/sem/.pause b/sem/.pause
new file mode 100644
index 0000000..1df730b
--- /dev/null
+++ b/sem/.pause
@@ -0,0 +1,27 @@
+#!/bin/ksh
+
+pause_options() {
+ if im $SEM_OWNER; then
+ $SEM -p < $SEM_FILE | grep '^P ' | awk '{ print $2 }'
+ elif [[ "$PRESENT" == "P $REMOTE_USER" ]]; then
+ echo $REMOTE_USER
+ fi
+}
+
+case "$REQUEST_METHOD" in
+ POST)
+ sem_op PAUSE `urldecode $ts` $id `urldecode $rest`
+
+ ;;
+ GET)
+ export _TITLE="`_ pause`"
+ export _DATE_TIME="`_ "Date / Time"`"
+ export _MORE_INFO="`_ "More information"`"
+ export SEM_MENU="`SemMenu pause`"
+ export NOW="`date -u +"%Y-%m-%dT%H:%M:%S"`"
+ export ID_OPTIONS="`pause_options | IdOptions`"
+ Normal 200 pause
+ Scat .template/pause
+ ;;
+ *) NotAllowed ;;
+esac
diff --git a/sem/.pay b/sem/.pay
new file mode 100644
index 0000000..1f8dcb3
--- /dev/null
+++ b/sem/.pay
@@ -0,0 +1,82 @@
+#!/bin/ksh
+
+pay_options() {
+ if im $SEM_OWNER; then
+ $SEM -p < $SEM_FILE | sed "/^. $REMOTE_USER$/d" | awk '{print $2}'
+ fi
+ echo $REMOTE_USER y
+}
+
+payments() {
+ cat $SEM_FILE | sed -n '/^PAY /p'
+}
+
+types="`payments | awk '{print $7; print $3}' | sort -u`"
+last_payment="`payments | sed -n "/^PAY [^ ]* $REMOTE_USER .* $type/p" | tail -n 1`"
+
+pay_info() {
+ cat $SEM_FILE | sed -n '/^PAY /p' | awk '{print $7 " " $3}'
+}
+
+type_options() {
+ echo $TYPE y
+ pay_info | awk '{ print $1 }' | sort -u | sed "/^$TYPE$/d"
+}
+
+date_get() {
+ local res="`date -j -f "%Y-%m-%dT%H:%M:%S" "$1" +"%Y-%m-%d" || true`"
+ if test -z "$res"; then
+ res="`date -j -f "%Y-%m-%d" "$1" +"%Y-%m-%d"`"
+ fi
+ echo $res
+}
+
+month_inc() {
+ read date
+ local year="`echo $date | awk '{print $1}'`"
+ local month="`echo $date | awk '{print $2}'`"
+ year="`echo | bc -e "if ( $month + 1 > 12 ) $year + 1 else $year"`"
+ year="`printf "%04u" $year`"
+ month="`echo | bc -e "if ( $month + 1 > 12 ) 1 else ( $month + 1 )"`"
+ month="`printf "%02u" $month`"
+ echo $year-$month-`echo $date | awk '{print $3}'`
+}
+
+set -- $last_payment
+export VALUE=$4
+export START="`date_get "$5" | tr '-' ' '`"
+export END="`date_get "$6" | tr '-' ' '` | "
+START="`echo $START | month_inc | tr ' ' '-'`T00:00:00"
+END="`echo $END | month_inc | tr ' ' '-'`T00:00:00"
+TYPE=$7
+if ! test -z "$type"; then
+ TYPE=$type
+fi
+export ENTITY=$8
+
+case "$REQUEST_METHOD" in
+ POST)
+ sem_op PAY `urldecode $ts` $id `urldecode $value` `urldecode $from` `urldecode $to` $type $entity $reference
+
+ ;;
+ GET)
+ export _TITLE="`_ pay`"
+ export _DATE_TIME="`_ "Date / Time"`"
+ export _VALUE="`_ Value`"
+ export _BP_START="`_ "Start of billing period"`"
+ export _BP_END="`_ "End of billing period"`"
+ export _TYPE="`_ Type`"
+ export _ENTITY="`_ Entity`"
+ export _REFERENCE="`_ Reference`"
+ export _SUBMIT="`_ Submit`"
+ export SEM_MENU="`SemMenu pay`"
+ export NOW="`date -u +"%Y-%m-%dT%H:%M:%S"`"
+ export DNOW="`date -u +"%Y-%m-%d"`T00:00:00"
+ export ID_OPTIONS="`pay_options | IdOptions`"
+ export TYPE_OPTIONS="`type_options | IdOptions`"
+ Normal 200 pay
+ Scat .template/pay
+
+ ;;
+ *) NotAllowed ;;
+esac
diff --git a/sem/.resume b/sem/.resume
new file mode 100644
index 0000000..52cd3df
--- /dev/null
+++ b/sem/.resume
@@ -0,0 +1,29 @@
+#!/bin/ksh
+
+resume_options() {
+ if im $SEM_OWNER; then
+ $SEM -p < $SEM_FILE | grep '^A ' | awk '{ print $2 }'
+ elif [[ "$PRESENT" == "A $REMOTE_USER" ]]; then
+ echo $REMOTE_USER
+ fi
+}
+
+case "$REQUEST_METHOD" in
+ POST)
+ sem_op RESUME `urldecode $ts` $id `urldecode $rest`
+
+ ;;
+ GET)
+ export _TITLE="`_ resume`"
+ export _DATE_TIME="`_ "Date / Time"`"
+ export _MORE_INFO="`_ "More information"`"
+ export _SUBMIT="`_ Submit`"
+ export SEM_MENU="`SemMenu resume`"
+ export NOW="`date -u +"%Y-%m-%dT%H:%M:%S"`"
+ export ID_OPTIONS="`resume_options | IdOptions`"
+ Normal 200 resume
+ Scat .template/resume
+
+ ;;
+ *) NotAllowed ;;
+esac
diff --git a/sem/.start b/sem/.start
new file mode 100644
index 0000000..79c8140
--- /dev/null
+++ b/sem/.start
@@ -0,0 +1,24 @@
+#!/bin/ksh
+
+im $SEM_OWNER || Forbidden
+
+case "$REQUEST_METHOD" in
+ POST)
+ sem_op START `urldecode $ts` $id `urldecode $tel` `urldecode $email` `urldecode $name`
+
+ ;;
+ GET)
+ export _TITLE="`_ start`"
+ export _DATE_TIME="`_ "Date / Time"`"
+ export _TELEPHONE="`_ Telephone`"
+ export _EMAIL="`_ Email`"
+ export _NAME="`_ Name`"
+ export _SUBMIT="`_ Submit`"
+ export SEM_MENU="`SemMenu start`"
+ export NOW="`date -u +"%Y-%m-%dT%H:%M:%S"`"
+ Normal 200 start
+ Scat .template/start
+
+ ;;
+ *) NotAllowed ;;
+esac
diff --git a/sem/.stop b/sem/.stop
new file mode 100644
index 0000000..dc3dfc1
--- /dev/null
+++ b/sem/.stop
@@ -0,0 +1,29 @@
+#!/bin/ksh
+
+stop_options() {
+ if im $SEM_OWNER; then
+ $SEM -p < $SEM_FILE | awk '{ print $2 }'
+ else
+ echo $REMOTE_USER
+ fi
+}
+
+case "$REQUEST_METHOD" in
+ POST)
+ sem_op STOP `urldecode $ts` $id `urldecode $rest`
+
+ ;;
+ GET)
+ export _TITLE="`_ stop`"
+ export _DATE_TIME="`_ "Date / Time"`"
+ export _MORE_INFO="`_ "More information"`"
+ export _SUBMIT="`_ Submit`"
+ export SEM_MENU="`SemMenu stop`"
+ export NOW="`date -u +"%Y-%m-%dT%H:%M:%S"`"
+ export ID_OPTIONS="`stop_options | IdOptions`"
+ Normal 200 stop
+ Scat .template/stop
+
+ ;;
+ *) NotAllowed ;;
+esac
diff --git a/sem/.sub-index b/sem/.sub-index
new file mode 100755
index 0000000..feb7427
--- /dev/null
+++ b/sem/.sub-index
@@ -0,0 +1,66 @@
+#!/bin/ksh
+
+[[ ! -z "$REMOTE_USER" ]] || Unauthorized
+
+sem_source
+
+SUB_ARG="`echo $DOCUMENT_URI | awk -F '/' '{print $4}'`"
+
+case "$SUB_ARG" in
+ download) . ./.download ; exit;;
+ buy) . ./.buy ; exit;;
+ pause) . ./.pause ; exit;;
+ pay) . ./.pay ; exit;;
+ resume) . ./.resume ; exit;;
+ start) . ./.start ; exit;;
+ stop) . ./.stop ; exit;;
+ transfer) . ./.transfer ; exit;;
+ diff) . ./.diff ; exit;;
+ .git) git_backend; exit;;
+esac
+
+export _TITLE="`_ $sem_id`"
+export _SUBMIT="`_ Submit`"
+export _DOWNLOAD="`_ Download`"
+export _GRAPH="`_ Graph`"
+export _DEBUG="`_ Debug`"
+export _HUMAN="`_ Human`"
+export _MACHINE="`_ Machine`"
+export _PRESENT="`_ Present`"
+options=""
+
+export SEM_MENU="`SemMenu`"
+
+if [[ "$graph" == "on" ]]; then
+ export graph_checked=checked
+ options=$options"g"
+fi
+
+if [[ "$debug" == "on" ]]; then
+ export debug_checked=checked
+ options=$options"d"
+fi
+
+if [[ "$human" == "on" ]]; then
+ export human_checked=checked
+ options=$options"h"
+fi
+
+if [[ "$machine" == "on" ]]; then
+ export machine_checked=checked
+ options=$options"m"
+fi
+
+if [[ "$present" == "on" ]]; then
+ export present_checked=checked
+ options=$options"p"
+fi
+
+if [[ ! -z "$options" ]]; then
+ options="-$options"
+fi
+
+export SEM="`$SEM $options 2>&1 < $SEM_FILE`"
+
+Normal 200 sem/$sem_id
+Scat .template/sub-index
diff --git a/sem/.template/add.html b/sem/.template/add.html
new file mode 100644
index 0000000..aae5373
--- /dev/null
+++ b/sem/.template/add.html
@@ -0,0 +1,17 @@
+<body class="f fic v">
+ $MENU
+
+ <h1 class="tac">$_TITLE</h1>
+
+ <form action="/sem/add" method="POST" class="v f fic" enctype="multipart/form-data">
+ <label>
+ $_SEM_ID
+ <input required name="sem_id"></input>
+ </label>
+ <label>
+ File
+ <input type="file" name="file" accept="txt"></input>
+ </label>
+ <button>$_SUBMIT</button>
+ </form>
+</body>
diff --git a/sem/.template/buy.html b/sem/.template/buy.html
new file mode 100644
index 0000000..3e4c711
--- /dev/null
+++ b/sem/.template/buy.html
@@ -0,0 +1,39 @@
+<body class="v f fic rel">
+ <header class="h f fic">
+ $SEM_MENU
+ <a class="$RB" href="/sem/$sem_id">👁</a>
+ $MENU
+ </header>
+ <h1 class="tac ttc">$_TITLE</h1>
+ <form action="./buy" method="POST" class="v f">
+ <label>
+ $_DATE_TIME
+ <input required name="ts" type="datetime-local" value="$NOW" step="1"></input>
+ </label>
+
+ <label>
+ Id
+ <select required name="id">
+ $ID_OPTIONS
+ </select>
+ </label>
+
+ <label>
+ $_VALUE
+ <input required type="number" name="value" placeholder="33.33" step="0.01"></input>
+ </label>
+
+ <label>
+ $_MORE_INFO
+ <textarea name="rest"></textarea>
+ </label>
+
+ <input type="hidden" name="sem_id" value="$sem_id"></input>
+
+ <button>$_SUBMIT</button>
+ </form>
+</body>
+
+<script>
+$JS
+</script>
diff --git a/sem/.template/index.html b/sem/.template/index.html
new file mode 100644
index 0000000..9378c98
--- /dev/null
+++ b/sem/.template/index.html
@@ -0,0 +1,6 @@
+<body class="v f fic">
+ $MENU
+ <h1 class="tac">$_TITLE</h1>
+ $SEMS
+ $SEM_ADD
+</body>
diff --git a/sem/.template/pause.html b/sem/.template/pause.html
new file mode 100644
index 0000000..a9e844a
--- /dev/null
+++ b/sem/.template/pause.html
@@ -0,0 +1,38 @@
+<style>
+pre { display: inline-block; }
+</style>
+
+<body class="v f fic rel">
+ <header class="h f fic">
+ $SEM_MENU
+ <a class="$RB" href="/sem/$sem_id">👁</a>
+ $MENU
+ </header>
+ <h1 class="tac ttc">$_TITLE</h1>
+ <form action="./pause" method="POST" class="v f">
+ <label>
+ $_DATE_TIME
+ <input required name="ts" type="datetime-local" value="$NOW" step="1"></input>
+ </label>
+
+ <label>
+ Id
+ <select required name="id">
+ $ID_OPTIONS
+ </select>
+ </label>
+
+ <label>
+ $_MORE_INFO
+ <textarea name="rest"></textarea>
+ </label>
+
+ <input type="hidden" name="sem_id" value="$sem_id"></input>
+
+ <button>Submit</button>
+ </form>
+</body>
+
+<script>
+$JS
+</script>
diff --git a/sem/.template/pay.html b/sem/.template/pay.html
new file mode 100644
index 0000000..b664930
--- /dev/null
+++ b/sem/.template/pay.html
@@ -0,0 +1,88 @@
+<script src="/qr-scanner.umd.min.js"></script>
+<!-- <script src="https://unpkg.com/html5-qrcode" type="text/javascript"></script> -->
+
+<body class="v f fic rel">
+ <header class="h f fic">
+ $SEM_MENU
+ <a class="$RB" href="/sem/$sem_id">👁</a>
+ $MENU
+ </header>
+ <h1 class="tac ttc">$_TITLE</h1>
+ <form action="./pay" method="POST" class="v f fic">
+ <label>
+ $_DATE_TIME
+ <input required name="ts" type="datetime-local" value="$NOW" step="1"></input>
+ </label>
+
+ <label>
+ Id
+ <select required name="id">
+ $ID_OPTIONS
+ </select>
+ </label>
+
+ <label>
+ $_VALUE
+ <input required type="number" name="value" placeholder="33.33" step="0.01" value="$VALUE"></input>
+ </label>
+
+ <label>
+ $_BP_START
+ <input required name="from" type="datetime-local" value="$START" step="1"></input>
+ </label>
+
+ <label>
+ $_BP_END
+ <input required name="to" type="datetime-local" value="$END" step="1"></input>
+ </label>
+
+ <label>
+ $_TYPE
+ <select name="type">
+ $TYPE_OPTIONS
+ </select>
+ </label>
+
+ <label>
+ $_ENTITY
+ <input required name="entity" pattern="[0-9]{5}" value="$ENTITY"></input>
+ </label>
+
+
+ <label>
+ $_REFERENCE
+ <input required name="reference" pattern="[0-9]{9}"></input>
+ </label>
+
+ <input type="hidden" name="sem_id" value="$sem_id"></input>
+
+ <button>$_SUBMIT</button>
+
+ <!-- <div id="reader" class="s_f"></div> -->
+ <video class="s_f"></video>
+ </form>
+</body>
+
+<script>
+$JS
+
+const video = document.querySelector("video");
+const entity = document.querySelector("input[name=entity]");
+
+function fill(data) {
+ alert(data.split("*").join("\n"));
+}
+
+const qrScanner = new QrScanner(
+ video,
+ result => fill(
+ result.data,
+ ),
+ {
+ highlightScanRegion: true,
+ returnDetailedScanResult: true,
+ }
+);
+// qrScanner.start();
+console.log(entity);
+</script>
diff --git a/sem/.template/resume.html b/sem/.template/resume.html
new file mode 100644
index 0000000..d8c83ba
--- /dev/null
+++ b/sem/.template/resume.html
@@ -0,0 +1,35 @@
+<body class="v f fic rel">
+ <header class="h f fic">
+ $SEM_MENU
+ <a class="$RB" href="/sem/$sem_id">👁</a>
+ $MENU
+ </header>
+ <h1 class="tac ttc">$_TITLE</h1>
+ <form action="./resume" method="POST" class="v f">
+ <label>
+ $_DATE_TIME
+ <input required name="ts" type="datetime-local" value="$NOW" step="1"></input>
+ </label>
+
+ <label>
+ Id
+ <select required name="id">
+ $ID_OPTIONS
+ </select>
+ </label>
+
+ <label>
+ $_MORE_INFO
+ <textarea name="rest"></textarea>
+ </label>
+
+ <input type="hidden" name="sem_id" value="$sem_id"></input>
+
+ <button>$_SUBMIT</button>
+ </form>
+</body>
+
+<script>
+$JS
+</script>
+
diff --git a/sem/.template/start.html b/sem/.template/start.html
new file mode 100644
index 0000000..3a4d2d1
--- /dev/null
+++ b/sem/.template/start.html
@@ -0,0 +1,42 @@
+<body class="v f fic rel">
+ <header class="h f fic">
+ $SEM_MENU
+ <a class="$RB" href="/sem/$sem_id">👁</a>
+ $MENU
+ </header>
+ <h1 class="tac ttc">$_TITLE</h1>
+ <form action="./start" method="POST" class="v f">
+ <label>
+ $_DATE_TIME
+ <input required name="ts" type="datetime-local" value="$NOW" step="1"></input>
+ </label>
+
+ <label>
+ Id
+ <input required name="id"></input>
+ </label>
+
+ <label>
+ $_TELEPHONE
+ <input required type="tel" name="tel" pattern="\+[0-9]{12}"></input>
+ </label>
+
+ <label>
+ $_EMAIL
+ <input required type="email" name="email"></input>
+ </label>
+
+ <label>
+ $_NAME
+ <input required name="name"></input>
+ </label>
+
+ <input type="hidden" name="sem_id" value="$sem_id"></input>
+
+ <button>$_SUBMIT</button>
+ </form>
+</body>
+
+<script>
+$JS
+</script>
diff --git a/sem/.template/stop.html b/sem/.template/stop.html
new file mode 100644
index 0000000..55da3c3
--- /dev/null
+++ b/sem/.template/stop.html
@@ -0,0 +1,34 @@
+<body class="v f fic rel">
+ <header class="h f fic">
+ $SEM_MENU
+ <a class="$RB" href="/sem/$sem_id">👁</a>
+ $MENU
+ </header>
+ <h1 class="tac ttc">$_TITLE</h1>
+ <form action="./stop" method="POST" class="v f">
+ <label>
+ $_DATE_TIME
+ <input required name="ts" type="datetime-local" value="$NOW" step="1"></input>
+ </label>
+
+ <label>
+ Id
+ <select required name="id">
+ $ID_OPTIONS
+ </select>
+ </label>
+
+ <label>
+ $_MORE_INFO
+ <input name="rest"></input>
+ </label>
+
+ <input type="hidden" name="sem_id" value="$sem_id"></input>
+
+ <button>$_SUBMIT</button>
+ </form>
+</body>
+
+<script>
+$JS
+</script>
diff --git a/sem/.template/sub-index.html b/sem/.template/sub-index.html
new file mode 100644
index 0000000..9294d99
--- /dev/null
+++ b/sem/.template/sub-index.html
@@ -0,0 +1,54 @@
+<style>
+pre { display: inline-block; }
+</style>
+
+<body class="v f fic">
+ <header class="h f fic">
+ $SEM_MENU
+ $MENU
+ </header>
+
+ <h1 class="tac">$_TITLE</h1>
+
+ <pre>$SEM</pre>
+
+ <form action="./$sem_id" method="GET" class="v tac">
+ <div class="fw f h">
+ <label class="h">
+ <input type="checkbox" name="graph" $graph_checked></input>
+ $_GRAPH
+ </label>
+
+ <label class="h">
+ <input type="checkbox" name="debug" $debug_checked></input>
+ $_DEBUG
+ </label>
+
+ <label class="h">
+ <input type="checkbox" name="human" $human_checked></input>
+ $_HUMAN
+ </label>
+
+ <label class="h">
+ <input type="checkbox" name="machine" $machine_checked></input>
+ $_MACHINE
+ </label>
+
+ <label class="h">
+ <input type="checkbox" name="present" $present_checked></input>
+ $_PRESENT
+ </label>
+ </div>
+ <span class="h f fcc">
+ <button>$_SUBMIT</button>
+ <a class="btn" href="./$sem_id/download">$_DOWNLOAD</a>
+ </span>
+ </form>
+ <div class="tac">
+ git clone https://tty.pt/sem/$sem_id/.git
+ </div>
+</body>
+
+<script>
+$JS
+</script>
diff --git a/sem/.template/transfer.html b/sem/.template/transfer.html
new file mode 100644
index 0000000..c7d0bf4
--- /dev/null
+++ b/sem/.template/transfer.html
@@ -0,0 +1,46 @@
+<body class="v f fic rel">
+ <header class="h f fic">
+ $SEM_MENU
+ <a class="$RB" href="/sem/$sem_id">👁</a>
+ $MENU
+ </header>
+ <h1 class="tac ttc">$_TITLE</h1>
+ <form action="./transfer" method="POST" class="v f">
+ <label>
+ $_DATE_TIME
+ <input required name="ts" type="datetime-local" value="$NOW" step="1"></input>
+ </label>
+
+ <label>
+ Id
+ <select required name="id">
+ $FROM_ID_OPTIONS
+ </select>
+ </label>
+
+ <label>
+ $_TO
+ <select required name="to">
+ $TO_ID_OPTIONS
+ </select>
+ </label>
+
+ <label>
+ $_VALUE
+ <input required type="number" name="value" placeholder="33.33" step="0.01"></input>
+ </label>
+
+ <label>
+ $_MORE_INFO
+ <textarea name="rest"></textarea>
+ </label>
+
+ <input type="hidden" name="sem_id" value="$sem_id"></input>
+
+ <button>$_SUBMIT</button>
+ </form>
+</body>
+
+<script>
+$JS
+</script>
diff --git a/sem/.transfer b/sem/.transfer
new file mode 100644
index 0000000..4f91855
--- /dev/null
+++ b/sem/.transfer
@@ -0,0 +1,36 @@
+#!/bin/ksh
+
+transfer_from_options() {
+ if im $SEM_OWNER; then
+ $SEM -p < $SEM_FILE | awk '{ print $2 }'
+ else
+ echo $REMOTE_USER
+ fi
+}
+
+transfer_to_options() {
+ $SEM -p < $SEM_FILE | awk '{ print $2 }'
+}
+
+case "$REQUEST_METHOD" in
+ POST)
+ sem_op TRANSFER `urldecode $ts` $id `urldecode $to` `urldecode $value` `urldecode $rest`
+
+ ;;
+ GET)
+ export _TITLE="`_ transfer`"
+ export _DATE_TIME="`_ "Date / Time"`"
+ export _TO="`_ To`"
+ export _VALUE="`_ Value`"
+ export _MORE_INFO="`_ "More information"`"
+ export _SUBMIT="`_ Submit`"
+ export SEM_MENU="`SemMenu transfer`"
+ export NOW="`date -u +"%Y-%m-%dT%H:%M:%S"`"
+ export FROM_ID_OPTIONS="`transfer_from_options | IdOptions`"
+ export TO_ID_OPTIONS="`transfer_to_options | IdOptions`"
+ Normal 200 sem/$sem_id/transfer
+ Scat .template/transfer
+
+ ;;
+ *) NotAllowed ;;
+esac
diff --git a/shop/.add b/shop/.add
new file mode 100644
index 0000000..a6ba658
--- /dev/null
+++ b/shop/.add
@@ -0,0 +1,25 @@
+#!/bin/ksh
+
+case "$REQUEST_METHOD" in
+ POST) ;;
+ GET) export _TITLE="`_ "Add shop"`"
+ export _SHOP_ID="`_ "Shop ID"`"
+ export _SUBMIT="`_ Submit`"
+
+ Normal 200 shop/add
+ Scat .template/add
+ ;;
+ *) NotAllowed ;;
+esac
+
+shop_id="`urldecode $shop_id`"
+
+invalid_id $shop_id && Fatal 400 Not a valid ID || true
+
+SHOP_PATH="$ROOT/shop/$shop_id"
+
+fmkdir $SHOP_PATH
+echo $REMOTE_USER | fwrite $SHOP_PATH/.owner
+fmkdir $SHOP_PATH/.orders
+
+_see_other /shop/$shop_id
diff --git a/shop/.cart b/shop/.cart
new file mode 100644
index 0000000..78a7323
--- /dev/null
+++ b/shop/.cart
@@ -0,0 +1,88 @@
+#!/bin/ksh
+
+case "$1" in
+ edit) shift; . ./.cart-edit ; exit 0 ;;
+esac
+
+
+EmptyContents() {
+ _EMPTY="`_ "Empty"`"
+ echo "<div class=\"tsxl tac\">$_EMPTY</div>"
+}
+
+Products() {
+ local product_id
+ while read product_id quantity; do
+ product_env $product_id
+ cat <<!
+<a class="card f v8 b0 fic p" href="/shop/$shop_id/$product_id">
+ `PImage $product_image_path`
+ <div class="tsxl">$product_title</div>
+ <div class="tsl">$quantity x $product_price€</div>
+ `echo "$product_description" | csurround p`
+</a>
+!
+ done
+}
+
+Contents() {
+ TOTAL_CART_EXP="`process_cart $CART_PATH`"
+ TOTAL="`echo "$TOTAL_CART_EXP" | bc -l`"
+ _SUBMIT="`_ Submit`"
+ PRODUCTS="`cat $CART_PATH | Products | fw`"
+
+ cat <<!
+$PRODUCTS
+
+<div class="tcv fic v">
+ <div class="tsxl">$TOTAL€</div>
+ <form action="/shop/$shop_id/order" method="POST">
+ <button>$_SUBMIT</Button>
+ </form>
+</div>
+!
+}
+
+if [[ -z "$shop_id" ]] || [[ ! -d $SHOP_PATH ]]; then
+ Fatal 404 Shop not found
+fi
+
+case "$REQUEST_METHOD" in
+ POST) ;;
+ GET)
+ if [[ -f "$CART_PATH" ]] && [[ ! -z `cat $CART_PATH` ]]; then
+ CONTENTS="`Contents`"
+ export EDIT_BTN="`EditBtn "/shop/$shop_id/cart/edit"`"
+
+ else
+ CONTENTS="`EmptyContents`"
+ fi
+ export CONTENTS
+
+ export _TITLE="`_ $shop_id` - `_ Cart`"
+
+ Normal 200 shop/$shop_id/cart
+ Scat .template/cart
+ ;;
+ *) NotAllowed ;;
+esac
+
+local PRODUCT_PATH=$SHOP_PATH/$product_id
+
+if [[ -z "$product_id" ]] || [[ ! -d "$PRODUCT_PATH" ]]; then
+ Fatal 404 Product not found
+fi
+
+product_env $product_id # TODO think twice about this use case
+
+if [[ -f $CART_PATH ]] && cat $CART_PATH | grep -q $product_id; then
+ # only do something if this is not the case,
+ # otherwise just redir
+ echo -n ""
+elif [[ "$product_stock" != 0 ]]; then
+ echo $product_id 1 | fappend $CART_PATH
+else
+ Fatal 400 Not enough stock
+fi
+
+_see_other /shop/$shop_id/cart/edit
diff --git a/shop/.cart-edit b/shop/.cart-edit
new file mode 100644
index 0000000..871c653
--- /dev/null
+++ b/shop/.cart-edit
@@ -0,0 +1,64 @@
+#!/bin/ksh
+
+Products() {
+ local product_id
+ while read product_id quantity; do
+ product_env $product_id
+ cat <<!
+<div class="card f v8 b0 fic p">
+ `PImage $product_image_path`
+ <a class="tsxl" href="/shop/$shop_id/$product_id">$product_title</a>
+ <div class="f _s fic">
+ <input name="quantity_$product_id" type="number" min="0" max="$product_stock" value="$quantity" class="s_4_5"></input>
+ <div class="tsl">x $product_price€</div>
+ </div>
+ `echo "$product_description" | csurround p`
+</div>
+!
+ done
+}
+
+case "$REQUEST_METHOD" in
+ POST) ;;
+ GET)
+ if [[ ! -f "$CART_PATH" ]] || [[ -z "`cat $CART_PATH`" ]]; then
+ Fatal 400 You can not edit an empty cart
+ fi
+
+ export PRODUCTS="`cat $CART_PATH | Products | fw`"
+
+ export _TITLE="`_ $shop_id` - `_ "Edit cart"`"
+ export _SUBMIT="`_ Submit`"
+
+ # TODO im $CART_OWNER $SHOP_OWNER || Forbidden
+
+ Normal 200 shop/$shop_id/cart/edit
+ Scat .template/cart-edit
+ ;;
+ *) NotAllowed ;;
+esac
+
+cat $CART_PATH | while read product_id quantity; do
+ local qname=quantity_$product_id
+ eval echo $product_id \$$qname
+done | cat $CART_PATH - | sort -s -k1,1 | while read product_id old_quantity; do
+ read ignore quantity
+
+ product_env $product_id
+
+ local diff_exp="($quantity - $old_quantity)"
+ local new_stock_exp="$product_stock - $diff_exp"
+ local available_exp="$new_stock_exp >= 0"
+ local available="`echo $available_exp | bc`"
+
+ [[ "$available" != "0" ]] || Fatal 400 Not enough stock
+
+ # this should only happen on order placement
+ # local new_stock="`echo "$new_stock_exp" | bc`"
+ # echo $new_stock | fwrite $product_path/stock
+
+ # echo $product_id $quantity
+ [[ "$quantity" == "0" ]] || echo $product_id $quantity
+done > $CART_PATH
+
+_see_other /shop/$shop_id/cart
diff --git a/shop/.edit b/shop/.edit
new file mode 100644
index 0000000..5b7c51a
--- /dev/null
+++ b/shop/.edit
@@ -0,0 +1,58 @@
+#!/bin/ksh
+
+lsshown() {
+ find $1 -type d -mindepth 1 -maxdepth 1 -name "[!.]*" | sed "s|$1||" | sed "s/\/$//"
+}
+
+Products() {
+ local product_id
+ while read product_id; do
+ if [[ "`cat $SHOP_PATH/$product_id/stock`" -gt 0 ]]; then
+ product_env $product_id
+ cat <<!
+<label class="card f v8 b0 fic p">
+ `PImage $product_image_path`
+ <div class="tsl">$product_price€</div>
+ <a class="tsxl" href="/shop/$shop_id/$product_id">$product_title</a>
+ `echo "$product_description" | csurround p`
+ <input name="delete_$product_id" type="checkbox"></input>
+</label>
+!
+ fi
+ done
+}
+
+if [[ -z "$shop_id" ]] || [[ ! -d "$SHOP_PATH" ]]; then
+ Fatal 404 Shop not found
+fi
+
+case "$REQUEST_METHOD" in
+ POST) ;;
+ GET)
+ export _TITLE="`_ $shop_id` - `_ "Edit shop"`"
+ export _DELETE_PRODUCTS="`_ "Delete products"`"
+
+ export PRODUCTS="`lsshown $SHOP_PATH/ | Products | fw`"
+ SHOP_OWNER="`cat $SHOP_PATH/.owner`"
+ export SHOP_BUTTONS="`ShopButtons`"
+ if im $SHOP_OWNER; then
+ export ADD_PRODUCT_BUTTON="<div class=\"tar\"><a class=\"tsxl round p8 btn\" href=\"/e/product-add?shop_id=$shop_id\">+</a></div>"
+ export EDIT_BTN="`EditBtn "/shop/$shop_id/edit"`"
+ fi
+
+ Normal 200 shop/$shop_id/edit
+ Scat .template/edit
+ ;;
+ *) NotAllowed ;;
+esac
+
+im $SHOP_OWNER || Forbidden
+
+lsshown $SHOP_PATH/ | while read product_id; do
+qname=delete_$product_id
+eval echo $product_id \$$qname
+done | while read product_id state; do
+ [[ "$state" != "on" ]] || product_rm $product_id
+done
+
+_see_other .
diff --git a/shop/.index b/shop/.index
new file mode 100755
index 0000000..ad8924f
--- /dev/null
+++ b/shop/.index
@@ -0,0 +1,22 @@
+#!/bin/ksh
+
+. $DOCUMENT_ROOT/lib/shop.sh
+
+if [[ ! -z "$1" ]]; then
+ case "$1" in
+ add) shift; . ./.add $@ ; exit;;
+ *) shift; . ./.sub-index $@ ; exit;;
+ esac
+fi
+
+[[ "$REQUEST_METHOD" == "GET" ]] || NotAllowed
+
+export _TITLE="`_ Shops`"
+
+if [[ ! -z "$REMOTE_USER" ]]; then
+ export SHOP_ADD="<a class=\"$RB\" href=\"/shop/add\">+</a>"
+fi
+
+export SHOPS="`ls $DOCUMENT_ROOT/shop | BigButtons shop`"
+Normal 200 shop
+Scat .template/index
diff --git a/shop/.order/index b/shop/.order/index
new file mode 100644
index 0000000..7c170c1
--- /dev/null
+++ b/shop/.order/index
@@ -0,0 +1,96 @@
+#!/bin/ksh
+
+. $ROOT/lib/order.sh
+
+if [[ ! -z "$1" ]]; then
+ . ./sub-index $@
+ exit 0
+fi
+
+Order() {
+ ORDER_PATH=$SHOP_PATH/.orders/$1
+ ORDER_OWNER="`cat $ORDER_PATH/owner`"
+ TOTAL_EXP="`process_cart $ORDER_PATH/raw`"
+ TOTAL="`echo "$TOTAL_EXP" | bc -l`"
+ ORDER_STATE_TEXT="`cat $ORDER_PATH/state`"
+ ORDER_STATE="`OrderState orders "$ORDER_STATE_TEXT" $1`"
+
+ cat <<!
+<a href="/shop/$shop_id/order/$1" class="b0 p v">
+ <span>
+ $_ORDER #$1 - $ORDER_OWNER $TOTAL€
+ </span>
+
+ $ORDER_STATE
+</a>
+!
+}
+
+VendorOrders() {
+ ls $SHOP_PATH/.orders | while read line; do
+ Order $line
+ done
+}
+
+UserOrders() {
+ ls $SHOP_PATH/.orders | while read line; do
+ ORDER_PATH=$SHOP_PATH/.orders/$line
+ ORDER_OWNER="`cat $ORDER_PATH/owner`"
+ im $ORDER_OWNER && Order $line || true
+ done
+}
+
+case "$REQUEST_METHOD" in
+ POST) ;;
+ GET)
+ ORDERS_PATH=$SHOP_PATH/.orders
+
+ export _TITLE="`_ $shop_id` - `_ Orders`"
+
+ _ORDER="`_ Order`"
+
+ if im $SHOP_OWNER; then
+ ORDERS="`VendorOrders`"
+ else
+ ORDERS="`UserOrders`"
+ fi
+
+ export ORDERS="`echo "$ORDERS" | fw`"
+
+ Normal 200 shop/$shop_id/order
+ Scat template/index
+ ;;
+ *) NotAllowed ;;
+esac
+
+if [[ -z "`zcat $CART_PATH`" ]]; then
+ Fatal 404 Cart not found
+fi
+
+if [[ -z "`zcat $USER_PATH/address_line_1`" ]] \
+ || [[ -z "`zcat $USER_PATH/address_line_2`" ]] \
+ || [[ -z "`zcat $USER_PATH/zip`" ]]; then
+ Fatal 400 Invalid shipping address
+fi
+
+ORDERS_PATH=$SHOP_PATH/.orders
+ORDER_ID_PATH=$SHOP_PATH/.orders/.count
+ORDER_ID="`counter_inc $ORDER_ID_PATH`"
+ORDER_PATH=$SHOP_PATH/.orders/$ORDER_ID
+
+fmkdir $ORDERS_PATH
+fmkdir $ORDER_PATH
+cat $CART_PATH | fwrite $ORDER_PATH/raw
+echo $REMOTE_USER | fwrite $ORDER_PATH/owner
+echo Pending_payment | fwrite $ORDER_PATH/state
+cat $USER_PATH/address_line_1 | fwrite $ORDER_PATH/address_line_1
+cat $USER_PATH/address_line_2 | fwrite $ORDER_PATH/address_line_2
+cat $USER_PATH/zip | fwrite $ORDER_PATH/zip
+
+cat $ORDER_PATH/raw | while read product_id quantity; do
+ counter_dec $SHOP_PATH/$product_id/stock $quantity
+done >/tmp/null
+
+rm $CART_PATH # TODO also remove unneeded directories?
+
+_see_other order/$ORDER_ID
diff --git a/shop/.order/sub-index b/shop/.order/sub-index
new file mode 100644
index 0000000..302e188
--- /dev/null
+++ b/shop/.order/sub-index
@@ -0,0 +1,150 @@
+#!/bin/ksh
+
+order_id=$1
+
+AccountInfo() {
+ ACCOUNT_IBAN="`zcat $ROOT/users/$SHOP_OWNER/iban`"
+
+ if [[ -z "$ACCOUNT_IBAN" ]]; then
+ return
+ fi
+
+ cat <<!
+<div>
+ <div>`_ "Account IBAN"`</div>
+ <div>$ACCOUNT_IBAN</div>
+</div>
+!
+}
+
+MBWayInfo() {
+ PHONE_NUMBER="`zcat $ROOT/users/$SHOP_OWNER/phone_number`"
+
+ if [[ -z $PHONE_NUMBER ]]; then
+ return
+ fi
+
+ cat <<!
+<div>
+ <span>`_ "Phone number"` (MBWay): </span>
+ <a href="tel:$PHONE_NUMBER">$PHONE_NUMBER</a>
+</div>
+!
+}
+
+TransferData() {
+ OWNER_PATH=$ROOT/users/$SHOP_OWNER
+ OWNER_EMAIL="`cat $OWNER_PATH/email`"
+ cat <<!
+<div>`_ "Please refer to the order number in the credit description."` (#$order_id)</div>
+<div>`_ "You can send an e-mail to"` <a href="mailto:$OWNER_EMAIL">$OWNER_EMAIL</a> `_ "to speed up shipment."`</div>
+`AccountInfo`
+`MBWayInfo`
+!
+}
+
+AddressInfo() {
+ if [[ "$ORDER_STATE_TEXT" != "Pending_shipment" ]] \
+ || [[ "$REMOTE_USER" != "$SHOP_OWNER" ]]; then
+ return;
+ fi
+
+ cat <<!
+<pre>
+`cat $ORDER_PATH/address_line_1`
+`cat $ORDER_PATH/address_line_2`
+`cat $ORDER_PATH/zip`
+</pre>
+
+!
+}
+
+Products() {
+ local product_id
+ while read product_id quantity; do
+ product_env $product_id
+ cat <<!
+<a class="card f v8 b0 fic p" href="/shop/$shop_id/$product_id">
+ `PImage $product_image_path`
+ <div class="tsxl">$product_title</div>
+ `echo "$product_description" | csurround p`
+ <div class="tsl">$quantity x $product_price€</div>
+</a>
+!
+ done
+}
+
+if [[ -z "$shop_id" ]] || [[ ! -d "$SHOP_PATH" ]]; then
+ Fatal 404 Shop not found
+fi
+
+DF_USER=$SHOP_OWNER
+
+case "$REQUEST_METHOD" in
+ POST) ;;
+ GET)
+ ORDER_PATH=$SHOP_PATH/.orders/$order_id
+ if [[ -z "$order_id" ]] || [[ ! -d "$ORDER_PATH" ]]; then
+ Fatal 404 Order not found
+ fi
+
+ ORDER_OWNER="`cat $ORDER_PATH/owner`"
+
+ im $ORDER_OWNER $SHOP_OWNER || Forbidden
+
+ export order_id
+
+ export _TITLE="`_ $shop_id` - `_ Order` #$order_id"
+
+ TOTAL_EXP="`process_cart $ORDER_PATH/raw`"
+ export TOTAL="`echo "$TOTAL_EXP" | bc -l`"
+ export PRODUCTS="`cat $ORDER_PATH/raw | Products`"
+ ORDER_STATE_TEXT="`cat $ORDER_PATH/state`"
+ export ADDRESS_INFO="`AddressInfo`"
+ export ORDER_STATE="`OrderState order "$ORDER_STATE_TEXT" $order_id`"
+ if im $ORDER_OWNER; then
+ case "$ORDER_STATE_TEXT" in
+ Pending_payment)
+ TRANSFER_DATA=`TransferData`
+ export TRANSFER_DATA
+ ;;
+ esac
+ fi
+ Normal 200 order/$order_id
+ Scat template/sub-index
+ ;;
+ *) NotAllowed ;;
+esac
+
+ORDER_PATH=$SHOP_PATH/.orders/$order_id
+
+im $SHOP_OWNER || Forbidden
+
+ORDER_STATE_TEXT="`cat $ORDER_PATH/state`"
+case "$ORDER_STATE_TEXT" in
+ Pending_payment)
+ ORDER_STATE_TEXT=Pending_shipment
+ ;;
+ Pending_shipment)
+ ORDER_STATE_TEXT=Shipped
+ ;;
+ Shipped)
+ ORDER_STATE_TEXT=Delivered
+ ;;
+ Delivered)
+ rm -rf $ORDER_PATH
+ _see_other /shop/$shop_id/order
+ exit
+ ;;
+esac
+
+echo $ORDER_STATE_TEXT | fwrite $ORDER_PATH/state
+
+case "$return" in
+ order)
+ _see_other /shop/$shop_id/order/$order_id
+ ;;
+ orders)
+ _see_other /shop/$shop_id/order
+ ;;
+esac
diff --git a/templates/orders.html b/shop/.order/template/index.html
similarity index 61%
rename from templates/orders.html
rename to shop/.order/template/index.html
index 43bea7a..6c7fb17 100644
--- a/templates/orders.html
+++ b/shop/.order/template/index.html
@@ -2,8 +2,8 @@
pre { display: inline-block; }
</style>
<body class="v f fic">
- <header class="_ f fic">
- <a class="$RB" href="/e/shop?shop_id=$shop_id">💰</a>
+ <header class="h f fic">
+ <a class="$RB" href="/shop/$shop_id">💰</a>
$MENU
</header>
<h1 class="tac">$_TITLE</h1>
diff --git a/templates/order.html b/shop/.order/template/sub-index.html
similarity index 72%
rename from templates/order.html
rename to shop/.order/template/sub-index.html
index aa6672a..f514767 100644
--- a/templates/order.html
+++ b/shop/.order/template/sub-index.html
@@ -2,8 +2,8 @@
pre { display: inline-block; }
</style>
<body class="v f fic">
- <header class="_ f fic">
- <a class="$RB" href="/e/shop?shop_id=$shop_id">💰</a>
+ <header class="h f fic">
+ <a class="$RB" href="/shop/$shop_id">💰</a>
$MENU
</header>
<h1 class="tac">$_TITLE</h1>
@@ -13,3 +13,4 @@ pre { display: inline-block; }
$TRANSFER_DATA
$ADDRESS_INFO
</body>
+
diff --git a/shop/.product/add b/shop/.product/add
new file mode 100644
index 0000000..5c599e0
--- /dev/null
+++ b/shop/.product/add
@@ -0,0 +1,47 @@
+#!/bin/ksh
+
+im $SHOP_OWNER || Forbidden
+
+js() {
+ cat <<!
+`cat $ROOT/js/nfiles.js`
+
+nfiles( 'images',
+ document.getElementById('images'),
+ document.getElementById('submit'),
+ '`_ Submit`', 'file[]', '/e/image-add', '/e/images-edit');
+!
+}
+
+case "$REQUEST_METHOD" in
+ POST) ;;
+ GET)
+ export _TITLE="`_ $shop_id` - `_ "Add product"`"
+ export __TITLE="`_ Title`"
+ export _DESCRIPTION="`_ Description`"
+ export _IMAGES="`_ Images`"
+ export _STOCK="`_ Stock`"
+ export _PRICE="`_ Price`"
+ export _SUBMIT="`_ Submit`"
+ export JS="`js`"
+
+ Normal 200 shop/$shop_id/add
+ Scat template/add
+ ;;
+ *) NotAllowed ;;
+esac
+
+PRODUCT_ID_PATH=$SHOP_PATH/.count
+PRODUCT_ID="`counter_inc $PRODUCT_ID_PATH`"
+PRODUCT_PATH=$SHOP_PATH/$PRODUCT_ID
+DF_USER=$SHOP_OWNER
+
+fmkdir $PRODUCT_PATH
+urldecode $title | fwrite $PRODUCT_PATH/title
+urldecode $description | fwrite $PRODUCT_PATH/description
+images="`nfiles $images`"
+[[ -z "$images" ]] || a2l $images | fwrite $PRODUCT_PATH/images
+echo $price | fwrite $PRODUCT_PATH/price
+echo $stock | fwrite $PRODUCT_PATH/stock
+
+_see_other /shop/$shop_id
diff --git a/shop/.product/delete b/shop/.product/delete
new file mode 100644
index 0000000..9164468
--- /dev/null
+++ b/shop/.product/delete
@@ -0,0 +1,8 @@
+#!/bin/ksh
+[[ "$REQUEST_METHOD" == "POST" ]] || NotAllowed
+
+local product_path=$SHOP_PATH/$product_id
+SHOP_OWNER="`cat $SHOP_PATH/.owner`"
+im $SHOP_OWNER || Forbidden
+product_rm $product_id
+_see_other /shop/$shop_id
diff --git a/shop/.product/edit b/shop/.product/edit
new file mode 100644
index 0000000..7f6b8db
--- /dev/null
+++ b/shop/.product/edit
@@ -0,0 +1,56 @@
+#!/bin/ksh
+
+im $SHOP_OWNER || Forbidden
+
+js() {
+ cat <<!
+`cat $ROOT/js/nfiles.js`
+
+nfiles( 'images',
+ document.getElementById('images'),
+ document.getElementById('submit'),
+ '`_ Submit`', 'file[]', '/e/image-add', '/e/images-edit');
+!
+}
+
+case "$REQUEST_METHOD" in
+ POST) ;;
+ GET)
+ export _TITLE="`_ $shop_id` - `_ "Edit product"` #$product_id"
+ export __TITLE="`_ Title`"
+ export _DESCRIPTION="`_ Description`"
+ export _IMAGES="`_ Images`"
+ export _ADD_TO_STOCK="`_ "Add to stock"`"
+ export _PRICE="`_ Price`"
+ export _SUBMIT="`_ Submit`"
+ export JS="`js`"
+
+ product_env $product_id
+ export product_id
+ export product_stock
+ export product_title
+ export product_description
+ export product_images
+ export product_price
+
+ Normal 200 shop/$shop_id/$product_id/edit
+ Scat template/edit
+ ;;
+ *) NotAllowed ;;
+esac
+
+PRODUCT_PATH=$SHOP_PATH/$product_id
+DF_USER=$SHOP_OWNER
+
+fmkdir $PRODUCT_PATH
+urldecode $title | fwrite $PRODUCT_PATH/title
+urldecode $description | fwrite $PRODUCT_PATH/description
+images="`nfiles $images`"
+[[ -z "$images" ]] || a2l $images | fwrite $PRODUCT_PATH/images
+echo $price | fwrite $PRODUCT_PATH/price
+
+local stock_exp="`cat $PRODUCT_PATH/stock` + $stock"
+local new_stock="`echo $stock_exp | bc`"
+echo $new_stock | fwrite $PRODUCT_PATH/stock
+
+_see_other /shop/$shop_id/$product_id
diff --git a/shop/.product/index b/shop/.product/index
new file mode 100644
index 0000000..2a49b68
--- /dev/null
+++ b/shop/.product/index
@@ -0,0 +1,7 @@
+#!/bin/ksh
+
+case "$1" in
+ add) shift; . ./add ; exit 0 ;;
+esac
+
+. ./sub-index
diff --git a/shop/.product/sub-index b/shop/.product/sub-index
new file mode 100644
index 0000000..e828177
--- /dev/null
+++ b/shop/.product/sub-index
@@ -0,0 +1,67 @@
+#!/bin/ksh
+
+product_id=$1
+PRODUCT_PATH=$SHOP_PATH/$product_id
+
+if [[ -z "$product_id" ]] || [[ ! -d "$PRODUCT_PATH" ]]; then
+ Fatal 404 Product not found
+fi
+
+shift
+case "$1" in
+ delete) shift; . ./delete ; exit 0 ;;
+ edit) shift; . ./edit ; exit 0 ;;
+esac
+
+ProductImages() {
+ while read product_image_path; do
+ PImage $product_image_path | surround a "href=\"$product_image_path\""
+ done
+}
+
+CartAdd() {
+ if [[ $product_stock -le 0 ]]; then
+ return
+ fi
+
+ cat <<!
+<form action="/shop/$shop_id/cart" method="POST">
+ <button class="rs ps">`_ "Add to cart"`</button>
+ <input type="hidden" name="shop_id" value="$shop_id"></input>
+ <input type="hidden" name="product_id" value="$product_id"></input>
+</form>
+!
+}
+
+ProductDelete() {
+ cat <<!
+<form action="/shop/$shop_id/$product_id/delete" method="POST">
+ <input type="hidden" name="shop_id" value="$shop_id"></input>
+ <input type="hidden" name="product_id" value="$product_id"></input>
+ <button class="rs ps c1">`_ "Delete product"`</button>
+</form>
+!
+}
+
+[[ "$REQUEST_METHOD" == "GET" ]] || NotAllowed
+
+export _TITLE="`_ $shop_id` - `_ Product` #$product_id"
+
+product_env $product_id
+export product_title
+export product_price
+export product_stock
+export PRODUCT_IMAGES="`echo "$product_images" | ProductImages | fw 8`"
+export _STOCK="`_ Stock`"
+
+if [[ "$product_stock" != "0" ]]; then
+ export ADD_TO_CART="`CartAdd $CART_PATH`"
+fi
+
+if im $SHOP_OWNER; then
+ export DELETE_PRODUCT="`ProductDelete $product_id`"
+ export EDIT_BTN="`EditBtn "/shop/$shop_id/$product_id/edit"`"
+fi
+
+Normal 200 shop/$shop_id/$product_id
+Scat template/index
diff --git a/templates/product-add.html b/shop/.product/template/add.html
similarity index 76%
rename from templates/product-add.html
rename to shop/.product/template/add.html
index c280ac1..9950c48 100644
--- a/templates/product-add.html
+++ b/shop/.product/template/add.html
@@ -2,14 +2,14 @@
pre { display: inline-block; }
</style>
<body class="f fic v">
- <div class="f _">
- <a class="$RB" href="/e/shop?shop_id=$shop_id">💰</a>
+ <div class="f h">
+ <a class="$RB" href="/shop/$shop_id">💰</a>
$MENU
</div>
<h1 class="tac">$_TITLE</h1>
- <form action="/e/product-add" method="POST" class="v f fic">
+ <form action="add" method="POST" class="v f fic">
<input type="hidden" name="shop_id" value="$shop_id" />
<label>
$__TITLE
@@ -21,7 +21,7 @@ pre { display: inline-block; }
</label>
<label>
$_IMAGES
- <div class="_ f fic">
+ <div id="images" class="h f fic">
<textarea type="url" name="images"></textarea>
<a class="$RB" href="/e/images" target="_blank">🔍</a>
</div>
@@ -34,6 +34,10 @@ pre { display: inline-block; }
$_PRICE
<input required type="number" name="price" min="0" step="0.01"></input>
</label>
- <button>$_SUBMIT</button>
+ <button id="submit">$_SUBMIT</button>
</form>
</body>
+
+<script>
+$JS
+</script>
diff --git a/shop/.product/template/edit.html b/shop/.product/template/edit.html
new file mode 100644
index 0000000..731072d
--- /dev/null
+++ b/shop/.product/template/edit.html
@@ -0,0 +1,46 @@
+<style>
+pre { display: inline-block; }
+</style>
+<body class="f fic v">
+ <div class="f h">
+ <a class="$RB" href="/shop/$shop_id">💰</a>
+ $MENU
+ </div>
+
+ <h1 class="tac">$_TITLE</h1>
+
+ <form action="edit" method="POST" class="v f fic">
+ <input type="hidden" name="shop_id" value="$shop_id" />
+ <input type="hidden" name="product_id" value="$product_id" />
+ <label>
+ $__TITLE
+ <input required name="title" value="$product_title"></input>
+ </label>
+ <label>
+ $_DESCRIPTION
+ <textarea name="description">$product_description</textarea>
+ </label>
+ <label>
+ $_IMAGES
+ <div id="images" class="h f fic">
+ <textarea type="url" name="images">$product_images</textarea>
+ <a class="$RB" href="/e/images" target="_blank">🔍</a>
+ </div>
+ </label>
+ <label>
+ $_ADD_TO_STOCK
+ <input required type="number" name="stock" value="0"></input>
+ </label>
+ <label>
+ $_PRICE
+ <input required type="number" name="price" min="0" step="0.01" value="$product_price"></input>
+ </label>
+ <button id="submit">$_SUBMIT</button>
+ </form>
+</body>
+
+<script>
+$JS
+</script>
+
+
diff --git a/shop/.product/template/index.html b/shop/.product/template/index.html
new file mode 100644
index 0000000..517294c
--- /dev/null
+++ b/shop/.product/template/index.html
@@ -0,0 +1,14 @@
+<body class="v f fic">
+ <header class="h f fic">
+ $EDIT_BTN
+ <a class="$RB" href="/shop/$shop_id">💰</a>
+ $MENU
+ </header>
+ <h1 class="tac">$_TITLE</h1>
+ <div class="f fw h8 v8 fic">$PRODUCT_IMAGES</div>
+ <span class="tsxl">$product_title</span>
+ <div class="tsl">$product_price€</div>
+ <div>$_STOCK: $product_stock</div>
+ $ADD_TO_CART
+ $DELETE_PRODUCT
+</body>
diff --git a/shop/.sub-index b/shop/.sub-index
new file mode 100644
index 0000000..b2d91a4
--- /dev/null
+++ b/shop/.sub-index
@@ -0,0 +1,93 @@
+#!/bin/ksh
+
+shop_source
+
+case "$1" in
+ cart) shift; . ./.cart ; exit 0 ;;
+ prod) shift; . ./.product ; exit 0 ;;
+ edit) shift; . ./.edit ; exit 0;;
+ order)
+ shift
+ cd .order
+ . ./index
+ exit 0
+ ;;
+ *)
+ if [[ ! -z "$1" ]]; then
+ cd .product
+ . ./index $@
+ exit 0
+ fi
+ ;;
+esac
+
+lsshown() {
+ find $1 -type d -mindepth 1 -maxdepth 1 -name "[!.]*" | sed "s|$1||" | sed "s/\/$//"
+}
+
+Products() {
+ local product_id
+ while read product_id; do
+ local card_class=""
+
+ product_env $product_id
+
+ if [[ "$product_stock" == "0" ]]; then
+ card_class="c0"
+ fi
+
+ cat <<!
+<a class="card f v8 b0 fic p $card_class" href="/shop/$shop_id/$product_id">
+ `PImage $product_image_path`
+ <div class="tsl">$product_price€</div>
+ <span class="tsxl">$product_title</span>
+ `echo "$product_description" | csurround p`
+</a>
+!
+ done
+}
+
+ShopButtons() {
+ [[ ! -z "$REMOTE_USER" ]] || return
+
+ cat <<!
+<a class="$RB" href="/shop/$shop_id/order">🚚</a>
+<a class="$RB" href="/shop/$shop_id/cart">🛒</a>
+!
+}
+
+case "$REQUEST_METHOD" in
+ POST) ;;
+ GET)
+ export _TITLE="`_ $shop_id`"
+
+ export PRODUCTS="`lsshown $SHOP_PATH/ | Products | fw`"
+ export SHOP_BUTTONS="`ShopButtons`"
+ if im $SHOP_OWNER; then
+ export ADD_PRODUCT_BUTTON="<div class=\"tar\"><a class=\"tsxl round ps btn\" href=\"/shop/$shop_id/add\">+</a></div>"
+ export EDIT_BTN="`EditBtn "/shop/$shop_id/edit"`"
+ fi
+
+ Normal 200 shop/$shop_id
+ Scat .template/sub-index
+ ;;
+ *) NotAllowed ;;
+esac
+
+case "$action" in
+ delete)
+ PRODUCT_PATH=$SHOP_PATH/$product_id
+ if [[ -z "$product_id" ]] || [[ ! -d "$PRODUCT_PATH" ]]; then
+ Fatal 404 Product not found
+ fi
+
+ im $SHOP_OWNER || Forbidden
+
+ rm -rf $SHOP_PATH/$product_id
+
+ _see_other shop/$shop_id
+ ;;
+ *)
+ Fatal 400 Invalid action
+ ;;
+esac
diff --git a/templates/shop-add.html b/shop/.template/add.html
similarity index 75%
rename from templates/shop-add.html
rename to shop/.template/add.html
index 4e4e0c1..a0b4fbc 100644
--- a/templates/shop-add.html
+++ b/shop/.template/add.html
@@ -3,7 +3,7 @@
<h1 class="tac">$_TITLE</h1>
- <form action="/e/shop-add" method="POST" class="v f fic">
+ <form action="add" method="POST" class="v f fic">
<label>
$_SHOP_ID
<input required name="shop_id"></input>
diff --git a/shop/.template/cart-edit.html b/shop/.template/cart-edit.html
new file mode 100644
index 0000000..8fd0107
--- /dev/null
+++ b/shop/.template/cart-edit.html
@@ -0,0 +1,16 @@
+<body class="v f fic">
+ <header class="h f fic">
+ <a class="$RB" href="/shop/$shop_id">💰</a>
+ $MENU
+ </header>
+
+ <h1 class="tac">$_TITLE</h1>
+
+ <form action="/shop/$shop_id/cart/edit" method="POST" class="v f fic">
+ $PRODUCTS
+
+ <input type="hidden" name="shop_id" value="$shop_id"></input>
+
+ <button>$_SUBMIT</Button>
+ </form>
+</body>
diff --git a/templates/cart.html b/shop/.template/cart.html
similarity index 61%
rename from templates/cart.html
rename to shop/.template/cart.html
index 61b23b8..289037b 100644
--- a/templates/cart.html
+++ b/shop/.template/cart.html
@@ -2,8 +2,9 @@
pre { display: inline-block; }
</style>
<body class="v f fic">
- <header class="_ f fic">
- <a class="$RB" href="/e/shop?shop_id=$shop_id">💰</a>
+ <header class="h f fic">
+ $EDIT_BTN
+ <a class="$RB" href="/shop/$shop_id">💰</a>
$MENU
</header>
<h1 class="tac">$_TITLE</h1>
diff --git a/shop/.template/edit.html b/shop/.template/edit.html
new file mode 100644
index 0000000..2625ef3
--- /dev/null
+++ b/shop/.template/edit.html
@@ -0,0 +1,22 @@
+<style>
+pre { display: inline-block; }
+//.card input[type="checkbox"] { display: none; }
+.card:has(:checked) {
+ background-color: var(--C1);
+}
+</style>
+
+<body class="v f fic">
+ <header class="h f fic">
+ <a class="$RB" href="/e/shop?shop_id=$shop_id">💰</a>
+ $MENU
+ </header>
+
+ <h1 class="tac">$_TITLE</h1>
+
+ <form action="/e/shop-edit" method="POST" class="v f fic">
+ $PRODUCTS
+ <button>$_DELETE_PRODUCTS</button>
+ <input type="hidden" name="shop_id" value="$shop_id"></input>
+ </form>
+</body>
diff --git a/templates/shops.html b/shop/.template/index.html
similarity index 100%
rename from templates/shops.html
rename to shop/.template/index.html
diff --git a/shop/.template/sub-index.html b/shop/.template/sub-index.html
new file mode 100644
index 0000000..7a4c4e1
--- /dev/null
+++ b/shop/.template/sub-index.html
@@ -0,0 +1,14 @@
+<style>
+pre { display: inline-block; }
+</style>
+
+<body class="v f fic">
+ <header class="h f fic">
+ $EDIT_BTN
+ $SHOP_BUTTONS
+ $MENU
+ </header>
+ <h1 class="tac">$_TITLE</h1>
+ $PRODUCTS
+ $ADD_PRODUCT_BUTTON
+</body>
diff --git a/template/commands.html b/template/commands.html
new file mode 100644
index 0000000..0b9c673
--- /dev/null
+++ b/template/commands.html
@@ -0,0 +1,11 @@
+<body class="f fic tac v tsxl">
+ <form action="/whisper" method="POST">
+ <input name="whisper" class="c0"></input>
+ </form>
+ $MENU
+ <h2>$_TITLE</h2>
+ <a class="btn" href="/diff">diff</a>
+ <a class="btn" href="/nd-diff">$_NEVERDARK diff</a>
+ <a class="btn" href="/df">df</a>
+ <a class="btn" href="/quota">quota</a>
+</body>
diff --git a/template/index.html b/template/index.html
new file mode 100644
index 0000000..57d52e5
--- /dev/null
+++ b/template/index.html
@@ -0,0 +1,14 @@
+<body class="f fic tac v tsxl">
+ $MENU
+ <h2>tty.pt</h2>
+ <div><a class="btn" href="poem">$_POEMS</a></div>
+ <div><a class="btn" href="nd">$_NEVERDARK</a></div>
+ <!-- <div><a class="btn" href="/e/schools">$_SCHOOLS</a></div> -->
+ <div><a class="btn" href="shop">$_SHOPS</a></div>
+ <div><a class="btn" href="sem">$_SEM</a></div>
+ <div><a class="btn" href="/e/cgit.cgi">$_SOURCE_CODE</a></div>
+ <div><a class="btn" href="tty">$_TERMINAL</a></div>
+ <div><a class="btn" href="commands">$_COMMANDS</a></div>
+ <div><a class="btn" href="winbuntu">Winbuntu</a></div>
+</body>
+
diff --git a/templates/login.html b/template/login.html
similarity index 76%
rename from templates/login.html
rename to template/login.html
index c97b6eb..d1f9700 100644
--- a/templates/login.html
+++ b/template/login.html
@@ -3,7 +3,7 @@
<h1 class="tac">$_TITLE</h1>
- <form action="./login" method="POST" class="v f fic">
+ <form action="login" method="POST" class="v f fic">
<label>
$_USERNAME: <input required name="username"></input>
</label>
@@ -14,7 +14,7 @@
<button>$_SUBMIT</button>
</form>
- <a class="btn" href="/e/register">
+ <a class="btn" href="register">
$_REGISTER
</a>
</body>
diff --git a/templates/register.html b/template/register.html
similarity index 79%
rename from templates/register.html
rename to template/register.html
index 5ccc70c..d18fad1 100644
--- a/templates/register.html
+++ b/template/register.html
@@ -1,7 +1,7 @@
<body class="f fic v">
$MENU
<h1 class="tac">$_REGISTER</h1>
- <form action="./register" method="post" class="v f fic">
+ <form action="register" method="post" class="v f fic">
<label>
$_USERNAME: <input required name="username"></input>
</label>
@@ -18,11 +18,11 @@
<button>$_SUBMIT</button>
</form>
- <a class="btn c1" href="/e/cookie">
+ <a class="btn c1" href="cookie">
$_COOKIE_POLICY
</a>
- <a class="btn" href="/e/login">
+ <a class="btn" href="login">
$_LOGIN
</a>
</body>
diff --git a/templates/tty.html b/template/tty.html
similarity index 88%
rename from templates/tty.html
rename to template/tty.html
index 9ec0e64..2c3748c 100644
--- a/templates/tty.html
+++ b/template/tty.html
@@ -3,7 +3,7 @@ pre,form { margin: 0 }
pre { display: inline-block; }
</style>
<body class="v f fic">
- <header class="_ f fw v fic fcc">
+ <header class="h f fw v fic fcc">
$MENU
</header>
<h1 class="tac">$_TITLE</h1>
diff --git a/templates/registration-complete.html b/template/welcome.html
similarity index 99%
rename from templates/registration-complete.html
rename to template/welcome.html
index a130cbd..3652593 100644
--- a/templates/registration-complete.html
+++ b/template/welcome.html
@@ -3,4 +3,3 @@
<h1 class="tac">$_REGISTRATION_COMPLETE</h1>
<p>$_ACCOUNT_CREATED</p>
</body>
-
diff --git a/templates/class-add.html b/templates/class-add.html
new file mode 100644
index 0000000..c9cb098
--- /dev/null
+++ b/templates/class-add.html
@@ -0,0 +1,29 @@
+<body class="f fic v">
+ <div class="f fic h">
+ $SCHOOL_BTN
+ $MENU
+ </div>
+
+ <h1 class="tac">$_TITLE</h1>
+
+ <form action="/e/class-add" method="POST" class="v f fic">
+ <label>
+ $_CLASS_ID
+ <input required name="class_id"></input>
+ </label>
+ <label>
+ $_CLASS_TITLE
+ <input required name="class_title"></input>
+ </label>
+ <label>
+ $_TEACHER
+ <input required name="teacher"></input>
+ </label>
+ <label>
+ $_SEMESTER
+ <input required name="semester" type="number" value="1" min="1" max="6"></input>
+ </label>
+ <button>$_SUBMIT</button>
+ <input type="hidden" name="school_id" value="$school_id"></input>
+ </form>
+</body>
diff --git a/templates/class-grading.html b/templates/class-grading.html
new file mode 100644
index 0000000..532b7d9
--- /dev/null
+++ b/templates/class-grading.html
@@ -0,0 +1,20 @@
+<body class="f fic v">
+ <div class="f fic h">
+ $SCHOOL_BTN
+ $MENU
+ </div>
+
+ <h1 class="tac">$_TITLE ($class_id $student_id)</h1>
+
+ <form action="/e/class-grading" method="POST" class="v f fic">
+ <label>
+ $_GRADE
+ <input required name="grade" type="number" min="0" max="20" step="0.01"></input>
+ </label>
+
+ <button>$_SUBMIT</button>
+ <input type="hidden" name="school_id" value="$school_id"></input>
+ <input type="hidden" name="class_id" value="$class_id"></input>
+ <input type="hidden" name="student_id" value="$student_id"></input>
+ </form>
+</body>
diff --git a/templates/class-teacher-associate.html b/templates/class-teacher-associate.html
new file mode 100644
index 0000000..a959220
--- /dev/null
+++ b/templates/class-teacher-associate.html
@@ -0,0 +1,19 @@
+<body class="f fic v">
+ <div class="f fic h">
+ $SCHOOL_BTN
+ $MENU
+ </div>
+
+ <h1 class="tac">$_TITLE ($class_id)</h1>
+
+ <form action="/e/class-teacher-associate" method="POST" class="v f fic">
+ <label>
+ $_TEACHER_ID
+ <input required name="teacher_id"></input>
+ </label>
+ <button>$_SUBMIT</button>
+ <input type="hidden" name="school_id" value="$school_id"></input>
+ <input type="hidden" name="class_id" value="$class_id"></input>
+ </form>
+</body>
+
diff --git a/templates/class.html b/templates/class.html
new file mode 100644
index 0000000..d9d08cc
--- /dev/null
+++ b/templates/class.html
@@ -0,0 +1,21 @@
+<body class="v f fic">
+ <header class="h f fic">
+ $SCHOOL_BTN
+ $MENU
+ </header>
+
+ <h1 class="tac">$class_id - $class_title</h1>
+
+ <div class="h">
+ <div>
+ $_SEMESTER $class_semester
+ </div>
+
+ $TEACHER
+ </div>
+
+ $COURSES
+
+ $ASSIGN_GRADES
+</body>
+
diff --git a/templates/classes.html b/templates/classes.html
new file mode 100644
index 0000000..e898ffd
--- /dev/null
+++ b/templates/classes.html
@@ -0,0 +1,9 @@
+<body class="v f fic">
+ <div class="h f fic">
+ $SCHOOL_BTN
+ $MENU
+ </div>
+ <h1 class="tac">$_TITLE</h1>
+ $CLASSES
+ $CLASS_ADD
+</body>
diff --git a/templates/command.html b/templates/command.html
new file mode 100644
index 0000000..873cbab
--- /dev/null
+++ b/templates/command.html
@@ -0,0 +1,13 @@
+<style>
+pre {
+ text-align: left;
+}
+</style>
+
+<body class="f fic tac v">
+ $MENU
+ <div class="tsxl">$_TITLE</div>
+ <pre>
+$OUTPUT
+ </pre>
+</body>
diff --git a/templates/course-add.html b/templates/course-add.html
new file mode 100644
index 0000000..0980f2e
--- /dev/null
+++ b/templates/course-add.html
@@ -0,0 +1,25 @@
+<body class="f fic v">
+ <div class="f fic h">
+ $SCHOOL_BTN
+ $MENU
+ </div>
+
+ <h1 class="tac">$_TITLE</h1>
+
+ <form action="/e/course-add" method="POST" class="v f fic">
+ <label>
+ $_COURSE_ID
+ <input required name="course_id"></input>
+ </label>
+ <label>
+ $_COURSE_TITLE
+ <input required name="course_title"></input>
+ </label>
+ <label>
+ $_REGENT
+ <input required name="teacher_id"></input>
+ </label>
+ <button>$_SUBMIT</button>
+ <input type="hidden" name="school_id" value="$school_id"></input>
+ </form>
+</body>
diff --git a/templates/course-class-associate.html b/templates/course-class-associate.html
new file mode 100644
index 0000000..3a9960c
--- /dev/null
+++ b/templates/course-class-associate.html
@@ -0,0 +1,18 @@
+<body class="f fic v">
+ <div class="f fic h">
+ $SCHOOL_BTN
+ $MENU
+ </div>
+
+ <h1 class="tac">$_TITLE ($course_id)</h1>
+
+ <form action="/e/course-class-associate" method="POST" class="v f fic">
+ <label>
+ $_CLASS_ID
+ <input required name="class_id"></input>
+ </label>
+ <button>$_SUBMIT</button>
+ <input type="hidden" name="school_id" value="$school_id"></input>
+ <input type="hidden" name="course_id" value="$course_id"></input>
+ </form>
+</body>
diff --git a/templates/course-teacher-associate.html b/templates/course-teacher-associate.html
new file mode 100644
index 0000000..e118f7e
--- /dev/null
+++ b/templates/course-teacher-associate.html
@@ -0,0 +1,18 @@
+<body class="f fic v">
+ <div class="f fic h">
+ $SCHOOL_BTN
+ $MENU
+ </div>
+
+ <h1 class="tac">$_TITLE ($course_id)</h1>
+
+ <form action="/e/course-teacher-associate" method="POST" class="v f fic">
+ <label>
+ $_TEACHER_ID
+ <input required name="teacher_id"></input>
+ </label>
+ <button>$_SUBMIT</button>
+ <input type="hidden" name="school_id" value="$school_id"></input>
+ <input type="hidden" name="course_id" value="$course_id"></input>
+ </form>
+</body>
diff --git a/templates/course.html b/templates/course.html
new file mode 100644
index 0000000..7c5b9a9
--- /dev/null
+++ b/templates/course.html
@@ -0,0 +1,16 @@
+<body class="v f fic">
+ <header class="h f fic">
+ $SCHOOL_BTN
+ $MENU
+ </header>
+
+ <h1 class="tac">$course_id - $course_title</h1>
+
+ $REGENT
+
+ $CLASSES
+
+ $STUDENTS
+</body>
+
+
diff --git a/templates/courses.html b/templates/courses.html
new file mode 100644
index 0000000..af34045
--- /dev/null
+++ b/templates/courses.html
@@ -0,0 +1,9 @@
+<body class="v f fic">
+ <div class="h f fic">
+ $SCHOOL_BTN
+ $MENU
+ </div>
+ <h1 class="tac">$_TITLE</h1>
+ $COURSES
+ $COURSE_ADD
+</body>
diff --git a/templates/index.html b/templates/index.html
index 7ce16ea..f613052 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -3,8 +3,10 @@
<h2>tty.pt</h2>
<a class="btn" href="/e/poems">$_POEMS</a>
<a class="btn" href="/e/neverdark">$_NEVERDARK</a>
+ <a class="btn" href="/e/schools">$_SCHOOLS</a>
<a class="btn" href="/e/shops">$_SHOPS</a>
- <a class="btn" href="/sem.html">$_SEM</a>
- <a class="btn" href="https://github.com/quirinpa/vim.css">vim.css</a>
+ <a class="btn" href="/sem">$_SEM</a>
+ <a class="btn" href="/e/cgit.cgi">$_SOURCE_CODE</a>
<a class="btn" href="/e/tty">$_TERMINAL</a>
+ <a class="btn" href="/e/commands">$_COMMANDS</a>
</body>
diff --git a/templates/poem.html b/templates/poem.html
index 0e6bdae..2aa9136 100644
--- a/templates/poem.html
+++ b/templates/poem.html
@@ -11,7 +11,7 @@ pre {
</style>
<body class="v">
- <header class="_ f fw v fic fcc">
+ <header class="h f fw v fic fcc">
<a href="#comments" class="$RB">💬</a>
$MENU
<div class="cf15 tsxl">$COUNTER</div>
@@ -23,7 +23,7 @@ pre {
$_POEM
</pre>
- <form action="./poem#comments" method="post" class="_ f fic">
+ <form action="./poem#comments" method="post" class="h f fic">
<input type="hidden" name="poem_id" value="$poem_id"></input>
<input class="fg" name="comment"></input>
</form>
diff --git a/templates/product.html b/templates/product.html
deleted file mode 100644
index c106684..0000000
--- a/templates/product.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<body class="v f fic">
- <header class="_ f fic">
- <a class="$RB" href="/e/shop?shop_id=$shop_id">💰</a>
- $MENU
- </header>
- <h1 class="tac">$_TITLE</h1>
- $PRODUCT
-</body>
-
diff --git a/templates/school-add.html b/templates/school-add.html
new file mode 100644
index 0000000..a1e2f52
--- /dev/null
+++ b/templates/school-add.html
@@ -0,0 +1,19 @@
+<body class="f fic v">
+ $MENU
+
+ <h1 class="tac">$_TITLE</h1>
+
+ <form action="/e/school-add" method="POST" class="v f fic">
+ <label>
+ $_SCHOOL_ID
+ <input required name="school_id"></input>
+ </label>
+ <label>
+ $_SCHOOL_TITLE
+ <input required name="school_title"></input>
+ </label>
+ <button>$_SUBMIT</button>
+ </form>
+</body>
+
+
diff --git a/templates/school.html b/templates/school.html
new file mode 100644
index 0000000..cad5adf
--- /dev/null
+++ b/templates/school.html
@@ -0,0 +1,13 @@
+<body class="v f fic">
+ <header class="h f fic">
+ $SCHOOL_MENU
+ $MENU
+ </header>
+
+ <h1 class="tac">$school_title</h1>
+
+ <a class="btn" href="/e/teachers?school_id=$school_id">$_TEACHERS</a>
+ <a class="btn" href="/e/students?school_id=$school_id">$_STUDENTS</a>
+ <a class="btn" href="/e/courses?school_id=$school_id">$_COURSES</a>
+ <a class="btn" href="/e/classes?school_id=$school_id">$_CLASSES</a>
+</body>
diff --git a/templates/schools.html b/templates/schools.html
new file mode 100644
index 0000000..3a9f3ce
--- /dev/null
+++ b/templates/schools.html
@@ -0,0 +1,6 @@
+<body class="v f fic">
+ $MENU
+ <h1 class="tac">$_TITLE</h1>
+ $SCHOOLS
+ $SCHOOL_ADD
+</body>
diff --git a/templates/shop.html b/templates/shop.html
deleted file mode 100644
index 953a820..0000000
--- a/templates/shop.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<style>
-pre { display: inline-block; }
-</style>
-
-<body class="v f fic">
- <header class="_ f fic">
- <!--
- <form action="./shops" method="get" class="_ f ps fic">
- <input autofocus type="search" name="query"></input>
- <select name="category" multiple>
- $SHOP_CATEGORIES
- </select>
- <button class="tl">🔎</button>
- </form>
- -->
- $SHOP_BUTTONS
- $MENU
- </header>
- <h1 class="tac">$_TITLE</h1>
- $PRODUCTS
- $ADD_PRODUCT_BUTTON
-</body>
diff --git a/templates/student-add.html b/templates/student-add.html
new file mode 100644
index 0000000..126e590
--- /dev/null
+++ b/templates/student-add.html
@@ -0,0 +1,29 @@
+<body class="f fic v">
+ <div class="f fic h">
+ $SCHOOL_BTN
+ $MENU
+ </div>
+
+ <h1 class="tac">$_TITLE</h1>
+
+ <form action="/e/student-add" method="POST" class="v f fic">
+ <label>
+ $_STUDENT_ID
+ <input required name="student_id"></input>
+ </label>
+
+ <label>
+ $_NAME
+ <input required type="text" name="name"></input>
+ </label>
+
+ <label>
+ $_DOB
+ <input required type="date" name="dob"></input>
+ </label>
+
+ <button>$_SUBMIT</button>
+
+ <input type="hidden" name="school_id" value="$school_id"></input>
+ </form>
+</body>
diff --git a/templates/student-course-associate.html b/templates/student-course-associate.html
new file mode 100644
index 0000000..28eae8c
--- /dev/null
+++ b/templates/student-course-associate.html
@@ -0,0 +1,19 @@
+<body class="f fic v">
+ <div class="f fic h">
+ $SCHOOL_BTN
+ $MENU
+ </div>
+
+ <h1 class="tac">$_TITLE ($student_id)</h1>
+
+ <form action="/e/student-course-associate" method="POST" class="v f fic">
+ <label>
+ $_COURSE_ID
+ <input required name="course_id"></input>
+ </label>
+ <button>$_SUBMIT</button>
+ <input type="hidden" name="school_id" value="$school_id"></input>
+ <input type="hidden" name="student_id" value="$student_id"></input>
+ </form>
+</body>
+
diff --git a/templates/student-edit.html b/templates/student-edit.html
new file mode 100644
index 0000000..75d30ed
--- /dev/null
+++ b/templates/student-edit.html
@@ -0,0 +1,25 @@
+<body class="v f fic">
+ <header class="h f fic">
+ $SCHOOL_BTN
+ $MENU
+ </header>
+
+ <h1 class="tac">$_EDIT $_STUDENT - $student_id</h1>
+
+ <form action="/e/student-edit" method="POST" class="v f fic">
+ <label>
+ $_NAME
+ <input required type="text" name="name" value="$name"></input>
+ </label>
+
+ <label>
+ $_DOB
+ <input required type="date" name="dob" value="$dob"></input>
+ </label>
+
+ <button>$_SUBMIT</button>
+
+ <input type="hidden" name="school_id" value="$school_id"></input>
+ <input type="hidden" name="student_id" value="$student_id"></input>
+ </form>
+</body>
diff --git a/templates/student.html b/templates/student.html
new file mode 100644
index 0000000..660ca6a
--- /dev/null
+++ b/templates/student.html
@@ -0,0 +1,19 @@
+<body class="v f fic">
+ <header class="h f fic">
+ $EDIT_BTN
+ $SCHOOL_BTN
+ $MENU
+ </header>
+
+ <h1 class="tac">$_STUDENT - $student_id</h1>
+
+ $RN
+
+ $NAME
+
+ $DOB
+
+ $COURSES
+
+ $GRADES
+</body>
diff --git a/templates/students.html b/templates/students.html
new file mode 100644
index 0000000..06db46c
--- /dev/null
+++ b/templates/students.html
@@ -0,0 +1,12 @@
+<body class="v f fic">
+ <div class="h f fic">
+ $SCHOOL_BTN
+ $MENU
+ </div>
+
+ <h1 class="tac">$_TITLE</h1>
+
+ $STUDENTS
+
+ $STUDENT_ADD
+</body>
diff --git a/templates/teacher-add.html b/templates/teacher-add.html
new file mode 100644
index 0000000..bd57b3b
--- /dev/null
+++ b/templates/teacher-add.html
@@ -0,0 +1,29 @@
+<body class="f fic v">
+ <div class="f fic h">
+ $SCHOOL_BTN
+ $MENU
+ </div>
+
+ <h1 class="tac">$_TITLE</h1>
+
+ <form action="/e/teacher-add" method="POST" class="v f fic">
+ <label>
+ $_TEACHER_ID
+ <input required name="teacher_id"></input>
+ </label>
+
+ <label>
+ $_NAME
+ <input required type="text" name="name"></input>
+ </label>
+
+ <label>
+ $_DOB
+ <input required type="date" name="dob"></input>
+ </label>
+
+ <button>$_SUBMIT</button>
+
+ <input type="hidden" name="school_id" value="$school_id"></input>
+ </form>
+</body>
diff --git a/templates/teacher-edit.html b/templates/teacher-edit.html
new file mode 100644
index 0000000..5cceebb
--- /dev/null
+++ b/templates/teacher-edit.html
@@ -0,0 +1,25 @@
+<body class="v f fic">
+ <header class="h f fic">
+ $SCHOOL_BTN
+ $MENU
+ </header>
+
+ <h1 class="tac">$_EDIT $_TEACHER - $teacher_id</h1>
+
+ <form action="/e/teacher-edit" method="POST" class="v f fic">
+ <label>
+ $_NAME
+ <input required type="text" name="name" value="$name"></input>
+ </label>
+
+ <label>
+ $_DOB
+ <input required type="date" name="dob" value="$dob"></input>
+ </label>
+
+ <button>$_SUBMIT</button>
+
+ <input type="hidden" name="school_id" value="$school_id"></input>
+ <input type="hidden" name="teacher_id" value="$teacher_id"></input>
+ </form>
+</body>
diff --git a/templates/teacher.html b/templates/teacher.html
new file mode 100644
index 0000000..f5e1f78
--- /dev/null
+++ b/templates/teacher.html
@@ -0,0 +1,19 @@
+<body class="v f fic">
+ <header class="h f fic">
+ $EDIT_BTN
+ $SCHOOL_BTN
+ $MENU
+ </header>
+
+ <h1 class="tac">$_TEACHER - $teacher_id</h1>
+
+ $NAME
+
+ $DOB
+
+ $SALARY
+
+ $CLASSES
+
+ $COURSES
+</body>
diff --git a/templates/teachers.html b/templates/teachers.html
new file mode 100644
index 0000000..24beb00
--- /dev/null
+++ b/templates/teachers.html
@@ -0,0 +1,12 @@
+<body class="v f fic">
+ <div class="h f fic">
+ $SCHOOL_BTN
+ $MENU
+ </div>
+
+ <h1 class="tac">$_TITLE</h1>
+
+ $TEACHERS
+
+ $TEACHER_ADD
+</body>
diff --git a/templates/user-edit.html b/templates/user-edit.html
new file mode 100644
index 0000000..c1aac5e
--- /dev/null
+++ b/templates/user-edit.html
@@ -0,0 +1,45 @@
+<body class="f fic v">
+ $MENU
+
+ <h1 class="tac">$_TITLE</h1>
+
+ <form action="/e/user-edit" method="POST" class="f v fic">
+ <div class="h f fw v fic fcc">
+ <div class="f v fic">
+ <label>
+ $_NAME
+ <input type="text" name="name" value="$name"></input>
+ </label>
+ <label>
+ $_ADDRESS_LINE_1
+ <input type="text" name="address_line_1" value="$address_line_1" autocomplete="address-line1"></input>
+ </label>
+ <label>
+ $_ADDRESS_LINE_2
+ <input type="text" name="address_line_2" value="$address_line_2" autocomplete="address-line2"></input>
+ </label>
+ <label>
+ $_ZIP_CODE
+ <input name="zip" type="text" value="$zip" autocomplete="postal-code">
+ </label>
+ </div>
+ <div class="f v fic">
+ <label>
+ $_PHONE_NUMBER
+ <input name="phone_number" type="tel" value="$phone_number">
+ </label>
+ <label>
+ $_ACCOUNT_IBAN
+ <input type="text" name="iban" value="$iban"></input>
+ </label>
+ <label>
+ $_ACCOUNT_BICSWIFT
+ <input type="text" name="bicswift" value="$bicswift"></input>
+ </label>
+ </div>
+ </div>
+
+ <button>$_SUBMIT</button>
+ </form>
+</body>
+
diff --git a/templates/user.html b/templates/user.html
deleted file mode 100644
index 2043372..0000000
--- a/templates/user.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<style>
-pre { display: inline-block; }
-</style>
-<body class="f fic v">
- $MENU
-
- <h1 class="tac">$_TITLE</h1>
-
- <div class="tsxl">$_WELCOME</div>
-
- <div class="tac tsxl f">
- <a class="btn" href="/e/logout">$_LOGOUT</a>
- </div>
-
- <div class="f _ fw v fic fcc">
- <form method="POST" class="v f fic">
- <input type="hidden" name="action" value="personal_data"></input>
- <p>
- $_CHANGE_PERSONAL_DATA
- </p>
- <label>
- $_ADDRESS_LINE_1
- <input type="text" name="address_line_1" value="$address_line_1" autocomplete="address-line1"></input>
- </label>
- <label>
- $_ADDRESS_LINE_2
- <input type="text" name="address_line_2" value="$address_line_2" autocomplete="address-line2"></input>
- </label>
- <label>
- $_ZIP_CODE
- <input name="zip" type="text" value="$zip" autocomplete="postal-code">
- </label>
- <label>
- $_PHONE_NUMBER
- <input name="phone_number" type="tel" value="$phone_number">
- </label>
- <button>$_SUBMIT</button>
- </form>
-
- <form method="POST" class="v f fic">
- <input type="hidden" name="action" value="vendor_data"></input>
- <p>
- $_CHANGE_VENDOR_DATA
- </p>
- <label>
- $_ACCOUNT_IBAN
- <input type="text" name="iban" value="$iban"></input>
- </label>
- <label>
- $_ACCOUNT_BICSWIFT
- <input type="text" name="bicswift" value="$bicswift"></input>
- </label>
- <button>$_SUBMIT</button>
- </form>
- </div>
-</body>
diff --git a/user/.index b/user/.index
new file mode 100644
index 0000000..4d2b153
--- /dev/null
+++ b/user/.index
@@ -0,0 +1,88 @@
+#!/bin/ksh
+
+USER_PATH=$ROOT/users/$REMOTE_USER
+
+Field() {
+ cat | cond || {
+ cat <<!
+<div class="vxs">
+ <div class="tsxs">$1</div>
+ <pre class="cf15">`cat $contents`</pre>
+</div>
+!
+ }
+}
+
+Address() {
+ Field "$_ADDRESS" <<!
+`zcat $USER_PATH/address_line_1`
+`zcat $USER_PATH/address_line_2`
+`zcat $USER_PATH/zip`
+!
+}
+
+PhoneNumber() {
+ if [[ ! -f "$USER_PATH/phone_number" ]]; then
+ return
+ fi
+
+ local label="`_ "Phone number"`"
+ local value="`cat $USER_PATH/phone_number`"
+
+ cat <<!
+<div class="vxs">
+ <div class="tsxs">$label</div>
+ <a href="tel:$value" class="ts cf15">$value</a>
+</div>
+!
+
+}
+
+AccountInfo() {
+ if [[ ! -f "$USER_PATH/iban" ]] || [[ ! -f "$USER_PATH/bicswift" ]]; then
+ return
+ fi
+
+ local label="`_ "Account information"`"
+ local value="`cat $USER_PATH/phone_number`"
+
+ cat <<!
+<div class="vxs tss">
+ <div class="tsxs">$label</div>
+ <div class="_xs">
+ <span class="tsxs">`_ IBAN`</span>
+ <span class="cf15">`cat $USER_PATH/iban`</span>
+ </div>
+ <div class="_xs">
+ <span class="tsxs">`_ BICSWIFT`</span>
+ <span class="cf15">`cat $USER_PATH/bicswift`</span>
+ </div>
+</div>
+!
+
+}
+
+[[ "$REQUEST_METHOD" == "GET" ]] || NotAllowed
+
+if [[ -z "$user_id" ]] || im $user_id; then
+ export EDIT_BTN="`EditBtn "/e/user-edit?user_id=$user_id"`"
+fi
+
+_NAME="`_ Name`"
+
+export NAME="`zcat $USER_PATH/name | Field "$_NAME"`"
+export ADDRESS="`Address`"
+export PHONE_NUMBER="`PhoneNumber`"
+export ACCOUNT_INFO="`AccountInfo`"
+
+export _TITLE="`_ User` - $REMOTE_USER"
+export _LOGOUT="`_ Logout`"
+export _SUBMIT="`_ Submit`"
+export _PAGE="`_ Page`"
+
+export iban="`zcat $USER_PATH/iban`"
+export bicswift="`zcat $USER_PATH/bicswift`"
+export REMOTE_USER
+
+Normal 200 user
+Scat .template/index
diff --git a/user/.template/index.html b/user/.template/index.html
new file mode 100644
index 0000000..a34031e
--- /dev/null
+++ b/user/.template/index.html
@@ -0,0 +1,29 @@
+<body class="f fic v">
+ <header class="h f fic">
+ $EDIT_BTN
+ $MENU
+ </header>
+
+ <h1 class="tac">$_TITLE</h1>
+
+ <div class="h f fw v">
+ <div class="f v">
+ $NAME
+
+ $ADDRESS
+ </div>
+ <div class="f v">
+ $PHONE_NUMBER
+
+ $ACCOUNT_INFO
+ </div>
+ </div>
+
+ <div class="tac tsxl f">
+ <a class="btn" href="~$REMOTE_USER">$_PAGE</a>
+ </div>
+
+ <div class="tac tsxl f">
+ <a class="btn" href="logout">$_LOGOUT</a>
+ </div>
+</body>
diff --git a/winbuntu/.index b/winbuntu/.index
deleted file mode 100755
index e87b548..0000000
--- a/winbuntu/.index
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/ksh
-
-[[ "$REQUEST_METHOD" == "GET" ]] || NotAllowed
-export _TITLE="Winbuntu"
-
-Normal 200 winbuntu
-Scat .template/index
diff --git a/winbuntu/.template/index.html b/winbuntu/.template/index.html
deleted file mode 100644
index 9a6ca35..0000000
--- a/winbuntu/.template/index.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<body class="v f fic">
- $MENU
- <h1 class="tac">$_TITLE</h1>
- <div class="tal v">
- <p>This is a Linux distro based on Ubuntu 22.04.1 with a customized gnome environment to look like windows. Currently only for amd64.</p>
- <h2>Installation</h2>
- <p><a href="winbuntu-22.04.4-2024.03.02-desktop-amd64.iso">Click here to download winbuntu-22.04.4</a> or:</p>
- <pre class="p c0">
-curl tty.pt/winbuntu/winbuntu-22.04.4-2024.03.02-desktop-amd64.iso -O
- </pre>
- <p>Check that the checksum matches:</p>
- <pre class="p c0">
-md5sum ./winbuntu-22.04.4-2024.03.02-desktop-amd64.iso
- </pre>
- <p>Should match:</p>
- <pre class="p c0">
-a00f121bc5c5dd525e253a4193d3867b winbuntu-22.04.4-2024.03.02-desktop-amd64.iso
- </pre>
- <p>Write to a pen drive:</p>
- <pre class="p c0">
-dd if=./winbuntu-22.04.4-2024.03.02-desktop-amd64.iso of=/dev/sda bs=1M
- </pre>
- <p>Follow the installation wizard, and you are good to go.</p>
- <h2>Screenshots</h2>
- <div class="h v f fw">
- <a href="img/winbuntu0.png"><img height="320" src="img/winbuntu0.png"></img></a>
- <a href="img/winbuntu1.png"><img height="320" src="img/winbuntu1.png"></img></a>
- <a href="img/winbuntu2.png"><img height="320" src="img/winbuntu2.png"></img></a>
- <a href="img/winbuntu3.png"><img height="320" src="img/winbuntu3.png"></img></a>
- </div>
- </div>
-</body>
-