tazbug view web/bugs.cgi @ rev 49

Add a small dashboard plugin and misc fixes
author Christophe Lincoln <pankso@slitaz.org>
date Sun Jan 05 00:01:34 2014 +0100 (2014-01-05)
parents a8652095c93f
children 02a11d8d636e
line source
1 #!/bin/sh
2 #
3 # TazBug Web interface
4 #
5 # Copyright (C) 2012-2014 SliTaz GNU/Linux - BSD License
6 #
7 . /usr/lib/slitaz/httphelper
8 [ -f "/etc/slitaz/bugs.conf" ] && . /etc/slitaz/bugs.conf
9 #. bugs.conf
11 # Internal variable
12 bugdir="$TAZBUG/bug"
13 plugins="plugins"
14 sessions="/tmp/bugs/sessions"
15 script="$SCRIPT_NAME"
16 po=""
18 # Content negotiation for Gettext
19 IFS=","
20 for lang in $HTTP_ACCEPT_LANGUAGE
21 do
22 lang=${lang%;*} lang=${lang# } lang=${lang%-*}
23 case "$lang" in
24 en) LANG="C" ;;
25 de) LANG="de_DE" ;;
26 es) LANG="es_ES" ;;
27 fr) LANG="fr_FR" ;;
28 it) LANG="it_IT" ;;
29 pt) LANG="pt_BR" ;;
30 ru) LANG="ru_RU" ;;
31 zh) LANG="zh_TW" ;;
32 esac
33 if echo "$po" | fgrep -q "$lang"; then
34 break
35 fi
36 done
37 unset IFS
38 export LANG LC_ALL=$LANG
40 # Internationalization: $(gettext "")
41 . /usr/bin/gettext.sh
42 TEXTDOMAIN='tazbug'
43 export TEXTDOMAIN
45 #
46 # Functions
47 #
49 # HTML 5 header.
50 html_header() {
51 cat lib/header.html
52 }
54 # HTML 5 footer.
55 html_footer() {
56 cat << EOT
57 </div>
59 <div id="footer">
60 <a href="$WEB_URL">SliTaz Bugs</a> -
61 <a href="$WEB_URL?README">README</a>
62 </div>
64 </body>
65 </html>
66 EOT
67 }
69 GETfiltered()
70 {
71 GET $1 | sed -e "s/'/\&#39;/g; s|\n|<br/>|g; s/\t/\&#09;/g;s/\%22/\"/g"
72 }
74 js_redirection_to()
75 {
76 js_log "Redirecting to $1"
77 echo "<script type=\"text/javascript\"> document.location = \"$1\"; </script>"
78 }
80 js_log()
81 {
82 echo "<script type=\"text/javascript\">console.log('$1')</script>";
83 }
85 js_set_cookie()
86 {
87 name=$1
88 value=$2
90 js_log 'Setting cookie.'
91 echo "<script type=\"text/javascript\">"
92 echo "document.cookie = \"$name=$value; expires=0; path=/\"";
93 echo "</script>"
94 }
96 js_unset_cookie()
97 {
98 name=$1
100 js_log 'Unsetting cookie.'
101 echo "<script type=\"text/javascript\">"
102 echo "document.cookie = \"$1=\"\"; expires=-1; path=/";
103 echo "</script>"
104 }
106 # Check if user is auth
107 check_auth() {
108 auth="$(COOKIE auth)"
109 user="$(echo $auth | cut -d ":" -f 1)"
110 md5cookie="$(echo $auth | cut -d ":" -f 2)"
111 [ -f "$sessions/$user" ] && md5session="$(cat $sessions/$user)"
112 if [ "$md5cookie" == "$md5session" ] && [ "$auth" ]; then
113 return 0
114 else
115 return 1
116 fi
117 }
119 # Check if user is admin
120 admin_user() {
121 fgrep -q 'ADMIN_USER="yes"' ${PEOPLE}/${user}/account.conf
122 }
124 # Authentified or not
125 user_box() {
127 IDLOC=""
128 if [[ "$(GET id)" ]] ;then
129 IDLOC="&id=$(GET id)"
130 fi
132 if check_auth; then
133 . $PEOPLE/$user/account.conf
134 cat << EOT
135 <div id="user">
136 <a href="?user=$user">$(get_gravatar $MAIL 20)</a>
137 <a href="?logout">$(gettext 'Logout')</a>
138 </div>
139 EOT
140 else
141 cat << EOT
142 <div id="user">
143 <a href="?login$IDLOC"><img src="images/avatar.png" alt="[ User ]" /></a>
144 <a href="?login$IDLOC">$(gettext 'Log in')</a>
145 </div>
146 EOT
147 fi
148 cat << EOT
150 <div id="search">
151 <form method="get" action="$WEB_URL">
152 <input type="text" name="search" placeholder="$(gettext 'Search')" />
153 <!-- <input type="submit" value="$(gettext 'Search')" /> -->
154 </form>
155 </div>
157 <!-- Content -->
158 <div id="content">
160 EOT
161 }
163 # Signup page
164 signup_page() {
165 cat << EOT
167 <div id="signup">
168 <form method="post" name="signup" action="$SCRIPT_NAME" onsubmit="return checkSignup();">
169 <input type="hidden" name="signup" value="new" />
170 <input type="text" name="name" placeholder="$(gettext "Real name")" />
171 <input type="text" name="user" placeholder="$(gettext "User name")" />
172 <input type="text" name="mail" placeholder="$(gettext "Email")" />
173 <input type="password" name="pass" placeholder="$(gettext "Password")" />
174 <div>
175 <input type="submit" value="$(gettext "Create new account")" />
176 </div>
177 </form>
178 </div>
180 EOT
181 }
183 # Link for online signup if enabled.
184 online_signup() {
185 if [ "$ONLINE_SIGNUP" == "yes" ]; then
186 echo -n "<p>" && gettext "Or:"; echo -n " "
187 echo -n "<a href='$script?signup&amp;online'>"
188 gettext "Sign Up Online"
189 echo '</a></p>'
190 fi
191 }
193 # Login page
194 login_page() {
196 IDLOC=""
197 if [[ "$(GET id)" ]] ;then
198 IDLOC="?id=$(GET id)"
199 fi
200 cat << EOT
201 <h2>$(gettext 'Login')</h2>
203 <div id="account-info">
204 <p>$(gettext "No account yet? You can signup using the SliTaz Bugs reporter \
205 on your SliTaz system.")</p>
206 $(online_signup)
207 <p>$(gettext "Tip: to attach big files or images, you can use SliTaz Paste \
208 services:") <a href="http://paste.slitaz.org/">paste.slitaz.org</a></p>
209 </div>
211 <div id="login">
212 <form method="post" action="$script">
213 <input type="text" name="auth" placeholder="$(gettext 'User name')" />
214 <input type="password" name="pass" placeholder="$(gettext 'Password')" />
215 <div>
216 <input type="submit" value="$(gettext 'Log in')" />
217 $error
218 </div>
219 </form>
220 </div>
222 <div style="clear: both;"></div>
223 EOT
224 }
226 # Display user public profile.
227 public_people() {
228 cat << EOT
229 <pre>
230 $(eval_gettext 'Real name : $NAME')
231 </pre>
232 EOT
233 }
235 # Display authentified user profile. TODO: change password
236 auth_people() {
237 cat << EOT
238 <pre>
239 $(eval_gettext 'Real name : $NAME')
240 $(eval_gettext 'Email : $MAIL')
241 $(eval_gettext 'Secure key : $KEY')
242 </pre>
243 EOT
244 }
246 # Usage: list_bugs STATUS
247 list_bugs() {
248 bug="$1"
249 echo "<h3>$(eval_gettext '$bug Bug')</h3>"
250 for pr in critical standard
251 do
252 for bug in $(fgrep -H "$1" $bugdir/*/bug.conf | cut -d ":" -f 1)
253 do
254 . $bug
255 id=$(basename $(dirname $bug))
256 if [ "$PRIORITY" == "$pr" ]; then
257 cat << EOT
258 <pre>
259 $(gettext 'Bug title :') <strong>$BUG</strong> <a href="?id=$id">$(gettext 'Show')</a>
260 $(gettext 'ID - Date :') $id - $DATE
261 $(gettext 'Creator :') <a href="?user=$CREATOR">$CREATOR</a>
262 </pre>
263 EOT
264 fi
265 done
266 done
267 }
269 # Stripped down Wiki parser for bug desc and messages which are simply
270 # displayed in <pre>
271 wiki_parser() {
272 sed \
273 -e s"#http://\([^']*\).png#<img src='\0' alt='[ Image ]' />#"g \
274 -e s"#http://\([^']*\).*# <a href='\0'>\1</a>#"g \
275 -e 's#\\\\n#\n#g;s#%22#"#g;s#%21#!#g'
276 }
278 # Bug page
279 bug_page() {
280 if [ -f "$PEOPLE/$CREATOR/account.conf" ]; then
281 . $PEOPLE/$CREATOR/account.conf
282 else
283 MAIL="default"
284 fi
285 cat << EOT
286 <h2>$(eval_gettext 'Bug $id')</h2>
287 <form method="get" action="$WEB_URL">
289 <p>
290 $(get_gravatar $MAIL 32)
291 <strong>$STATUS</strong>
292 $BUG - $DATE -
293 $(eval_gettext 'Priority $PRIORITY') -
294 $(eval_ngettext '$msgs message' '$msgs messages' $msgs)
295 </p>
297 <pre>
298 $(echo "$DESC" | wiki_parser)
299 </pre>
301 <div id="tools">
302 EOT
303 if check_auth; then
304 if [ "$STATUS" == "OPEN" ]; then
305 cat << EOT
306 <a href="?id=$id&amp;close">$(gettext "Close bug")</a>
307 <a href="?edit=$id">$(gettext "Edit bug")</a>
308 EOT
309 else
310 cat << EOT
311 <a href="?id=$id&amp;open">$(gettext "Re open bug")</a>
312 EOT
313 fi
314 fi
315 cat << EOT
316 </div>
318 <h3>$(gettext "Messages")</h3>
319 EOT
320 [ "$msgs" == "0" ] && gettext "No messages"
321 for msg in $(ls -1tr $bugdir/$id/msg.*)
322 do
323 . $msg
324 if [ "$MSG" ]; then
325 msgid=$(echo $msg | cut -d "." -f 2)
326 del=""
327 # User can delete his post.
328 [ "$user" == "$USER" ] && \
329 del="<a href=\"?id=$id&amp;delmsg=$msgid\">delete</a>"
330 cat << EOT
331 <p><strong>$USER</strong> $DATE $del</p>
332 <pre>
333 $(echo "$MSG" | wiki_parser)
334 </pre>
335 EOT
336 fi
337 unset NAME DATE MSG
338 done
339 if check_auth; then
340 cat << EOT
341 <div>
342 <h3>$(gettext "New message")</h3>
344 <input type="hidden" name="id" value="$id" />
345 <textarea name="msg" rows="8"></textarea>
346 <p><input type="submit" value="$(gettext 'Send message')" /></p>
347 </form>
348 </div>
349 EOT
350 fi
351 }
353 # Write a new message
354 new_msg() {
355 date=$(date "+%Y-%m-%d %H:%M")
356 msgs=$(ls -1 $bugdir/$id/msg.* | wc -l)
357 count=$(($msgs + 1))
358 if check_auth; then
359 USER="$user"
360 fi
361 js_log "Will write message in $bugdir/$id/msg.$count "
362 sed "s/$(echo -en '\r') /\n/g" > $bugdir/$id/msg.$count << EOT
363 USER="$USER"
364 DATE="$date"
365 MSG="$(GETfiltered msg)"
366 EOT
367 }
369 # Create a new Bug
370 new_bug() {
371 count=$(ls -1 $bugdir | wc -l)
372 date=$(date "+%Y-%m-%d %H:%M")
373 # Sanity check, JS may be disabled.
374 [ ! "$(GET bug)" ] && echo "Missing bug title" && exit 1
375 [ ! "$(GET desc)" ] && echo "Missing bug description" && exit 1
376 if check_auth; then
377 USER="$user"
378 fi
379 mkdir -p $bugdir/$count
380 sed "s/$(echo -en '\r') /\n/g" > $bugdir/$count/bug.conf << EOT
381 # SliTaz Bug configuration
383 BUG="$(GETfiltered bug)"
384 STATUS="OPEN"
385 PRIORITY="$(GET priority)"
386 CREATOR="$USER"
387 DATE="$date"
388 PKGS="$(GETfiltered pkgs)"
390 DESC="$(GETfiltered desc)"
391 EOT
392 }
394 # New bug page for the web interface
395 new_bug_page() {
396 cat << EOT
397 <h2>$(gettext "New Bug")</h2>
398 <div id="newbug">
400 <form method="get" action="$WEB_URL" onsubmit="return checkNewBug();">
401 <input type="hidden" name="addbug" />
402 <table>
403 <tbody>
404 <tr>
405 <td>$(gettext "Bug title")*</td>
406 <td><input type="text" name="bug" /></td>
407 </tr>
408 <tr>
409 <td>$(gettext "Description")*</td>
410 <td><textarea name="desc"></textarea></td>
411 </tr>
412 <tr>
413 <td>$(gettext "Packages")</td>
414 <td><input type="text" name="pkgs" /></td>
415 </tr>
416 <tr>
417 <td>$(gettext "Priority")</td>
418 <td>
419 <select name="priority">
420 <option value="standard">$(gettext "Standard")</option>
421 <option value="critical">$(gettext "Critical")</option>
422 </select>
423 <input type="submit" value="$(gettext "Create Bug")" />
424 </td>
425 </tr>
426 </tbody>
427 </table>
428 </form>
430 <p>
431 $(gettext "* field is obligatory. You can also specify affected packages.")
432 </p>
434 </div>
435 EOT
436 }
439 # Edit/Save a bug configuration file
440 edit_bug() {
441 cat << EOT
442 <h2>$(eval_gettext 'Edit Bug $bug')</h2>
443 <div id="edit">
445 <form method="get" action="$WEB_URL">
446 <textarea name="bugconf">$(cat $bugdir/$bug/bug.conf)</textarea>
447 <input type="hidden" name="bug" value="$bug" />
448 <input type="submit" value="$(gettext 'Save configuration')" />
449 </form>
451 </div>
452 EOT
453 }
456 save_bug() {
457 bug="$(GET bug)"
458 content="$(GET bugconf)"
459 sed "s|\"|'|" | sed "s/$(echo -en '\r') /\n/g" > $bugdir/$bug/bug.conf << EOT
460 $content
461 EOT
462 }
465 # Close a fixed bug
466 close_bug() {
467 sed -i s'/OPEN/CLOSED/' $bugdir/$id/bug.conf
468 }
471 # Re open an old bug
472 open_bug() {
473 sed -i s'/CLOSED/OPEN/' $bugdir/$id/bug.conf
474 }
477 # Get and display Gravatar image: get_gravatar email size
478 # Link to profile: <a href="http://www.gravatar.com/$md5">...</a>
479 get_gravatar() {
480 email=$1
481 size=$2
482 [ "$size" ] || size=48
483 url="http://www.gravatar.com/avatar"
484 md5=$(md5crypt $email)
485 echo "<img src=\"$url/$md5?d=identicon&amp;s=$size\" alt=\"\" />"
486 }
488 # Create a new user in AUTH_FILE and PEOPLE
489 new_user_config() {
490 if [ ! "$online" ]; then
491 name="$(GET name)"
492 mail="$(GET mail)"
493 pass="$(GET pass)"
494 echo "Creating Server Key..."
495 fi
496 key=$(echo -n "$user:$mail:$pass" | md5sum | awk '{print $1}')
497 echo "$user:$pass" >> $AUTH_FILE
498 mkdir -pm0700 $PEOPLE/$user/
499 cat > $PEOPLE/$user/account.conf << EOT
500 # SliTaz user configuration
501 #
503 NAME="$name"
504 USER="$user"
505 MAIL="$mail"
506 KEY="$key"
508 COMMUNITY="$(GET scn)"
509 LOCATION="$(GET location)"
510 RELEASES="$(GET releases)"
511 PACKAGES="$(GET packages)"
512 EOT
513 chmod 0600 $PEOPLE/$user/account.conf
514 if [ ! -f $PEOPLE/$user/account.conf ]; then
515 echo "ERROR: User creation failed!"
516 fi
517 }
519 ########################################################################
520 # POST actions #
521 ########################################################################
523 case " $(POST) " in
524 *\ auth\ *)
525 header
526 html_header
527 # Authenticate user. Create a session file in $sessions to be used
528 # by check_auth. We have the user login name and a peer session
529 # md5 string in the COOKIE.
530 user="$(POST auth)"
531 pass="$(echo -n "$(POST pass)" | md5sum | awk '{print $1}')"
533 IDLOC=""
534 if [[ "$(GET id)" ]] ;then
535 IDLOC="&id=$(GET id)"
536 fi
538 if [ ! -f $AUTH_FILE ] ; then
539 js_log "$AUTH_FILE (defined in \$AUTH_FILE) have not been found."
540 js_redirection_to "$WEB_URL?login$IDLOC"
541 fi;
543 valid=$(fgrep "${user}:" $AUTH_FILE | cut -d ":" -f 2)
544 if [ "$pass" == "$valid" ] && [ "$pass" != "" ]; then
545 if [[ "$(GET id)" ]] ;then
546 IDLOC="?id=$(GET id)"
547 fi
548 md5session=$(echo -n "$$:$user:$pass:$$" | md5sum | awk '{print $1}')
549 mkdir -p $sessions
550 echo "$md5session" > $sessions/$user
551 js_set_cookie 'auth' "$user:$md5session"
552 js_log "Login authentification have been executed & accepted :)"
553 js_redirection_to "$WEB_URL$IDLOC"
554 else
555 js_log "Login authentification have been executed & refused"
556 js_redirection_to "$WEB_URL?login&error$IDLOC"
557 fi
558 html_footer ;;
559 *\ signup\ *)
560 # POST action for online signup
561 name="$(POST name)"
562 user="$(POST user)"
563 mail="$(POST mail)"
564 pass="$(md5crypt "$(POST pass)")"
565 if ! grep "^${user}:" $AUTH_FILE; then
566 online="yes"
567 new_user_config
568 header "Location: $SCRIPT_NAME?login"
569 else
570 header
571 html_header
572 user_box
573 echo "<h2>$(gettext "User already exists:") $user</h2>"
574 html_footer && exit 0
575 fi ;;
576 esac
578 #
579 # Plugins Now!
580 #
581 for p in $(ls -1 $plugins)
582 do
583 [ -f "$plugins/$p/$p.conf" ] && . $plugins/$p/$p.conf
584 [ -x "$plugins/$p/$p.cgi" ] && . $plugins/$p/$p.cgi
585 done
587 ########################################################################
588 # GET actions #
589 ########################################################################
591 case " $(GET) " in
592 *\ README\ *)
593 header
594 html_header
595 user_box
596 echo '<h2>README</h2>'
597 echo '<pre>'
598 cat /usr/share/doc/tazbug/README
599 echo '</pre>'
600 html_footer ;;
601 *\ closed\ *)
602 # Show all closed bugs.
603 header
604 html_header
605 user_box
606 list_bugs CLOSED
607 html_footer ;;
608 *\ login\ *)
609 # The login page
610 [ "$(GET error)" ] && \
611 error="<span class='error'>$(gettext 'Bad login or pass')</span>"
612 header
613 html_header
614 user_box
615 login_page
616 html_footer ;;
617 *\ logout\ *)
618 header
619 html_header
620 if check_auth; then
621 rm -f "$sessions/$user"
622 js_unset_cookie 'auth'
623 js_redirection_to "$WEB_URL"
625 fi ;;
626 *\ user\ *)
627 # User profile
628 header
629 html_header
630 user_box
631 . $PEOPLE/"$(GET user)"/account.conf
632 echo "<h2>$(get_gravatar $MAIL) $(GET user)</h2>"
633 if check_auth && [ "$(GET user)" == "$user" ]; then
634 auth_people
635 else
636 public_people
637 fi
638 html_footer ;;
639 *\ newbug\ *)
640 # Add a bug from web interface.
641 header
642 html_header
643 user_box
644 if check_auth; then
645 new_bug_page
646 else
647 echo "<p>$(gettext 'You must be logged in to post a new bug')</p>"
648 fi
649 html_footer ;;
650 *\ addbug\ *)
651 # Add a bug from web interface.
652 header
653 html_header
654 if check_auth; then
655 new_bug
656 js_redirection_to "$WEB_URL?id=$count"
657 fi ;;
658 *\ edit\ *)
659 bug="$(GET edit)"
660 header
661 html_header
662 user_box
663 edit_bug
664 html_footer ;;
665 *\ bugconf\ *)
666 header
667 html_header
668 if check_auth; then
669 save_bug
670 js_redirection_to "$WEB_URL?id=$bug"
671 fi ;;
672 *\ id\ *)
673 # Empty deleted messages to keep msg count working.
674 header
675 html_header
676 id="$(GET id)"
677 [ "$(GET close)" ] && close_bug
678 [ "$(GET open)" ] && open_bug
679 [ "$(GET msg)" ] && new_msg
680 [ "$(GET delmsg)" ] && rm -f $bugdir/$id/msg.$(GET delmsg) && \
681 touch $bugdir/$id/msg.$(GET delmsg)
682 msgs=$(fgrep MSG= $bugdir/$id/msg.* | wc -l)
683 user_box
684 . $bugdir/$id/bug.conf
685 bug_page
686 html_footer ;;
687 *\ signup\ *)
688 # Signup
689 if [ "$(GET online)" ];then
690 header
691 html_header
692 user_box
693 echo "<h2>$(gettext "Sign Up")</h2>"
694 if [ "$ONLINE_SIGNUP" == "yes" ]; then
695 signup_page
696 else
697 gettext "Online registration is disabled"
698 fi
699 html_footer && exit 0
700 else
701 header "Content-type: text/plain;"
702 user="$(GET signup)"
703 echo "Requested user login : $user"
704 if fgrep -q "$user:" $AUTH_FILE; then
705 echo "ERROR: User already exists" && exit 1
706 else
707 echo "Creating account for : $(GET name)"
708 new_user_config
709 fi
710 fi ;;
711 *\ key\ *)
712 # Let user post new bug or message with crypted key (no gettext)
713 #
714 # Testing only and is security acceptable ?
715 #
716 key="$(GET key)"
717 id="$(GET bug)"
718 header "Content-type: text/plain;"
719 echo "Checking secure key..."
720 if fgrep -qH $key $PEOPLE/*/account.conf; then
721 conf=$(fgrep -H $key $PEOPLE/*/account.conf | cut -d ":" -f 1)
722 . $conf
723 echo "Authentified: $NAME ($USER)"
724 case " $(GET) " in
725 *\ msg\ *)
726 [ ! "$id" ] && echo "Missing bug ID" && exit 0
727 echo "Posting new message to bug: $id"
728 echo "Message: $(GET msg)"
729 new_msg ;;
730 *\ bug\ *)
731 echo "Adding new bug: $(GET bug)"
732 echo "Description: $(GET desc)"
733 new_bug ;;
734 esac
735 else
736 echo "Not a valid SliTaz user key"
737 exit 0
738 fi ;;
739 *\ search\ *)
740 header
741 html_header
742 user_box
743 cat << EOT
744 <h2>$(gettext "Search")</h2>
745 <form method="get" action="$WEB_URL">
746 <input type="text" name="search" />
747 <input type="submit" value="$(gettext 'Search')" />
748 </form>
749 <div>
750 EOT
752 #found=0 JS to notify or write results nb under the search box.
753 for bug in $bugdir/*
754 do
755 result=$(fgrep -i "$(GET search)" $bug/*)
756 if [ "$result" ]; then
757 #found=$(($found + 1))
758 id=${bug#bug/}
759 echo "<p><strong>Bug $id</strong> <a href=\"?id=$id\">"$(gettext 'Show')"</a></p>"
760 echo '<pre>'
761 fgrep -i "$(GET search)" $bugdir/$id/* | \
762 sed s"/$(GET search)/<span class='ok'>$(GET search)<\/span>/"g
763 echo '</pre>'
764 else
765 get_search=$(GET search)
766 echo "<p>$(eval_gettext 'No result found for: $get_search')</p>"
767 fi
768 done
769 echo '</div>'
770 html_footer ;;
771 *)
772 # Default page.
773 bugs=$(ls -1 $bugdir | wc -l)
774 close=$(fgrep "CLOSED" $bugdir/*/bug.conf | wc -l)
775 fixme=$(fgrep "OPEN" $bugdir/*/bug.conf | wc -l)
776 msgs=$(find $bugdir -name msg.* ! -size 0 | wc -l)
777 pct=0
778 [ $bugs -gt 0 ] && pct=$(( ($close * 100) / $bugs ))
779 header
780 html_header
781 user_box
782 cat << EOT
784 <h2>$(gettext "Summary")</h2>
786 <p>
787 $(eval_ngettext 'Bug: $bugs in total -' 'Bugs: $bugs in total -' $bugs)
788 $(eval_ngettext '$close fixed -' '$close fixed -' $close)
789 $(eval_ngettext '$fixme to fix -' '$fixme to fix -' $fixme)
790 $(eval_ngettext '$msgs message' '$msgs messages' $msgs)
791 </p>
793 <div class="pctbar">
794 <div class="pct" style="width: ${pct}%;">${pct}%</div>
795 </div>
797 <p>$(gettext "Please read the <a href=\"?README\">README</a> for help and \
798 more information. You may also be interested by the SliTaz \
799 <a href=\"http://roadmap.slitaz.org/\">Roadmap</a> and the packages \
800 <a href=\"http://cook.slitaz.org/\">Cooker</a>. To perform a search \
801 enter your term and press ENTER.")
802 </p>
804 <div id="tools">
805 <a href="?closed">$(gettext 'View closed bugs')</a>
806 EOT
807 if check_auth; then
808 echo "<a href='?newbug'>$(gettext 'Create a new bug')</a>"
809 echo "$PLUGINS_TOOLS"
810 fi
811 cat << EOT
812 </div>
813 EOT
814 list_bugs OPEN
815 html_footer ;;
816 esac
818 exit 0