s4

view s4-blog.sh @ 622:5f1d4bbf9dea

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