Mercurial > hgrepos > hgweb.cgi > s4
changeset 815:66d9b07edcc2
First complete merge with featureWorld branch
author | HIROSE Yuuji <yuuji@gentei.org> |
---|---|
date | Tue, 16 Jun 2020 13:11:18 +0900 |
parents | 70e056d2443a (current diff) 04034092338d (diff) |
children | de988b0a7afa |
files | |
diffstat | 9 files changed, 627 insertions(+), 39 deletions(-) [+] |
line wrap: on
line diff
--- a/examples/common/default/default.css Tue Jun 16 13:10:57 2020 +0900 +++ b/examples/common/default/default.css Tue Jun 16 13:11:18 2020 +0900 @@ -16,6 +16,7 @@ box-shadow: #242 2px 3px 5px; text-shadow: #fff 0px 0px 10px; } +div.topmenu ul li.worldname {background: #eeeeff;} div.topmenu ul li:hover {background: #8fa;} div.topmenu ul a {text-decoration: none;} @@ -331,6 +332,20 @@ input[type="reset"] {margin-left: 4em;} /* + * World List + */ +li.casmenu div {display: none; position: relative; width: 200%; + min-width: 80%; margin-right: 0;} +li.casmenu div table { + background: white; position: absolute; top: 0em; border: 3px solid navy; + max-width: 100%; +} +li.casmenu div table td {text-align: left; padding: 0.5ex 1em;} +li.casmenu:hover div, li.casmenu:active div, +li.casmenu div:hover, li.casmenu div:active +{display: block;} + +/* * PR Web */ body.pr {font-size: 200%;}
--- a/examples/common/default/footer.m4.html Tue Jun 16 13:10:57 2020 +0900 +++ b/examples/common/default/footer.m4.html Tue Jun 16 13:11:18 2020 +0900 @@ -1,6 +1,6 @@ <p class="copyright">Driven by <a href="http://www.gentei.org/~yuuji/software/s4/">s4</a> -©2015-2019 by +©2015-2020 by <a href="http://www.gentei.org/~yuuji/">yuuji</a> </body> </html>
--- a/examples/common/default/html.m4.html Tue Jun 16 13:10:57 2020 +0900 +++ b/examples/common/default/html.m4.html Tue Jun 16 13:11:18 2020 +0900 @@ -7,7 +7,7 @@ `<meta name="theme-color" content="_S4COLOR_">', `<meta name="theme-color" content="#8ea">') <meta name="viewport" content="width=device-width,initial-scale=0.5"> -<title>_TITLE_|ifdef(`_S4NAME_',`_S4NAME_',s4)</title> +<title>_TITLE_|ifdef(`_S4WORLD_',`{_S4WORLD_}')ifdef(`_S4NAME_',`_S4NAME_',s4)</title> <link rel="stylesheet" type="text/css" href="templ/default/default.css"> <script type="text/javascript" src="s4-main.js" charset="utf-8"></script> ifdef(`_S4CSS_', @@ -18,17 +18,19 @@ <body class="_BODYCLASS_"> <div class="topmenu"> <ul> - <li><a href="?home" accesskey="1" title="Shortcut: 1 -Home">ホーム</a></li> + <li class="casmenu"><a href="?home" accesskey="1" title="Shortcut: 1 +Home">ホーム</a>ifdef(`_S4WORLDS_',`_S4WORLDS_')</li> <!-- <li><a href="?blog">話題作成</a></li> --> <li><a href="?mems" accesskey="2" title="Shortcut: 2 Members">参加者一覧</a></li> - <li><a href="?grps" accesskey="3" title="Shortcut: 3 -Groups">グループ一覧</a></li> - <li><a href="?invite" accesskey="4" title="Shortcut: 4 -Invite">招待</a></li> + <li class="casmenu"><a href="?grps" accesskey="3" title="Shortcut: 3 +Groups">グループ一覧</a>ifdef(`_S4WORLDGRPS_',`_S4WORLDGRPS_')</li> +ifdef(`_S4WORLDNAME_',`', +` <li><a href="?invite" accesskey="4" title="Shortcut: 4 +Invite">招待</a></li>')dnl <li><a href="?login" accesskey="5" title="Shortcut: 5 Sign out">再ログイン</a></li> <!-- <li><a href="?userconf">userconf</a></li> --> +ifdef(`_S4WORLDNAME_',`<li class="worldname">@_S4WORLDNAME_</li>',`')dnl </ul> </div>
--- a/s4-blog.sh Tue Jun 16 13:10:57 2020 +0900 +++ b/s4-blog.sh Tue Jun 16 13:11:18 2020 +0900 @@ -127,7 +127,7 @@ td=`getcachedir "article/$2"` [ -d "$td" ] || mkdir -p $td tbl=${1%%[!A-Z0-9a-z_]*} rowid=${2%%[!A-Z0-9a-z_]*} - err blow_showentry: rowid=$rowid, '$2'=$2 user=$user + err blog_showentry: rowid=$rowid, '$2'=$2 user=$user ts=${tbl}_s tm=${tbl}_m at=article as=article_s am=article_m serial=$(($(date +%s)-1420038000))s$$ @@ -532,7 +532,7 @@ echo "</td></tr>" } > "$cachefile.$$" ######## New ROW Creation Ends here ######## # Care about race condition - if [ -s $cachefile -a $cachefile -nt $cachestamp ]; then + if [ -z "$hte" -a -s $cachefile -a $cachefile -nt $cachestamp ]; then # If other process have created cache, give up to serve our file rm -f $cachefile.$$ else
--- a/s4-funcs.sh Tue Jun 16 13:10:57 2020 +0900 +++ b/s4-funcs.sh Tue Jun 16 13:11:18 2020 +0900 @@ -4,20 +4,39 @@ [ -f s4-config.sh ] && . ./s4-config.sh +test -n "$HTTP_HOST" && isCGI=true || isCGI=false +if $isCGI; then + case "$SCRIPT_NAME" in + *-world-*) + S4WORLD=${SCRIPT_NAME#*world-} + S4WORLD=${S4WORLD%.*} + echo S4WORLD=$S4WORLD >&2 + worldconf=s4-config-${S4WORLD}.sh + ;; + *) + worldconf=s4-config.sh + ;; + esac + echo worldconf=$worldconf >&2 + [ -n "$worldconf" -a -e "$worldconf" ] && . ./$worldconf + echo DB=$DB >&2 +fi myname=`basename ${SCRIPT_NAME:-$0}` mydir=`dirname ${SCRIPT_FILENAME:-$0}` +cgiext=${CGIEXT:-.cgi} myargs="$@" -test -n "$HTTP_HOST" && isCGI=true PATH=/usr/local/sqlite3/bin:/usr/local/vim7/bin:/usr/iekei/ImageMagick/bin:/usr/local/ImageMagick/bin:$PATH tmpdir=${TMPDIR:-tmp} dbdir=${DBDIR:-db} +logdir=${LOGDIR:-tmp} tmpfiles="" +querylog=${QUERYLOG:-$logdir/query.log} +searchlog=${SEARCHLOG:-$logdir/search.log} db=${DB:-$dbdir/cgi.sq3} -querylog=${QUERYLOG:-$tmpdir/query.log} -searchlog=${SEARCHLOG:-$tmpdir/search.log} +sessdb=${SESSDB:-$dbdir/sess.sq3} +userupdateflag=$dbdir/userupdate +sesstb=tmp.sess workdb=$dbdir/tmpdata.sq3 -sessdb=$dbdir/sess.sq3 -sesstb=tmp.sess listentlimit=${LISTENTLIMIT:-30} listartlimit=${LISTARTLIMIT:-50} admin=${ADMIN:-hostmaster@example.org} @@ -59,16 +78,36 @@ session=$main_session tconfs="" -imgcached=cache/img.`date +%Y/%m` +imgcached=cache/${S4WORLD:+$S4WORLD/}img.`date +%Y/%m` conftbl=_tblconf nl=" " likeesc=`printf '\037'` # ESCAPE char of LIKE operator iconcachekey="profimgcache_S" + +# Start debug logging +logtag="${S4WORLD:+{$S4WORLD\}}" +exec 3>> $logdir/debug.out +err() { + echo "[`date +%F-%T%z`]$logtag $@" 1>&3 +} case "$HTTP_USER_AGENT" in *i[Pp]hone*|*[Aa]ndroid*) touchpanel=1 ;; *) touchpanel="" ;; esac + +# If S4MASTERDB is set, behave in another world +### if [ -n "$S4MASTERDB" -a -s "$S4MASTERDB" ]; then +# If S4WORLDLIST is set, this s4 have world! +if [ -n "$S4WORLDLIST" ]; then + . ./s4-world.sh 2>> $logdir/debug.out + # Variables set in s4-world.sh + # $S4WORLDS, $S4WROLDNAME, $S4WORLDGRPS + # Files created in s4-world.sh + # $worldlistfile, $worldoptionfile, $worldnamefile, $worldgrpfile +fi + + [ -f ./s4-cgi.sh ] && . ./s4-cgi.sh : <<EOF @@ -335,10 +374,10 @@ EOF logstart() { - echo "`date '+%F %T'`:[${user:-NULL}] <<<" >> ${1:-$querylog} + echo "`date '+%F %T'`:[${user:-NULL}]$logtag <<<" >> ${1:-$querylog} } logend() { - echo ">>>" >> ${1:-$querylog} + echo ">>>$logtag" >> ${1:-$querylog} } sqlog() { logstart @@ -372,12 +411,11 @@ #tail -f $sqi | sq $db & # "tail -f" is too heavy. DO NOT USE!! sq $db < $sqi & sq3pid="`jobs -p` $!" - if [ -n "$isCGI" ]; then - exec 2>> $tmpdir/error.out + if $isCGI; then + exec 2>> $logdir/error.out fi - exec 3>> $tmpdir/debug.out exec 5> $sqi # Turning $sqi access through fd5 for continuous open state - chmod o-r $tmpdir/error.out $tmpdir/debug.out + chmod o-r $logdir/error.out $logdir/debug.out rm $sqi # Attach supplemental DB cat >&5 <<-EOF @@ -424,7 +462,11 @@ } _m4() { #S4NAME=f,f,f - m4 ${S4NAME:+"-D_S4NAME_=${S4NAME}"} ${S4CSS:+-D_S4CSS_="$S4CSS"} "$@" + m4 ${S4NAME:+"-D_S4NAME_=${S4NAME}"} ${S4CSS:+-D_S4CSS_="$S4CSS"} \ + ${S4WORLD:+-D_S4WORLD_="$S4WORLD"} \ + ${S4WORLDNAME:+-D_S4WORLDNAME_="$S4WORLDNAME"} \ + ${S4WORLDGRPS:+-D_S4WORLDGRPS_="$S4WORLDGRPS"} \ + ${S4WORLDS:+-D_S4WORLDS_="$S4WORLDS"} "$@" } ismember() { # $1=user, $2=group @@ -1216,6 +1258,7 @@ for kv in `echo $HTTP_COOKIE|sed 's/[;, ]/ /g'`; do k="${kv%%=*}" v="`echo ${kv#*=}|nkf -Ww -mQ|sed -e 's/\"/\"\"/g'`" + ## err "GetCookie: $k=[$v]" case "$k" in user) _user="$v" ;; skey) _skey="$v" ;; @@ -1235,7 +1278,7 @@ # smail rcpts subj (file) # $SMAIL_TO <- Recipient value of To: header # $MAIL_FROM <- From: header value - from=`echo "${MAIL_FROM:-$admin}"|nkf -jM|tr -d '\n'` + from=`echo "${MAIL_FROM:-$admin}"|nkf -jM|tr : /|tr -d '\n'` rcpt=`echo $1|tr ' ' '\n'|sort -u|tr '\n' ' '` # uniq and strip newlines rcptheader=`echo $1|tr ' ' '\n'|sort -u|sed '2,$s/^/To: /g'` subj=`echo $2|nkf -jM|tr -d '\n'` @@ -1345,7 +1388,7 @@ newpswd=`genrandom` # newsalt=`genrandom 5` #encpswd=`mycrypt "$newpswd" "$newsalt"` encpswd=`echo $newpswd|mypwhash` - dbsetbyid user $user pswd "$encpswd" + dbsetbyid user $user pswd "$encpswd" && touch $userupdateflag # Avoid $user substitution with m4, because $url comes from user input. _m4 -D_PSWD_="$newpswd" -D_URL_="$url" -D_ADMIN_="$admin" \ $msgdir/mail-newaccount.m4 \ @@ -1420,9 +1463,6 @@ trap cleanup INT HUP EXIT TERM PIPE # trap cleanup INT HUP -err() { - echo "[`date +%F-%T%z`] $@" 1>&3 -} cgiinit() { tmpd=`tmpd=$tmpdir mktempd` @@ -1827,10 +1867,38 @@ # GF_ACTION="?grp+$1" edittable "$formdir/grp.def" "grp" "$rowid" #2015-0804 GF_STAGE="groupupdate" edittable "$formdir/grp.def" "grp" "$rowid" if [ -z "$STOPCLONEMSG" ]; then - html div 'class="fold"' <<-EOF - `cgi_checkbox clone yes id="clone"`<label - for="clone">同一メンバーで別グループを作成する</label> - <div> + ## Setup migration menu + height="10em" ## Ugly!! + if [ -n "$S4WORLDLIST" ]; then + v=`fgrep -v "value=\"$worldconf\"" $worldoptionfile` + err v=$v + if [ -n "$v" ]; then + migrate=$(cat<<-EOF + `cgi_radio grpaction migrate id="migrate"`<label + for="migrate">別Worldへ移住</label> + <div style="height: $height;"> + <form action="?migrategrp"> + <p>移住先:<select name="migrateto">$nl$v$nl</select></p> + <p>グループや掲示板のURLが変わります。 + 外部からリンクしている場合は飛べなくなります。 + すでにリンクされた掲示板を多数含む場合は既存グループを温存し、 + 「グループのクローン」で + メンバーを引き継いだ上でそのクローンを移住するのがお勧めです。</p> + <p><label>`cgi_checkbox emichk yes`確認</label></p> + `cgi_hidden stage migrategrp` + `cgi_hidden rowid $rowid` + `cgi_submit OK` + `cgi_reset Reset` + </form> + </div> + EOF + ) + fi + fi + html div 'class="foldtabs"' <<-EOF + `cgi_radio grpaction clone id="clone"`<label + for="clone">グループのクローン作成</label> + <div style="height: $height;"> <p>構成メンバーが同じ新規グループを作成します。</p> <table> <tr><td><a href="?groupclone+$rowid"> @@ -1843,9 +1911,55 @@ <p>ボタンを押すと即作成します。不要な場合はグループ編集で 削除してください。</p> </div> + $migrate + `cgi_radio grpaction close id="x"`<label for="x" accesskey="x">×</label> + <div style="height: $height; background: transparent;"></div> EOF fi } +migrategrp() { + rowid=`getpar rowid` + rowid=${rowid%%[!0-9]*} + grp=`getgroupbyid $rowid` + if ! isgrpowner "$user" "$grp"; then + echo "<p><a href=\"?grp+$rowid\">`echo "$grp"|htmlescape`</a></p>" + return + fi + if [ x`getpar emichk` != x"yes" ]; then + echo "移住確認未チェックなので中止します。" | html p + grp "$rowid" + return + fi + destconf=`getpar migrateto` + err destconf=$destconf + if [ ! -e $destconf ]; then + echo "移住先Worldが認識できないので中止します($destconf)。" | html p + grp "$rowid" + return + fi + if [ -n "$worldconf" ]; then + srcconf=$worldconf + else + srcconf=s4-config.sh + fi + _m4 -D_TITLE_="移住操作" -D_BODYCLASS_="" $layout/html.m4.html + echo "移住操作" | html h1 + echo '<pre>' + set -- "$srcconf" "$destconf" "$rowid" + err ./s4-migrate.sh "$srcconf" "$destconf" "$rowid" + . ./s4-migrate.sh # Dot(.) sourcing might not pass arguments + rc=$? + echo "</pre>" + if [ $rc -eq 0 ]; then + echo "World [$world] への移住完了。" | html p + echo "<p><a href=\"$dsturl?grp+$destrowid\">移住先</a></p>" + clean-orphaned + else + echo "移住失敗" | html p + echo "移動先に重複がないか確認して下さい。" | html p + fi + return +} mems() { _m4 -D_TITLE_="参加者一覧" -D_BODYCLASS_=listmember $layout/html.m4.html kwd=`getpar kwd` @@ -2067,8 +2181,14 @@ cond="gname in (select gname from grp_mem where user='$uname')" search_form_args="" if [ x"$user" = x"$uname" ]; then - usermenu="<a href=\"?userconf\" accesskey=\"e\" - title=\"Shortcut: E${nl}Edit Profile\">プロフィールの編集</a> / + if [ -z "$S4MASTERDB" ]; then + usermenu="<a href=\"?userconf\" accesskey=\"e\" + title=\"Shortcut: E${nl}Edit Profile\">プロフィールの編集</a> / " + elif [ -n "$S4MASTERURL" ]; then + usermenu="<a href=\"$S4MASTERURL\" accesskey=\"e\" + title=\"Shortcut: E${nl}Main Site\">Base World</a> / " + fi + usermenu="$usermenu <a href=\"?blog\" accesskey=\"n\" title=\"Shortcut: N${nl}New blog\">新規話題の作成</a>" # Display folders sql="select count(id) from article_m where id @@ -2091,7 +2211,8 @@ tf=$tmpd/title.$$ pf=$tmpd/profile.$$ bf=$tmpd/blogs.$$ sf=$tmpd/search.$$ search_form "$search_form_args" > $sf - printf "%s さん" "$gecos"|htmlescape > $tf + printf "%s さん%s" "$gecos" "${S4WORLDNAME:+@$S4WORLDNAME}" \ + | htmlescape > $tf { echo "<div class=\"noprofimg\">" viewtable $formdir/user.def user $1 echo "</div>" @@ -2390,7 +2511,7 @@ # Note that mtime is stored only in grp_s. ## err LE:sql.1="$sql" total=`query "with x as ($sql) select count(*) from x;"` - echo "${entity} 一覧" | html h2 + echo "${entity} 一覧" "${S4WORLDNAME:+@$S4WORLDNAME}" | html h2 echo '<div class="listentry">' # List-entry div # Show owner/member filter button METHOD=GET @@ -3654,6 +3775,26 @@ [ "$ddd" ] && err "----- `gdate +%FT%T.%3N` ------------666666" } +clean-orphaned() { + # This shoud be done by foreign_key rules, but some db lack them + query<<-EOF + -- Find blogs that have no parent + WITH orphanedblog AS ( + SELECT blog.id,val FROM blog JOIN blog_s bs + ON blog.id=bs.id AND key='owner' + WHERE val NOT IN (SELECT gname FROM grp) + AND val NOT IN (SELECT name FROM user) + ) -- Remove them + DELETE FROM blog WHERE id IN (SELECT id FROM orphanedblog); + + -- Find articles that have no parent blog + WITH orphanedarticle AS ( + SELECT id FROM article + WHERE blogid NOT IN (SELECT id FROM blog) + ) -- Remove them + DELETE FROM article WHERE id IN (SELECT id FROM orphanedarticle); + EOF +} par2table() ( # copy current parameters of par into destination table # $1=definition-file @@ -3708,6 +3849,9 @@ if [ x"$rm" = x"yes" ]; then if [ x"$rm$cfm" = x"yesyes" ]; then query "delete from $tbl where rowid=$rowid;" + if [ x"$tbl" = x"grp" -o x"$tbl" = x"blog" ]; then + clean-orphaned + fi return 4 else echo "消去確認のチェックがないので消さなかったの..." | html p @@ -3960,8 +4104,10 @@ .read $transaction RELEASE SAVEPOINT pa2table_insert; EOF - return $? - ##err donee + rc=$? + [ $rc -eq 0 -a x"$tbl" = x"user" ] && touch $userupdateflag + ## err "Table:$tbl update done " + return $rc ) genform() { # $1 = form definition file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/s4-migrate.sh Tue Jun 16 13:11:18 2020 +0900 @@ -0,0 +1,201 @@ +#!/bin/sh +# s4 - migration module +# (C)2020 by HIROSE, Yuuji + +srcdb=`unset DB; [ -f $1 ] && . ./$1 && echo ${DB:-db/cgi.sq3}` +dst=`unset DB; [ -f $2 ] && . ./$2 && echo "${DB:-db/cgi.sq3}|$URL"` +dstdb=${dst%\|*} +dsturl=${dst##*\|} +type htmlescape >/dev/null 2>&1 || . `dirname $1`/s4-funcs.sh +case "$2" in + s4-config.sh) world=Base ;; + *) world=${2##*-config-}; world=${world%.*} ;; +esac +htmlworld=`echo "$world"|htmlescape` + +err "--- Migration Started with \$1=$1 \$2=$2 at `date` ---" +err srcdb=$srcdb dstdb=$dstdb +err URL=$URL +err dstURL=$dsturl + +shift 2 + +query "ATTACH DATABASE \"$dstdb\" AS dst;" || abort "Cannot attach db #{dstdb}" + +failure=0 +for grid; do + grid=$((0 + $grid)) + gnamesql="(SELECT gname FROM main.grp WHERE rowid=$grid)" + grp=`query "SELECT gname FROM main.grp WHERE rowid=$grid;"` + htmlgrp=`echo "$grp"|htmlescape` + qgrp=`sqlquote "$grp"` + if [ -n "`query \"SELECT gname FROM dst.grp WHERE gname=$qgrp;\"`" ]; then + echo "[$htmlgrp]グループがWorld[$htmlworld]にあるので中止します。"|html p + failure=$((failure+1)) + continue + fi + echo "Copying $grid..." + query "BEGIN;" + query "REPLACE INTO dst.grp SELECT * FROM main.grp WHERE rowid=$grid;" + destrowid=`query "SELECT last_insert_rowid();"` + for tbl in grp_s grp_m grp_mem grp_mem_s grp_mem_m \ + grp_adm grp_adm_s grp_adm_m; do + query "REPLACE INTO dst.$tbl SELECT * FROM main.$tbl + WHERE gname=$gnamesql;" + done + blogs=`query "SELECT group_concat(\"'\"||id||\"'\", ',') + FROM main.blog_s WHERE key='owner' AND val=$gnamesql;"` + echo blogs=$blogs + for tbl in blog blog_s blog_m; do + query <<-EOF + REPLACE INTO dst.$tbl + SELECT * FROM main.$tbl + WHERE id IN ($blogs); + EOF + done + for tbl in article article_s article_m; do + query <<-EOF + REPLACE INTO dst.$tbl + SELECT * FROM main.$tbl + WHERE id IN (SELECT id FROM main.article WHERE blogid IN ($blogs)) + ORDER BY rowid; + EOF + done + ## Check the equality of two DBs + echo "grid=$grid grp=$grp qgrp=$qgrp" | htmlescape + # grp + d1=$(query <<-EOF + SELECT * FROM main.grp + NATURAL LEFT JOIN main.grp_s + NATURAL LEFT JOIN main.grp_m + WHERE gname=$qgrp + EXCEPT + SELECT * FROM dst.grp + NATURAL LEFT JOIN dst.grp_s + NATURAL LEFT JOIN dst.grp_m + WHERE gname=$qgrp; + EOF + ) + err DONE + err d1="$d1" + # blog + d2=$(query <<-EOF + SELECT * FROM main.blog + NATURAL LEFT JOIN main.blog_s + NATURAL LEFT JOIN main.blog_m + WHERE id IN (SELECT id FROM main.blog_s + WHERE key='owner' AND val=$qgrp) + EXCEPT + SELECT * FROM dst.blog + NATURAL LEFT JOIN dst.blog_s + NATURAL LEFT JOIN dst.blog_m + WHERE id IN (SELECT id FROM dst.blog_s + WHERE key='owner' AND val=$qgrp); + EOF + ) + err d2="$d2" + # article + d3=$(query <<-EOF + SELECT * FROM main.article + NATURAL LEFT JOIN main.article_s + NATURAL LEFT JOIN main.article_m + WHERE blogid IN ($blogs) + EXCEPT + SELECT * FROM dst.article + NATURAL LEFT JOIN dst.article_s + NATURAL LEFT JOIN dst.article_m + WHERE blogid IN ($blogs); + EOF + ) + err d3="$d3" + if [ -z "$d1$d2$d3" ]; then + echo "Copying done, rewriting article links..." + echo "Old URL: $URL" + echo "New URL: $dsturl" + query <<-EOF + UPDATE dst.article_s + SET val=replace(val, + '${URL}?grp+$grid', + '${dsturl}?grp+$destrowid') + WHERE key='text' AND val LIKE '%${URL}%'; + EOF + # Create blog-rowid conversion table + sedfile=$tmpd/arttrans.sed + # sedfile=tmp/arttrans.sed + query <<-EOF > $sedfile + WITH arttrans AS ( + SELECT s.rowid srcrid, d.rowid dstrid + FROM main.article s JOIN dst.article d ON s.id=d.id + WHERE s.id in (SELECT id + FROM article WHERE blogid IN ($blogs)) + ) SELECT printf("/^>/s/\#%s($|[^0-9])/\#%s\1/g", srcrid, dstrid) + FROM arttrans; + EOF + query <<-EOF > $tmpd/repl.art.rowid + SELECT rowid FROM dst.article_s + WHERE key='text' AND val GLOB '>*#[1-9]*' + AND id IN (SELECT id FROM article WHERE blogid IN ($blogs)); + EOF + sql=$tmpd/update.sql + for arid in `cat $tmpd/repl.art.rowid`; do + newval=`query "SELECT hex(val) FROM dst.article_s WHERE rowid=$arid;" \ + | unhexize | sed -Ef "$sedfile" | hexize` + echo "UPDATE dst.article_s SET val=X'$newval' WHERE rowid=$arid;" + done >$sql + # Rewrite blog-links in the group + # Create sed script + sedfile2=${sedfile}2 + query <<-EOF > $sedfile2 + WITH blogtrans AS ( + SELECT s.rowid srcrid, d.rowid dstrid + FROM main.blog s JOIN dst.blog d ON s.id=d.id + WHERE s.id IN ($blogs) + ) SELECT printf('s/(\?replyblog)\+%s($|[^0-9])/\1+%s\2/g', + srcrid, dstrid) + FROM blogtrans; + EOF + bloglinks=$tmpd/bloglinks.rowid + query <<-EOF > $bloglinks + SELECT rowid FROM dst.article_s + WHERE key='text' AND val LIKE '%?replyblog+%' + AND id IN (SELECT id FROM article WHERE blogid IN ($blogs)); + EOF + for arid in `cat $bloglinks`; do + newval=`query "SELECT hex(replace(val, '$URL', '$dsturl')) + FROM dst.article_s WHERE rowid=$arid;" \ + | unhexize | sed -Ef "$sedfile2" | hexize` + echo "UPDATE dst.article_s SET val=X'$newval' WHERE rowid=$arid;" >>$sql + done + if [ -z "`query \".read $sql\"`" ]; then + query <<-EOF + DELETE FROM main.article WHERE blogid IN ($blogs); + DELETE FROM main.blog WHERE id IN ($blogs); + DELETE FROM main.grp WHERE rowid=$grid; + EOF + s=`query "SELECT * FROM main.grp WHERE rowid=$grid;"` + if [ -z "$s" ]; then + echo "Success!!" + query "END;" + clean-orphaned + echo "Done." + else + echo Removal failed + echo "現行グループ消去ができませんでした。" + echo "書き込みの多いグループの場合は空いている時間帯に試して下さい。" + query "ROLLBACK;" + failure=-2 + fi + else + failure=-1 + echo "Replacing failed." + query "ROLLBACK;" + fi + else + failure=$((failure + 1)) + echo "Fail!" + query "ROLLBACK;" + fi +done + +err "Migration ended at `date` with failure=$failure" +return $failure
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/s4-newworld.sh Tue Jun 16 13:11:18 2020 +0900 @@ -0,0 +1,86 @@ +#!/bin/ksh +#!/bin/sh +# Create New Wolrd in s4 +# Arguments: +# $1 = World Display Name in UTF-8 +# $2 = World ShortName in alpha-numeric +# $3 = World Description in UTF-8 +. `dirname $0`/s4-config.sh +if ! type htmlescape >/dev/null 2>&1; then + . `dirname $0`/s4-funcs.sh ### > /dev/null 2>&1 + trap 'exit 1' INT QUIT +fi +dispname=$1 +shortname=$2 +desc=$3 + +readvar() { # $1=varname $2=PromptString + echo -n "${2:-$1=:} " + read $1 +} + +echo db=$db URL=$URL isCGI=$isCGI +if ! $isCGI; then + while true; do + dispname=`echo $dispname | tr -d ': \t\n"' | fold -w 28 | head -1` + test -n "$dispname" && break + readvar dispname "分かりやすいWorld名14字以内" + done + while true; do + shortname=`echo $shortname | tr -c -d '_0-9A-Za-z.-' | colrm 11` + test -n "$shortname" && break + readvar shortname "英数字のみ10字以内のWorldシンボル(URLの一部)" + done + while true; do + desc=`echo $desc | tr -d ': \t\n"'` + test -n "$desc" && break + readvar desc "概要(どのような基準でこのWorldを使うかなど)" + done +fi +echo "wl=$S4WORLDLIST" +echo "$dispname:$shortname:$desc" +newworld=$( + { echo "$S4WORLDLIST" | tr ' ' '\n' \ + | awk -F: "\$2 != \"$shortname\"{print}" + echo "$dispname:$shortname:$desc" + } | tr '\n' ' ' | tr -d '"' + ) +if [ -z "$newworld" ]; then + exit +fi + +# Create config +bgcolor=$( + od -An -tu1 -N3 < /dev/urandom \ + | { read r g b + r=$((192+r/4)); g=$((192+g/4)); b=$((192+b/4)) + printf "#%x%x%x" $r $g $b + }) +cat<<-EOF > s4-config-$shortname.sh + S4MASTERURL=\$URL + URL=`dirname ${URL}.`/s4-world-$shortname$cgiext + S4COLOR="$bgcolor" # Change this! + DB=$dbdir/$shortname.sq3 + SESSDB=$dbdir/sess.sq3 + S4MASTERDB=$db + S4CSS=$shortname.css + TMPDIR=$tmpdir/$shortname +EOF +# Create CSS +cat<<-EOF > $shortname.css + body {background: $bgcolor;} + body.moderated {background: $bgcolor; border: 3px gold solid;} +EOF +mkdir -m 1775 $tmpdir/$shortname +# Update s4-config.sh +cat<<-EOF | ed s4-config.sh + g/^S4WORLDLIST=/d + \$a + S4WORLDLIST="`echo $newworld`" + . + wq +EOF +DB=db/$shortname.sq3 `dirname $0`/s4-init.sh +(S4MASTERDB=$db; db=db/$shortname.sq3; . ./s4-world.sh) +(cd `dirname $0`; ln -s s4$cgiext s4-world-$shortname$cgiext) +echo $newworld added
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/s4-world.sh Tue Jun 16 13:11:18 2020 +0900 @@ -0,0 +1,138 @@ +#!/bin/sh + +# Setup variables for running time +if $isCGI; then + case "$S4WORLDLIST" in + *:*:*) + worldlistfile=cache/worldlist + worldgrpfile=cache/worldgrps + worldoptionfile=cache/worldoption + worldnamefile=cache/worldname + if [ ! -e $worldlistfile -o $worldlistfile -ot s4-config.sh \ + -o ! -e $worldoptionfile -o $worldoptionfile -ot s4-config.sh \ + -o s4-world.sh -nt $worldoptionfile ] + then + echo S4MASTERURL=$S4MASTERURL >> tmp/debug.out + cat <<-EOF > $worldlistfile + <div><table> + <tr><th>World List</th></tr> + <tr><td title="Base World$nl拠点となるWorldです">⇒ + <a href="${S4MASTERURL:-$URL}">Base</a></td></tr> + EOF + true > $worldoptionfile + for i in $S4WORLDLIST; do + echo $i | { + IFS=: read name short d + cgi="s4-world-$short$cgiext" + conf="s4-config-$short.sh" + cat<<-EOF >>$worldlistfile + <tr><td title="$d">⇒ <a href="$cgi">$name</a></td></tr> + EOF + cat<<-EOF >>$worldoptionfile + <option title="$d" value="$conf">$name</option> + EOF + echo "$name" > $worldnamefile.$short + } + done + if [ -s "$worldoptionfile" ]; then + echo "<option value=\"s4-config.sh\">Base</option>" >> $worldoptionfile + echo "</table>$nl</div>" >> $worldlistfile + sed 's/href="\([^>]*\)"/href="\1?grps"/' $worldlistfile \ + > $worldgrpfile + else + true > $worldoptionfile; true > $worldlistfile # Remove contents + rm -f ${worldnamefile}.* + fi + fi + if [ -s "$worldlistfile" ]; then + S4WORLDS="▼spaste(\`$worldlistfile')" + S4WORLDNAME=${S4WORLD:+`cat $worldnamefile.$S4WORLD`} + S4WORLDGRPS="▼spaste(\`$worldgrpfile')" + fi + ;; + esac +fi + +err "db=$db mas=$S4MASTERDB sessdb=$sessdb" +# If in parent world, no need to do rest of jobs +if [ -z "$S4MASTERDB" -o ! -s "$S4MASTERDB" ]; then + return +fi +# Confim child +if [ "$db" -ef "$S4MASTERDB" ]; then + return # Points to the same file +fi + +# Now Another world is ACTIVE +# sessdb=`dirname $S4MASTERDB`/sess.sq3 +## skey="skey-`basename $mydir`" +syncflag=${db%.*}.synctime +runflag=${db%.*}.run +userupdateflag=`dirname $S4MASTERDB`/`basename $userupdateflag` +test ! -e "$userupdateflag" && return +test "$syncflag" -nt "$userupdateflag" && return +if [ -s "$runflag" ]; then + limit=`cat $runflag|tr -c -d 0-9` + if [ -n "$limit" -a "$limit" -gt `date +%s` ]; then + err "World $S4WORLD account sync withholded by process $$" + return # Running sync by other process not leaching timeout + fi +fi +echo $((`date +%s` + 10)) > $runflag # Setting running flag by timeout 10s + +# for sub.sq3 +# +# main: user: 'taro', 'hanako', 'shige' +# sub: user: 'taro', 'hanako', 'shige' +# sub2: user_s: ('taro', 't'), ('hanako', 'h'), ('shige', 's') +# then update +# + +## sqlite3 -cmd '.timer 1' -cmd '.echo 1' $db <<EOF +err "`gdate +%S.%3N` Starting account synchronization[$$]" +## cat > tmp/sql <<EOF +num=$(sqlite3 -bail -cmd 'PRAGMA FOREIGN_KEYS=on' $db <<EOF +.timeout 1000 +ATTACH DATABASE "$S4MASTERDB" AS m; +CREATE TABLE IF NOT EXISTS user(name, primary key(name)); +BEGIN; +DElETE FROM main.user WHERE rowid NOT IN (SELECT rowid FROM m.user); +INSERT INTO main.user(rowid, name) + SELECT rowid, name FROM m.user + WHERE m.user.rowid NOT IN (SELECT rowid FROM user); +UPDATE user SET name = (SELECT name FROM m.user WHERE main.user.rowid=m.user.rowid); +DELETE FROM main.user_s WHERE rowid NOT IN (SELECT rowid FROM m.user_s); +REPLACE INTO main.user_s(rowid, name, key, type, val, bin) + SELECT rowid,* FROM m.user_s; +DELETE FROM main.user_m WHERE rowid NOT IN (SELECT rowid FROM m.user_m); +REPLACE INTO main.user_m(rowid, name, key, type, val, bin) + SELECT rowid,* FROM m.user_m + WHERE key NOT LIKE '%cache%'; +END; + +/* Compare user tables */ +WITH master AS ( + SELECT p.rowid,* FROM m.user p + NATURAL LEFT JOIN m.user_s + NATURAL LEFT JOIN m.user_m +), thisworld AS ( + SELECT p.rowid,* FROM user p + NATURAL LEFT JOIN user_s + NATURAL LEFT JOIN user_m +), m_a AS ( + SELECT * FROM master EXCEPT SELECT * FROM thisworld +), a_m AS ( + SELECT * FROM thisworld EXCEPT SELECT * FROM master +) SELECT (SELECT count(*) FROM m_a) + (SELECT count(*) FROM a_m); +DETACH DATABASE m; +EOF +) +### num=$(sqlite3 -bail -cmd 'PRAGMA FOREIGN_KEYS=on' $db < tmp/sql ) +if [ -n "$num" -a $num -eq 0 ]; then + err "`gdate +%S.%3N` Account synchronization[$$] done in difference $num" + echo "`date '+%F %T'`: Sync done by process $$" >> $syncflag +else + err "Account synch[$$] failed or bailed with num=[$num]" +fi +test -e "$runflag" && rm -f "$runflag" +return $num
--- a/scripts/s4-sns.case Tue Jun 16 13:10:57 2020 +0900 +++ b/scripts/s4-sns.case Tue Jun 16 13:11:18 2020 +0900 @@ -19,7 +19,7 @@ showattc "$@" exit 0 # Do not output further chunks ;; - invite|groupman|userconf|groupconf|mems|grps|grp|groupupdate|groupclone|grpaction|joingrpadmit|commission|editheading|editart|showattc|send2mem|mvart) + invite|groupman|userconf|groupconf|mems|grps|grp|groupupdate|groupclone|grpaction|joingrpadmit|commission|editheading|editart|showattc|send2mem|mvart|migrategrp) contenttype; echo [ -n "$1" ] && shift $stage "$@"