s4

view s4-blog.sh @ 642:209d74364eca

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