tinycm view index.cgi @ rev 36

Improve user profile
author Christophe Lincoln <pankso@slitaz.org>
date Tue Jan 07 18:28:46 2014 +0100 (2014-01-07)
parents 6172acda8b17
children 2f4b9f31ee08
line source
1 #!/bin/sh
2 #
3 # TinyCM - Small, fast and elegent CGI/SHell Content Manager
4 #
5 # Copyright (C) 2012-2014 SliTaz GNU/Linux - BSD License
6 #
7 . /usr/lib/slitaz/httphelper
9 # Let's have a peer site config file with a .cgi extension so content
10 # is secure even if left in a web server directory.
11 . config.cgi
13 tiny="$PWD"
14 po="en fr"
15 content="content"
16 wiki="$content/wiki"
17 index="index"
18 cache="cache"
19 plugins="plugins"
20 tmp="/tmp/tinycm"
21 sessions="$tmp/sessions"
22 script="$SCRIPT_NAME"
23 activity="$cache/log/activity.log"
25 # Content negotiation for Gettext
26 IFS=","
27 for lang in $HTTP_ACCEPT_LANGUAGE
28 do
29 lang=${lang%;*} lang=${lang# } lang=${lang%-*}
30 if echo "$po" | fgrep -q "$lang"; then
31 break
32 fi
33 case "$lang" in
34 en) lang="C" ;;
35 fr) lang="fr_FR" ;;
36 pt) lang="pt_BR" ;;
37 ru) lang="ru_RU" ;;
38 esac
39 done
40 unset IFS
41 export LANG=$lang LC_ALL=$lang
43 #
44 # Functions
45 #
47 # Used by edit to display language name and the language box. This is
48 # for CM content not gettext support.
49 get_lang() {
50 lang=$(echo $d | cut -d "/" -f 1)
51 doc=${d#$lang/}
52 echo '<div id="lang">'
53 for l in $LANGUAGES
54 do
55 case $lang in
56 en) i18n="English" ;;
57 fr) i18n="Français" ;;
58 pt) i18n="Português" ;;
59 ru) i18n="Русский" ;;
60 *) i18n="*" ;;
61 esac
62 echo "<a href='?d=$l/$doc'>$l</a>"
63 done
64 echo '</div>'
65 }
67 # HTML 5 header.
68 html_header() {
69 if [ -f "$tiny/lib/header.html" ]; then
70 cat $tiny/lib/header.html | sed -e s!'%TITLE%'!"$TITLE - $d"!g
71 else
72 cat << EOT
73 <!DOCTYPE html>
74 <html xmlns="http://www.w3.org/1999/xhtml">
75 <head>
76 <title>$TITLE</title>
77 <meta charset="utf-8" />
78 <style type="text/css">body { margin: 40px 120px; }</style>
79 </head>
80 <body>
81 <!-- Content -->
82 <div id="content">
83 EOT
84 fi
85 }
87 # HTML 5 footer.
88 html_footer() {
89 if [ -f "$tiny/lib/footer.html" ]; then
90 cat $tiny/lib/footer.html
91 else
92 cat << EOT
94 <!-- End content -->
95 </div>
97 <div id="footer">&hearts;</div>
99 </body>
100 </html>
101 EOT
102 fi
103 }
105 # Default index if missing
106 default_index() {
107 mkdir -p "$wiki"
108 cat > $wiki/$index.txt << EOT
109 ==== Welcome ====
111 <p>
112 This is the default index page of your TinyCM, you can login then start to
113 edit and adding some content. You can read the help about text formating
114 and functions: <a href='?d=en/help'>Help page</a>
115 </p>
117 EOT
118 }
120 # Log main activity.
121 log_activity() {
122 [ -d "$cache/log" ] || mkdir -p ${cache}/log
123 #gravatar="$(get_gravatar $MAIL 24)"
124 grep ^[A-Z] | \
125 sed s"#^[A-Z]\([^']*\)#$user|$(date '+%Y-%m-%d')|\0#" \
126 >> $cache/log/activity.log
127 }
129 # Log documents activity.
130 log() {
131 grep ^[A-Z] | \
132 sed s"#^[A-Z]\([^']*\)#$(date '+%Y-%m-%d %H:%M') : \0#" \
133 >> $cache/$d/activity.log
134 }
136 # Check if user is auth
137 check_auth() {
138 auth="$(COOKIE auth)"
139 user="$(echo $auth | cut -d ":" -f 1)"
140 md5cookie="$(echo $auth | cut -d ":" -f 2)"
141 [ -f "$sessions/$user" ] && md5session="$(cat $sessions/$user)"
142 if [ "$md5cookie" == "$md5session" ] && [ "$auth" ]; then
143 . $PEOPLE/$user/account.conf
144 return 0
145 else
146 return 1
147 fi
148 }
150 # Check if user is admin
151 admin_user() {
152 fgrep -q 'ADMIN_USER="yes"' ${PEOPLE}/${user}/account.conf
153 }
155 # Authentified or not
156 user_box() {
157 if check_auth; then
158 cat << EOT
160 <div id="user">
161 <a href="$script?user=$user">$(get_gravatar $MAIL 20)</a>
162 <a href="$script?logout">Logout</a>
163 </div>
165 EOT
166 else
167 cat << EOT
169 <div id="user">
170 <a href="$script?login"><img src="images/avatar.png" alt="[ User ]" /></a>
171 <a href="$script?login">Login</a>
172 </div>
174 EOT
175 fi
176 cat << EOT
177 <!--
178 <div id="search">
179 <form method="get" action="$script">
180 <input type="text" name="search" placeholder="$(gettext "Search")" />
181 </form>
182 </div>
183 -->
184 EOT
185 }
187 # Link for online signup if enabled.
188 online_signup() {
189 if [ "$ONLINE_SIGNUP" == "yes" ]; then
190 echo -n "<p><a href='$script?signup'>"
191 gettext "Create a new account"
192 echo '</a></p>'
193 fi
194 }
196 # Login page
197 login_page() {
198 cat << EOT
199 <h2>$(gettext "Login")</h2>
201 <div id="account-info">
202 $(gettext "No account yet or trouble with you account? Please send
203 a request to $ADMIN_MAIL with your real name, user name, mail and password.")
204 $(online_signup)
205 </div>
207 <div id="login">
208 <form method="post" action="$script">
209 <input type="text" name="auth" placeholder="$(gettext "User name")" />
210 <input type="password" name="pass" placeholder="$(gettext "Password")" />
211 <div>
212 <input type="submit" value="Login" /> $error
213 </div>
214 </form>
215 </div>
217 <div style="clear: both;"></div>
218 EOT
219 }
221 # Signup page
222 signup_page() {
223 cat << EOT
225 <div id="signup">
226 <form method="post" name="signup" action="$script" onsubmit="return checkSignup();">
227 <input type="hidden" name="signup" value="new" />
228 <input type="text" name="name" placeholder="$(gettext "Real name")" />
229 <input type="text" name="user" placeholder="$(gettext "User name")" />
230 <input type="text" name="mail" placeholder="$(gettext "Email")" />
231 <input type="password" name="pass" placeholder="$(gettext "Password")" />
232 <div>
233 <input type="submit" value="$(gettext "Create new account")" />
234 </div>
235 </form>
236 </div>
238 EOT
239 }
241 # Create a new user in AUTH_FILE and PEOPLE
242 new_user_config() {
243 if [ ! -f "$AUTH_FILE" ];then
244 touch $(DESTDIR)$(LOGIN)/auth/people
245 chmod 0600 $(DESTDIR)$(LOGIN)/auth/people
246 fi
247 key=$(echo -n "$user:$mail:$pass" | md5sum | awk '{print $1}')
248 echo "$user:$pass" >> $AUTH_FILE
249 mkdir -p $PEOPLE/$user/
250 cat > $PEOPLE/$user/account.conf << EOT
251 # SliTaz user configuration
252 #
254 NAME="$name"
255 USER="$user"
256 MAIL="$mail"
257 KEY="$key"
259 EOT
260 chmod 0600 $PEOPLE/$user/account.conf
261 # First created user is admin
262 if [ $(ls ${PEOPLE} | wc -l) == "1" ]; then
263 echo 'ADMIN_USER="yes"' >> $PEOPLE/$user/account.conf
264 fi
265 }
267 # Display user public profile.
268 public_people() {
269 echo "</pre>"
270 # Display personnal user profile
271 if [ -f "$PEOPLE/$USER/profile.txt" ]; then
272 cat $PEOPLE/$USER/profile.txt | wiki_parser
273 fi
274 }
276 # Display authentified user profile. TODO: change password
277 auth_people() {
278 cat << EOT
279 Email : $MAIL
280 Secure key : $KEY
281 </pre>
282 EOT
283 # Each user can have personal profile page
284 if [ -f "$PEOPLE/$USER/profile.txt" ]; then
285 cat $PEOPLE/$USER/profile.txt | wiki_parser
286 cat << EOT
287 <div id="tools">
288 <a href="$script?edit=profile">$(gettext "Edit profile")</a>
289 </div>
290 EOT
291 else
292 cat << EOT
293 <div id="tools">
294 <a href="$script?edit=profile">$(gettext "Create a profile page")</a>
295 </div>
296 EOT
297 fi
298 }
300 # The CM style parser. Just a title, simple text formating and internal
301 # links, as well as images and use HTML for other stuff. Keep it fast!
302 # To make TinyCM as easy as possible we have a small HTML editor/helper
303 # written in Javascript
304 wiki_parser() {
305 doc="[0-9a-zA-Z\.\#/~\_%=\?\&,\+\:@;!\(\)\*\$'\-]*"
306 sed \
307 -e s"#====\([^']*\)====#<h2>\1</h2>#"g \
308 -e s"#===\([^']*\)===#<h3>\1</h3>#"g \
309 -e s"#==\([^']*\)==#<h4>\1</h4>#"g \
310 -e s"#\*\*\([^']*\)\*\*#<b>\1</b>#"g \
311 -e s"#''\([^']*\)''#<em>\1</em>#"g \
312 -e s"#__\([^']*\)__#<u>\1</u>#"g \
313 -e s"#\[\([^]]*\)|\($doc\)\]#<a href='$script?d=\2'>\1</a>#"g \
314 -e s"#\[\([^]]*\)!\($doc\)\]#<a href='\2'>\1</a>#"g \
315 -e s"#\[\(http://*[^]]*.png\)\]#<img src='\1' />#"g \
316 -e s"#\[\([^]]*.png\)\]#<img src='content/cloud/\1' />#"g
317 }
319 link_user() {
320 echo "<a href='$(basename $script)?user=$user'>$user</a>"
321 }
323 # Save a document. Do we need more than 1 backup and diff ?
324 save_document() {
325 mkdir -p $cache/$d $(dirname $wiki/$d)
326 # May be a new page.
327 if [ ! -f "$wiki/$d.txt" ]; then
328 new=0
329 touch $wiki/$d.txt
330 fi
331 cp $wiki/$d.txt $cache/$d/last.bak
332 sed "s/$(echo -en '\r') /\n/g" > $wiki/$d.txt << EOT
333 $(GET content)
334 EOT
335 diff $cache/$d/last.bak $wiki/$d.txt > $cache/$d/last.diff
336 # Log
337 if [ "$new" ]; then
338 echo "Page created by: $(link_user)" | log
339 echo "New document: <a href='$script?d=$d'>$d</a>" | log_activity
340 if [ "$HG" == "yes" ]; then
341 cd $content && hg -q add
342 hg commit -q -u "$NAME <$MAIL>" -m "Created new document: $d"
343 cd $tiny
344 fi
345 else
346 # Here we may clean log: cat && tail -n 40
347 echo "Page edited by: $(link_user)" | log
348 if [ "$HG" == "yes" ]; then
349 cd $content && hg commit -q -u "$NAME <$MAIL>" \
350 -m "Edited document: $d"
351 cd $tiny
352 fi
353 fi
354 }
356 # Save a user profile.
357 save_profile() {
358 path="$PEOPLE/$user"
359 cp -f ${path}/${d}.txt ${path}/${d}.bak
360 sed "s/$(echo -en '\r') /\n/g" > ${path}/${d}.txt << EOT
361 $(GET content)
362 EOT
363 }
365 # CM tools (edit, diff, etc).
366 wiki_tools() {
367 cat << EOT
368 <div id="tools">
369 <a href="$script?edit=$d">$(gettext "Edit document")</a>
370 <a href="$script?diff=$d">$(gettext "Last diff")</a>
371 <a href="$script?log=$d">$(gettext "File log")</a>
372 <a href="$script?dashboard">$(gettext "Dashboard")</a>
373 $([ "$HG" == "yes" ] && echo "<a href='$script?hg'>Hg Log</a>")
374 </div>
375 EOT
376 }
378 # Get and display Gravatar image: get_gravatar email size
379 # Link to profile: <a href="http://www.gravatar.com/$md5">...</a>
380 get_gravatar() {
381 email=$1
382 size=$2
383 [ "$size" ] || size=48
384 url="http://www.gravatar.com/avatar"
385 md5=$(md5crypt $email)
386 echo "<img src='$url/$md5?d=identicon&s=$size' alt='&lowast;' />"
387 }
389 # List hg logs
390 hg_log() {
391 cd $content
392 cat << EOT
393 <table>
394 <thead>
395 <td>$(gettext "User")</td>
396 <td>$(gettext "Description")</td>
397 <td>$(gettext "Revision")</td>
398 </thead>
399 EOT
400 hg log --template "<tr><td>{author}</td><td>{desc}</td><td>{rev}</td></tr>\n"
401 echo '</table>'
402 }
404 #
405 # POST actions
406 #
408 case " $(POST) " in
409 *\ auth\ *)
410 # Authenticate user. Create a session file in $sessions to be used
411 # by check_auth. We have the user login name and a peer session
412 # md5 string in the COOKIE.
413 user="$(POST auth)"
414 pass="$(md5crypt "$(POST pass)")"
415 valid=$(fgrep "${user}:" $AUTH_FILE | cut -d ":" -f 2)
416 if [ "$pass" == "$valid" ] && [ "$pass" != "" ]; then
417 md5session=$(echo -n "$$:$user:$pass:$$" | md5sum | awk '{print $1}')
418 [ -d $sessions ] || mkdir -p $sessions
419 date '+%Y-%m-%d' > ${PEOPLE}/${user}/last
420 echo "$md5session" > $sessions/$user
421 header "Location: $script" \
422 "Set-Cookie: auth=$user:$md5session; HttpOnly"
423 else
424 header "Location: $script?login&error"
425 fi ;;
426 *\ signup\ *)
427 # POST action for signup
428 name="$(POST name)"
429 user="$(POST user)"
430 mail="$(POST mail)"
431 pass="$(md5crypt "$(POST pass)")"
432 if ! grep "^${user}:" $AUTH_FILE; then
433 new_user_config
434 header "Location: $script?login"
435 else
436 header
437 html_header
438 user_box
439 echo "<h2>gettext "User already exists: $user"</h2>"
440 html_footer
441 fi ;;
442 esac
444 #
445 # Plugins
446 #
447 for p in $(ls -1 $plugins)
448 do
449 [ -f "$plugins/$p/$p.conf" ] && . $plugins/$p/$p.conf
450 [ -x "$plugins/$p/$p.cgi" ] && . $plugins/$p/$p.cgi
451 done
453 #
454 # GET actions
455 #
457 case " $(GET) " in
458 *\ edit\ *)
459 d="$(GET edit)"
460 header
461 html_header
462 user_box
463 get_lang
464 if check_auth; then
465 if [ "$doc" == "profile" ]; then
466 wiki="$PEOPLE/$user"
467 fi
468 cat << EOT
469 <h2>$(gettext "Edit $doc [ $i18n ]")</h2>
471 <div id="edit">
473 <form method="get" action="$script" name="editor">
474 <input type="hidden" name="save" value="$d" />
475 <textarea name="content">$(cat "$wiki/$d.txt")</textarea>
476 <input type="submit" value="$(gettext "Save document")" />
477 $(gettext "Code Helper:")
478 $(cat lib/jseditor.html)
479 </form>
481 </div>
482 EOT
483 else
484 gettext "You must be logged in to edit pages"
485 fi
486 html_footer ;;
488 *\ save\ *)
489 d="$(GET save)"
490 if check_auth; then
491 # User profile
492 if [ "$d" == "profile" ]; then
493 save_profile
494 header "Location: $script?user=$user"
495 else
496 save_document
497 fi
498 fi
499 header "Location: $script?d=$d" ;;
501 *\ log\ *)
502 d="$(GET log)"
503 header
504 html_header
505 user_box
506 # Main activity
507 if [ "$d" == "log" ]; then
508 echo "<h2>$(gettext "Activity")</h2>"
509 if check_auth; then
510 echo "<div id='tools'>"
511 echo "<a href='$script?dashboard'>Dashboard</a>"
512 echo "</div>"
513 fi
514 echo '<pre>'
515 if [ -f "$cache/log/activity.log" ]; then
516 IFS="|"
517 tac $cache/log/activity.log | while read USER DATE LOG
518 do
519 . ${PEOPLE}/${USER}/account.conf
520 cat << EOT
521 <a href='$script?user=$USER'>$(get_gravatar $MAIL 24)</a>\
522 <span class='date'>$DATE -</span> $LOG
523 EOT
524 done
525 unset IFS
526 else
527 gettext "No activity log yet"; echo
528 fi
529 echo '</pre>'
530 html_footer && exit 0
531 fi
532 get_lang
533 echo "<h2>$(gettext "Activity for:") <a href='$script?d=$d'>$d</a></h2>"
534 echo '<pre>'
535 if [ -f "$cache/$d/activity.log" ]; then
536 tac $cache/$d/activity.log
537 else
538 gettext "No log for: $d"; echo
539 fi
540 echo '</pre>'
541 if check_auth; then
542 wiki_tools
543 fi
544 html_footer ;;
546 *\ ls\ *)
547 d="Document list"
548 header
549 html_header
550 user_box
551 echo "<h2>$(gettext "Document list")</h2>"
552 if check_auth; then
553 echo "<div id='tools'>"
554 echo "<a href='$script?dashboard'>Dashboard</a>"
555 echo "</div>"
556 fi
557 echo '<pre>'
558 cd ${wiki}
559 for d in $(find . -type f | sed s'/.\///')
560 do
561 echo "<a href='$script?d=${d%.txt}'>${d%.txt}</a>"
562 done
563 echo '</pre>'
564 html_footer ;;
566 *\ diff\ *)
567 d="$(GET diff)"
568 date="last"
569 header
570 html_header
571 user_box
572 get_lang
573 echo "<h2>$(gettext "Diff for:") <a href='$script?d=$d'>$d</a></h2>"
574 echo '<pre>'
575 if [ -f "$cache/$d/$date.diff" ]; then
576 cat $cache/$d/$date.diff | sed \
577 -e 's|&|\&amp;|g' -e 's|<|\&lt;|g' -e 's|>|\&gt;|g' \
578 -e s"#^-\([^']*\).#<span style='color: red;'>\0</span>#"g \
579 -e s"#^+\([^']*\).#<span style='color: green;'>\0</span>#"g \
580 -e s"#@@\([^']*\)@@#<span style='color: blue;'>@@\1@@</span>#"g
581 else
582 gettext "No diff for: $d"; echo
583 fi
584 echo '</pre>'
585 if check_auth; then
586 wiki_tools
587 fi
588 html_footer ;;
590 *\ login\ *)
591 # The login page
592 d="Login"
593 [ "$(GET error)" ] && \
594 error="<p class="error">$(gettext "Bad login or pass")</p>"
595 header
596 html_header
597 user_box
598 login_page
599 html_footer ;;
601 *\ signup\ *)
602 # The login page
603 d="$(gettext "Sign Up")"
604 header
605 html_header
606 user_box
607 echo "<h2>$d</h2>"
608 if [ "$ONLINE_SIGNUP" == "yes" ]; then
609 signup_page
610 else
611 gettext "Online registration is disabled"
612 fi
613 html_footer ;;
615 *\ logout\ *)
616 # Set a Cookie in the past to logout.
617 expires="Expires=Wed, 01-Jan-1980 00:00:00 GMT"
618 if check_auth; then
619 rm -f "$sessions/$user"
620 header "Location: $script" "Set-Cookie: auth=none; $expires; HttpOnly"
621 fi ;;
623 *\ user\ *)
624 # User profile
625 d="$(GET user)"
626 last="$(cat $PEOPLE/"$(GET user)"/last)"
627 header
628 html_header
629 user_box
630 . $PEOPLE/"$(GET user)"/account.conf
631 cat << EOT
632 <h2>$(get_gravatar $MAIL) $NAME</h2>
634 <pre>
635 $(gettext "User name :") $USER
636 $(gettext "Last login :") $last
637 EOT
638 if check_auth && [ "$(GET user)" == "$user" ]; then
639 auth_people
640 else
641 # check_auth will set VARS to current logged user: re-source
642 . $PEOPLE/"$(GET user)"/account.conf
643 public_people
644 fi
645 html_footer ;;
647 *\ dashboard\ *)
648 # For now simply list plugins and users info. We could have a
649 # dashbord only for ADMINS found in the config file. The dashboard
650 # should also be a plugin.
651 d="Dashboard"
652 header
653 html_header
654 user_box
655 users=$(ls -1 $PEOPLE | wc -l)
656 docs=$(find $wiki -type f | wc -l)
657 wikisize="$(du -sh $wiki | awk '{print $1}')"
658 cachesize="$(du -sh $cache | awk '{print $1}')"
659 [ "$HG" != "yes" ] && hg=$(gettext "disabled")
660 [ "$HG" == "yes" ] && hg=$(gettext "enabled")
661 echo "<h2>$d</h2>"
662 if check_auth; then
663 cat << EOT
664 <div id="tools">
665 <a href='$script?log'>Activity log</a>
666 <a href='$script?ls'>List files</a>
667 </div>
669 <pre>
670 Users : $users
671 Wiki : $docs ($wikisize)
672 Cache : $cachesize
673 Mercurial : $hg
674 </pre>
675 <h3>Admin users</h3>
676 EOT
677 # Get the list of administrators
678 for u in $(ls $PEOPLE)
679 do
680 user=${u}
681 if admin_user; then
682 echo "<a href='?user=$u'>$u</a>"
683 fi
684 done
685 cat << EOT
686 <h3>$(gettext "Plugins")</h3>
687 <pre>
688 EOT
689 for p in $(ls -1 $plugins)
690 do
691 . $plugins/$p/$p.conf
692 echo "<a href='?$p'>$PLUGIN</a> - $SHORT_DESC"
693 done
694 echo '</pre>'
695 else
696 gettext "You must be logged in to view the dashboard."
697 fi
698 html_footer ;;
700 *\ hg\ *)
701 header
702 [ "$HG" != "yes" ] && gettext "Hg is disabled" && exit 0
703 [ ! -x /usr/bin/hg ] && gettext "Hg is not installed" && exit 0
704 d="Hg Log"
705 html_header
706 user_box
707 echo "<h2>$d</h2>"
708 case " $(GET hg) " in
709 *\ init\ *)
710 if check_auth; then
711 [ -d "$content/.hg" ] && exit 0
712 echo '<pre>'
713 gettext "Executing: hg init"; echo
714 cd $content/ && hg init
715 echo '[hooks]' > .hg/hgrc
716 echo 'incoming = hg update' >> .hg/hgrc
717 gettext "Adding current content and committing"; echo
718 [ ! -f "$wiki/index.txt" ] && touch $wiki/$index.txt
719 hg add && hg commit -u "$NAME <$MAIL>" \
720 -m "Initial commit with current content"
721 echo '</pre>' && cd ..
722 fi ;;
723 esac
724 hg_log
725 html_footer ;;
727 *)
728 # Display requested page
729 d="$(GET d)"
730 [ "$d" ] || d=$index
731 header
732 html_header
733 user_box
734 get_lang
735 # Generate a default index on first run
736 if [ ! -f "$wiki/$index.txt" ]; then
737 if ! default_index; then
738 echo "<pre class='error'>Directory : content/ is not writable"
739 html_footer && exit 0
740 fi
741 fi
742 # Check cache dir
743 if [ ! -w "$cache" ]; then
744 echo "<pre class='error'>Directory : cache/ is not writable"
745 echo "Command : install -m 0777 -d $tiny/cache</pre>"
746 html_footer && exit 0
747 fi
748 # Wiki document
749 if [ ! -f "$wiki/$d.txt" ]; then
750 echo "<h2>$d</h2>"
751 gettext "The document does not exist. You can create it or read the"
752 echo " <a href='?d=en/help'>help</a>"
753 else
754 if fgrep -q [NOWIKI] $wiki/$d.txt; then
755 cat $wiki/$d.txt | sed '/\[NOWIKI\]/'d
756 else
757 cat $wiki/$d.txt | wiki_parser
758 fi
759 fi
760 if check_auth; then
761 wiki_tools
762 if [ "$HG" == "yes" ] && [ ! -d "$content/.hg" ]; then
763 echo '<p class="error box">'
764 gettext "Mercurial is enabled but no repository found"
765 echo ": <a href='?hg=init'>Hg init</a>"
766 echo '</p>'
767 fi
768 fi
769 html_footer ;;
770 esac
772 exit 0