# HG changeset patch # User Christophe Lincoln # Date 1333447979 -7200 # Node ID 5adb233a979be8b427375e378ec872ac59272310 # Parent b3ab30f7f7ae8c77f39bbe538f2d35c91723cbd0 Add the web interface diff -r b3ab30f7f7ae -r 5adb233a979b Makefile --- a/Makefile Tue Apr 03 12:10:12 2012 +0200 +++ b/Makefile Tue Apr 03 12:12:59 2012 +0200 @@ -46,10 +46,10 @@ install-server: install -m 0700 -d $(DESTDIR)$(VAR)/people install -m 0700 -d $(DESTDIR)$(VAR)/auth - install -m 0777 -d $(DESTDIR)$(WEB) install -m 0777 -d $(DESTDIR)$(PREFIX)/share/doc/tazbug touch $(DESTDIR)$(VAR)/auth/people chmod 0600 $(DESTDIR)$(VAR)/auth/people cp -a web $(DESTDIR)$(WEB)/bugs cp README $(DESTDIR)$(PREFIX)/share/doc/tazbug chown -R www.www $(DESTDIR)$(VAR)/* + chown -R www.www $(DESTDIR)$(WEB)/bug diff -r b3ab30f7f7ae -r 5adb233a979b web/bug/0/bug.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/bug/0/bug.conf Tue Apr 03 12:12:59 2012 +0200 @@ -0,0 +1,11 @@ +# SliTaz Bug configuration + +BUG="Use SliTaz Bug Tracker" +STATUS="OPEN" +PRIORITY="standard" +CREATOR="root" +DATE="2012-03-29" +TAGS="" +PKGS="tazbug" + +DESC="The bug description with link and usefull information" diff -r b3ab30f7f7ae -r 5adb233a979b web/bugs.cgi --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/bugs.cgi Tue Apr 03 12:12:59 2012 +0200 @@ -0,0 +1,641 @@ +#!/bin/sh +# +# TazBug Web interface +# +# Copyright (C) 2012 SliTaz GNU/Linux - BSD License +# +. /usr/lib/slitaz/httphelper +[ -f "/etc/slitaz/tazbug.conf" ] && . /etc/slitaz/tazbug.conf +[ -f "../tazbug.conf" ] && . ../tazbug.conf + +# Internal variable +bugdir="bug" +sessions="/tmp/tazbug/sessions" + +# Content negotiation for Gettext +IFS="," +for lang in $HTTP_ACCEPT_LANGUAGE +do + lang=${lang%;*} lang=${lang# } lang=${lang%-*} + [ -d "$lang" ] && break + case "$lang" in + en) lang="C" ;; + fr) lang="fr_FR" ;; + esac +done +unset IFS +export LANG=$lang LC_ALL=$lang + +# Internationalization: $(gettext "") +. /usr/bin/gettext.sh +TEXTDOMAIN='tazbug' +export TEXTDOMAIN + +# +# Functions +# + +# HTML 5 header. +html_header() { + cat lib/header.html +} + +# HTML 5 footer. +html_footer() { + cat << EOT + + + + + + +EOT +} + +# Crypt pass when login +crypt_pass() { + echo -n "$1" | md5sum | awk '{print $1}' +} + +# Check if user is auth +check_auth() { + auth="$(COOKIE auth)" + user="$(echo $auth | cut -d ":" -f 1)" + md5cookie="$(echo $auth | cut -d ":" -f 2)" + [ -f "$sessions/$user" ] && md5session="$(cat $sessions/$user)" + if [ "$md5cookie" == "$md5session" ] && [ "$auth" ]; then + return 0 + else + return 1 + fi +} + +# Authentified or not +user_box() { + if check_auth; then + . $PEOPLE/$user/slitaz.conf + cat << EOT +
+$(get_gravatar $MAIL 20) +$user +Logout +
+EOT + else + cat << EOT +
+ [ User ] + Login +
+EOT + fi + cat << EOT + + +
+ +EOT +} + +# Login page +login_page() { + cat << EOT + +
+ +

$(gettext "Login")

