s4

view s4-blog.sh @ 638:b29e31dc3fbd

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