tinycm view index.cgi @ rev 26

remove the README function: do better
author Christophe Lincoln <pankso@slitaz.org>
date Sun Jan 05 23:18:19 2014 +0000 (2014-01-05)
parents 558dc3b9d373
children 09f5185ff6e0
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"
24 # Content negotiation for Gettext
25 IFS=","
26 for lang in $HTTP_ACCEPT_LANGUAGE
27 do
28 lang=${lang%;*} lang=${lang# } lang=${lang%-*}
29 if echo "$po" | fgrep -q "$lang"; then
30 break
31 fi
32 case "$lang" in
33 en) lang="C" ;;
34 fr) lang="fr_FR" ;;
35 pt) lang="pt_BR" ;;
36 ru) lang="ru_RU" ;;
37 esac
38 done
39 unset IFS
40 export LANG=$lang LC_ALL=$lang
42 #
43 # Functions
44 #
46 # Used by edit to display language name and the language box. This is
47 # for CM content not gettext support.
48 get_lang() {
49 lang=$(echo $d | cut -d "/" -f 1)
50 doc=${d#$lang/}
51 echo '<div id="lang">'
52 for l in $LANGUAGES
53 do
54 case $lang in
55 en) i18n="English" ;;
56 fr) i18n="Français" ;;
57 pt) i18n="Português" ;;
58 ru) i18n="Русский" ;;
59 *) i18n="*" ;;
60 esac
61 echo "<a href='?d=$l/$doc'>$l</a>"
62 done
63 echo '</div>'
64 }
66 # HTML 5 header.
67 html_header() {
68 if [ -f "$tiny/lib/header.html" ]; then
69 cat $tiny/lib/header.html | sed -e s!'%TITLE%'!"$TITLE - $d"!g
70 else
71 cat << EOT
72 <!DOCTYPE html>
73 <html xmlns="http://www.w3.org/1999/xhtml">
74 <head>
75 <title>$TITLE</title>
76 <meta charset="utf-8" />
77 <style type="text/css">body { margin: 40px 120px; }</style>
78 </head>
79 <body>
80 <!-- Content -->
81 <div id="content">
82 EOT
83 fi
84 }
86 # HTML 5 footer.
87 html_footer() {
88 if [ -f "$tiny/lib/footer.html" ]; then
89 cat $tiny/lib/footer.html
90 else
91 cat << EOT
93 <!-- End content -->
94 </div>
96 <div id="footer">&hearts;</div>
98 </body>
99 </html>
100 EOT
101 fi
102 }
104 # Default index if missing
105 default_index() {
106 mkdir -p "$wiki"
107 cat > $wiki/$index.txt << EOT
108 ==== Welcome ====
110 This is the default index page of your CM, you can start to edit and adding
111 some content to your TinyCM.
113 EOT
114 }
116 # Log documents activity.
117 log() {
118 grep ^[A-Z] | \
119 sed s"#^[A-Z]\([^']*\)#$(date '+%Y-%m-%d %H:%M') : \0#" \
120 >> $cache/$d/activity.log
121 }
123 # Check if user is auth
124 check_auth() {
125 auth="$(COOKIE auth)"
126 user="$(echo $auth | cut -d ":" -f 1)"
127 md5cookie="$(echo $auth | cut -d ":" -f 2)"
128 [ -f "$sessions/$user" ] && md5session="$(cat $sessions/$user)"
129 if [ "$md5cookie" == "$md5session" ] && [ "$auth" ]; then
130 . $PEOPLE/$user/account.conf
131 return 0
132 else
133 return 1
134 fi
135 }
137 # Authentified or not
138 user_box() {
139 if check_auth; then
140 cat << EOT
142 <div id="user">
143 <a href="$script?user=$user">$(get_gravatar $MAIL 20)</a>
144 <a href="$script?logout">Logout</a>
145 </div>
147 EOT
148 else
149 cat << EOT
151 <div id="user">
152 <a href="$script?login"><img src="images/avatar.png" alt="[ User ]" /></a>
153 <a href="$script?login">Login</a>
154 </div>
156 EOT
157 fi
158 cat << EOT
159 <!--
160 <div id="search">
161 <form method="get" action="$script">
162 <input type="text" name="search" placeholder="$(gettext "Search")" />
163 </form>
164 </div>
165 -->
166 EOT
167 }
169 # Link for online signup if enabled.
170 online_signup() {
171 if [ "$ONLINE_SIGNUP" == "yes" ]; then
172 echo -n "<p><a href='$script?signup'>"
173 gettext "Create a new account"
174 echo '</a></p>'
175 fi
176 }
178 # Login page
179 login_page() {
180 cat << EOT
181 <h2>$(gettext "Login")</h2>
183 <div id="account-info">
184 $(gettext "No account yet or trouble with you account? Please send
185 a request to $ADMIN_MAIL with your real name, user name, mail and password.")
186 $(online_signup)
187 </div>
189 <div id="login">
190 <form method="post" action="$script">
191 <input type="text" name="auth" placeholder="$(gettext "User name")" />
192 <input type="password" name="pass" placeholder="$(gettext "Password")" />
193 <div>
194 <input type="submit" value="Login" /> $error
195 </div>
196 </form>
197 </div>
199 <div style="clear: both;"></div>
200 EOT
201 }
203 # Signup page
204 signup_page() {
205 cat << EOT
207 <div id="signup">
208 <form method="post" name="signup" action="$script" onsubmit="return checkSignup();">
209 <input type="hidden" name="signup" value="new" />
210 <input type="text" name="name" placeholder="$(gettext "Real name")" />
211 <input type="text" name="user" placeholder="$(gettext "User name")" />
212 <input type="text" name="mail" placeholder="$(gettext "Email")" />
213 <input type="password" name="pass" placeholder="$(gettext "Password")" />
214 <div>
215 <input type="submit" value="$(gettext "Create new account")" />
216 </div>
217 </form>
218 </div>
220 EOT
221 }
223 # Create a new user in AUTH_FILE and PEOPLE
224 new_user_config() {
225 if [ ! -f "$AUTH_FILE" ];then
226 touch $(DESTDIR)$(LOGIN)/auth/people
227 chmod 0600 $(DESTDIR)$(LOGIN)/auth/people
228 fi
229 key=$(echo -n "$user:$mail:$pass" | md5sum | awk '{print $1}')
230 echo "$user:$pass" >> $AUTH_FILE
231 mkdir -p $PEOPLE/$user/
232 cat > $PEOPLE/$user/account.conf << EOT
233 # SliTaz user configuration
234 #
236 NAME="$name"
237 USER="$user"
238 MAIL="$mail"
239 KEY="$key"
241 EOT
242 chmod 0600 $PEOPLE/$user/account.conf
243 }
245 # Display user public profile.
246 public_people() {
247 cat << EOT
248 <pre>
249 Real name : $NAME
250 </pre>
251 EOT
252 # Display personnal user profile
253 if [ -f "$PEOPLE/$USER/profile.txt" ]; then
254 cat $PEOPLE/$USER/profile.txt | wiki_parser
255 fi
256 }
258 # Display authentified user profile. TODO: change password
259 auth_people() {
260 cat << EOT
261 <pre>
262 Real name : $NAME
263 Email : $MAIL
264 Secure key : $KEY
265 </pre>
266 EOT
267 # Each user can have personal profile page
268 if [ -f "$PEOPLE/$USER/profile.txt" ]; then
269 cat $PEOPLE/$USER/profile.txt | wiki_parser
270 cat << EOT
271 <div id="tools">
272 <a href="$script?edit=profile">$(gettext "Edit profile")</a>
273 </div>
274 EOT
275 else
276 cat << EOT
277 <div id="tools">
278 <a href="$script?edit=profile">$(gettext "Create a profile page")</a>
279 </div>
280 EOT
281 fi
282 }
284 # The CM style parser. Just a title, simple text formating and internal
285 # links, as well as images and use HTML for other stuff. Keep it fast!
286 # To make TinyCM as easy as possible we have a small HTML editor/helper
287 # written in Javascript
288 wiki_parser() {
289 doc="[0-9a-zA-Z\.\#/~\_%=\?\&,\+\:@;!\(\)\*\$'\-]*"
290 sed \
291 -e s"#====\([^']*\)====#<h2>\1</h2>#"g \
292 -e s"#===\([^']*\)===#<h3>\1</h3>#"g \
293 -e s"#==\([^']*\)==#<h4>\1</h4>#"g \
294 -e s"#\*\*\([^']*\)\*\*#<b>\1</b>#"g \
295 -e s"#''\([^']*\)''#<em>\1</em>#"g \
296 -e s"#__\([^']*\)__#<u>\1</u>#"g \
297 -e s"#\[\([^]]*\)|\($doc\)\]#<a href='$script?d=\2'>\1</a>#"g \
298 -e s"#\[\([^]]*\)!\($doc\)\]#<a href='\2'>\1</a>#"g \
299 -e s"#\[\(http://*[^]]*.png\)\]#<img src='\1' />#"g \
300 -e s"#\[\([^]]*.png\)\]#<img src='content/cloud/\1' />#"g
301 }
303 link_user() {
304 echo "<a href='$(basename $script)?user=$user'>$user</a>"
305 }
307 # Save a document. Do we need more than 1 backup and diff ?
308 save_document() {
309 mkdir -p $cache/$d $(dirname $wiki/$d)
310 # May be a new page.
311 if [ ! -f "$wiki/$d.txt" ]; then
312 new=0
313 touch $wiki/$d.txt
314 fi
315 cp $wiki/$d.txt $cache/$d/last.bak
316 sed "s/$(echo -en '\r') /\n/g" > $wiki/$d.txt << EOT
317 $(GET content)
318 EOT
319 diff $cache/$d/last.bak $wiki/$d.txt > $cache/$d/last.diff
320 # Log
321 if [ "$new" ]; then
322 echo "Page created by: $(link_user)" | log
323 if [ "$HG" == "yes" ]; then
324 cd $content && hg -q add
325 hg commit -q -u "$NAME <$MAIL>" -m "Created new document: $d"
326 cd $tiny
327 fi
328 else
329 # Here we will clean log: cat && tail -n 40
330 echo "Page edited by: $(link_user)" | log
331 if [ "$HG" == "yes" ]; then
332 cd $content && hg commit -q -u "$NAME <$MAIL>" \
333 -m "Edited document: $d"
334 cd $tiny
335 fi
336 fi
337 }
339 # Save a user profile.
340 save_profile() {
341 path="$PEOPLE/$user"
342 cp -f ${path}/${d}.txt ${path}/${d}.bak
343 sed "s/$(echo -en '\r') /\n/g" > ${path}/${d}.txt << EOT
344 $(GET content)
345 EOT
346 }
348 # CM tools (edit, diff, etc).
349 wiki_tools() {
350 cat << EOT
351 <div id="tools">
352 <a href="$script?edit=$d">$(gettext "Edit document")</a>
353 <a href="$script?diff=$d">$(gettext "Last diff")</a>
354 <a href="$script?log=$d">$(gettext "Activity")</a>
355 <a href="$script?dashboard">Dashboard</a>
356 $([ "$HG" == "yes" ] && echo "<a href='$script?hg'>Hg Log</a>")
357 </div>
358 EOT
359 }
361 # Get and display Gravatar image: get_gravatar email size
362 # Link to profile: <a href="http://www.gravatar.com/$md5">...</a>
363 get_gravatar() {
364 email=$1
365 size=$2
366 [ "$size" ] || size=48
367 url="http://www.gravatar.com/avatar"
368 md5=$(md5crypt $email)
369 echo "<img src='$url/$md5?d=identicon&s=$size' alt='&lowast;' />"
370 }
372 # List hg logs
373 hg_log() {
374 cd $content
375 cat << EOT
376 <table>
377 <thead>
378 <td>$(gettext "User")</td>
379 <td>$(gettext "Description")</td>
380 <td>$(gettext "Revision")</td>
381 </thead>
382 EOT
383 hg log --template "<tr><td>{author}</td><td>{desc}</td><td>{rev}</td></tr>\n"
384 echo '</table>'
385 }
387 #
388 # POST actions
389 #
391 case " $(POST) " in
392 *\ auth\ *)
393 # Authenticate user. Create a session file in $sessions to be used
394 # by check_auth. We have the user login name and a peer session
395 # md5 string in the COOKIE.
396 user="$(POST auth)"
397 pass="$(md5crypt "$(POST pass)")"
398 valid=$(fgrep "${user}:" $AUTH_FILE | cut -d ":" -f 2)
399 if [ "$pass" == "$valid" ] && [ "$pass" != "" ]; then
400 md5session=$(echo -n "$$:$user:$pass:$$" | md5sum | awk '{print $1}')
401 [ -d $sessions ] || mkdir -p $sessions
402 echo "$md5session" > $sessions/$user
403 header "Location: $script" \
404 "Set-Cookie: auth=$user:$md5session; HttpOnly"
405 else
406 header "Location: $script?login&error"
407 fi ;;
408 *\ signup\ *)
409 # POST action for signup
410 name="$(POST name)"
411 user="$(POST user)"
412 mail="$(POST mail)"
413 pass="$(md5crypt "$(POST pass)")"
414 if ! grep "^${user}:" $AUTH_FILE; then
415 new_user_config
416 header "Location: $script?login"
417 else
418 header
419 html_header
420 user_box
421 echo "<h2>gettext "User already exists: $user"</h2>"
422 html_footer
423 fi ;;
424 esac
426 #
427 # Plugins
428 #
429 for p in $(ls -1 $plugins)
430 do
431 [ -f "$plugins/$p/$p.conf" ] && . $plugins/$p/$p.conf
432 [ -x "$plugins/$p/$p.cgi" ] && . $plugins/$p/$p.cgi
433 done
435 #
436 # GET actions
437 #
439 case " $(GET) " in
440 *\ edit\ *)
441 d="$(GET edit)"
442 header
443 html_header
444 user_box
445 get_lang
446 if check_auth; then
447 if [ "$doc" == "profile" ]; then
448 wiki="$PEOPLE/$user"
449 fi
450 cat << EOT
451 <h2>$(gettext "Edit $doc [ $i18n ]")</h2>
453 <div id="edit">
455 <form method="get" action="$script" name="editor">
456 <input type="hidden" name="save" value="$d" />
457 <textarea name="content">$(cat "$wiki/$d.txt")</textarea>
458 <input type="submit" value="$(gettext "Save document")" />
459 $(gettext "Code Helper:")
460 $(cat lib/jseditor.html)
461 </form>
463 </div>
464 EOT
465 else
466 gettext "You must be logged in to edit pages"
467 fi
468 html_footer ;;
470 *\ save\ *)
471 d="$(GET save)"
472 if check_auth; then
473 # User profile
474 if [ "$d" == "profile" ]; then
475 save_profile
476 header "Location: $script?user=$user"
477 else
478 save_document
479 fi
480 fi
481 header "Location: $script?d=$d" ;;
483 *\ log\ *)
484 d="$(GET log)"
485 header
486 html_header
487 user_box
488 get_lang
489 echo "<h2>$(gettext "Activity for:") <a href='$script?d=$d'>$d</a></h2>"
490 echo '<pre>'
491 if [ -f "$cache/$d/activity.log" ]; then
492 tac $cache/$d/activity.log
493 else
494 gettext "No log for: $d"; echo
495 fi
496 echo '</pre>'
497 if check_auth; then
498 wiki_tools
499 fi
500 html_footer ;;
502 *\ diff\ *)
503 d="$(GET diff)"
504 date="last"
505 header
506 html_header
507 user_box
508 get_lang
509 echo "<h2>$(gettext "Diff for:") <a href='$script?d=$d'>$d</a></h2>"
510 echo '<pre>'
511 if [ -f "$cache/$d/$date.diff" ]; then
512 cat $cache/$d/$date.diff | sed \
513 -e 's|&|\&amp;|g' -e 's|<|\&lt;|g' -e 's|>|\&gt;|g' \
514 -e s"#^-\([^']*\).#<span style='color: red;'>\0</span>#"g \
515 -e s"#^+\([^']*\).#<span style='color: green;'>\0</span>#"g \
516 -e s"#@@\([^']*\)@@#<span style='color: blue;'>@@\1@@</span>#"g
517 else
518 gettext "No diff for: $d"; echo
519 fi
520 echo '</pre>'
521 if check_auth; then
522 wiki_tools
523 fi
524 html_footer ;;
526 *\ login\ *)
527 # The login page
528 d="Login"
529 [ "$(GET error)" ] && \
530 error="<p class="error">$(gettext "Bad login or pass")</p>"
531 header
532 html_header
533 user_box
534 login_page
535 html_footer ;;
537 *\ signup\ *)
538 # The login page
539 d="$(gettext "Sign Up")"
540 header
541 html_header
542 user_box
543 echo "<h2>$d</h2>"
544 if [ "$ONLINE_SIGNUP" == "yes" ]; then
545 signup_page
546 else
547 gettext "Online registration is disabled"
548 fi
549 html_footer ;;
551 *\ logout\ *)
552 # Set a Cookie in the past to logout.
553 expires="Expires=Wed, 01-Jan-1980 00:00:00 GMT"
554 if check_auth; then
555 rm -f "$sessions/$user"
556 header "Location: $script" "Set-Cookie: auth=none; $expires; HttpOnly"
557 fi ;;
559 *\ user\ *)
560 # User profile
561 d="$(GET user)"
562 header
563 html_header
564 user_box
565 . $PEOPLE/"$(GET user)"/account.conf
566 echo "<h2>$(get_gravatar $MAIL) $(GET user)</h2>"
567 loglines=$(fgrep $(GET user) $(find $cache -name *.log) | wc -l)
568 gettext "Activities:"; echo " $loglines"
569 if check_auth && [ "$(GET user)" == "$user" ]; then
570 auth_people
571 else
572 public_people
573 fi
574 html_footer ;;
576 *\ dashboard\ *)
577 # For now simply list plugins and users info. We could have a
578 # dashbord only for ADMINS found in the config file. The dashboard
579 # should also be a plugin.
580 d="Dashboard"
581 header
582 html_header
583 user_box
584 users=$(ls -1 $PEOPLE | wc -l)
585 docs=$(find $wiki -type f | wc -l)
586 wikisize="$(du -sh $wiki | awk '{print $1}')"
587 cachesize="$(du -sh $cache | awk '{print $1}')"
588 [ "$HG" != "yes" ] && hg=$(gettext "disabled")
589 [ "$HG" == "yes" ] && hg=$(gettext "enabled")
590 echo "<h2>$d</h2>"
591 if check_auth; then
592 cat << EOT
593 <pre>
594 Users : $users
595 Wiki : $docs ($wikisize)
596 Cache : $cachesize
597 Mercurial : $hg
598 </pre>
600 <div id="tools">
602 </div>
604 <h3>$(gettext "Plugins")</h3>
605 <pre>
606 EOT
607 for p in $(ls -1 $plugins)
608 do
609 . $plugins/$p/$p.conf
610 echo "<a href='?$p'>$PLUGIN</a> - $SHORT_DESC"
611 done
612 echo '</pre>'
613 else
614 gettext "You must be logged in to view the dashboard."
615 fi
616 html_footer ;;
618 *\ hg\ *)
619 header
620 [ "$HG" != "yes" ] && gettext "Hg is disabled" && exit 0
621 [ ! -x /usr/bin/hg ] && gettext "Hg is not installed" && exit 0
622 d="Hg Log"
623 html_header
624 user_box
625 echo "<h2>$d</h2>"
626 case " $(GET hg) " in
627 *\ init\ *)
628 if check_auth; then
629 [ -d "$content/.hg" ] && exit 0
630 echo '<pre>'
631 gettext "Executing: hg init"; echo
632 cd $content/ && hg init
633 echo '[hooks]' > .hg/hgrc
634 echo 'incoming = hg update' >> .hg/hgrc
635 gettext "Adding current content and committing"; echo
636 [ ! -f "$wiki/index.txt" ] && touch $wiki/$index.txt
637 hg add && hg commit -u "$NAME <$MAIL>" \
638 -m "Initial commit with current content"
639 echo '</pre>' && cd ..
640 fi ;;
641 esac
642 hg_log
643 html_footer ;;
645 *)
646 # Display requested page
647 d="$(GET d)"
648 [ "$d" ] || d=$index
649 header
650 html_header
651 user_box
652 get_lang
653 # Generate a default index on first run.
654 if [ ! -f "$wiki/$index.txt" ]; then
655 default_index
656 fi
657 if [ ! -f "$wiki/$d.txt" ]; then
658 echo "<h2>$d</h2>"
659 gettext "The document does not exist. You can create it or read the"
660 echo " <a href='?d=en/help'>help</a>"
661 else
662 if fgrep -q [NOWIKI] $wiki/$d.txt; then
663 cat $wiki/$d.txt | sed '/[NOWIKI]/'d
664 else
665 cat $wiki/$d.txt | wiki_parser
666 fi
667 fi
668 if check_auth; then
669 wiki_tools
670 if [ "$HG" == "yes" ] && [ ! -d "$content/.hg" ]; then
671 echo '<p class="error box">'
672 gettext "Mercurial is enabled but no repository found"
673 echo ": <a href='?hg=init'>Hg init</a>"
674 echo '</p>'
675 fi
676 fi
677 html_footer ;;
678 esac
680 exit 0