+ +
+$(gettext "Not yet and account ? Please signup using SliTaz Bugs formular +from your SliTaz system.

Tip: to attach big files or images, you can use +SliTaz Paste service:") paste.slitaz.org +

+
+ +
+
+ + + + + + + + + + + + + + + +
$(gettext "User name")
$(gettext "Password")
$error
+
+
+ +
+EOT +} + +# Display user public profile. +public_people() { + cat << EOT +
+Real name : $NAME
+
+EOT +} + +# Display authentified user profile. TODO: change password +auth_people() { + cat << EOT +
+Real name  : $NAME
+Email      : $MAIL
+Secure key : $KEY
+
+EOT +} + +# Usage: list_bugs STATUS +list_bugs() { + echo "

$1 Bugs

" + for pr in critical standard + do + for bug in $(fgrep -H "$1" $bugdir/*/bug.conf | cut -d ":" -f 1) + do + . $bug + id=$(dirname $bug | cut -d "/" -f 2) + if [ "$PRIORITY" == "$pr" ]; then + cat << EOT +
+Bug title  : $BUG
+ID - Date  : $id - $DATE
+Creator    : $CREATOR - \
+Show Bug
+
+EOT + fi + done + done +} + +# Stripped down Wiki parser for bug desc and messages wich are simply +# displyed in
+wiki_parser() {
+	sed \
+		-e s"#http://\([^']*\).png#[ Image ]#"g \
+		-e s"#http://\([^']*\).*# \1#"g
+}
+
+# Bug page
+bug_page() {
+	if [ -f "$PEOPLE/$CREATOR/slitaz.conf" ]; then
+		. $PEOPLE/$CREATOR/slitaz.conf
+	else
+		MAIL="defaul"
+	fi
+	cat << EOT
+

Bug $id

+
+ +

+ $(get_gravatar $MAIL 32) $STATUS $BUG - $DATE - Priority $PRIORITY + - $msgs messages +

+ +
+$(echo "$DESC" | wiki_parser)
+
+ +
+EOT + if check_auth; then + if [ "$STATUS" == "OPEN" ]; then + cat << EOT +$(gettext "Close bug") +$(gettext "Edit bug") +EOT + else + cat << EOT +$(gettext "Re open bug") +EOT + fi + fi + cat << EOT +
+ +

$(gettext "Messages")

+EOT + [ "$msgs" == "0" ] && gettext "No messages" + for msg in $(ls -1tr $bugdir/$id/msg.*) + do + . $msg + if [ "$MSG" ]; then + msgid=$(echo $msg | cut -d "." -f 2) + del="" + # User can delete his post. + [ "$user" == "$USER" ] && \ + del="delete" + cat << EOT +

$USER $DATE $del

+
+$(echo "$MSG" | wiki_parser)
+
+EOT + fi + unset NAME DATE MSG + done + if check_auth; then + cat << EOT +
+

$(gettext "New message")

+ + + +

+ +
+EOT + fi +} + +# Write a new message +new_msg() { + date=$(date "+%Y-%m-%d %H:%M") + msgs=$(ls -1 $bugdir/$id/msg.* | wc -l) + count=$(($msgs + 1)) + if check_auth; then + USER="$user" + fi + sed "s/$(echo -en '\r') /\n/g" > $bugdir/$id/msg.$count << EOT +USER="$USER" +DATE="$date" +MSG="$(GET msg)" +EOT +} + +# Create a new Bug +new_bug() { + count=$(ls -1 $bugdir | wc -l) + date=$(date "+%Y-%m-%d %H:%M") + # Sanity check, JS may be disabled. + [ ! "$(GET bug)" ] && echo "Missing bug title" && exit 1 + [ ! "$(GET desc)" ] && echo "Missing bug description" && exit 1 + if check_auth; then + USER="$user" + fi + mkdir -p $bugdir/$count + sed "s/$(echo -en '\r') /\n/g" > $bugdir/$count/bug.conf << EOT +# SliTaz Bug configuration + +BUG="$(GET bug)" +STATUS="OPEN" +PRIORITY="$(GET priority)" +CREATOR="$USER" +DATE="$date" +PKGS="$(GET pkgs)" + +DESC="$(GET desc)" +EOT +} + +# New bug page for the web interface +new_bug_page() { + cat << EOT +

$(gettext "New Bug")

+
+ +
+ + + + + + + + + + + + + + + + + + + + +
$(gettext "Bug title")*
$(gettext "Description")*
$(gettext "Packages")
$(gettext "Priority") + + +
+
+ +

+$(gettext "* filed is obligatory. You can also specify affected packages.") +

+ +
+EOT +} + +# Edit/Save a bug configuration file +edit_bug() { + cat << EOT +

$(gettext "Edit Bug $bug")

