s4

view s4-blog.sh @ 649:535d961e71c1

Gethandout should be only served in report/quiz/enquete mode
author HIROSE Yuuji <yuuji@gentei.org>
date Sat, 09 May 2020 12:57:29 +0900
parents 8ec02e0fd1d5
children ef138b0c44a5
line source
1 #
2 type cgiinit >/dev/null 2>&1 || . ./s4-funcs.sh
4 # Global error flags
5 BLOG_NOTMEM=1
6 BLOG_FROZEN=2
7 FROZEN_TAG='<span class="frozen">[凍結]</span>'
9 blog_genform() {
10 #
11 t=$1
12 }
14 blog_writable() (
15 # $1=articleid $2=user
16 # Return: $?=0 - Writable
17 # =1 - NOT Writable because user is not a member
18 # =2 - NOT Writable because blog is frozen
19 blogowner=`getvalbyid blog owner "$1"`
20 state=`getvalbyid blog state "$1"`
21 rc=0
22 [ x"$blogowner" = x"$2" ] || isuser "$blogowner" || ismember "$2" "$blogowner" || rc=$((rc+$BLOG_NOTMEM))
23 [ "$state" = "frozen" ] && rc=$((rc+$BLOG_FROZEN))
24 return $rc
25 )
26 blog_readable() {
27 # $1=articleid $2=user
28 mode=`getgroupattr $grp regmode`
29 }
30 blog_getteam() {
31 # $1=rowid of blog
32 blogid="${1%%[!A-Z0-9a-z_]*}"
33 # team cannot get `getvalbyid blog team "$blogid"` because it's not
34 # defined in blog.def. Yes, it is Illegal USE!!
35 query "SELECT val FROM blog_s
36 WHERE id=(SELECT id FROM blog WHERE rowid=$blogid)
37 AND key='team';"
38 }
39 blog_notify_reply() (
40 # $1=blogid $2=ReplyingUser $3=WrittenText $4(optional)=Action
41 blogid="${1%%[!A-Z0-9a-z_]*}"
42 blogowner=`getvalbyid blog owner "$blogid"`
43 blogtitle=`getvalbyid blog title "$blogid"`
44 blogurl="$urlbase?replyblog+$blogid"
45 action=${4:-書き込み}
46 mode=`getvalbyid blog notify "$blogid"`
47 isgroup "$blogowner" && _isgroup=true || _isgroup=false
48 ### EXCEPT=`sqlquote "$user"` ## User should receive to feal some annoyance
49 case $mode in
50 admin)
51 if $_isgroup; then
52 emails=`getgroupadminmails $blogowner`
53 else
54 emails=`collectemail $blogowner`
55 fi
56 notifyto=`getpar notifyto`
57 if [ -n "$notifyto" ]; then
58 emails=$emails" `email4groupbyuid \"$blogowner\" $notifyto`"
59 fi
60 ;;
61 no) emails="" ;;
62 *) team=`blog_getteam "$blogid"`
63 # team cannot get by `getvalbyid blog team "$blogid"`
64 emails=`TEAM=$team collectemail $blogowner` ;;
65 esac
66 ## 2017-0210 Respond to the direct reply mark such as: >#1234
67 replymark=`echo "$3"|nkf -w -Z0|grep '^ *>#'`
68 authgecos=`gecos $2`
69 if [ -z "$4" -a -n "$replymark" ]; then
70 # If the action is new subscription($4="") and has ">#123" marks...
71 ids=`echo "$replymark"|sed 's/[^#0-9]*#\([0-9]*\)[^#0-9]*/\1 /g'`
72 ids=`echo $ids|tr -dc '[0-9 ]'|tr ' ' ','`
73 # -> 123,345,347
74 unames=`query "SELECT distinct author FROM article \
75 WHERE rowid in ($ids)\
76 AND blogid=(SELECT id FROM blog WHERE rowid=$blogid);"`
77 if [ -n "$unames" ]; then
78 e4g=$(if $_isgroup; then
79 email4group "$blogowner" $unames
80 else
81 for u in $unames; do
82 collectemail $u
83 done
84 fi)
85 emails=$emails" $e4g"
86 for e in $unames; do
87 g=`gecos $e`
88 whom=$whom"${whom:+,}${g:-$e}さん"
89 done
90 action="${whom}への返信"
91 fi
92 else
93 [ x"$2" = x"$blogowner" ] && return # If author=blogowner, unnecessary
94 fi
95 test -z "$emails" && return
96 err notify: user=$user Admins=`getgroupadmins $blogowner` Mode=$mode Emails="[$emails]"
97 MAIL_FROM=$noreply_from \
98 SMAIL_TO="`echo "$blogowner" | nkf -jM | tr -d '\n'` readers <$noreply>" \
99 smail "$emails" "${action}通知 $urlbase"<<EOF
100 [$blogtitle]板に${action}がありました。
101 ※※※このメイルには返信できません(返信は次のURLへ)※※※
102 場所: $blogurl (返信先)
103 所有: $blogowner
104 題目: $blogtitle
105 筆者: $authgecos
106 内容:
107 `echo "$3"|sed 's/^/> /'`
109 ※※このメイルに返信しても通知者には伝わりません。
110 ※※上記URLから${S4NAME:-s4}掲示板に書き込んでください。
111 EOF
112 )
114 blog_showentry() {
115 # $1=table $2=rowid
116 # if [ -n "$2" ]; then
117 # if [ -n "$imgcached" ]; then
118 # bstmpdir=$tmpdir/$imgcached/$thumbxy
119 # else
120 # bstmpdir=$tmpd
121 # # tmpd=`mktempd`
122 # # tmpfiles=$tmpfiles" $tmpd"
123 # fi
124 # fi
125 td=`getcachedir "article/$2"`
126 [ -d "$td" ] || mkdir -p $td
127 tbl=${1%%[!A-Z0-9a-z_]*} rowid=${2%%[!A-Z0-9a-z_]*}
128 err blow_showentry: rowid=$rowid, '$2'=$2 user=$user
129 ts=${tbl}_s tm=${tbl}_m
130 at=article as=article_s am=article_m
131 serial=$(($(date +%s)-1420038000))s$$
132 cannotread='<div class="relative"><img class="overlap" src="img/key.png" alt="(読み取り不可)"></div>'
133 blog_writable $rowid $user
134 rc=$?
135 if [ $rc = 0 ]; then
136 iswritable=true
137 ismem=true
138 else
139 iswritable=false
140 if [ $((rc & $BLOG_NOTMEM)) -gt 0 ]; then
141 ismem=false
142 else
143 ismem=true
144 fi
145 fi
146 # This function grasps blog entry definiton directly.
147 # blog: id
148 # blog_s: title,ctime,heading
149 # blog_m: *article
151 blogowner=`getvalbyid blog owner "$2"`
152 isgroup "$blogowner" && isgroup=true || isgroup=false
153 isgrpadmin=false # Reversed later (*1)
154 test x"$user" = x"$blogowner" && isowner=true || isowner=false
156 # 2015-10-05 check readable
157 if ! $iswritable; then
158 # err blogowner=$blogowner
159 if $isgroup; then
160 regmode=`getgroupattr $blogowner regmode`
161 # err regmode=$regmode
162 if [ x"$regmode" = x"moderated" ]; then
163 # if ! ismember $user $blogowner; then
164 if ! $ismem; then
165 echo "加入してからどうぞ" | html p
166 return
167 fi
168 fi
169 fi
170 else # if writable
171 isgrpowner "$user" "$blogowner" && isgrpadmin=true # (*1)
172 fi
173 blog_notify=`getvalbyid blog notify "$rowid"`
174 blog_team=`blog_getteam "$rowid"`
175 blog_mode=`getvalbyid blog mode "$rowid"`
176 case "$blog_notify" in # "all", "admin" or "no" (or NULL)
177 admin) notifyto=adm ;;
178 *) notifyto="" ;;
179 esac
180 case $blog_mode in
181 *quiz*|*close*|*euquete*) f_exclusive=1 ;;
182 *) f_exclusive='' ;;
183 esac
185 # err "SELECT id from $tbl where rowid=$rowid"
186 id=`query "select id from $tbl where rowid=$rowid;"`
187 #err id=$id
188 #err "select val from $ts where key='title' and id='$id';"
190 #(1)Display root article
191 cat<<EOF
192 <form class="replyblog" action="$myname?replyblog+${rowid}#bottom" method="POST" enctype="multipart/form-data">
193 <table class="bloghead">
194 EOF
196 href="<a href=\"?editheading+$rowid\" accesskey=\"e\" title=\"E\"> 編集 </a>"
197 if $ismem; then
198 case $blog_mode in
199 *report*|*quiz*|*enquete*)
200 href2="<a href=\"?lshandout+$rowid\" accesskey=\"l\" title=\"L\"> 提出状況 </a>"
201 href3="(<a href=\"?gethandout+$rowid\" accesskey=\"f\" title=\"F\">ファイル取得</a>)"
202 ;;
203 esac
204 fi
205 href4='<a href="#bottom" accesskey="b" title="B"> 末尾へ</a>'
206 $isgrpadmin &&
207 href5="<a href=\"?blogseen+$rowid\" accesskey=\"s\" title=\"S\"> 読刻</a>"
208 quizmodefile=$tmpd/quiz; rm -f "$quizmodefile" # XXX: Global state
209 midfile=$tmpd/midfile
211 query<<-EOF > $midfile
212 SELECT coalesce((SELECT "yes" FROM blog
213 -- GrpAdmin CAN EDIT heading since 2019-08-15
214 WHERE '$isgrpadmin' = 'true'
215 OR (rowid=$rowid AND author='$user')),
216 ''),
217 max(CASE key WHEN 'ctime' THEN val END) ctime,
218 max(CASE key WHEN 'heading' THEN hex(val) END) heading,
219 CASE (SELECT val FROM $ts WHERE key="mode" AND id="$id")
220 WHEN 'report-closed' THEN 'レポート提出用(closed)'
221 WHEN 'report-open' THEN 'レポート提出用(open)'
222 WHEN 'quiz' THEN 'クイズ'
223 WHEN 'enquete' THEN '集計'
224 ELSE ''
225 END
226 FROM $ts WHERE id='$id' GROUP BY id;
227 EOF
228 if test -s $midfile && IFS='|' read edit ctime hexhead blogtype < $midfile
229 then
230 cat<<-EOF
231 <tr><td>${edit:+$href }$ctime $blogtype $href2${edit:+$href3} $href4 $href5</td></tr>
232 <tr class="preface${frozen_class:+ }$frozen_class">
233 <td>`echo "$hexhead"|unhexize|htmlescape|hreflink|minitbl`</td></tr>
234 </table>
235 EOF
236 case "$blogtype" in
237 "クイズ"|"XXXX集計")
238 echo "${blogtype}モードは本人と管理者の書き込みのみが表示されます。"
239 ;;
240 esac | html p 'class="warn"'
241 echo '<table class="blog_replies"> <!-- blog:blog_showentry() main table -->'
242 if [ x"$blogtype" = x"クイズ" -o x"$blogtype" = x"XXXX集計" ]; then
243 if $isgroup; then
244 # Failsafe to query timeout
245 qgrp=`sqlquote "$blogowner"`
246 cat<<-EOF > $quizmodefile
247 AND (author IN (SELECT user FROM grp_adm WHERE gname=$qgrp)
248 OR
249 author='$user')
250 EOF
251 if isgrpowner "$user" "$blogowner"; then
252 : > $quizmodefile
253 fi
254 else # if user-blog
255 if [ x"$user" != x"$blogowner" ]; then
256 cat<<-EOF > $quizmodefile
257 AND author IN ('$blogowner', '$user')
258 EOF
259 fi
260 fi
261 fi
262 else # Cannot read SQL output
263 echo "時間をおいて繋いでください(Please visit later)." | html p
264 return
265 fi
266 lkhome="<a href=\"$myname?home" lke='">'
267 lkedit="<a href=\"$myname?editart"
268 hlink="$myname?home" elink="$myname?editart"
269 catlink="$myname?showattc+article_m"
270 deficon="img/file-icon.png"
271 # 2016-08-15 Newer flag introduced
272 atime=`query "SELECT time FROM acclog
273 WHERE tbl='blog' AND tblrowid=$rowid AND user='$user';"`
274 iconcleaner=$tmpd/iconcleaner.$$
275 [ -s $quizmodefile ] && cond_qz=`cat $quizmodefile`
276 # *** DO NOT USE query(), use "sq $db" instead here ***
277 # because the next block in pipe line uses query() repeatedly.
278 ###### TEST: 2020-04-23 Use intermediate file to shorten duration of db-lock
279 ###### sq $db<<EOF |
280 query <<EOF > $midfile
281 WITH a_s AS (
282 SELECT id,
283 max(CASE key WHEN 'ctime' THEN val END) TIME,
284 max(CASE key WHEN 'text' THEN val END) TEXT
285 FROM article_s
286 GROUP by id
287 )
288 SELECT a.id,
289 CASE author
290 WHEN '$user' THEN a.rowid||'+'||$rowid
291 ELSE ''
292 END edit,
293 CASE -- 「通知送信」ボタンの有無
294 WHEN '$notifyto' = '' THEN '' -- 不要モードならなし
295 WHEN '$user' = author THEN '' -- 筆者自身ならなし
296 ELSE "yes"
297 END notify,
298 (SELECT rowid FROM user WHERE name=author) user_rid,
299 author,
300 coalesce((SELECT val FROM user_s
301 WHERE name=author AND key='gecos'),
302 author) uname,
303 (SELECT val FROM user_s WHERE name=author AND key='$iconcachekey')
304 icon,
305 a.rowid,
306 s.TIME,
307 CASE WHEN s.TIME < '2019-05'
308 THEN printf('平成%d年%d月%d日%s',
309 substr(s.TIME, 1, 4)-1988,
310 substr(s.TIME, 6, 2),
311 substr(s.TIME, 9, 2),
312 substr(s.TIME, 12)
313 )
314 WHEN s.TIME < '2020'
315 THEN printf('令和元年%d月%d日%s',
316 substr(s.TIME, 6, 2),
317 substr(s.TIME, 9, 2),
318 substr(s.TIME, 12))
319 WHEN s.TIME < '2050'
320 THEN printf('令和%d年%d月%d日%s',
321 substr(s.TIME, 1, 4)-2018,
322 substr(s.TIME, 6, 2),
323 substr(s.TIME, 9, 2),
324 substr(s.TIME, 12))
325 ELSE s.TIME
326 END reki,
327 CASE WHEN s.TIME > '$atime' THEN 'new' ELSE '' END newer,
328 hex(s.TEXT),
329 CASE -- File Accessibility to attached file
330 WHEN '$f_exclusive' = '' THEN ''
331 WHEN '$isgrpadmin' = 'true' THEN ''
332 WHEN '$user' = author THEN ''
333 ELSE 'Unreadable'
334 END cannotread,
335 (SELECT group_concat(rowid||':'||length(bin)||':'||hex(val), ' ')
336 FROM article_m
337 WHERE id=a.id AND key='image') imxgids
338 FROM (select rowid,id,author from article
339 where blogid in
340 (select id from blog where rowid=$rowid)
341 $cond_qz) a
342 LEFT JOIN
343 a_s s
344 ON a.id=s.id;
345 EOF
346 if [ $? -ne 0 -a ! -s $midfile ]; then
347 echo "時間をおいてください(Visit later please)." | html p
348 return
349 fi
350 cat $midfile |
351 while IFS='|' read id edit notify uid author uname icon aid \
352 tm reki new hte fa imgids
353 do
354 mf2=$tmpd/midfile2
355 cachefile="$td/$id.row.html"
356 stampfile="$td/$id.row.stamp"
357 editlink="${edit:+<a href="$elink+$edit">編集</a> }"
358 nt="<label style=\"font-size: 70%;\"><input type=\"checkbox\"\
359 name=\"notifyto\" value=\"$uid\">返信通知送信</label>"
360 # fa is file accessibility flag # err "----r=$aid fa=[$fa]----"
362 # First, check the availability of user-icon.
363 # If not existent, clear and reset row cache by rm $stampfile
364 if [ ! -s "$icon" ]; then
365 rm -f "$stampfile"; unset stampfile
366 fi
367 if test -s "$stampfile" &&
368 test -s "$cachefile" &&
369 { ts=`cat "$stampfile"`; test -n "$ts"; } &&
370 test "$ts" '>' "$tm" && # Cache timestamp is newer
371 test "$stampfile" -nt "$icon"; then # UserIcon is older
372 : Nothing to do
373 else
374 { ######## New ROW creation begins here ######## >$cachefile
375 cachestamp=$tmpd/cache.$$.stamp
376 touch $cachestamp
377 tdcls="__NEWCLS__repatt"
378 if [ -s "$icon" ]; then
379 icfn=`echo "$icon"|htmlescape`
380 picon="<p class=\"proficon\"><a href=\"$hlink+$uid\" title=\"${author%@*}\"><img src=\"$icfn\"></a></p>"
381 else
382 echo "DELETE FROM user_s WHERE key='$iconcachekey' AND
383 val=`sqlquotestr \"$icon\"`;" >> $iconcleaner
384 picon=""
385 fi
387 cat<<EOF
388 <tr id="$id">
389 <td class="$tdcls">${picon}__EDIT__<a href="#$aid">#$aid</a>
390 <a href="$hlink+$uid" title="${author%@*}">$uname</a>
391 <span title="$tm">${reki:-$tm}</span>
392 <__NOTIFY__></td>
393 EOF
394 echo -n "<td id=\"$aid\" class=\"repl\">"
395 echo "$hte"|unhexize|htmlescape|hreflink|minitbl
396 usecache='' tsfile=$td/$id.stamp
397 for i in $imgids; do
398 mrid=${i%%:*}; i=${i#*:}; sz=`size_h ${i%%:*}`
399 fn=`echo "${i#*:}"|unhexize`
400 fnb=$fn"(${sz})"
401 case "$fn" in
402 *.[Pp][Nn][Gg]|*.[Jj][Pp][Gg]|*.[Jj][Pp][Ee][Gg]|*.[GgTt][Ii][Ff])
403 # fmt=${fn##*.} # convert - jpg:- is slow...why
404 case "$fn" in
405 *.[Pp][Nn][Gg]) fmt=png ;;
406 *.[Gg][Ii][Ff]) fmt=gif ;;
407 *) fmt=jpeg ;;
408 esac
409 outfile=$td/$mrid-${fn%.*}.$fmt
410 #err fn=$fn outfile=$outfile
411 #err "usecache=$usecache `ls -l $outfile`"
412 #err tm=$tm
413 #err tsfile=$tsfile=`cat $tsfile`
414 if [ -s "$outfile" ] && # $outfile should be > 0
415 { [ "$usecache" ] || # And usecache flag is true, or...
416 { [ -s "$tsfile" ] && [ x"`cat $tsfile`" = x"$tm" ]
417 };}; then
418 usecache=1 # Set usecache flag on
419 cat<<-EOF
420 <a href="$catlink+$mrid"><img src="$outfile">
421 $fnb</a>
422 EOF
423 # !!NOTE!! Create row stamp ONLY WHEN imgcache is active
424 else
425 query "SELECT hex(bin) FROM article_m WHERE rowid=$mrid;" \
426 > $mf2 # Stop query here 2020-04-23
427 if cat $mf2 | unhexize \
428 | convert -define ${fmt}:size=100x100 -resize 100x100'>' \
429 - ${fmt}:- > $outfile
430 then
431 cat "$outfile" \
432 | hexize \
433 | sed -e 's/\(..\)/%\1/g' \
434 -e "s|^|<a href=\"$catlink+$mrid\"><img src=\"data:image/$fmt,|" \
435 -e "s|\$|\">$fnb</a>|"
436 unset stampfile # img data stream is not suitable to cache
437 echo $tm > $tsfile
438 else # Failed to convert
439 rm -f $outfile
440 echo "<a href=\"$catlink+$mrid\">$fnb</a>"
441 fi
442 fi
443 ;;
444 *)
445 echo "<__UNREADABLE__><a href=\"$catlink+$mrid\"><img src=\"$deficon\">$fnb</a>"
446 ;;
447 esac
448 done
449 echo "</td></tr>"
450 } > "$cachefile.$$" ######## New ROW Creation Ends here ########
451 # Care about race condition
452 if [ -s $cachefile -a $cachefile -nt $cachestamp ]; then
453 # If other process have created cache, give up to serve our file
454 rm -f $cachefile.$$
455 else
456 mv -f $cachefile.$$ $cachefile
457 fi
458 test -n "$stampfile" && date "+%F %T" > $stampfile
459 fi
460 # Printing a cached row
461 sed -e "/^<td class=/s/__NEWCLS__/$new${new:+ }/" \
462 -e "/^<td class=/s,__EDIT__,$editlink," \
463 -e "/^<__NOTIFY__>/s,,${notify:+$nt}," \
464 -e "/<__UNREADABLE__>/s,,${fa:+$cannotread}," \
465 $cachefile
466 done
468 help="=== コメントに使用できる特殊記法 ===
469 行頭に href=URL でURLへのリンク
470 行頭に iframe=URL でURL先を開く iframe
471 [[#記事番号]] でs4内の記事番号に飛ぶリンク
472 [[#検索キーワード]] でs4内の記事検索(記号はいくつか使えない)
473 [[URL]] でURLへのリンク、 [[URL|文字列]]でアンカー文字列指定
474 {{画像URL}} でインライン画像、 {{画像URL|幅}} でピクセル幅指定
475 {{{URL}}} でURL先を開く iframe、 {{{URL|高さ}}} ピクセル高さ指定
476 行頭: ## 大見出し, ### 中見出し, #### 小見出し
477 行末の2連続スペースで強制改行(<br>)
478 |*見出し列|列2|列3… と行頭から始まる縦棒区切り行を続けて表
479 ' *語群* ' で強調(両側の空白必要、** でもっと強調。*の代わりに _ でも可)
480 - [ ] と - [x] でチェックボックス"
481 touchhelp="${touchpanel:+<p class=\"help\">$help</p>}"
482 filehelp="《添付の注意》
483 $file_accept_help"
484 ntmode="通知モード=$blog_notify${blog_team:+ (team=$blog_team)}"
485 textform='<div class="fold">
486 <input type="checkbox" id="cmt" checked><label
487 accesskey="c" title="C" for="cmt">コメントする</label><div>
488 <table class="b">
489 <tr><td><textarea id="text" name="text" cols="72" rows="4" title="'"$help"'">
490 </textarea>'"$touchhelp</td></tr>
491 <tr><td>添付ファイル(${filesize_max_MB}以下):"'
492 <input type="file" name="image"'" $file_accept title=\"$filehelp\" multiple></td></tr>"'
493 </table>
494 <input type="submit" value="送信"'" class=\"$blog_notify\" title=\"$ntmode\""'>
495 <input type="reset" value="リセット"></div></div>
496 '
497 cat<<-EOF
498 </table> <!-- end of s4-blog:blog_showentry() main table -->
499 <p class="update_link"><a
500 href="?reload/$rowid" accesskey="r" title="R">再読込</a> / <a
501 href="#title" id="bottom" accesskey="t" title="T">先頭へ</a></p>
502 EOF
503 $iswritable && cat<<-EOF
504 <div class="blogcomment">
505 <input type="hidden" name="blogid" value="$id">
506 <input type="hidden" name="id" value="`genserial`">
507 <input type="hidden" name="stage" value="replyblog">
508 $textform
509 </div>
510 </form> <!-- End of s4-blog:blog_showentry() main form -->
511 EOF
512 # Clean up orphaned icon cache
513 [ -s $iconcleaner ] && query ".read '$iconcleaner'"
514 # Record access log
515 acclog blog $rowid
516 }
518 lshandout() {
519 # $1=rowid of blog
520 blog_writable $1 $user
521 rc=$? # =0: writable, $BLOG_NOTMEM bit set => not member
522 if [ $((rc & $BLOG_NOTMEM)) -gt 0 ] ; then
523 echo "メンバー以外は利用できません。" | html p; return
524 fi
525 time=`getvalbyid blog ctime $1|colrm 11`
526 owner=`getvalbyid blog owner $1`
527 title=`getvalbyid blog title $1`
528 ge=`gecos $owner`
529 fh=$tmpd/formhead
530 echo "$time [$title]@${ge:-$owner}" > $fh
531 lshandoutsub $owner "$@" \
532 |_m4 -D_TITLE_="提出状況" \
533 -D_FORMHEAD_="syscmd(cat $fh)" \
534 -D_FORM_="syscmd(cat)" -D_DUMPHEAD_= -D_DUMPTABLE_= \
535 $layout/html.m4.html $layout/form+dump-whead.m4.html
536 gn=`echo $owner|htmlescape`
537 echo "<p><a href=\"?lshandoutall+$1\">グループ $gn すべてのレポート板集計</a></p>"
538 }
539 gethandoutcsv() {
540 # contenttype; echo
541 CATCSV=1 lshandoutall "$1"
542 }
543 gethandoutcsv2() {
544 # contenttype; echo
545 SQL=$(cat<<-EOF
546 WITH this_blog_articles AS (
547 SELECT rtb.id bid, rtb.brid, a.id aid, author, title, ctime
548 FROM report_type_blogs rtb JOIN article a ON rtb.id=a.blogid
549 ), text_or_file AS (
550 SELECT bid, author, title, ctime, 'text' shu, count(val) cnt
551 FROM this_blog_articles tba, article_s s
552 ON tba.aid=s.id
553 WHERE key='text'
554 GROUP by bid, author
555 UNION
556 SELECT bid, author, title, ctime, 'file' shu, count(val) cnt
557 FROM this_blog_articles tba, article_m m
558 ON tba.aid=m.id
559 WHERE key='image'
560 GROUP by bid, author
561 ), count_list AS (
562 SELECT author,
563 substr(ctime, 1, 10)||upper(substr(shu, 1, 1)) unit,
564 cnt
565 FROM text_or_file
566 )
567 SELECT gecos "名前",
568 substr(author, 1, instr(author, '@')-1) "uname",
569 unit,
570 cnt "post"
571 FROM count_list cl JOIN gecoses g ON cl.author=g.name;
572 EOF
573 ) gethandoutcsv "$1"
574 }
575 lshandout_ulink_table() {
576 # NO Args. Read stdin as SQL
577 echo '<table class="b td3rr td3evw">'
578 hrb="<a href=\"?home+"
579 # echo "$sql" | sq -header -html $db \ # Formerly, this is called via sq()
581 printf ".mode html\n.header ON\n" | query
582 cat | query \
583 | sed -e "s,\(<TR><TD>\)\([^ ]*\) \(.*\)</TD>,\1$hrb\2\">\3</TD>," -e 's,<TD>0</TD>,<TD class="warn">0</TD>,'
584 echo '</table>'
585 printf ".mode list\n.header OFF\n" | query
586 }
587 lshandoutall() {
588 # $1=rowid of blog
589 blog_writable $1 $user
590 rc=$? # =0: writable, $BLOG_NOTMEM bit set => not member
591 if [ $((rc & $BLOG_NOTMEM)) -gt 0 ] ; then
592 echo "メンバー以外は利用できません。" | html p; return
593 fi
594 rowid=$(($1 + 0))
595 owner=`getvalbyid blog owner $1`
596 qowner=`sqlquotestr "$owner"`
598 query<<-EOF
599 CREATE TEMPORARY TABLE IF NOT EXISTS report_type_blogs AS
600 WITH blog_owner_mode AS (
601 SELECT id,
602 blog.rowid brid,
603 max(CASE key WHEN 'owner' THEN val END) owner,
604 max(CASE key WHEN 'mode' THEN val END) mode,
605 max(CASE key WHEN 'title' THEN val END) title,
606 max(CASE key WHEN 'ctime' THEN val END) ctime
607 FROM blog NATURAL JOIN blog_s
608 GROUP BY id
609 )
610 SELECT id, brid, title, ctime FROM blog_owner_mode
611 /* WHERE owner=$qowner AND mode LIKE '%report%'; */
612 WHERE owner=$qowner
613 AND
614 (mode LIKE '%report%' OR mode LIKE '%quiz%'
615 OR mode LIKE '%enquete%');
616 /* ↑これでレポート形式の blogid 一覧を得る */
617 EOF
618 if [ -z "$CATCSV" ]; then
619 _m4 -D_TITLE_="提出状況" $layout/html.m4.html
620 ge=`gecos "$owner"`
621 tbls=""
622 grptxt=`echo "${ge:-$owner}"|htmlescape`
623 echo "<h1>$grptxt 書き込み状況一覧</h1>"
624 fi
625 if [ -z "$SQL" ]; then
626 bridlist=`query "SELECT brid FROM report_type_blogs;"`
627 for brid in $bridlist; do # Skip this loop if $SQL set
628 brid=$(($brid + 0)) # Ensure to be a number
629 [ $brid = 0 ] && continue
630 time=`getvalbyid blog ctime $brid|colrm 11`
631 title=`getvalbyid blog title $brid|htmlescape`
632 state=`getvalbyid blog state $brid|htmlescape`
633 tt="handout_$brid"
634 [ "$state" = "frozen" ] && frozen=" $FROZEN_TAG" || frozen=""
635 if [ -z "$CATCSV" ]; then
636 echo "<h2>$time - <a href=\"?replyblog+$brid\">$title</a>$frozen</h2>"
637 lshandoutsub "$owner" $brid "$tt"
638 else
639 lshandoutsub "$owner" $brid "$tt" >/dev/null # Only create temp.table
640 fi
641 tbls="$tbls${tbls:+ NATURAL JOIN }$tt"
642 done
643 fi
644 sql=${SQL:-"SELECT * FROM $tbls;"}
645 if [ -z "$CATCSV" ]; then
646 echo "<hr><h2>総合</h2>"
647 echo "$sql" | lshandout_ulink_table
648 echo "<h2>総合(<a href=\"?gethandoutcsv+$rowid\">CSV</a>)</h2>"
649 printf ".mode csv\n.header ON\n" | query
650 echo '<pre class="list">'
651 echo "$sql" | query | sed 's/^"[0-9]* /"/'
652 echo "</pre>"
653 echo "<pre><a href=\"?gethandoutcsv2+$rowid\">縦持ちCSV</a></pre>"
654 else
655 contenttype "Application/CSV"
656 printf ".mode csv\n.header ON\n" | query >/dev/null
657 fn=report-count.csv
658 printf 'Content-Disposition: filename="%s"\n' "$fn"
659 outfile=$tmpd/out-$$.csv
660 echo "$sql" | query | sed 's/^"[0-9]* /"/' > $outfile
661 echo "Content-Length: " `cat $outfile | wc -c`; echo
663 cat $outfile
664 exit 0
665 fi
666 printf ".mode list\n.header OFF\n.separator |\n" | query
667 }
668 lshandoutsub() {
669 # $1=owner $2=rowid of blog &optional $3=temp_table name
670 qgname=`sqlquote "$1"`
671 if isgroup "$1"; then
672 sample="(select user from grp_mem where gname=$qgname)"
673 else
674 sample="(select distinct author as user from arts)"
675 echo "(集計は板への投稿者のみ)" | html p
676 fi
677 tmpname="${3:-handout_$2}"
678 sql="CREATE TEMPORARY TABLE IF NOT EXISTS $tmpname AS
679 with arts as (select id,author from article \
680 where blogid=(select id from blog where rowid=$2))\
681 select (select rowid from user where name=c0.user)||' '|| \
682 (select gecos from gecoses where name=c0.user) as 'メンバー',\
683 substr(c0.user, 1, instr(c0.user, '@')-1) 'uname',\
684 sum(case when c1.key is not null then 1 else 0 end)\
685 as '[$title] コメント記入',\
686 sum(case when c2.key is not null then 1 else 0 end)\
687 as '[$title] ファイルの提出'\
688 from $sample c0 \
689 left join (select id,author from arts) a\
690 on c0.user=a.author\
691 left join (select id,key from article_s where key='text') c1\
692 on a.id=c1.id left join (select id,key from article_m ) c2\
693 on c1.id=c2.id group by c0.user order by c0.user;\
694 \
695 SELECT * FROM $tmpname;"
696 # err ishandoutsub: sql="$sql"
697 echo "$sql" | lshandout_ulink_table
698 }
699 gethandout() {
700 # $1=rowid of blog
701 rid=`numericalize "$1"`
702 blog_writable $rid $user
703 rc=$? # =0: writable, $BLOG_NOTMEM bit set => not member
704 if [ $((rc & $BLOG_NOTMEM)) -gt 0 ] ; then
705 contenttype; echo
706 echo "メンバー以外は利用できません。" | html p; return
707 fi
708 # Here, this blog is writable by $user
709 owner=`getvalbyid blog owner $1`
710 if [ x"$user" = x"$owner" ]; then
711 : OK
712 elif isgrpowner "$user" "$owner"; then
713 : OK
714 else
715 contenttype; echo
716 echo "板の所有者以外は利用できません。" | html p; return
717 fi
718 mode=`getvalbyid blog mode $1`
719 copy2csv=false
720 blogid=`getvalbyid blog id $1`
721 isgroup "$owner" && isgroup=true || isgroup=false
722 isgrpowner "$user" "$owner" && isgrpadmin=true || isgrpadmin=false
724 i=0
725 midfile=$tmpd/midfile
726 bd=$tmpd/archive.$$
727 mkdir $bd
728 case "$mode" in
729 *quiz*)
730 copy2csv=true ;;
731 *enquete*)
732 copy2csv=true
733 csvline=`getvalbyid blog heading $1 | grep "..*,." | head -1`
734 # Create CSV-base table for questionnaire
735 # If heading in blog_s has at least 1 CSV line,
736 # we take the line as column list.
737 # Otherwise we produce two column CSV as below:
738 # USER,ANSWER
739 query "DROP TABLE IF EXISTS tmp_q;"
740 if [ -n "$csvline" ]; then
741 query <<-EOF
742 CREATE TEMPORARY TABLE tmp_q("user", $csvline);
743 EOF
744 if [ $? != 0 ]; then
745 contenttype; echo
746 cat <<-EOF | html p; exit
747 掲示板のヘッダにあるCSV定義が不正でCSV出力できません。
748 $csvline
749 空白なしの項目名を半角カンマ区切りで1行で書いてください。
750 EOF
751 fi
752 else
753 query <<-EOF
754 CREATE TEMPORARY TABLE tmp_q(user text PRIMARY KEY, answer);
755 EOF
756 fi
757 esac
758 if $copy2csv; then
759 mkdir $bd/$rid
760 outcsv=$bd/$rid/migrate-$rid.csv
761 fullcsv=$bd/$rid/all-text-full-$rid.csv
762 sq "$db" <<-EOF | tr '|' ',' > $outcsv
763 SELECT author as "USER",
764 replace(val, x'0a', ',') as "${csvline:-ANSWER}"
765 FROM article a JOIN article_s s ON a.id=s.id
766 AND blogid=(SELECT id FROM blog WHERE rowid=$rid)
767 AND s.key='text';
768 EOF
769 sq "$db" <<-EOF > $fullcsv
770 .mode csv
771 .head 1
772 SELECT author as "ユーザ",
773 (SELECT gecos FROM gecoses g WHERE author=g.name) as "表示名",
774 val as "テキスト"
775 FROM article a JOIN article_s s ON a.id=s.id
776 AND blogid=(SELECT id FROM blog WHERE rowid=$rid)
777 AND s.key='text';
778 EOF
779 fi
780 query <<-EOF > $midfile # Using tempfile for quick db-unlock
781 SELECT a.rowid, a.id artid, a.author, hex(s.val)
782 FROM article a JOIN article_s s ON a.id=s.id
783 WHERE blogid=(SELECT id FROM blog WHERE rowid=$rid);
784 EOF
785 cat $midfile | while IFS='|' read rowid artid author text; do
786 isfilereadable $user article_s $rowid || continue
787 dir=`printf $bd/%d/%06d "$rid" "$rowid"`
788 mkdir -p $dir
789 echo "$author" > $dir/Author
790 echo "$text" | unhexize > $dir/Text
791 i=0
792 query "SELECT m.rowid, m.val FROM article_m m \
793 WHERE id='$artid' AND m.key IN ('image', 'document', 'binary');" \
794 | while IFS='|' read mrowid filename; do
795 i=$((i+1))
796 outfile=`printf "%s/%02d-%s" "$dir" $i "$filename"`
797 query "SELECT quote(bin) FROM article_m WHERE rowid=$mrowid;" \
798 | unhexize > $outfile
799 done
800 done
801 if [ ! -d $bd/$rid ]; then
802 contenttype; echo
803 echo "取得できるファイルがありませんでした。" | html p
804 return
805 fi
807 if $copy2csv; then
808 query <<-EOF > $bd/$rid/all-text-1stline-$rid.csv
809 .mode csv
810 .head 1
811 .import $outcsv tmp_q
812 SELECT * FROM tmp_q;
813 .mode list
814 .head 0
815 EOF
816 fi
817 err "BDLIST: `ls -l $bd`"
818 arcname=archive-$rid.tar.gz
819 (cd $bd
820 # query() CANNOT BE used in this subshell
821 tar zcf .archive.tar.gz $rid && mv .archive.tar.gz "$arcname"
822 err Creating tar archive "`ls -l "$arcname"`"
823 )
824 arcfile=$bd/$arcname
825 echo "Content-type: application/x-gzip"
826 echo "Content-Length: `cat $arcfile|wc -c`"
827 echo "Content-Disposition: filename=\"$arcname\""
828 echo
829 cat $arcfile
830 }
831 blogseen() { # $1 = blogid
832 blogid=${1%%[!0-9]*}
833 if [ -z "$blogid" ]; then
834 echo "Invalid blog id" | html p; exit
835 fi
836 blog_writable "$blogid" "$user"
837 rc=$? # =0: writable, $BLOG_NOTMEM bit set => not member
838 if [ $((rc & $BLOG_NOTMEM)) -gt 0 ] ; then
839 echo "メンバー以外は利用できません。" | html p; return
840 fi
841 owner=`getvalbyid blog owner $rowid`
842 qowner=`sqlquotestr "$owner"`
843 grprowid=`query "SELECT rowid FROM grp WHERE gname=$qowner;"`
844 ge=`gecos "$owner" | htmlescape`
845 title=`getvalbyid blog title $rowid | htmlescape`
846 h1="アクセス時刻"
847 link2board="<a href=\"?replyblog+$rowid\">$title</a>"
848 link2group="<a href=\"?grp+$grprowid\">$ge</a>"
849 _m4 -D_TITLE_="$h1" $layout/html.m4.html
850 echo "$h1" | html h1
851 echo "[$link2board]@$link2group" | html h2
852 warn=' class="warn"'
853 cat <<-EOF
854 <table class="b">
855 <tr><th>メンバー</th><th>uname</th><th>最終閲覧時刻</th></tr>
856 EOF
857 query <<-EOF |
858 WITH grpmem as (
859 SELECT user, (SELECT gecos FROM gecoses WHERE name=user) gecos
860 FROM grp_mem
861 WHERE gname=(SELECT val FROM blog_s
862 WHERE id=(select id from blog where rowid=$blogid)
863 AND key='owner')
864 ), acctime AS (
865 SELECT user, max(time) atime
866 FROM tblaccesses
867 WHERE tbl='blog' AND tblrowid=$blogid
868 GROUP BY user
869 )
870 SELECT g.user,
871 (SELECT rowid FROM user u WHERE u.name=g.user),
872 hex(gecos),
873 atime
874 FROM grpmem g LEFT JOIN acctime t
875 ON g.user = t.user
876 GROUP BY g.user
877 ORDER BY atime DESC;
878 EOF
879 while IFS='|' read u uid hexge time; do
880 td=${time:+"<td>"} # If the variable time is set, td=<td>
881 td=${td:-"<td$warn>"} # else td=<td class="warn">
882 cat <<-EOF
883 <tr>
884 <td><a href="?home+$uid">`echo "$hexge"|unhexize|htmlescape`</a></td>
885 <td>`echo ${u%%@*}|htmlescape`</td>
886 $td${time:----}</td></tr>
887 EOF
888 done
889 cat <<-EOF
890 </table>
891 <p><a href="?replyblog+$rowid">[$title]に戻る</a></p>
892 </html>
893 EOF
894 }
895 lsmyfile() { # $1(optional)=SortBy
896 case "$1" in
897 ""|CTIME-DESC)
898 by="CTIME" ord="DESC" ;;
899 CTIME*) by="CTIME" ;;
900 FILE*) by="FILE" ;;
901 OWNER*) by="OWNER" ;;
902 TITLE*) by="TITLE" ;;
903 esac
904 case "$1" in
905 *DESC) ord="DESC" ;;
906 esac
907 case "$ord" in
908 DESC) lkod="" jord="降順" ;;
909 *) lkod="-DESC" jord="昇順" ;;
910 esac
911 sql="select m.val||'/'||m.rowid FILE,
912 coalesce(
913 case when (select name from user where name=bs.owner)
914 is not null
915 then (select val from user_s where name=bs.owner
916 and key='gecos')
917 when (select gname from grp where gname=bs.owner)
918 is not null
919 then (select val from grp_s where gname=bs.owner
920 and key='gecos')
921 else
922 null
923 end,
924 bs.owner
925 ) OWNER,
926 a_s.val CTIME,
927 ',t,'||bs.title||':'||b.rowid||'#'||a.id TITLE
928 from (select rowid,id,val from article_m where id
929 in (select id from article where author='$user')
930 and type like 'file:%')
931 m left join article a on m.id=a.id
932 left join article_s a_s on a.id=a_s.id and a_s.key='ctime'
933 left join (select id,
934 max(case key when 'owner' then val end) as owner,
935 max(case key when 'title' then val end) as title
936 from blog_s group by id)
937 bs on a.blogid=bs.id
938 left join blog b on bs.id=b.id
939 where m.val is not null order by $by $ord;"
940 err lshandoutbyauthor: sql=`echo "$sql"`
941 title="個人提出ファイル"
942 _m4 -D_TITLE_=$title $layout/html.m4.html
943 hra="<a href=\"?lsmyfile+"
944 hrb="<a href=\"?showattc+article_m+"
945 hrc="<a href=\"?replyblog+"
946 (echo '<table class="b">'
947 echo "$sql"|sq -html -header $db ) \
948 | sed -e "s|\(<TR><TD>\)\([^/]*\)/\([0-9]*\)|\1$hrb\3\">\2</a>|" \
949 -e "s|,t,\(.*\):\([^<]*\)\(</TD>\)|$hrc\2\">\1</a>\3|" \
950 -e "s|\(<TH>\)\([A-Z]*\)\(</TH>\)|\1$hra\2$lkod\">\2</a>|" \
951 | _m4 -D_TITLE_=$title -D_FORM_="<p>($by$jord)</p>" \
952 -D_DUMPTABLE_="syscmd(cat)" $layout/form+dump.m4.html
953 echo '</table>'
954 }
955 searchart() {
956 kwd=`getpar kwd|nkf -wZ1` # Convert Zenkaku-SPC to ASCII-SPC
957 bloglist=`getpar bloglist|sed 's/[^0-9,]//g'`
958 kwdgrp=""
959 authcond=""
960 if [ -z "$kwd" ]; then
961 echo "検索語を指定してください" | html p; return
962 fi
963 if logstart "$searchlog"; then
964 { echo "kwd=$kwd"
965 test -n "$bloglist" && echo "bloglist=$bloglist"
966 } >> $searchlog
967 logend "$searchlog"
968 fi
969 if expr x"$kwd" : 'x#[1-9][0-9]*$' >/dev/null 1>&2; then
970 # Like '#1234', assume as artID
971 rowid=$((${kwd#\#} + 0)) # Force to be a number
972 kc="ar.rowid = $rowid"
973 else
974 for k in `echo "$kwd" | sed "s/'/''/g"`; do # With wrap quotes
975 ctime=""
976 if expr x"$k" : 'x@[><= ]*[1-9][][0-9]*-[][0-9:-]*$' >/dev/null >&2; then
977 # '@<2016-10-10' -> ctime < '2016-10-10'
978 # '@>=2016-10-10' -> ctime >= '2016-10-10'
979 # '@2016-10-10' -> ctime GLOB '@2016-10-10'
980 k=${k#@}
981 case "$k" in
982 [\<\>]*) op=${k%%[!<>=]*}; ctime=${k##*[><= ]} ;;
983 *) op='GLOB'; ctime="${k##*[><= ]}*" ;;
984 esac
985 kc=$kc${kc:+" AND "}"ctime $op '${ctime}'"
986 # Not sure GROUP BY a.blogid is comfortable for searchers...?
987 ##### kwdgrp=" GROUP BY a.blogid" ## Add this to lessen results
988 elif [ x"$k" = x"@today" -o x"$k" = x"@今日" ]; then
989 ctime=`date +%F`
990 elif n=`expr x"$k" : 'x@\([0-9]*\)days*'` >/dev/null >&2; then
991 ctime=`query "SELECT datetime('now', 'localtime', '-$n days');"`
992 elif [ x"$k" = x"@week" ]; then
993 ctime=`query "SELECT datetime('now', 'localtime', '-7 days');"`
994 elif n=`expr x"$k" : 'x@\([0-9]*\)weeks*'` >/dev/null >&2; then
995 n=$((n * 7))
996 ctime=`query "SELECT datetime('now', 'localtime', '-$n days');"`
997 elif [ x"$k" = x"@month" ]; then
998 ctime=`query "SELECT datetime('now', 'localtime', '-1 month');"`
999 elif n=`expr x"$k" : 'x@\([0-9]*\)months*'` >/dev/null >&2; then
1000 ctime=`query "SELECT datetime('now', 'localtime', '-$n month');"`
1001 elif [ x"$k" = x"@year" ]; then
1002 ctime=`query "SELECT datetime('now', 'localtime', '-1 year');"`
1003 elif n=`expr x"$k" : 'x@\([0-9]*\)years*'` >/dev/null >&2; then
1004 ctime=`query "SELECT datetime('now', 'localtime', '-$n year');"`
1005 fi
1006 if [ -n "$ctime" ]; then
1007 kc=$kc${kc:+" AND "}"ctime > '${ctime}'"
1008 else
1009 e=""
1010 case "$k" in
1011 *${likeesc}*) e="" ;; # Giving up char-escaping
1012 *%*|*_*) k=`echo "$k"|sed "s/\([%_]\)/${likeesc}\1/g"`
1013 e=" ESCAPE '$likeesc'" ;;
1014 esac
1015 kc=$kc${kc:+" AND "}"content LIKE '%$k%'$e"
1016 fi
1017 done
1018 fi
1019 kwd=`echo "$kwd"|htmlescape`
1020 owner=`getpar owner`
1021 owner=${owner:-$1}
1022 msg=""
1023 if [ -n "$owner" ]; then
1024 cond="where key='owner' and val='$owner'"
1025 if isuser $owner; then
1026 msg="(`linkhome $owner` さんの記録から)"
1027 else
1028 linkhome $owner 1>&3
1029 msg="(`linkhome $owner` グループから)"
1030 fi
1031 elif { author=`getpar author`; test -n "$author"; }; then
1032 atptn=`sqlquotestr $author`
1033 #kc="$kc${kc:+ AND }author=$atptn"
1034 authcond="WHERE author=$atptn"
1035 if isuser $author; then
1036 msg="(`linkhome $author` さんの書き込みから)"
1037 fi
1038 fi
1039 if [ -n "$bloglist" ]; then
1040 blogcond="AND bl.rid IN ($bloglist)"
1041 fi
1043 sf=`search_form "$search_form_args" "$kwd" | sed '1d;$d'` # rm <div></div>
1044 echo "$sf" | sed -e "/POST SENTENCE/s/.*/__PS__/" -e "/EOF/q" \
1045 | _m4 -D__PS__="による検索結果$msg"
1046 echo "(上記入力窓で再検索すると下記の掲示板のみに絞って再検索します)" \
1047 | html p 'class="small"'
1048 # article_s: id=article-id, key='text', val='TEXT'
1049 # article: id=article-id, blogid=blogkd
1050 # blog: id=blog-id, author=LeaderAuthor
1051 # blog_s: id=blog-id, key='title', val='BLOG-TITLE'
1052 # WANT: blog-ROWid,article-id,val(TEXT)
1053 sql2="`sql4readableblogs` -- Extract user-readable blogs
1054 -- 0.3sec
1055 WITH artsm AS (
1056 SELECT a.id,ctime, text || ' ' || coalesce(files, '') content
1057 FROM article a
1058 LEFT JOIN
1059 (SELECT ars.id, ctime, text, coalesce(files, '') files
1060 FROM (SELECT id,
1061 max(CASE key WHEN 'ctime' THEN val END) ctime,
1062 max(CASE key WHEN 'text' THEN val END) text
1063 FROM article_s
1064 GROUP BY id) ars
1065 LEFT JOIN
1066 (SELECT id, group_concat(val) files
1067 FROM article_m
1068 WHERE type LIKE 'file:%'
1069 GROUP BY id) arm
1070 ON ars.id=arm.id
1071 ) ar
1072 ON a.id=ar.id
1073 ), ar AS (
1074 SELECT a.rowid, a.blogid, a.id, a.author, ctime, content
1075 FROM article a JOIN artsm ON a.id=artsm.id
1076 $authcond
1077 ), bl AS (
1078 SELECT blg.rid, blg.*, blog_s.val TITLE
1079 FROM readableblogs blg JOIN blog_s ON blg.id=blog_s.id AND blog_s.key='title'
1081 SELECT bl.rid||'#'||ar.id '',
1082 bl.title TITLE,
1083 (SELECT gecos FROM gecoses WHERE name=ar.author) AUTHOR,
1084 substr(ctime, 0, 11) DATE,
1085 substr(content, 0, 78) TEXT
1086 FROM ar JOIN bl
1087 ON ar.blogid=bl.id
1088 WHERE $kc AND bl.id IN (SELECT id FROM blog_s $cond) $blogcond
1089 ORDER by DATE DESC, TITLE, ctime;"
1090 sedopt="s,<TR><TD>\([^<]*\)</TD>,<TR><TD><a\
1091 href=\"?replyblog+\1\">VIEW</a></TD>,"
1092 # echo "$sql2" > tmp/sql.out
1093 result=$tmpd/result.$$
1094 cat<<EOF
1095 <table class="b searchart">
1096 `sq -header -html $db "$sql2"|sed "$sedopt"|tee $result`
1097 </table>
1098 EOF
1099 if [ -s "$result" ]; then
1100 found=$((`grep "^<TR><TD>" $result | wc -l` + 0)) # Cast to INT
1101 one=${found%1}
1102 echo "$found match${one:+es} found"
1103 # <a href="?replyblog+39#12345">VIEW</a>
1104 # -> 39,49,55, -> 39,49,55
1105 # -> <input type="hidden" name="bloglist" value="39,49,55">
1106 sed -n "/.*href=.*replyblog\+\([0-9][0-9]*\).*/s//\1/p" "$result" \
1107 | sort | uniq | tr '\n' ',' \
1108 | sed -e 's/,$//' \
1109 -e 's/^/<input type="hidden" name="bloglist" value="/' \
1110 -e 's/$/">/'
1111 else
1112 echo orz...
1113 fi
1114 echo "$sf" | sed "1,/-- EOF/d" # Close <form>
1116 listblog() (
1117 # $1={user,group}
1118 qow=`sqlquote $1`
1119 cond="where a.id in (select id from blog_s where key='owner' and val=$qow) order by ctime desc"
1120 cgi_form searchart<<EOF
1121 <label>`cgi_text kwd`という語を含む記事をこの一覧から検索</label>
1122 `cgi_hidden owner $user`
1123 EOF
1124 DT_CHLD=article:blogid DT_QOWNER=$qow \
1125 dumptable html blog 'ctime title heading' "$cond"
1128 blog_addentry() {
1129 # $1=GRPname(if it is a group)
1130 grprowid=`numericalize $1`
1131 rowid=`getpar rowid`
1132 ## err blog_addentry0: rowid=$rowid
1133 if [ -n "$grprowid" ]; then
1134 owner=`getgroupbyid $grprowid`
1135 else
1136 owner=`getpar owner`
1137 fi
1138 err blog-add: \$1=$grprowid rowid=$rowid owner=$owner
1139 if isgroup "$owner"; then
1140 groupmode=1 listing=$owner guide="[${owner}]" GF_OWNER=$owner
1141 else
1142 usermode=1 listing=$user guide="[個人]"
1143 fi
1145 if [ -n "`getpar title`" ]; then
1146 if [ "$usermode" ]; then
1147 err usermode: user=$user owner=$owner
1148 if [ x"$user" != x"$owner" ]; then
1149 echo "他人の日記は書けません" | html p
1150 return 2
1151 fi
1152 elif [ "$groupmode" ]; then # if write to group log
1153 grp=$owner #\`getpar grp\`
1154 err ismember: $user $grp
1155 if ! ismember "$user" "$grp"; then
1156 echo "(話題作成はこのグループに加入してから)" | html p
1157 return 3
1158 fi
1159 fi
1160 par2table $formdir/blog.def
1161 serial=`getpar serial`
1162 ## err SERIAL: $serial ROWID=$rowid listing=$listing
1163 id=""
1164 if [ -n "$rowid" ]; then
1165 # Here, id becomes NULL when removal of entries at par2table
1166 id=`query "select rowid from blog where rowid=$rowid;"`
1167 elif [ -n "$serial" ]; then
1168 # If new blog leader created, traverse to its head.
1169 id=`query "select rowid from blog where id='$serial';"`
1170 ## err new-Leader: "select rowid from blog where id='$serial';" id=$id
1171 fi
1172 if [ -n "$id" ]; then
1173 ## If new aritcle is entered, JUMP to blog_reply
1174 blog_reply $id
1175 return
1176 fi
1177 fi
1178 echo "${guide}新規話題作成" > $tmpd/title.$$
1179 listblog $listing > $tmpd/listblog.$$
1180 genform $formdir/blog.def \
1181 | _m4 -D_TITLE_="spaste(\`$tmpd/title.$$')" \
1182 -D_FORMHEAD_="序文は簡単に詳しくはコメントに" \
1183 -D_DUMPHEAD_="これまでの蓄積" \
1184 -D_FORM_="syscmd(\`cat')" \
1185 -D_DUMPTABLE_="spaste(\`$tmpd/listblog.$$')" \
1186 $layout/html.m4.html \
1187 $layout/form+dump-whead.m4.html
1190 blog_reply() { # Posting to blog article
1191 rowid=`numericalize $1` # Ensure (already purified in s4.cgi)
1193 if [ -z "$rowid" ]; then
1194 echo "表示する日記番号が未指定です。" | html p
1195 return
1196 fi
1197 title=`getvalbyid blog title $rowid`
1198 owner=`getvalbyid blog owner $rowid`
1199 qowner=`sqlquotestr "$owner"`
1200 if [ -z "$title" ]; then
1201 echo "日記番号指定が無効です。" | html p
1202 return
1203 fi
1204 blog_writable $rowid $user; rc=$?
1205 if [ $rc = 0 ]; then
1206 iswritable=true
1207 else
1208 iswritable=false
1209 if [ $((rc & $BLOG_FROZEN)) -gt 0 ]; then
1210 isfrozen=true
1211 frozen_class='frozen"'
1212 frozen_flag=$FROZEN_TAG
1213 fi
1214 fi
1215 if isuser "$owner"; then
1216 subtitle="`gecos $owner` さんの話題"
1217 else
1218 grprowid=`query "select rowid from grp where gname=$qowner;"`
1219 subtitle="グループ
1220 <a href=\"?grp+$grprowid\" accesskey=\"h\" title=\"H\">$owner</a> での話題
1221 `query \"SELECT printf('(チーム:%s)', val)\
1222 FROM blog_s
1223 WHERE id=(SELECT id FROM blog WHERE rowid=$rowid)
1224 AND key='team';
1225 \"|htmlescape`"
1226 memclass=`grp_getbodyclass "$owner"`
1227 fi
1229 text=`getpar text`
1230 if [ -n "$text" ]; then
1231 if $iswritable; then
1232 par2table $formdir/article.def
1233 st=$?
1234 case $st in
1235 0|4)
1236 [ "$st" = "4" ] && act="書込削除"
1237 blog_notify_reply $rowid $user "$text" $act
1238 if [ -n "$grprowid" ]; then
1239 qgrp=$(sqlquote "$owner")
1240 dbsetbyid grp $owner wtime "`date '+%F %T'`"
1241 else
1242 dbsetbyid user "$user" wtime "`date '+%F %T'`"
1243 fi
1244 ;;
1245 esac
1246 else
1247 if $isfrozen; then
1248 title="$title(凍結板につき書き込み不可)"
1249 else
1250 title="$title(加入してないので書き込み不可)"
1251 fi
1252 fi
1253 fi
1254 def=$formdir/article.def
1255 echo "$title" > $tmpd/title.$$
1256 echo "$subtitle$frozen_flag" > $tmpd/subtitle.$$
1257 ${BLOG_SHOW:-blog_showentry} blog $rowid \
1258 | _m4 -D_TITLE_="spaste(\`$tmpd/title.$$')" \
1259 -D_BODYCLASS_=general"${memclass:+ $memclass}" \
1260 -D_FORMHEAD_="spaste(\`$tmpd/subtitle.$$')" \
1261 -D_FORM_='' \
1262 -D_DUMPTABLE_="syscmd(cat)" -D_DUMPHEAD_="" \
1263 $layout/html.m4.html $layout/form+dump-whead.m4.html
1266 blog_reply_article() { # Direct link to article in some blog
1267 arid=${1:-0} # Already sanitized to digits
1268 brid=`query "SELECT rowid FROM blog WHERE \
1269 id=(SELECT blogid FROM article WHERE rowid=$arid);"`
1270 if [ -n "$brid" ]; then
1271 newurl="?replyblog+$brid#$arid"
1272 echo "Refresh: 0; $newurl"; echo
1273 exit 0
1274 else
1275 contenttype; echo
1276 echo "無効な記事番号です." | html p
1277 fi