s4

view s4-blog.sh @ 595:d4fe749996fd

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