+
+ +
+ + + +
+ +
+EOT +} + +save_bug() { + bug="$(GET bug)" + content="$(GET bugconf)" + sed "s/$(echo -en '\r') /\n/g" > $bugdir/$bug/bug.conf << EOT +$content +EOT +} + +# Close a fixed bug +close_bug() { + sed -i s'/OPEN/CLOSED/' $bugdir/$id/bug.conf +} + +# Re open an old bug +open_bug() { + sed -i s'/CLOSED/OPEN/' $bugdir/$id/bug.conf +} + +# Get and display Gravatar image: get_gravatar email size +# Link to profile: ... +get_gravatar() { + email=$1 + size=$2 + [ "$size" ] || size=48 + url="http://www.gravatar.com/avatar" + md5=$(echo -n $email | md5sum | cut -d " " -f 1) + echo "" +} + +# Create a new user +new_user_config() { + mail="$(GET mail)" + pass="$(GET pass)" + key=$(echo -n "$user:$mail:$pass" | md5sum | awk '{print $1}') + echo "$user:$pass" >> $AUTH_FILE + mkdir -p $PEOPLE/$user/ + cat > $PEOPLE/$user/slitaz.conf << EOT +# SliTaz user configuration +# + +NAME="$(GET name)" +USER="$user" +MAIL="$mail" +KEY="$key" + +COMMUNITY="$(GET scn)" +LOCATION="$(GET location)" +RELEASES="$(GET releases)" +PACKAGES="$(GET packages)" +EOT + chmod 0600 $PEOPLE/$user/slitaz.conf +} + +# +# POST actions +# + +case " $(POST) " in + *\ auth\ *) + # Authenticate user. Create a session file in $sessions to be used + # by check_auth. We have the user login name and a peer session + # md5 string in the COOKIE. + user="$(POST auth)" + pass="$(crypt_pass "$(POST pass)")" + valid=$(fgrep "${user}:" $AUTH_FILE | cut -d ":" -f 2) + if [ "$pass" == "$valid" ] && [ "$pass" != "" ]; then + md5session=$(echo -n "$$:$user:$pass:$$" | md5sum | awk '{print $1}') + mkdir -p $sessions + echo "$md5session" > $sessions/$user + header "Location: $WEB_URL" \ + "Set-Cookie: auth=$user:$md5session; HttpOnly" + else + header "Location: $WEB_URL?login&error" + fi ;; +esac + +# +# GET actions +# + +case " $(GET) " in + *\ README\ *) + header + html_header + user_box + echo '

README

' + echo '
'
+		cat /usr/share/doc/tazbug/README
+		echo '
' + html_footer ;; + *\ closed\ *) + # Show all closed bugs. + header + html_header + user_box + list_bugs CLOSED + html_footer ;; + *\ login\ *) + # The login page + [ "$(GET error)" ] && \ + error="$(gettext "Bad login or pass")" + header + html_header + login_page + html_footer ;; + *\ logout\ *) + # Set a Cookie in the past to logout. + expires="Expires=Wed, 01-Jan-1980 00:00:00 GMT" + if check_auth; then + rm -f "$sessions/$user" + header "Location: $WEB_URL" "Set-Cookie: auth=none; $expires; HttpOnly" + fi ;; + *\ user\ *) + # User profile + header + html_header + user_box + . $PEOPLE/"$(GET user)"/slitaz.conf + echo "

$(get_gravatar $MAIL) $(GET user)

" + if check_auth && [ "$(GET user)" == "$user" ]; then + auth_people + else + public_people + fi + html_footer ;; + *\ newbug\ *) + # Add a bug from web interface. + header + html_header + user_box + if check_auth; then + new_bug_page + else + echo "

$(gettext "You must be logged to post a new bug")

" + fi + html_footer ;; + *\ addbug\ *) + # Add a bug from web interface. + if check_auth; then + new_bug + header "Location: $WEB_URL?id=$count" + fi ;; + *\ edit\ *) + bug="$(GET edit)" + header + html_header + user_box + edit_bug + html_footer ;; + *\ bugconf\ *) + if check_auth; then + save_bug + header "Location: $WEB_URL?id=$bug" + fi ;; + *\ id\ *) + # Empty deleted messages to keep msg count working. + id="$(GET id)" + [ "$(GET close)" ] && close_bug + [ "$(GET open)" ] && open_bug + [ "$(GET msg)" ] && new_msg + [ "$(GET delmsg)" ] && rm -f $bugdir/$id/msg.$(GET delmsg) && \ + touch $bugdir/$id/msg.$(GET delmsg) + msgs=$(fgrep MSG= $bugdir/$id/msg.* | wc -l) + header + html_header + user_box + . $bugdir/$id/bug.conf + bug_page + html_footer ;; + *\ signup\ *) + # Signup + header "Content-type: text/plain;" + user="$(GET signup)" + echo "Requested user login : $user" + if fgrep -q "$user:" $AUTH_FILE; then + echo "ERROR: User already exist" && exit 1 + else + echo "Creating account for : $(GET name)" + new_user_config + fi ;; + *\ key\ *) + # Let user post new bug or message with crypted key (no gettext) + # + # Testing only and is security acceptable ? + # + key="$(GET key)" + id="$(GET bug)" + header "Content-type: text/plain;" + echo "Checking secure key..." + if fgrep -qH $key $PEOPLE/*/slitaz.conf; then + conf=$(fgrep -H $key $PEOPLE/*/slitaz.conf | cut -d ":" -f 1) + . $conf + echo "Authentified: $NAME ($USER)" + case " $(GET) " in + *\ msg\ *) + [ ! "$id" ] && echo "Missing bug ID" && exit 0 + echo "Posting new message to bug: $id" + echo "Message: $(GET msg)" + new_msg ;; + *\ bug\ *) + echo "Adding new bug: $(GET bug)" + echo "Description: $(GET desc)" + new_bug ;; + esac + else + echo "Not a valid SliTaz user key" + exit 0 + fi ;; + *\ search\ *) + header + html_header + user_box + cat << EOT +

$(gettext "Search")

+
+ + +
+
+EOT
+		IFS="/"
+		grep -i -H $(GET search) $bugdir/*/* | while read bug id file
+		do
+			echo -n "Bug $id : " 
+			echo $file | cut -d : -f 2 | \
+				sed s"/$(GET search)/$(GET search)<\/span>/"g
+		done
+		unset IFS
+		echo '
' + html_footer ;; + *) + # Default page. + bugs=$(ls -1 $bugdir | wc -l) + close=$(fgrep "CLOSED" $bugdir/*/bug.conf | wc -l) + fixme=$(fgrep "OPEN" $bugdir/*/bug.conf | wc -l) + msgs=$(find $bugdir -name msg.* ! -size 0 | wc -l) + pct=0 + [ $bugs -gt 0 ] && pct=$(( ($close * 100) / $bugs )) + header + html_header + user_box + cat << EOT + +

$(gettext "Summary")

+ +

+ Bugs: $bugs in total - $close fixed - $fixme to fix - $msgs messages +

+ +
+
${pct}%
+
+ +

+ Beta code! Please read the README for more + information. +

+ +
+ View closed bugs +EOT + if check_auth; then + echo "$(gettext "Create a new bug")" + fi + cat << EOT +
+ + +
+
+EOT + list_bugs OPEN + html_footer ;; +esac + +exit 0 diff -r b3ab30f7f7ae -r 5adb233a979b web/favicon.ico Binary file web/favicon.ico has changed diff -r b3ab30f7f7ae -r 5adb233a979b web/images/avatar.png Binary file web/images/avatar.png has changed diff -r b3ab30f7f7ae -r 5adb233a979b web/images/home.png Binary file web/images/home.png has changed diff -r b3ab30f7f7ae -r 5adb233a979b web/images/logo.png Binary file web/images/logo.png has changed diff -r b3ab30f7f7ae -r 5adb233a979b web/lib/functions.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/lib/functions.js Tue Apr 03 12:12:59 2012 +0200 @@ -0,0 +1,18 @@ +// SliTaz Bugs Javascript functions. +// + +// Check form to avoid empty values and bad email. +function checkNewBug() { + if(document.forms["addbug"]["title"].value == "") + { + alert("Please enter a title for the new bug"); + document.forms["addbug"]["title"].focus(); + return false; + } + if(document.forms["addbug"]["desc"].value == "") + { + alert("Please fill in the bug description"); + document.forms["addbug"]["desc"].focus(); + return false; + } +} diff -r b3ab30f7f7ae -r 5adb233a979b web/lib/header.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/lib/header.html Tue Apr 03 12:12:59 2012 +0200 @@ -0,0 +1,27 @@ + + + + SliTaz Bug Tracker + + + + + + + + diff -r b3ab30f7f7ae -r 5adb233a979b web/style.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/style.css Tue Apr 03 12:12:59 2012 +0200 @@ -0,0 +1,192 @@ +/* CSS style for SliTaz Bugs */ + +html { min-height: 102%; } +body { font: 13px sans-serif, vernada, arial; margin: 0; } +h1 { margin: 0; padding: 8px; color: #fff; font-size: 20px; } +h1 a { color: #fff; text-decoration: none; } +h2 { color: #444; } h3 { color: #666; font-size: 140%; } +a { text-decoration: underline; color: #215090; } +a:hover { text-decoration: none; } +img { border: 0pt none; vertical-align: middle; } +pre { + overflow: auto; + font-size: 96%; +} +textarea { width: 100%; } + +/* Header */ + +#header { + background: #351a0a; + height: 40px; + border-bottom: 8px solid #d66018; +} + +#header h1 { + margin: 0; + padding: 8px 0 0 42px; + width: 250px; +} + +#header h1 a { + color: white; + text-decoration: none; + font-size: 20px; + font-style: italic; +} + +#header h1 a:hover, #network a:hover { + color: #d66018; +} + +/* Header links */ + +#network { + float: right; + padding: 10px 5px 0; + font-size: 12px; +} + +#network a { + padding: 0 6px; + color: #fff; + font-weight: bold; + text-decoration: none; +} + +/* Logo */ + +#logo { + background: url(images/logo.png) no-repeat left; + position: absolute; + float: left; + left: 0px; + top: 0px; + width: 40px; + height: 40px; +} + +/* Content */ + +#content { + margin: 40px auto; + text-align: justify; + width: 720px; +} + +#login { + width: 280px; + float: left; + height: 120px; +} + +#login input[type="text"], #login input[type="password"], +#tools input[type="text"] { + width: 180px; padding: 3px; } +#tools input[type="submit"] { padding: 3px; } +#login input[type="submit"] { float: none; } + +#user { + min-width: 180px; + height: 20px; + float: right; + position: absolute; + right: 20px; + top: 68px; +} +#user a { padding: 0 4px; } + +#account-info { width: 380px; height: 120px; float: right; } + +#newbug textarea { width: 460px; } + +#edit textarea { width: 100%; height: 240px; } + +.box, pre, #user, #login, #account-info { + background-color: #f8f8f8; + border: 1px solid #ddd; + padding: 10px; +} + +.error { color: red; } +.ok { color: green; } + +/* Progress bar */ + +.pct { background: #9dff4a; padding: 2px 4px; } + +.pctbar { + margin: 0; + color: #666; + background: #f1f1f1; + border: 1px solid #ddd; + overflow: hidden; + clear: both; +} + +/* Form */ + +form { display: inline; } +textarea { border: 2px solid #ccc; padding: 4px; width: 100%; } +select { min-width: 180px; } +input[type="submit"], input[type="text"], input[type="password"], +select, #tools a { + color: #444444; + border: 1px solid #cccccc; + padding: 4px; + margin: 4px 0px; + font-size: 14px; + line-height: 1.2em; + background-image: -webkit-linear-gradient(#FAFAFA, #F4F4F4 40%, #E5E5E5); + background-image: -moz-linear-gradient(#FAFAFA, #F4F4F4 40%, #E5E5E5); + -webkit-appearance: none; + -webkit-padding-end: 12px; + -webkit-padding-start: 6px; +} + +input[type="text"], input[type="password"] { + background: #fefefe; border: 2px solid #ccc; + width: 460px; } +/*input[type="file"] { border: 2px solid #ddd; }*/ +/*input[type="checkbox"] { background: #fefefe; }*/ + +/* Be compatible with old FF and Webkit version. */ +input[type="submit"] { + -webkit-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1); +} + +input[type="submit"]:hover, #tools a:hover { + cursor: pointer; + color: black; +} + +select { + background-image: url(images/down.png), + -webkit-linear-gradient(#FAFAFA, #F4F4F4 40%, #E5E5E5); + background-position: center right; + background-repeat: no-repeat; +} + +#tools a { text-decoration: none; margin: 4px 6px 4px 0px; } + +/* Round corner */ + +pre, .button, .pctbar, #login, #account-info, #user, img, input, +textarea, select, #tools a { + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; +} + +/* Footer */ + +#footer { + text-align: center; + padding: 20px; + border-top: 1px solid #ddd; + font-size: 90%; +} + +#footer a { padding: 0 2px; }