فهرست منبع

Merge branch 'laravel' of https://github.com/iapt-platform/mint into laravel

bhikkhu-kosalla-china 4 سال پیش
والد
کامیت
0a13293267
81فایلهای تغییر یافته به همراه1581 افزوده شده و 114 حذف شده
  1. 1 0
      .gitignore
  2. 6 2
      app/Http/Controllers/DhammaTermController.php
  3. 186 0
      app/Http/Controllers/SentenceController.php
  4. 11 0
      app/Models/CustomBook.php
  5. 11 0
      app/Models/CustomBookId.php
  6. 11 0
      app/Models/CustomBookSentence.php
  7. 5 1
      change-logs.md
  8. 0 0
      dashboard/.editorconfig
  9. 0 0
      dashboard/.gitignore
  10. 0 0
      dashboard/.prettierignore
  11. 0 0
      dashboard/.prettierrc
  12. 0 0
      dashboard/.umirc.ts
  13. 0 0
      dashboard/README.md
  14. 0 0
      dashboard/mock/.gitkeep
  15. 0 0
      dashboard/package.json
  16. 0 0
      dashboard/src/components/demo.tsx
  17. 0 0
      dashboard/src/pages/404.tsx
  18. 10 0
      dashboard/src/pages/[username]/index.tsx
  19. 0 0
      dashboard/src/pages/demo/course/[id]/edit.tsx
  20. 0 0
      dashboard/src/pages/demo/course/[id]/show.tsx
  21. 0 0
      dashboard/src/pages/demo/course/index.tsx
  22. 0 0
      dashboard/src/pages/demo/day-1.tsx
  23. 0 0
      dashboard/src/pages/demo/day-2.tsx
  24. 0 0
      dashboard/src/pages/demo/day-3.tsx
  25. 0 0
      dashboard/src/pages/demo/day-4.tsx
  26. 0 0
      dashboard/src/pages/demo/day-5.json
  27. 0 0
      dashboard/src/pages/demo/day-5.tsx
  28. 0 0
      dashboard/src/pages/demo/day-6.tsx
  29. 0 0
      dashboard/src/pages/demo/index.tsx
  30. 0 0
      dashboard/src/pages/demo/items/[id]/edit.tsx
  31. 0 0
      dashboard/src/pages/demo/items/[id]/show.tsx
  32. 0 0
      dashboard/src/pages/demo/items/index.tsx
  33. 0 0
      dashboard/src/pages/index.tsx
  34. 0 0
      dashboard/tsconfig.json
  35. 0 0
      dashboard/typings.d.ts
  36. 39 0
      database/migrations/2022_02_11_090826_create_custom_books_table.php
  37. 49 0
      database/migrations/2022_02_13_024642_create_custom_book_sentences_table.php
  38. 34 0
      database/migrations/2022_02_14_094254_create_custom_book_ids_table.php
  39. 13 1
      public/app/article/article.js
  40. 3 3
      public/app/article/function.php
  41. 15 0
      public/app/article/print.css
  42. 12 0
      public/app/article/style.css
  43. 1 1
      public/app/article/templiates/glossary.tpl
  44. 15 7
      public/app/config.table.php
  45. 6 4
      public/app/db/channel.php
  46. 36 9
      public/app/db/custom_book.php
  47. 2 2
      public/app/db/table.php
  48. 12 3
      public/app/db/user.php
  49. 4 4
      public/app/hostsetting/function.php
  50. 53 13
      public/app/palicanon/palicanon.js
  51. 4 0
      public/app/public/js/comm.js
  52. 1 1
      public/app/public/lang/default.json
  53. 1 1
      public/app/public/lang/en.json
  54. 22 22
      public/app/public/lang/my.json
  55. 1 1
      public/app/public/lang/si.json
  56. 1 1
      public/app/public/lang/zh-cn.json
  57. 1 1
      public/app/public/lang/zh-tw.json
  58. 112 0
      public/app/search/sentence.js
  59. 244 0
      public/app/search/sentence.php
  60. 2 2
      public/app/term/note.js
  61. 22 5
      public/app/term/term.css
  62. 5 7
      public/app/term/term.js
  63. 1 1
      public/app/term/term_edit_dlg.js
  64. 2 2
      public/app/ucenter/index.php
  65. 11 5
      public/app/ucenter/invite.php
  66. 4 0
      public/app/ucenter/invite_letter_cn.html
  67. 6 0
      public/app/ucenter/invite_letter_en.html
  68. 2 2
      public/app/ucenter/reset.php
  69. 13 0
      public/app/ucenter/reset_pwd_letter_cn.html
  70. 13 0
      public/app/ucenter/reset_pwd_lettet_en.html
  71. 13 6
      public/app/ucenter/sign.js
  72. 7 7
      public/app/ucenter/sign_up.php
  73. 7 0
      public/app/ucenter/testhost.php
  74. 17 0
      public/db/sqlite/custom_book/book_sn.sql
  75. 40 0
      public/db/sqlite/custom_book/up.sql
  76. 28 0
      public/documents/tables.md
  77. 2 0
      routes/api.php
  78. 9 0
      v1/scripts/install5.sh
  79. 175 0
      v1/scripts/migrations/20220211155400_custom_book_copy.php
  80. 185 0
      v1/scripts/migrations/20220213092400_custom_book_sentence_copy.php
  81. 95 0
      v1/scripts/migrations/20220214163000_custom_book_id_copy.php

+ 1 - 0
.gitignore

@@ -18,3 +18,4 @@ yarn-error.log
 /yarn.lock
 /composer.lock
 *.swp
+*.log

+ 6 - 2
app/Http/Controllers/DhammaTermController.php

@@ -116,6 +116,10 @@ class DhammaTermController extends Controller
             return $this->error($validator);
         } else {
             #查询重复的
+            /*
+            重复判定:
+            一个channel下面word+tag+language 唯一
+            */
             $table = DhammaTerm::where('owner', $_COOKIE["user_uid"])
                     ->where('word',$request->get("word"))
                     ->where('tag',$request->get("tag"));
@@ -130,7 +134,7 @@ class DhammaTermController extends Controller
             if($isDoesntExist){
                 #不存在插入数据
                 $term = new DhammaTerm;
-                $term->id=$snowflake->id();
+                $term->id=app('snowflake')->id();
                 $term->guid=Str::uuid();
                 $term->word=$request->get("word");
                 $term->meaning=$request->get("meaning");
@@ -143,7 +147,7 @@ class DhammaTermController extends Controller
             // store
             /*
             $data = $request->all();
-            $data['id'] = $snowflake->id();
+            $data['id'] = app('snowflake')->id();
             $data['guid'] = Str::uuid();
             DhammaTerm::create($data);
             */

+ 186 - 0
app/Http/Controllers/SentenceController.php

@@ -0,0 +1,186 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Models\Sentence;
+use Illuminate\Http\Request;
+
+class SentenceController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function index(Request $request)
+    {
+        $result=false;
+		$indexCol = ['id','book_id','paragraph','word_start','word_end','content','channel_uid','updated_at'];
+
+		switch ($request->get('view')) {
+            case 'fulltext':
+                if(isset($_COOKIE['user_uid'])){
+                    $userUid = $_COOKIE['user_uid'];
+                }
+                $key = $request->get('key');
+                if(empty($key)){
+			        return $this->error("没有关键词");
+                }
+                $table = Sentence::select($indexCol)
+								  ->where('content','like', '%'.$key.'%')
+                                  ->where('editor_uid',$userUid);
+				if(!empty($request->get('order')) && !empty($request->get('dir'))){
+					$table->orderBy($request->get('order'),$request->get('dir'));
+				}else{
+					$table->orderBy('updated_at','desc');
+				}
+				$count = $table->count();
+				if(!empty($request->get('limit'))){
+					$offset = 0;
+					if(!empty($request->get("offset"))){
+						$offset = $request->get("offset");
+					}
+					$table->skip($offset)->take($request->get('limit'));
+				}
+				$result = $table->get();
+                break;
+			case 'user':
+				# code...
+                $userUid = $_COOKIE['user_uid'];
+                $search = $request->get('search');
+				$table = Sentence::select($indexCol)
+									->where('owner', $userUid);
+				if(!empty($search)){
+					$table->where('word', 'like', $search."%")
+                          ->orWhere('word_en', 'like', $search."%")
+                          ->orWhere('meaning', 'like', "%".$search."%");
+				}
+				if(!empty($request->get('order')) && !empty($request->get('dir'))){
+					$table->orderBy($request->get('order'),$request->get('dir'));
+				}else{
+					$table->orderBy('updated_at','desc');
+				}
+				$count = $table->count();
+				if(!empty($request->get('limit'))){
+					$offset = 0;
+					if(!empty($request->get("offset"))){
+						$offset = $request->get("offset");
+					}
+					$table->skip($offset)->take($request->get('limit'));
+				}
+				$result = $table->get();
+				break;
+			case 'word':
+				$result = Sentence::select($indexCol)
+									->where('word', $request->get("word"))
+									->orderBy('created_at','desc')
+									->get();
+				break;
+            case 'hot-meaning':
+                $key='term/hot_meaning';
+                $value = Cache::get($key, function()use($request) {
+                    $hotMeaning=[];
+                    $words = Sentence::select('word')
+                                ->where('language',$request->get("language"))
+                                ->groupby('word')
+                                ->get();
+                    
+                    foreach ($words as $key => $word) {
+                        # code...
+                        $result = Sentence::select(DB::raw('count(*) as word_count, meaning'))
+                                ->where('language',$request->get("language"))
+                                ->where('word',$word['word'])
+                                ->groupby('meaning')
+                                ->orderby('word_count','desc')
+                                ->first();
+                        if($result){
+                            $hotMeaning[]=[
+                                'word'=>$word['word'],
+                                'meaning'=>$result['meaning'],
+                                'language'=>$request->get("language"),
+                                'owner'=>'',
+                            ];
+                        }
+                    }
+                    Cache::put($key, $hotMeaning, 3600);
+                    return $hotMeaning;
+                });
+                return $this->ok(["rows"=>$value,"count"=>count($value)]);
+                break;
+			default:
+				# code...
+				break;
+		}
+		if($result){
+			return $this->ok(["rows"=>$result,"count"=>$count]);
+		}else{
+			return $this->error("没有查询到数据");
+		}
+    }
+
+    /**
+     * Show the form for creating a new resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function create()
+    {
+        //
+    }
+
+    /**
+     * Store a newly created resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return \Illuminate\Http\Response
+     */
+    public function store(Request $request)
+    {
+        //
+    }
+
+    /**
+     * Display the specified resource.
+     *
+     * @param  \App\Models\Sentence  $sentence
+     * @return \Illuminate\Http\Response
+     */
+    public function show(Sentence $sentence)
+    {
+        //
+    }
+
+    /**
+     * Show the form for editing the specified resource.
+     *
+     * @param  \App\Models\Sentence  $sentence
+     * @return \Illuminate\Http\Response
+     */
+    public function edit(Sentence $sentence)
+    {
+        //
+    }
+
+    /**
+     * Update the specified resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \App\Models\Sentence  $sentence
+     * @return \Illuminate\Http\Response
+     */
+    public function update(Request $request, Sentence $sentence)
+    {
+        //
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     *
+     * @param  \App\Models\Sentence  $sentence
+     * @return \Illuminate\Http\Response
+     */
+    public function destroy(Sentence $sentence)
+    {
+        //
+    }
+}

+ 11 - 0
app/Models/CustomBook.php

@@ -0,0 +1,11 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class CustomBook extends Model
+{
+    use HasFactory;
+}

+ 11 - 0
app/Models/CustomBookId.php

@@ -0,0 +1,11 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class CustomBookId extends Model
+{
+    use HasFactory;
+}

+ 11 - 0
app/Models/CustomBookSentence.php

@@ -0,0 +1,11 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class CustomBookSentence extends Model
+{
+    use HasFactory;
+}

+ 5 - 1
change-logs.md

@@ -56,4 +56,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ## [1.0.7] - 2022-02-01
 
 - add REDIS_NAMESPACE to .env.example
-- add redis namespace to config.sample.php
+- add redis namespace to config.sample.php
+
+## [1.0.8] - 2022-02-24
+
+- 优化打印显示效果 去掉channel列表 逐句首字母大写

+ 0 - 0
public/dashboard/.editorconfig → dashboard/.editorconfig


+ 0 - 0
public/dashboard/.gitignore → dashboard/.gitignore


+ 0 - 0
public/dashboard/.prettierignore → dashboard/.prettierignore


+ 0 - 0
public/dashboard/.prettierrc → dashboard/.prettierrc


+ 0 - 0
public/dashboard/.umirc.ts → dashboard/.umirc.ts


+ 0 - 0
public/dashboard/README.md → dashboard/README.md


+ 0 - 0
public/dashboard/mock/.gitkeep → dashboard/mock/.gitkeep


+ 0 - 0
public/dashboard/package.json → dashboard/package.json


+ 0 - 0
public/dashboard/src/components/demo.tsx → dashboard/src/components/demo.tsx


+ 0 - 0
public/dashboard/src/pages/404.tsx → dashboard/src/pages/404.tsx


+ 10 - 0
dashboard/src/pages/[username]/index.tsx

@@ -0,0 +1,10 @@
+import {Link} from 'umi';
+
+export default ({match}) => {
+  return (
+    <div>
+      <h1>welcome to  {match.params.username} zone</h1>
+      <Link to="/demo">Go home</Link>
+    </div>
+  )
+}

+ 0 - 0
public/dashboard/src/pages/demo/course/[id]/edit.tsx → dashboard/src/pages/demo/course/[id]/edit.tsx


+ 0 - 0
public/dashboard/src/pages/demo/course/[id]/show.tsx → dashboard/src/pages/demo/course/[id]/show.tsx


+ 0 - 0
public/dashboard/src/pages/demo/course/index.tsx → dashboard/src/pages/demo/course/index.tsx


+ 0 - 0
public/dashboard/src/pages/demo/day-1.tsx → dashboard/src/pages/demo/day-1.tsx


+ 0 - 0
public/dashboard/src/pages/demo/day-2.tsx → dashboard/src/pages/demo/day-2.tsx


+ 0 - 0
public/dashboard/src/pages/demo/day-3.tsx → dashboard/src/pages/demo/day-3.tsx


+ 0 - 0
public/dashboard/src/pages/demo/day-4.tsx → dashboard/src/pages/demo/day-4.tsx


+ 0 - 0
public/dashboard/src/pages/demo/day-5.json → dashboard/src/pages/demo/day-5.json


+ 0 - 0
public/dashboard/src/pages/demo/day-5.tsx → dashboard/src/pages/demo/day-5.tsx


+ 0 - 0
public/dashboard/src/pages/demo/day-6.tsx → dashboard/src/pages/demo/day-6.tsx


+ 0 - 0
public/dashboard/src/pages/demo/index.tsx → dashboard/src/pages/demo/index.tsx


+ 0 - 0
public/dashboard/src/pages/demo/items/[id]/edit.tsx → dashboard/src/pages/demo/items/[id]/edit.tsx


+ 0 - 0
public/dashboard/src/pages/demo/items/[id]/show.tsx → dashboard/src/pages/demo/items/[id]/show.tsx


+ 0 - 0
public/dashboard/src/pages/demo/items/index.tsx → dashboard/src/pages/demo/items/index.tsx


+ 0 - 0
public/dashboard/src/pages/index.tsx → dashboard/src/pages/index.tsx


+ 0 - 0
public/dashboard/tsconfig.json → dashboard/tsconfig.json


+ 0 - 0
public/dashboard/typings.d.ts → dashboard/typings.d.ts


+ 39 - 0
database/migrations/2022_02_11_090826_create_custom_books_table.php

@@ -0,0 +1,39 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateCustomBooksTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('custom_books', function (Blueprint $table) {
+            $table->bigInteger('id')->primary();
+            $table->integer('book_id')->uniqid();
+            $table->string('title',512)->index();
+            $table->string('owner',36)->index();
+            $table->bigInteger('editor_id')->index();
+            $table->string('lang',16);
+            $table->integer('status');
+
+            $table->timestamp('created_at')->useCurrent()->index();
+			$table->timestamp('updated_at')->useCurrent()->useCurrentOnUpdate()->index();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('custom_books');
+    }
+}

+ 49 - 0
database/migrations/2022_02_13_024642_create_custom_book_sentences_table.php

@@ -0,0 +1,49 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateCustomBookSentencesTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('custom_book_sentences', function (Blueprint $table) {
+            $table->bigInteger('id')->primary();
+
+            $table->integer('book')->index();
+            $table->integer('paragraph');
+            $table->integer('word_start');
+            $table->integer('word_end');
+            $table->text('content');
+            $table->enum('content_type',['markdown','text','html'])->default('markdown');
+            $table->integer('length');
+            $table->string('owner',36)->index();
+            $table->string('lang',16);
+            $table->integer('status')->default(10);
+
+            $table->bigInteger('create_time')->index();
+            $table->bigInteger('modify_time')->index();
+
+            $table->timestamp('created_at')->useCurrent()->index();
+			$table->timestamp('updated_at')->useCurrent()->useCurrentOnUpdate()->index();
+
+            $table->index(['book','paragraph','word_start','word_end']);
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('custom_book_sentences');
+    }
+}

+ 34 - 0
database/migrations/2022_02_14_094254_create_custom_book_ids_table.php

@@ -0,0 +1,34 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateCustomBookIdsTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('custom_book_ids', function (Blueprint $table) {
+            $table->id();
+            $table->string('key',32)->default('max_book_number');
+            $table->integer('value');
+            $table->timestamp('created_at')->useCurrent()->index();
+			$table->timestamp('updated_at')->useCurrent()->useCurrentOnUpdate()->index();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('custom_book_ids');
+    }
+}

+ 13 - 1
public/app/article/article.js

@@ -514,7 +514,19 @@ function render_toc(){
 					nextChapter = it.next_chapter;
 					prevChapter = it.prev_chapter;
 				}
-				arrToc.push({article:it.paragraph,title:it.toc,level:it.level});
+                let strTitle;
+                switch (getCookie('language')) {
+                    case 'my':
+                        strTitle = roman_to_my(it.toc);
+                        break;
+                    case 'si':
+                        strTitle = roman_to_si(it.toc);
+                        break;
+                    default:
+                        strTitle = it.toc;
+                        break;
+                }
+				arrToc.push({article:it.paragraph,title:strTitle,title_roman:it.toc,level:it.level});
 			}
 			$("#toc_content").fancytree({
 				autoScroll: true,

+ 3 - 3
public/app/article/function.php

@@ -119,9 +119,9 @@ class Article extends Table
 			}
 		}
 		#查询共享权限,如果共享权限更大,覆盖上面的的
-		$sharePower = share_get_res_power($_COOKIE["user_uid"],$id);
+		$sharePower = share_get_res_power($userId,$id);
 		if($collectionId!=""){
-			$sharePowerCollection = share_get_res_power($_COOKIE["user_uid"],$collectionId);
+			$sharePowerCollection = share_get_res_power($userId,$collectionId);
 		}
 		else{
 			$sharePowerCollection =0;
@@ -133,7 +133,7 @@ class Article extends Table
 			$iPower=$sharePowerCollection;
 		}
 		if($this->redis!==false){
-			$this->redis->hSet("power://article/".$id,$_COOKIE["user_uid"],$iPower);
+			$this->redis->hSet("power://article/".$id,$userId,$iPower);
 		}
 		return $iPower;
 	}

+ 15 - 0
public/app/article/print.css

@@ -39,4 +39,19 @@ note > .tran {
 
 .main_view {
 	margin-left: auto;
+}
+
+note {
+    border: unset;
+}
+
+.contents_div {
+    width: auto;
+}
+
+#right_pannal {
+    display: none;
+}
+.note_foot{
+    display:none;
 }

+ 12 - 0
public/app/article/style.css

@@ -317,4 +317,16 @@ img {
 #contents_nav{
 	display: flex;
     justify-content: space-between;
+}
+td, th {
+    border: unset;
+    vertical-align: baseline;
+    padding:6px;
+}
+table {
+  box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
+  border-collapse: collapse;
+}
+tr {
+  border-bottom: 1px solid gray;
 }

+ 1 - 1
public/app/article/templiates/glossary.tpl

@@ -1,7 +1,7 @@
 <h2>Glossary</h2>
 {{#glossary.word}}
 <div>
-<b>{{pali}}</b>:{{meaning}}
+<b>{{pali}}</b>:{{meaning}}; {{meaning2}}
 </div>
 {{/glossary.word}}
 

+ 15 - 7
public/app/config.table.php

@@ -333,8 +333,8 @@ define("_SQLITE_TABLE_CUSTOM_BOOK_", "custom_book");
 define("_SQLITE_TABLE_CUSTOM_BOOK_SENT_", "custom_book_sentence");
 
 define("_PG_DB_USER_CUSTOM_BOOK_", _PDO_DB_DSN_);
-define("_PG_TABLE_CUSTOM_BOOK_", "custom_book");
-define("_PG_TABLE_CUSTOM_BOOK_SENT_", "custom_book_sentence");
+define("_PG_TABLE_CUSTOM_BOOK_", "custom_books");
+define("_PG_TABLE_CUSTOM_BOOK_SENT_", "custom_book_sentences");
 
 # 逐词译和译文编辑消息 无需迁移数据
 define("_SQLITE_DB_MESSAGE_", "sqlite:" . __DIR__ . "/../tmp/user/message.db");
@@ -403,8 +403,13 @@ define("_FILE_DB_USER_RBAC_",  __DIR__ . "/../tmp/user/rbac.db3");
 define("_TABLE_FTS_", "fts_texts");
 
 //很少使用
-# 网站设置
-define("_FILE_DB_HOSTSETTING_", "sqlite:" . __DIR__ . "/../tmp/user/hostsetting.db3");
+
+
+define("_SQLITE_DB_HOSTSETTING_", "sqlite:" . __DIR__ . "/../tmp/user/hostsetting.db3");
+define("_SQLITE_TABLE_HOSTSETTING_", "setting");
+
+define("_PG_DB_CUSTOM_BOOK_ID_", _PDO_DB_DSN_);
+define("_PG_TABLE_CUSTOM_BOOK_ID_", "custom_book_ids");
 
 #巴缅字典
 //define("_DICT_DB_PM_", _DB_ENGIN_.":host="._DB_HOST_.";port="._DB_PORT_.";dbname="._DB_NAME_.";user="._DB_USERNAME_.";password="._DB_PASSWORD_.";");
@@ -660,9 +665,9 @@ define("_TABLE_FILEINDEX_", _PG_TABLE_FILEINDEX_);
 
 
 # 用户自定义书
-define("_FILE_DB_USER_CUSTOM_BOOK_", _SQLITE_DB_USER_CUSTOM_BOOK_);
-define("_TABLE_CUSTOM_BOOK_", _SQLITE_TABLE_CUSTOM_BOOK_);
-define("_TABLE_CUSTOM_BOOK_SENT_", _SQLITE_TABLE_CUSTOM_BOOK_SENT_);
+define("_FILE_DB_USER_CUSTOM_BOOK_", _PG_DB_USER_CUSTOM_BOOK_);
+define("_TABLE_CUSTOM_BOOK_", _PG_TABLE_CUSTOM_BOOK_);
+define("_TABLE_CUSTOM_BOOK_SENT_", _PG_TABLE_CUSTOM_BOOK_SENT_);
 
 #点赞
 define("_FILE_DB_LIKE_", _SQLITE_DB_LIKE_);
@@ -687,4 +692,7 @@ define("_TABLE_MESSAGE_", _SQLITE_TABLE_MESSAGE_);
 define("_FILE_DB_USER_DICT_", _SQLITE_DB_USER_DICT_);
 define("_TABLE_USER_DICT_", _SQLITE_TABLE_USER_DICT_);
 
+# 网站设置
+define("_FILE_DB_HOSTSETTING_", _PG_DB_CUSTOM_BOOK_ID_);
+define("_TABLE_HOSTSETTING_", _PG_TABLE_CUSTOM_BOOK_ID_);
 ?>

+ 6 - 4
public/app/db/channel.php

@@ -37,15 +37,17 @@ class Channel extends Table
 			}
 			$json = file_get_contents('php://input');
 			$data = json_decode($json,true);
-			$data["owner"] = $_COOKIE["userid"];			
+			$data["owner_uid"] = $_COOKIE["user_uid"];
+			$data["editor_id"] = $_COOKIE["user_id"];
 		}
 
-		$isExist = $this->medoo->has($this->table,["owner"=>$data["owner"],"name"=>$data["name"]]);
+		$isExist = $this->medoo->has($this->table,["owner_uid"=>$data["owner_uid"],"name"=>$data["name"]]);
 		if(!$isExist){
-			$data["id"] = UUID::v4();
+			$data["id"] = $this->SnowFlake->id();
+			$data["uid"] = UUID::v4();
 			$data["create_time"] = mTime();
 			$data["modify_time"] = mTime();
-			$result =  $this->_create($data,["id","owner","lang","name","summary","status","create_time","modify_time"]);
+			$result =  $this->_create($data,["id","uid","owner_uid",'editor_id',"lang","name","summary","status","create_time","modify_time"]);
 		}
 		else{
 			$this->result["ok"]=false;

+ 36 - 9
public/app/db/custom_book.php

@@ -3,10 +3,11 @@ require_once "../config.php";
 require_once "../db/table.php";
 require_once '../hostsetting/function.php';
 
+
 class CustomBook extends Table
 {
     function __construct($redis=false) {
-		parent::__construct(_FILE_DB_USER_CUSTOM_BOOK_, "custom_book", "", "",$redis);
+		parent::__construct(_FILE_DB_USER_CUSTOM_BOOK_, _TABLE_CUSTOM_BOOK_, "", "",$redis);
     }
 
 	public function new($title,$data,$lang)
@@ -34,9 +35,18 @@ class CustomBook extends Table
 				return $respond;
 			}
 
-			$query="INSERT INTO {$this->table} ('book_id','title','owner','lang','status','modify_time','create_time') VALUES (?, ?, ?, ?, ?, ?, ?)";
-
-			$stmt = $this->execute($query,array($currBook,$title,$_COOKIE["userid"],$lang,10,mTime(),mTime()));
+			$query="INSERT INTO {$this->table} 
+            (
+                id,
+                book_id,
+                title,
+                owner,
+                editor_id,
+                lang,
+                status
+                ) VALUES (?,?, ?, ?, ?, ? , ?)";
+
+			$stmt = $this->execute($query,array($this->SnowFlake->id(),$currBook,$title,$_COOKIE["user_uid"],$_COOKIE["user_id"],$lang,10));
 			if($stmt){
 				$CSent = new CustomBookSentence($this->redis);
 				$respond = $CSent->insert($currBook,$sent,$lang);
@@ -53,11 +63,11 @@ class CustomBook extends Table
 class CustomBookSentence extends Table
 {
     function __construct($redis=false) {
-		parent::__construct(_FILE_DB_USER_CUSTOM_BOOK_, "custom_book_sentence", "", "",$redis);
+		parent::__construct(_FILE_DB_USER_CUSTOM_BOOK_, _TABLE_CUSTOM_BOOK_SENT_, "", "",$redis);
     }
 
 	public function getAll($book,$para,$start,$end){
-		$query="SELECT text,length,lang,modify_time,create_time,owner FROM custom_book_sentence WHERE book = ? AND paragraph = ? AND begin=? AND end = ?";
+		$query="SELECT content as text,length,lang,modify_time,create_time,owner FROM {$this->table} WHERE book = ? AND paragraph = ? AND word_start = ? AND word_end = ?";
 		$result = $this->fetch($query,array($book,$para,$start,$end));
 		if($result){
 			return $result;
@@ -76,7 +86,21 @@ class CustomBookSentence extends Table
 		$respond['content']="";
 		# 开始一个事务,关闭自动提交 
 		$this->dbh->beginTransaction();
-		$query="INSERT INTO custom_book_sentence ('book','paragraph','begin','end','length','text','lang','owner','status','create_time','modify_time') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+		$query="INSERT INTO {$this->table} 
+        (
+            id,
+            book,
+            paragraph,
+            word_start,
+            word_end,
+            length,
+            content,
+            lang,
+            owner,
+            status,
+            create_time,
+            modify_time
+        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
 		
 		$sth = $this->dbh->prepare($query);
 		
@@ -112,6 +136,7 @@ class CustomBookSentence extends Table
 					$newText .='{{'."{$book}-{$para}-{$sentNum}-{$sentNum}"."}}\n";
 					$sth->execute(
 							array(
+                                $this->SnowFlake->id(),
 								$book,
 								$para,
 								$sentNum,
@@ -146,6 +171,7 @@ class CustomBookSentence extends Table
 				$newText .='{{'."{$book}-{$para}-{$sentNum}-{$sentNum}"."}}\n";
 				$sth->execute(
 						array(
+                            $this->SnowFlake->id(),
 							$book,
 							$para,
 							$sentNum,
@@ -169,6 +195,7 @@ class CustomBookSentence extends Table
 			$newText .='{{'."{$book}-{$para}-{$sentNum}-{$sentNum}"."}}\n";
 			$sth->execute(
 					array(
+                        $this->SnowFlake->id(),
 						$book,
 						$para,
 						$sentNum,
@@ -204,10 +231,10 @@ class CustomBookSentence extends Table
 	}
 
 	public function getText($book,$para,$start,$end){
-		$query="SELECT text FROM custom_book_sentence WHERE book = ? AND paragraph = ? AND begin=? AND end = ?";
+		$query="SELECT content  FROM {$this->table} WHERE book = ? AND paragraph = ? AND word_start=? AND word_end = ?";
 		$result = $this->fetch($query,array($book,$para,$start,$end));
 		if($result){
-			return $result["text"];
+			return $result["content"];
 		}
 		else{
 			return "unkow";

+ 2 - 2
public/app/db/table.php

@@ -23,7 +23,7 @@ class Table
     protected $SnowFlake;
     function __construct($db,$table,$user="",$password="",$redis=false) {
         $this->dbh = new PDO($db, _DB_USERNAME_, _DB_PASSWORD_,array(PDO::ATTR_PERSISTENT=>true));
-        $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
+        $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 		$database = new Medoo([
 			// Initialized and connected PDO object.
 			'pdo' => $this->dbh,
@@ -60,7 +60,7 @@ class Table
 			$updateDate
 		);
 
-		$updateDate["id"] = $this->medoo->id();
+		//$updateDate["id"] = $newData;
 		$this->result["data"] = $updateDate;
 		return $this->result;
 	}

+ 12 - 3
public/app/db/user.php

@@ -129,15 +129,24 @@ class User extends Table
 				$data["setting"] = "{}";
 				$result = $this->_create($data,["userid","username","email","password","nickname","setting","create_time","modify_time"]);
 				if($result["ok"]){
+                    $newUserId = $this->medoo->get(
+                        $this->table,
+                        'id',
+                        ["userid"=>$data['userid']]
+                    );
 					$channel = new Channel($this->redis);
-					$newChannel1 = $channel->create(["owner"=>$data["userid"],
+					$newChannel1 = $channel->create([
+                                                    "owner_uid"=>$data["userid"],
+                                                    "editor_id"=>$newUserId,
 													"lang"=>$data["lang"],
 													"name"=>$data["username"],
 													"lang"=>$data["lang"],
 													"status"=>30,
 													"summary"=>""
 													]);
-					$newChannel2 = $channel->create(["owner"=>$data["userid"],
+					$newChannel2 = $channel->create([
+                                                    "owner_uid"=>$data["userid"],
+                                                    "editor_id"=>$newUserId,
 													"lang"=>$data["lang"],
 													"name"=>"draft",
 													"lang"=>$data["lang"],
@@ -312,7 +321,7 @@ class User extends Table
 			$this->result["message"]="::username_too_short";
 			return false;
 		}
-		if(preg_match("/@|\s|\//",$username)!==0){
+		if(preg_match("/@|\s|\/|[A-Z]/",$username)!==0){
 			$this->result["ok"]=false;
 			$this->result["message"]="::username_invaild_symbol";
 			return false;

+ 4 - 4
public/app/hostsetting/function.php

@@ -6,15 +6,15 @@ class Hostsetting
     public $dbh;
     public function __construct()
     {
-        $dns = "" . _FILE_DB_HOSTSETTING_;
-        $this->dbh = new PDO($dns, "", "", array(PDO::ATTR_PERSISTENT => true));
+        $dns = _FILE_DB_HOSTSETTING_;
+        $this->dbh = new PDO($dns, _DB_USERNAME_,_DB_PASSWORD_, array(PDO::ATTR_PERSISTENT => true));
         $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
     }
 
     public function get($key)
     {
         if ($this->dbh) {
-            $query = "SELECT value FROM setting WHERE key= ? ";
+            $query = "SELECT value FROM "._TABLE_HOSTSETTING_." WHERE key= ? ";
             $stmt = $this->dbh->prepare($query);
             $stmt->execute(array($key));
             $row = $stmt->fetch(PDO::FETCH_NUM);
@@ -31,7 +31,7 @@ class Hostsetting
     public function set($key, $value)
     {
         if ($this->dbh) {
-            $query = "UPDATE setting SET value = ?  WHERE key= ? ";
+            $query = "UPDATE "._TABLE_HOSTSETTING_." SET value = ? , updated_at = now() WHERE key= ? ";
             $stmt = $this->dbh->prepare($query);
             $stmt->execute(array($value, $key));
             if (!$stmt || ($stmt && $stmt->errorCode() != 0)) {

+ 53 - 13
public/app/palicanon/palicanon.js

@@ -19,6 +19,7 @@ function palicanon_onload() {
 	$("#tag_input").keypress(function () {
 		tag_render_others();
 	});
+    render_main_tag();
 }
 
 function palicanon_load_term() {
@@ -32,7 +33,7 @@ function palicanon_load_term() {
             break;    
         case '':
             lang = 'en';
-            break;  
+            break;
     }
 	$.get(
 		"/api/v2/terms",
@@ -67,13 +68,17 @@ function tag_changed() {
 	}
 	console.log(strTags);
 	let lang = getCookie("language");
-	if (lang == "zh-cn") {
-		lang = "zh-hans";
-	} else if (lang == "zh-tw") {
-		lang = "zh-hant";
-	} else if (lang == "") {
-		lang = "en";
-	}
+    switch (lang) {
+        case 'zh-cn':
+            lang = 'zh-hans';
+            break;
+        case 'zh-tw':
+            lang = 'zh-hant';
+            break;    
+        case '':
+            lang = 'en';
+            break;
+    }
 	$.get(
 		"./book_tag.php",
 		{
@@ -206,7 +211,21 @@ function render_chapter_head(chapter_info, parent) {
 	let link = "../reader/?view=chapter&book=" + chapter_info.book + "&par=" + chapter_info.paragraph;
 	html += "<div class='title'>";
 	if (typeof chapter_info.trans_title == "undefined") {
-		html += "	<div class='title_1'><a href='" + link + "' target='_blank'>" + chapter_info.text + "</a></div>";
+		html += "	<div class='title_1'>";
+        html += "<a href='" + link + "' target='_blank'>" ;
+        switch (getCookie('language')) {
+            case 'my':
+                html += roman_to_my(chapter_info.text);
+                break;
+            case 'si':
+                html += roman_to_si(chapter_info.text);
+                break;        
+            default:
+                html += chapter_info.text ;
+                break;
+        }
+        html += "</a>";
+        html += "</div>";
 	} else {
 		html +=
 			"	<div class='title_1'><a href='" + link + "' target='_blank'>" + chapter_info.trans_title + "</a></div>";
@@ -310,7 +329,20 @@ function palicanon_render_chapter_row(chapter) {
 	html += '<div class="title">';
 
 	if (typeof chapter.trans_title == "undefined") {
-		html += "	<div class='title_1'>" + chapter.title + "</div>";
+		html += "	<div class='title_1'>" ;
+        switch (getCookie('language')) {
+            case 'my':
+                html += roman_to_my(chapter.title);
+                break;
+            case 'si':
+                html += roman_to_si(chapter.title);
+                break;
+            default:
+                html += chapter.title ;
+                break;
+        }
+        
+        html += "</div>";
 	} else {
 		html += "	<div class='title_1'>" + chapter.trans_title + "</div>";
 	}
@@ -342,10 +374,18 @@ function palicanon_render_chapter_row(chapter) {
 }
 function tag_get_local_word(word) {
 	let termKey = term_lookup_my(word, "", getCookie("userid"), getCookie("language"));
-	if (termKey) {
-		return termKey.meaning;
+	if (typeof termKey == 'undefined' || termKey === false || termKey === '') {
+        switch (getCookie('language')) {
+            case 'my':
+                return roman_to_my(word);
+            case 'si':
+                return roman_to_si(word);
+            default:
+                return word;
+        }        
+		
 	} else {
-		return word;
+        return termKey.meaning;
 	}
 }
 function tag_render_others() {

+ 4 - 0
public/app/public/js/comm.js

@@ -292,6 +292,10 @@ function testCJK(string){
 	return reg.test(string);
 
 }
+//显示程序行号
+function get_line(){
+    return (new Error().stack.split(':')[7]);
+}
 
 //所有页面都需要在加载的的时候设置浏览器时区
 setTimeZone();

+ 1 - 1
public/app/public/lang/default.json

@@ -368,7 +368,7 @@
 		"nick_name": "nickname",
 		"name_for_show": "name showed for others",
 		"email_address": "E-mail address",
-		"account_demond": "Username may only contain alphanumeric characters, and try to avoid using ? : ! ; , -  etc.",
+		"account_demond": "Username may only contain alphanumeric lower case characters, and try to avoid using ? : ! ; , -  etc.",
 		"password_demond": "Make sure it's at least 5 characters including both numbers and letters",
 		"login_with_google": "Log in with Google",
 		"login_with_facebook": "Log in with Facebook",

+ 1 - 1
public/app/public/lang/en.json

@@ -368,7 +368,7 @@
 		"nick_name": "nickname",
 		"name_for_show": "name showed for others",
 		"email_address": "E-mail address",
-		"account_demond": "Username may only contain alphanumeric characters, and try to avoid using ? : ! ; , -  etc.",
+		"account_demond": "Username may only contain alphanumeric lower case characters, and try to avoid using ? : ! ; , -  etc.",
 		"password_demond": "Make sure it's at least 5 characters including both numbers and letters",
 		"login_with_google": "Log in with Google",
 		"login_with_facebook": "Log in with Facebook",

+ 22 - 22
public/app/public/lang/my.json

@@ -32,7 +32,7 @@
 		"buddhist_calendar": "Buddhist Calendar",
 		"budha": "ဗုဓ",
 		"by": "By",
-		"cancel": "Cancel",
+		"cancel": "ဖျက်သိမ်းသည်",
 		"canda": "စန္ဒ",
 		"caption": "Caption",
 		"CE": "CE",
@@ -45,13 +45,13 @@
 		"click_word_to": "click word to ",
 		"code_convert": "Code Convert",
 		"color": "Color",
-		"column_compare": "Up&nbsp;&&nbsp;Down",
+		"column_compare": "ပေါ်&nbsp;&&nbsp;အောက်",
 		"commentary": "Commentary",
 		"completely_delete": "completely delete",
 		"computer": "Computer",
 		"confirm": "Confirm",
-		"content": "Content",
-		"contents": "Table of Content",
+		"content": "မာတိကာ",
+		"contents": "မာတိကာ",
 		"copy": "copy",
 		"copy_to_clipboard": "copy the link to clipboard",
 		"creat_a_new_file_by_yourself": "Creat a new file by yourself",
@@ -71,7 +71,7 @@
 		"dict": "Dict",
 		"dict_match": "Match the Dictionary and Document",
 		"dict_terms": "Terms",
-		"dictionary": "Dictionary",
+		"dictionary": "အဘိဓာန်",
 		"dictionary_match_result": "Dictionary Match Result",
 		"dictsouce": "Source of Terms",
 		"difficulty": "difficulty level",
@@ -80,8 +80,8 @@
 		"download": "[Download]",
 		"draft": "As Draft",
 		"dawn": "dawn",
-		"each_paragraph": "E&nbsp;paragraph",
-		"each_sentence": "E&nbsp;sentence",
+		"each_paragraph": "paragraph",
+		"each_sentence": "ဝါကျကဏ္ဍ",
 		"eat": "eat",
 		"edit": "Edit",
 		"edit_now": "Edit in Studio",
@@ -147,11 +147,11 @@
 		"input": "input",
 		"kala": "ကာလ",
 		"keywords": "Keywords",
-		"language": "Language",
+		"language": "ဘာသာ",
 		"language_select": "ဘာသာ",
 		"layout": "Layout",
 		"left": "Remains ",
-		"lesson": "lesson",
+		"lesson": "သင်တန်း",
 		"letters": "&nbsp;letters",
 		"level": "Lv",
 		"list": "List",
@@ -220,8 +220,8 @@
 		"pa_auk_dictionary": "Pa-auk Dictionary",
 		"pacchā_māsa": "ပစ္ဆာ-မာသ",
 		"pakkha": "Lunar Phases ",
-		"pāli": "Pāli",
-		"pali_canon": "Pāḷi Canon",
+		"pāli": "ပါဠိ",
+		"pali_canon": "တိပိဋက",
 		"pāli_code": "Pāli Code",
 		"para": "&nbsp;Paragraphs",
 		"paragraph": "Paragraph",
@@ -245,7 +245,7 @@
 		"pubba_māsa": "ပုဗ္ဗ-မာသ",
 		"publish": "Publish",
 		"ravi": "ရဝိ",
-		"read": "Read",
+		"read": "စာဖတ်",
 		"read_only": "Read Only",
 		"recent_scan": "Recent Scan",
 		"recycle_bin": "Recycle Bin",
@@ -261,7 +261,7 @@
 		"revision_mode": "Revision Mode",
 		"round_1": "Round ",
 		"round_2": "&nbsp;dictionary",
-		"row_compare": "Left&nbsp;&&nbsp;Right",
+		"row_compare": "ဘယ်&nbsp;&&nbsp;ညာ",
 		"same_word": "same words",
 		"saṃvacchara": "သံဝစ္ဆရ",
 		"sandhi": "Sandhi",
@@ -270,7 +270,7 @@
 		"sandhi_end": "Sandhi End",
 		"sandhi_orginal_word": "Sandhi Orginal Word",
 		"sandhi_splited_word": "Sandhi Splited Word",
-		"save": "Save",
+		"save": "သိမ်းထားသည",
 		"script": "Script",
 		"search": "Search",
 		"season": "Season ",
@@ -312,7 +312,7 @@
 		"total_workload": "total workload",
 		"totally": "Totally ",
 		"tran_workload": "whole passage translate ",
-		"translate": "Translate",
+		"translate": "စကားပြန်",
 		"translate_convert": "Translate Convert",
 		"translate1": "Translated By ",
 		"translation": "Translation",
@@ -321,10 +321,10 @@
 		"undo_shared": "undo shared",
 		"unsplit": "Slur Splited",
 		"up": "Up",
-		"up_and_down": "Up And Down",
+		"up_and_down": "ပေါ် And အောက်",
 		"update_all_wbw_to_database": "Update All WBW to Database",
 		"user": "User",
-		"to_user_dictionary": "Save & Add to My Vocabulary List",
+		"to_user_dictionary": "သိမ်းထားသည & Add to My Vocabulary List",
 		"user_id": "User ID",
 		"userdict": "Vocabulary List",
 		"vannana": "vaṇṇanā",
@@ -368,7 +368,7 @@
 		"nick_name": "nickname",
 		"name_for_show": "name showed for others",
 		"email_address": "E-mail address",
-		"account_demond": "Username may only contain alphanumeric characters, and try to avoid using ? : ! ; , -  etc.",
+		"account_demond": "Username may only contain alphanumeric lower case characters, and try to avoid using ? : ! ; , -  etc.",
 		"password_demond": "Make sure it's at least 5 characters including both numbers and letters",
 		"login_with_google": "Log in with Google",
 		"login_with_facebook": "Log in with Facebook",
@@ -387,7 +387,7 @@
 		"add_to_folder": "add to folder",
 		"rename": "rename",
 		"collaborate": "collaborate",
-		"help": "help",
+		"help": "အကူအညီ",
 		"function_introduce": "functions of Wikipāḷi",
 		"vedio_link": "vedio link",
 		"project_introduce": "conference of pāḷi-translating platform",
@@ -463,7 +463,7 @@
 		"comment": "comments",
 		"my_term": "my term",
 		"scan_in_reader": "scan in reader",
-		"selected": "selected",
+		"selected": "မှတ်ပါ",
 		"to_be_selected": "to be selected",
 		"text_without_title": "text without title",
 		"end_of_text": "No Prev",
@@ -626,7 +626,7 @@
 		"years_ago": "&nbsp;years ago",
 		"similar": "similar",
 		"suggest": "suggest",
-		"next_line": "new line",
+		"next_line": "နောက်တစ်ကြောင်း",
 		"link": "link",
 		"co_channel": "collaborative channels",
 		"permission": "permission",
@@ -935,7 +935,7 @@
 		},
 		{
 			"id": ".comp.",
-			"value": "သမာသ"
+			"value": "စကားပေါင်း"
 		},
 		{
 			"id": ".pre.",

+ 1 - 1
public/app/public/lang/si.json

@@ -373,7 +373,7 @@
 		"nick_name": "nickname",
 		"name_for_show": "name showed for others",
 		"email_address": "E-mail address",
-		"account_demond": "Username may only contain alphanumeric characters, and try to avoid using ? : ! ; , -  etc.",
+		"account_demond": "Username may only contain alphanumeric lower case characters, and try to avoid using ? : ! ; , -  etc.",
 		"password_demond": "Make sure it's at least 5 characters including both numbers and letters",
 		"login_with_google": "Log in with Google",
 		"login_with_facebook": "Log in with Facebook",

+ 1 - 1
public/app/public/lang/zh-cn.json

@@ -369,7 +369,7 @@
 		"nick_name": "称呼(昵称)",
 		"name_for_show": "给他人看的名字",
 		"email_address": "电子邮箱地址",
-		"account_demond": "请在半角下使用英文本母、数字、标点符号。并避免使用这些符号?:!;,",
+		"account_demond": "请在半角下使用小写英文字母和数字。并避免使用这些符号?:!;,",
 		"password_demond": "请混合使用五个字符以上的字母和数字",
 		"login_with_google": "使用谷歌登录",
 		"login_with_facebook": "使用脸书登录",

+ 1 - 1
public/app/public/lang/zh-tw.json

@@ -369,7 +369,7 @@
 		"nick_name": "稱呼(暱稱)",
 		"name_for_show": "給他人看的名字",
 		"email_address": "電子信箱地址",
-		"account_demond": "請在半形下使用英文字母、數字、標點符號。並避免使用這些符號?:!;,",
+		"account_demond": "請在半形下使用小寫英文字母和數字。並避免使用這些符號?:!;,",
 		"password_demond": "請混合使用五個字元以上的字母和數字",
 		"login_with_google": "使用Google登入",
 		"login_with_facebook": "使用Facebook登入",

+ 112 - 0
public/app/search/sentence.js

@@ -0,0 +1,112 @@
+var dict_pre_searching = false;
+var dict_pre_search_curr_word = "";
+var dict_search_xml_http = null;
+var _key_word = "";
+var _page = 0;
+var _filter_word = new Array();
+var _bookId = new Array();
+
+$(document).ready(function () {
+	paliword_search(_key_word);
+});
+
+function paliword_search(keyword, words = new Array(), book = new Array()) {
+	$.getJSON(
+		"/api/v2/sentence",
+		{
+			view: "fulltext",
+			key: keyword,
+			page: _page,
+		},
+		function (data) {
+			let result = data;
+			console.log(result.time);
+			let html = "";
+			html += "<div>查询到 "+result.data.rows.length+" 条结果 "+"</div>";
+			for (const iterator of result.data.rows) {
+				html += render_word_result(iterator);
+			}
+			$("#contents").html(html);
+
+		}
+	);
+}
+
+
+function highlightWords(line, word) {
+	if (line && line.length > 0) {
+		let output = line;
+		for (const iterator of word) {
+			let regex = new RegExp("(" + iterator + ")", "gi");
+			output = output.replace(regex, "<highlight>$1</highlight>");
+		}
+		return output;
+	} else {
+		return "";
+	}
+}
+function render_word_result(worddata) {
+	let html = "";
+	html += "<div class='search_result'>";
+
+	html += "<div class='title'>";
+	html +=
+		"<a href='../article/index.php?view=sent&book=" +
+		worddata.book_id +
+		"&par=" +
+		worddata.paragraph +
+        "&start=" +
+		worddata.word_start +
+        "&end=" +
+		worddata.word_end +
+		"' target='_blank'>";
+	html += "Open" + "</a></div>";
+
+	let highlightStr;
+
+	highlightStr= highlightWords(worddata.content, _key_word);
+
+
+	html += "<div class='wizard_par_div'>" + highlightStr + "</div>";
+	html += "<div class='path'>" + worddata.book_id + "-" + worddata.paragraph + "-" + worddata.word_start + "-" + worddata.word_end + "</div>";
+	html += "</div>";
+	return html;
+}
+
+
+function gotoPage(index) {
+	_page = index;
+	paliword_search(_key_word, _filter_word, _bookId);
+}
+
+
+function dict_input_change(obj) {
+	search_pre_search(obj.value);
+}
+
+
+
+function search_input_onfocus() {
+	if ($("#dict_ref_search_input").val() == "") {
+		//search_show_history();
+	}
+}
+function search_input_keyup(e, obj) {
+	var keynum;
+	var keychar;
+	var numcheck;
+
+	if (window.event) {
+		// IE
+		keynum = e.keyCode;
+	} else if (e.which) {
+		// Netscape/Firefox/Opera
+		keynum = e.which;
+	}
+	var keychar = String.fromCharCode(keynum);
+	if (keynum == 13) {
+		//search_search(obj.value);
+		window.location.assign("../search/sentence.php?key=" + obj.value);
+	}
+}
+

+ 244 - 0
public/app/search/sentence.php

@@ -0,0 +1,244 @@
+<?PHP
+include "../pcdl/html_head.php";
+?>
+<body>
+<link type="text/css" rel="stylesheet" href="../search/search.css"/>
+
+<?php
+	require_once("../pcdl/head_bar.php");
+	require_once("../search/toobar.php");
+?>
+    <style>
+        #dt_pali , #dt_pali_1{
+            border-bottom: 2px solid var(--link-hover-color);
+        }
+        #index_list{
+			display:flex;
+		}
+
+		.main_view{
+		padding: 0 1em;
+		max-width: 1280px;
+		margin-left: auto;
+		margin-right: auto;
+	}
+
+	.fun_frame {
+		border-bottom: 1px solid gray;
+		margin-right: 10px;
+		margin-bottom: 10px;
+	}
+	.fun_frame .title{
+		padding:6px;
+		font-weight: 700;
+	}
+	.fun_frame>.content{
+		padding:6px;
+		overflow-y: scroll;
+	}
+	
+	.fixed{
+		position:fixed;
+		right: 0;
+    	top: 0;
+	}
+	.when_right_fixed{
+		padding-right:20em;
+	}
+
+
+	#contents_view{
+		display:flex;
+	}
+	#contents_div{
+		flex:7;
+		max-width: 70vw;
+	}
+	#contents{
+
+	}
+	#contents li{
+		white-space: normal;
+	}
+	#right_pannal{
+		flex:3;
+		max-width:20em;
+	}
+	#head_bar{
+		height:unset;
+	}
+	#contents_foot{
+		margin-bottom: 70vh;
+	}
+
+	#pre_search_word_content{
+		display:block;
+	}
+	@-webkit-keyframes spin {
+	from {
+		-webkit-transform: rotate(0deg);
+	}
+	to {
+		-webkit-transform: rotate(360deg);
+	}
+}
+
+@keyframes spin {
+	from {
+		transform: rotate(0deg);
+	}
+	to {
+		transform: rotate(360deg);
+	}
+}
+.icon_spin {
+	-webkit-animation: spin 2.5s linear infinite;
+	animation: spin 2.5s linear infinite;
+}
+
+    </style>
+    <style  media="screen and (max-width:800px)">
+		#index_list{
+			display:block;
+		}
+		#contents_view{
+		display:block;
+	}
+	#dict_ref_search_result{
+		display:none;
+	}
+	#footer_nav{
+    display: none;
+}
+#contents_foot {
+    margin-bottom: 70vh;
+    position: absolute;
+    left: 0;
+	width: 100vw;
+	margin-bottom: 10vh;
+}
+#contents_nav{
+	overflow-x: scroll;
+}
+.page_nav{
+	display:flex;
+}
+.foot_div{
+	margin-top:10vh;
+}
+	</style>
+	<script language="javascript" src="sentence.js"></script>
+	<script>
+		<?php
+		if(isset($_GET["key"])){
+			echo " _key_word = '{$_GET["key"]}';";
+		}
+		if(isset($_GET["page"])){
+			echo " _page = '{$_GET["page"]}';";
+		}		
+		?>
+	</script>
+
+	<div id="main_view" class="main_view">
+
+<div id="contents_view">
+	<div id="contents_div" style="padding: 0 1em 0 30px;">
+		<div id="contents" >
+			<div id="index_list">
+				<div style="flex:3;margin:12px;">
+					<div class="card" style="padding:10px;">
+						<div>最近搜索</div>
+						<div id="title_histray"></div>
+					</div>
+				</div>
+				<div style="flex:3;margin:12px;">
+					<div class="card" style="padding:10px;">
+						<div>热搜</div>
+						<div id="title_hot"></div>
+					</div>
+				</div>
+				<div style="flex:3;margin:12px;">
+					<div class="card" style="padding:10px;">
+						<div id="guide_title_search_index"></div>
+					</div>
+				</div>
+			</div>
+			<div style="text-align: center;display:none;">
+				<svg class='icon_spin' style='fill: saddlebrown;height: 4em;width: 4em; '>
+					<use xlink='http://www.w3.org/1999/xlink' href='../studio/svg/icon.svg#dhammacakkha'></use>
+				</svg>
+			</div>
+		</div>
+		<div id="contents_foot">
+			<div id="contents_nav" style="">
+			</div>
+		</div>
+	</div>
+
+	<div id="right_pannal">
+		<div class="fun_frame">
+			<div style="display:flex;justify-content: space-between;">
+				<div class="title"><?php echo $_local->gui->real_declension; ?></div>
+				<div id="case_tools" style="display:flex;">
+					<div class="select_button" style="margin:auto 0"  onclick="onWordFilterStart()"><?php echo $_local->gui->select; ?></div>
+					<div class="filter" >
+						<button onclick='word_search_filter()'><?php echo $_local->gui->filter; ?></button>
+						<button onclick='filter_cancel()'><?php echo $_local->gui->cancel; ?></button>
+					</div>
+				</div>
+			</div>
+			<div id = "case_content" class="content" style="max-height:20em;">
+			</div>
+		</div>
+		<div class="fun_frame">
+			<div style="display:flex;justify-content: space-between;">
+				<div class="title"><?php echo $_local->gui->book_name.$_local->gui->list; ?></div>
+				<div id="book_tools" style="display:flex;">
+					<div class="select_button" style="margin:auto 0" onclick="onBookFilterStart()"><?php echo $_local->gui->select; ?></div>
+					<div class="filter">
+						<button onclick='book_search_filter()'><?php echo $_local->gui->filter; ?></button>
+						<button onclick='book_filter_cancel()'><?php echo $_local->gui->cancel; ?></button>
+					</div>
+				</div>
+			</div>
+			<div id="book_list" class="content" >
+			</div>
+		</div>
+	</div>
+</div>
+
+</div>
+
+
+	<div id="dict_ref_search_result" style="background-color:white;color:black;display:none;">
+	</div>
+
+
+    <div id="index_list">
+			<div style="flex:3;margin:12px;">
+				<div class="card" style="padding:10px;">
+					<div><?php echo $_local->gui->search.$_local->gui->history; ?></div>
+                    <div id="search_histray"></div>
+				</div>
+			</div>
+			<div style="flex:3;margin:12px;">
+				<div class="card" style="padding:10px;">
+					<div><?php echo $_local->gui->top_search; ?></div>
+                    <div id="title_hot"></div>
+				</div>
+			</div>
+			<div style="flex:3;margin:12px;">
+				<div class="card" style="padding:10px;">
+                    <div id="guide_pali_search_index"></div>
+				</div>
+			</div>
+	</div>
+    <script>
+    search_show_history();
+    guide_get("pali_search_index");
+    </script>
+
+<?php
+include "../pcdl/html_foot.php";
+?>
+

+ 2 - 2
public/app/term/note.js

@@ -89,7 +89,7 @@ function note_init(input,channel="",editor="",lang="en") {
 
 		output += "</div>";
 
-		let newString = output.replace(/\{\{/g, '<span class="note_shell"><note style="border: solid 2px var(--btn-bg-color);" info="');
+		let newString = output.replace(/\{\{/g, '<span class="note_shell"><note style="" info="');
 		newString = newString.replace(/\}\}/g, '" ></note></span>');
 
 		return newString;
@@ -308,7 +308,7 @@ function render_read_mode_sent(iterator) {
 	htmlSent += "</div>";
 	htmlSent += "<div class='sent_tran_div'>";
 	for (const oneTran of iterator.translation) {
-		let html = "<span class='tran_sent' lang='" + oneTran.lang + "' channal='" + oneTran.channal + "'>";
+		let html = "<span class='sent_tran' lang='" + oneTran.lang + "' channal='" + oneTran.channal + "'>";
 
 		//将绝对链接转换为 用户连接的主机链接
 		//oneTran.text = oneTran.text.replace(/www-[A-z]*.wikipali.org/g,location.host);

+ 22 - 5
public/app/term/term.css

@@ -404,6 +404,10 @@ note {
 	display: block;
 	background-color: #80808014;
 	position: relative;
+    border: solid 2px var(--btn-bg-color);
+}
+.read note {
+    border:unset;
 }
 note > .bottm_tool_button {
 	border-radius: 5px;
@@ -668,6 +672,12 @@ pw {
 .preview {
 	font-size: 110%;
 }
+.preview::first-letter {
+	text-transform:capitalize;
+}
+.sent_tran > p::first-letter {
+	text-transform:capitalize;
+}
 .compact .body > .head_bar {
 	display: flex;
 }
@@ -887,7 +897,7 @@ w:hover {
 .sent_mode .note_shell {
 	display: block;
 }
-.tran_sent p {
+.sent_tran p {
 	display: inline;
 }
 .sent_tran li {
@@ -923,11 +933,14 @@ span.keybutton {
 	padding: 0.7rem;
 	word-break: break-word;
 }
-span.tran_sent {
+span.sent_tran {
 	line-height: 1.7em;
 }
-.tran_sent ul,
-.tran_sent li {
+.sent_mode span.sent_tran {
+    display: inline-block;
+}
+.sent_tran ul,
+.sent_tran li {
 	list-style-type: unset;
 	margin-left: 1em;
 }
@@ -1084,7 +1097,7 @@ pali>p {
 }
 
 .term_mean {
-    text-transform: capitalize;
+    /*text-transform: capitalize;*/
 }
 .term_at_menu_ul>.trem_focus{
 	border-radius:unset;
@@ -1092,4 +1105,8 @@ pali>p {
 	margin:unset;
 	padding:unset;
 	background-color: var(--btn-border-color);
+}
+
+span.sent_tran::first-letter {
+    text-transform: capitalize;
 }

+ 5 - 7
public/app/term/term.js

@@ -712,12 +712,8 @@ function term_get_dict(callback=null) {
 		},
 		function (data, status) {
 			if (data.length > 0) {
-				try {
-					arrMyTerm = JSON.parse(data);
-					term_updata_translation(callback);
-				} catch (e) {
-					console.error(e.error + " data:" + data);
-				}
+				arrMyTerm = JSON.parse(data);
+				term_updata_translation(callback);
 			}
 		}
 	);
@@ -728,11 +724,13 @@ function term_get_used(){
     $("term").each(function () {
         let word = $(this).attr("pali");
         let meaning = $(this).attr("mean");
+        let meaning2 = $(this).attr("mean2");
         if(word !== ""){
             output[word] = {
                 pali:word,
                 pali_en:com_getPaliEn(word),
-                meaning:meaning
+                meaning:meaning,
+                meaning2:meaning2
             };
         }
 

+ 1 - 1
public/app/term/term_edit_dlg.js

@@ -175,7 +175,7 @@ function term_edit_dlg_render(word = null,obj=null) {
         if(word.channel === ''){
             output += "通用于<b>所有版本</b>";
             //判断是否只读
-            if(sentChannel.power !== 30){
+            if(sentChannel !==null && sentChannel.power !== 30){
                 output += "(只读)";
             }
         }else{

+ 2 - 2
public/app/ucenter/index.php

@@ -410,8 +410,8 @@ if ($op == "new") {
 
 					<div>
 						<span id='tip_password' class='form_field_name'><?php echo $_local->gui->password; ?></span>
-						<input type="password" name="password" placeholder="密码" value="<?php echo $post_password; ?>" />
-						<input type="password" name="repassword" placeholder="再次输入密码" value="<?php echo $post_password; ?>" />
+						<input type="password" name="password" placeholder="<?php echo $_local->gui->password; ?>" value="<?php echo $post_password; ?>" />
+						<input type="password" name="repassword" placeholder="<?php echo $_local->gui->password_again; ?>" value="<?php echo $post_password; ?>" />
 					</div>
 					<div class="form_help">
 					<?php echo $_local->gui->password_demond; ?>

+ 11 - 5
public/app/ucenter/invite.php

@@ -12,8 +12,13 @@ require_once "../redis/function.php";
 require_once "../public/function.php";
 
 if (PHP_SAPI == "cli") {
-	if ($argc == 2) {
+	if ($argc >= 2) {
 		$email = $argv[1];
+        if($argc > 2){
+            $lang = $argv[2];
+        }else{
+            $lang = "cn";
+        }
         $redis = redis_connect();
         if ($redis == false) {
             echo "no redis connect\n";
@@ -23,14 +28,15 @@ if (PHP_SAPI == "cli") {
 		$invitecode = "invitecode://".$uuid;
 		$redis->set($invitecode,$email);
 		$redis->expire($invitecode,7*20*3600);
-		$SignUpLink="https://".$_SERVER['SERVER_NAME'] . "/app/ucenter/sign_up.php?invite=".$uuid;
-		$SignUpString="https://".$_SERVER['SERVER_NAME'] . "/app/ucenter/sign_up.php";
+		$SignUpLink="https://www-hk.wikipali.org/app/ucenter/sign_up.php?invite=".$uuid;
+		$SignUpString="https://www-hk.wikipali.org/app/ucenter/sign_up.php";
 
-			// 打开文件并读取数据
+		// 打开文件并读取数据
 		$irow=0;
 		$strSubject = "";
 		$strBody = "";
-		if(($fp=fopen("invite_letter.html", "r"))!==FALSE){
+        $filename = "invite_letter_{$lang}.html";
+		if(($fp=fopen($filename, "r"))!==FALSE){
 			while(($data=fgets($fp))!==FALSE){
 				$irow++;
 				if($irow==1){

+ 4 - 0
public/app/ucenter/invite_letter_cn.html

@@ -0,0 +1,4 @@
+wikipali 注册邀请
+点击此链接注册wikipali账号。此链接邀请只可以注册一个账户。有效期7天。
+<a href="%SignUpLink%">%SignUpString%</a><br>
+此邮件为系统自动发送,请勿回复。

+ 6 - 0
public/app/ucenter/invite_letter_en.html

@@ -0,0 +1,6 @@
+wikipali sign up invitation
+
+click this link to sign up on wikipali.
+<a href="%SignUpLink%">%SignUpString%</a><br>
+This link will be expired within 7 days.<br>
+This email is sent automatically by system, please don't reply.

+ 2 - 2
public/app/ucenter/reset.php

@@ -201,8 +201,8 @@ if (!isset($_GET["token"])) {
 					<div>
 						<div>
 							<span id='tip_password' class='form_field_name'><?php echo $_local->gui->password; ?></span>
-							<input type="password" id="password" maxlength="32" name="password" placeholder="密码" value="" />
-							<input type="password" id="repassword" maxlength="32" name="repassword" placeholder="再次输入密码" value="" />
+							<input type="password" id="password" maxlength="32" name="password" placeholder="<?php echo $_local->gui->password; ?>" value="" />
+							<input type="password" id="repassword" maxlength="32" name="repassword" placeholder="<?php echo $_local->gui->password_again; ?>" value="" />
 						</div>
 						<div class="form_help">至少6个字符</div>
 						<div id="error_password" class="form_error"></div>

+ 13 - 0
public/app/ucenter/reset_pwd_letter_cn.html

@@ -0,0 +1,13 @@
+wikipali reset password
+<p>
+您收到这封邮件是因为系统接到您的账号需要重置密码的申请。<br>
+如果您没有进行过此操作请忽略这个邮件。
+</p>
+<p>
+点击此链接重置您的wikipali账号的密码。此链接一小时内有效。
+<a href="%ResetLink%">%ResetString%</a>
+</p>
+<p>
+	此链接包含重置密码所需要的密钥。<b>请勿发给他人</b>。
+	此邮件为系统自动发送,请勿回复。
+</p>

+ 13 - 0
public/app/ucenter/reset_pwd_lettet_en.html

@@ -0,0 +1,13 @@
+wikipali reset password
+<p>
+We recieve your request of resetting passwords.<br>
+If you have never done this, please ignore this mail.
+</p>
+<p>
+Click this link to reset your passwords on wikipali.
+<a href="%ResetLink%">%ResetString%</a>
+</p>
+<p>
+	This link include the secret-key for resetting passwords.<b>Don't send to others.</b>
+	As this is an automated mail, please do not reply to this email.
+</p>

+ 13 - 6
public/app/ucenter/sign.js

@@ -7,7 +7,7 @@ function isValidPassword(str){
 	}
 }
 function isValidUserName(str){
-	let patt=new RegExp(/@|\s|\//);
+	let patt=new RegExp(/@|\s|\/|[A-Z]/);
 	if(patt.test(str)){
 		return false;
 	}else{
@@ -17,16 +17,23 @@ function isValidUserName(str){
 function submit(){
 	let hasError = false;
 	if($("#password").val()!==$("#repassword").val()){
-		$("#error_password").text("两次密码输入不一致");
+		$("#error_password").text("password and repassword is not match");
 		hasError = true;
 	}
 	if(isValidPassword($("#password").val())==false){
-		$("#error_password").text("密码包含无效字符。  / 空格 ");
+		$("#error_password").text(gLocal.gui.password_invaild_symbol);
+		hasError = true;
+	}
+	if($("#password").val().length < 6){
+		$("#error_password").text('Password is too short');
+		hasError = true;
+	}
+    if($("#password").val().length > 31){
+		$("#error_password").text('Password is too long');
 		hasError = true;
 	}
-
 	if(isValidUserName($("#username").val())==false){
-		$("#error_password").text("用户名包含无效字符。@  / 空格 ");
+		$("#error_username").text(gLocal.gui.username_invaild_symbol);
 		hasError = true;
 	}
 
@@ -62,7 +69,7 @@ function submit(){
 			if(data.ok){
 				$("#form_div").hide();
 				$("#message").removeClass("form_error");
-				$("#message").html("注册成功。<a href='index.php?op=login'>"+gLocal.gui.login+"</a>");
+				$("#message").html(gLocal.gui.successful+" <a href='index.php?op=login'>"+gLocal.gui.login+"</a>");
 			}else{
 				$("#message").addClass("form_error");
 				$("#message").text(ConvertServerMsgToLocalString(data.message));

+ 7 - 7
public/app/ucenter/sign_up.php

@@ -170,7 +170,7 @@ require_once "../redis/function.php";
 		<div id = "login_form_div" class="fun_block" >
 
 			<div class="title">
-			注册wikipali账号
+			wikipali sign up
 			</div>
 			<div class="login_new">
 				<span class="form_help"><?php echo $_local->gui->have_account; ?> ?</span><a href="index.php?language=<?php echo $currLanguage; ?>">&nbsp;&nbsp;&nbsp;&nbsp;<?php echo $_local->gui->login; //登入账户 ?></a>
@@ -178,17 +178,17 @@ require_once "../redis/function.php";
 			<div class="form_error">
 			<?php
 			if (!isset($_GET["invite"])) {
-				echo "目前只支持邀请码注册。";
+				echo "Only for invited person";
 				exit;
 			}else{
 				$redis = redis_connect();
 				if ($redis == false) {
-					echo "服务器故障,请稍后重试。<br> 错误代码:no_redis_connect";
+					echo "Server Error,please try again.<br> no_redis_connect";
 					exit;
 				}
 				$code = $redis->exists("invitecode://".$_REQUEST["invite"]);
 				if(!$code){
-					echo "无效的邀请码,或邀请码已经过期。";
+					echo "Invalid invide code or code expired.";
 					exit;
 				}
 				$invite_email = $redis->get("invitecode://".$_REQUEST["invite"]);				
@@ -216,8 +216,8 @@ require_once "../redis/function.php";
 					<div>
 						<div>
 							<span id='tip_password' class='form_field_name'><?php echo $_local->gui->password; ?></span>
-							<input type="password" id="password"  maxlength="32"  name="password"  value="" />
-							<input type="password" id="repassword" maxlength="32"  name="repassword" placeholder="再次输入密码" value="" />
+							<input type="password" id="password"  maxlength="32"  name="password" placeholder="<?php echo $_local->gui->password; ?>" value="" />
+							<input type="password" id="repassword" maxlength="32"  name="repassword" placeholder="<?php echo $_local->gui->password_again; ?>" value="" />
 						</div>
 						<div class="form_help">
 						<?php echo $_local->gui->password_demond; ?>
@@ -226,7 +226,7 @@ require_once "../redis/function.php";
 					</div>
 
 						<div>
-							<span id='tip_language' class='viewswitch_on'><?php echo "惯常使用的语言"; ?></span>
+							<span id='tip_language' class='viewswitch_on'><?php echo "惯常使用的语言 Usual Language"; ?></span>
 							<select id="lang" name="language" style="width: 100%;">
 							<?php
 							$currLang = $_COOKIE["language"];

+ 7 - 0
public/app/ucenter/testhost.php

@@ -0,0 +1,7 @@
+<?php
+
+echo "SERVER_NAME:".$_SERVER['SERVER_NAME'].PHP_EOL;
+echo "HTTP_HOST:".$_SERVER['HTTP_HOST'].PHP_EOL;
+
+echo "SERVER_NAME:".getenv('SERVER_NAME').PHP_EOL;
+echo "HTTP_HOST:".getenv('HTTP_HOST').PHP_EOL;

+ 17 - 0
public/db/sqlite/custom_book/book_sn.sql

@@ -0,0 +1,17 @@
+--
+-- 由SQLiteStudio v3.1.1 产生的文件 周一 2月 14 16:11:21 2022
+--
+-- 文本编码:UTF-8
+--
+PRAGMA foreign_keys = off;
+BEGIN TRANSACTION;
+
+-- 表:setting
+CREATE TABLE setting (

+    [key]     TEXT PRIMARY KEY,

+    value     TEXT,

+    [default] TEXT

+);
+
+COMMIT TRANSACTION;
+PRAGMA foreign_keys = on;

+ 40 - 0
public/db/sqlite/custom_book/up.sql

@@ -0,0 +1,40 @@
+--
+-- 由SQLiteStudio v3.1.1 产生的文件 周五 2月 11 15:33:54 2022
+--
+-- 文本编码:UTF-8
+--
+PRAGMA foreign_keys = off;
+BEGIN TRANSACTION;
+
+-- 表:custom_book
+CREATE TABLE custom_book 
+(
+    id INTEGER PRIMARY KEY AUTOINCREMENT, 
+    book_id INTEGER NOT NULL, 
+    title VARCHAR (256) NOT NULL, 
+    owner VARCHAR (36) NOT NULL, 
+    lang VARCHAR (8) NOT NULL, 
+    status INTEGER NOT NULL DEFAULT (0), 
+    modify_time INTEGER NOT NULL,
+    create_time INTEGER NOT NULL
+);
+
+-- 表:custom_book_sentence
+CREATE TABLE custom_book_sentence 
+(
+    id INTEGER PRIMARY KEY AUTOINCREMENT, 
+    book INTEGER, 
+    paragraph INTEGER, 
+    "begin" INTEGER, 
+    "end" INTEGER, 
+    length INTEGER, 
+    text TEXT, 
+    lang VARCHAR (8), 
+    owner VARCHAR (36) NOT NULL, 
+    status INTEGER DEFAULT (0), 
+    modify_time INTEGER NOT NULL, 
+    create_time INTEGER NOT NULL
+);
+
+COMMIT TRANSACTION;
+PRAGMA foreign_keys = on;

+ 28 - 0
public/documents/tables.md

@@ -0,0 +1,28 @@
+# Tables
+
+业务表
+
+|name|description|
+|-|-|
+|wbws|逐词解析|
+|wbw_blocks|逐词解析段落索引|
+|channels|版本|
+|sentences|用户上传的句子|
+|sent_blocks|句子段落索引|
+|sent_prs|句子修改建议|
+|sent_histories|句子历史记录|
+|user_dicts|用户字典|
+|user_operation_dailies|用户操作记录(每日)|
+|user_operation_frames|用户操作记录(连续时间片段)|
+|user_operation_logs|用户操作记录(所有学习行为)|
+|articles|文章|
+|collections|文集|
+|article_collections|文章文集多对多|
+|dhamma_terms|术语|
+|shares|资源分享和协作|
+|group_infos|工作组|
+|group_members|工作组成员|
+|file_indices|逐词解析文件索引|
+|custom_books|用户自定义书名|
+|custom_book_sentences|用户自定义书句子|
+|custom_book_ids|用户自定义书最大序列号|

+ 2 - 0
routes/api.php

@@ -4,6 +4,7 @@ use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Route;
 use App\Http\Controllers\WbwTemplateController;
 use App\Http\Controllers\DhammaTermController;
+use App\Http\Controllers\SentenceController;
 /*
 |--------------------------------------------------------------------------
 | API Routes
@@ -22,4 +23,5 @@ Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
 Route::group(['prefix' => 'v2'],function(){
 	Route::apiResource('wbw_templates',WbwTemplateController::class);
 	Route::apiResource('terms',DhammaTermController::class);
+	Route::apiResource('sentence',SentenceController::class);
 });

+ 9 - 0
v1/scripts/install5.sh

@@ -0,0 +1,9 @@
+#!/bin/sh
+
+date
+
+php ./migrations/20220211155400_custom_book_copy.php
+php ./migrations/20220213092400_custom_book_sentence_copy.php
+php ./migrations/20220214163000_custom_book_id_copy.php
+
+date

+ 175 - 0
v1/scripts/migrations/20220211155400_custom_book_copy.php

@@ -0,0 +1,175 @@
+<?php
+/*
+迁移  article 库
+从旧数据表中提取数据插入到新的表
+插入时用uuid判断是否曾经插入
+曾经插入就不插入了
+*/
+require_once __DIR__."/../../../public/app/config.php";
+require_once __DIR__."/../../../public/app/public/snowflakeid.php";
+
+set_exception_handler(function($e){
+	fwrite(STDERR,"error-msg:".$e->getMessage().PHP_EOL);
+	fwrite(STDERR,"error-file:".$e->getFile().PHP_EOL);
+	fwrite(STDERR,"error-line:".$e->getLine().PHP_EOL);
+	exit;
+});
+$start = time();
+# 雪花id
+$snowflake = new SnowFlakeId();
+
+$fpError = fopen(__DIR__.'/log/'.basename($_SERVER['PHP_SELF'],'.php').".err.data.csv",'w');
+
+#user info
+$user_db=_FILE_DB_USERINFO_;#user数据库
+$user_table=_TABLE_USER_INFO_;#user表名
+
+# 
+$src_db = _SQLITE_DB_USER_CUSTOM_BOOK_;#源数据库
+$src_table = _SQLITE_TABLE_CUSTOM_BOOK_;#源表名
+
+$dest_db = _PG_DB_USER_CUSTOM_BOOK_;#目标数据库
+$dest_table = _PG_TABLE_CUSTOM_BOOK_;#目标表名
+
+fwrite(STDOUT,"migarate custom book".PHP_EOL);
+#打开user数据库
+$PDO_USER = new PDO($user_db,_DB_USERNAME_,_DB_PASSWORD_,array(PDO::ATTR_PERSISTENT=>true));
+$PDO_USER->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+fwrite(STDOUT,"open user table".PHP_EOL);
+
+#打开源数据库
+$PDO_SRC = new PDO($src_db,_DB_USERNAME_,_DB_PASSWORD_,array(PDO::ATTR_PERSISTENT=>true));
+$PDO_SRC->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+fwrite(STDOUT,"open src table".PHP_EOL);
+
+#打开目标数据库
+$PDO_DEST = new PDO($dest_db,_DB_USERNAME_,_DB_PASSWORD_,array(PDO::ATTR_PERSISTENT=>true));
+$PDO_DEST->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+fwrite(STDOUT,"open dest table".PHP_EOL);
+
+$queryInsert = "INSERT INTO ".$dest_table." 
+								(
+                                    id,
+                                    book_id,
+									title,
+									owner,
+									editor_id,
+									lang,
+									status,
+									updated_at,
+									created_at) 
+									VALUES (? , ? , ? , ? , ?, ? , ? , ? , ? )";
+$stmtDEST = $PDO_DEST->prepare($queryInsert);
+
+$commitData = [];
+$allInsertCount = 0;
+$allSrcCount = 0;
+$count = 0;
+
+#从user数据表中读取
+$query = "SELECT id,userid  FROM ".$user_table." WHERE userid = ? ";
+$stmtUser = $PDO_USER->prepare($query);
+
+#从源数据表中读取
+$query = "SELECT *  FROM ".$src_table;
+$stmtSrc = $PDO_SRC->prepare($query);
+$stmtSrc->execute();
+while($srcData = $stmtSrc->fetch(PDO::FETCH_ASSOC)){
+	$allSrcCount++;
+
+    if($srcData["owner"]=='visuddhinanda'){
+		$srcData["owner"] = 'ba5463f3-72d1-4410-858e-eadd10884713';
+	}
+    if($srcData["owner"]=='test7'){
+		$srcData["owner"] = '6bd2f4d7-d970-419c-8ee5-f4bac42f4bc1';
+	}
+    if($srcData["owner"]=='Dhammadassi'){
+		$srcData["owner"] = 'd8538ebd-d369-4777-b99a-3ccb1aff8bfc';
+	}
+    if($srcData["owner"]=='pannava'){
+		$srcData["owner"] = '4db550c4-bc1b-43f2-a518-2740cb478f37';
+	}
+    if($srcData["owner"]=='NST'){
+		$srcData["owner"] = '5c23e629-56a3-48e9-97c7-2af73b59c3b9';
+	}
+    if($srcData["owner"]=='viranyani'){
+		$srcData["owner"] = 'C1AB2ABF-EAA8-4EEF-B4D9-3854321852B4';
+	}
+    if($srcData["owner"]=='test6'){
+		$srcData["owner"] = 'f81c7140-64b4-4025-b58c-45a3b386324a';
+	}
+	if($srcData["owner"]=='test28'){
+		$srcData["owner"] = 'df0ad9bc-c0cd-4cd9-af05-e43d23ed57f0';
+	}
+	if($srcData["owner"]=='290fd808-2f46-4b8c-b300-0367badd67ed'){
+		$srcData["owner"] = 'f81c7140-64b4-4025-b58c-45a3b386324a';
+	}
+	if($srcData["owner"]=='BA837178-9ABD-4DD4-96A0-D2C21B756DC4'){
+		$srcData["owner"] = 'ba5463f3-72d1-4410-858e-eadd10884713';
+	}
+	$stmtUser->execute(array($srcData["owner"]));
+	$userId = $stmtUser->fetch(PDO::FETCH_ASSOC);
+	if(!$userId){
+		fwrite(STDERR,time()."error,no user id {$srcData["owner"]}".PHP_EOL);
+		continue;
+	}
+	if(strlen($srcData["owner"])>36){
+		fwrite(STDERR,time().",error,user id too long {$srcData["owner"]}".PHP_EOL);
+		continue;	
+	}
+
+    $srcData["status"] = 30;
+
+    if(empty($srcData["modify_time"])){
+        $srcData["modify_time"] = $srcData["create_time"];
+    }
+
+    if($srcData["create_time"] < 15987088320){
+        $srcData["create_time"] *= 1000;
+    }
+    if($srcData["modify_time"] < 15987088320){
+        $srcData["modify_time"] *= 1000;
+    }
+	//查询是否已经插入
+	$queryExsit = "SELECT id  FROM ".$dest_table." WHERE id = ? ";
+	$getExist = $PDO_DEST->prepare($queryExsit);
+	$getExist->execute(array($srcData["id"]));
+	$exist = $getExist->fetch(PDO::FETCH_ASSOC);
+	if($exist){
+		continue;
+	}
+	#插入目标表
+	$created_at = date("Y-m-d H:i:s.",$srcData["create_time"]/1000).($srcData["create_time"]%1000)." UTC";
+	$updated_at = date("Y-m-d H:i:s.",$srcData["modify_time"]/1000).($srcData["modify_time"]%1000)." UTC";
+	$commitData = array(
+            $snowflake->id(),
+			$srcData["book_id"],
+			$srcData["title"],
+			$srcData["owner"],
+			$userId["id"],
+			$srcData["lang"],
+			$srcData["status"],
+			$created_at,
+			$updated_at
+		);
+	$stmtDEST->execute($commitData);
+
+	$count++;	
+	$allInsertCount++;
+
+
+	if($count ==10000){
+		#10000行输出log 一次
+		echo "finished $count".PHP_EOL;
+		$count=0;
+	}	
+}
+
+fwrite(STDOUT,"insert done $allInsertCount in $allSrcCount ".PHP_EOL) ;
+fwrite(STDOUT, "all done in ".(time()-$start)."s".PHP_EOL);
+
+fclose($fpError);
+
+
+
+

+ 185 - 0
v1/scripts/migrations/20220213092400_custom_book_sentence_copy.php

@@ -0,0 +1,185 @@
+<?php
+/*
+迁移  article 库
+从旧数据表中提取数据插入到新的表
+插入时用uuid判断是否曾经插入
+曾经插入就不插入了
+*/
+require_once __DIR__."/../../../public/app/config.php";
+require_once __DIR__."/../../../public/app/public/snowflakeid.php";
+
+set_exception_handler(function($e){
+	fwrite(STDERR,"error-msg:".$e->getMessage().PHP_EOL);
+	fwrite(STDERR,"error-file:".$e->getFile().PHP_EOL);
+	fwrite(STDERR,"error-line:".$e->getLine().PHP_EOL);
+	exit;
+});
+$start = time();
+# 雪花id
+$snowflake = new SnowFlakeId();
+
+$fpError = fopen(__DIR__.'/log/'.basename($_SERVER['PHP_SELF'],'.php').".err.data.csv",'w');
+
+#user info
+$user_db=_FILE_DB_USERINFO_;#user数据库
+$user_table=_TABLE_USER_INFO_;#user表名
+
+# 
+$src_db = _SQLITE_DB_USER_CUSTOM_BOOK_;#源数据库
+$src_table = _SQLITE_TABLE_CUSTOM_BOOK_SENT_;#源表名
+
+$dest_db = _PG_DB_USER_CUSTOM_BOOK_;#目标数据库
+$dest_table = _PG_TABLE_CUSTOM_BOOK_SENT_;#目标表名
+
+fwrite(STDOUT,"migarate custom book".PHP_EOL);
+#打开user数据库
+$PDO_USER = new PDO($user_db,_DB_USERNAME_,_DB_PASSWORD_,array(PDO::ATTR_PERSISTENT=>true));
+$PDO_USER->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+fwrite(STDOUT,"open user table".PHP_EOL);
+
+#打开源数据库
+$PDO_SRC = new PDO($src_db,_DB_USERNAME_,_DB_PASSWORD_,array(PDO::ATTR_PERSISTENT=>true));
+$PDO_SRC->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+fwrite(STDOUT,"open src table".PHP_EOL);
+
+#打开目标数据库
+$PDO_DEST = new PDO($dest_db,_DB_USERNAME_,_DB_PASSWORD_,array(PDO::ATTR_PERSISTENT=>true));
+$PDO_DEST->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+fwrite(STDOUT,"open dest table".PHP_EOL);
+
+$queryInsert = "INSERT INTO ".$dest_table." 
+								(
+                                    id,
+									book,
+									paragraph,
+									word_start,
+									word_end,
+									content,
+                                    length,
+                                    owner,
+                                    lang,
+                                    status,
+                                    create_time,
+                                    modify_time,
+									updated_at,
+									created_at) 
+									VALUES (? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ?)";
+$stmtDEST = $PDO_DEST->prepare($queryInsert);
+
+$commitData = [];
+$allInsertCount = 0;
+$allSrcCount = 0;
+$count = 0;
+
+#从user数据表中读取
+$query = "SELECT id,userid  FROM ".$user_table." WHERE userid = ? ";
+$stmtUser = $PDO_USER->prepare($query);
+
+#从源数据表中读取
+$query = "SELECT *  FROM ".$src_table;
+$stmtSrc = $PDO_SRC->prepare($query);
+$stmtSrc->execute();
+while($srcData = $stmtSrc->fetch(PDO::FETCH_ASSOC)){
+	$allSrcCount++;
+
+    if($srcData["owner"]=='visuddhinanda'){
+		$srcData["owner"] = 'ba5463f3-72d1-4410-858e-eadd10884713';
+	}
+    if($srcData["owner"]=='test7'){
+		$srcData["owner"] = '6bd2f4d7-d970-419c-8ee5-f4bac42f4bc1';
+	}
+    if($srcData["owner"]=='Dhammadassi'){
+		$srcData["owner"] = 'd8538ebd-d369-4777-b99a-3ccb1aff8bfc';
+	}
+    if($srcData["owner"]=='pannava'){
+		$srcData["owner"] = '4db550c4-bc1b-43f2-a518-2740cb478f37';
+	}
+    if($srcData["owner"]=='NST'){
+		$srcData["owner"] = '5c23e629-56a3-48e9-97c7-2af73b59c3b9';
+	}
+    if($srcData["owner"]=='viranyani'){
+		$srcData["owner"] = 'C1AB2ABF-EAA8-4EEF-B4D9-3854321852B4';
+	}
+    if($srcData["owner"]=='test6'){
+		$srcData["owner"] = 'f81c7140-64b4-4025-b58c-45a3b386324a';
+	}
+	if($srcData["owner"]=='test28'){
+		$srcData["owner"] = 'df0ad9bc-c0cd-4cd9-af05-e43d23ed57f0';
+	}
+	if($srcData["owner"]=='290fd808-2f46-4b8c-b300-0367badd67ed'){
+		$srcData["owner"] = 'f81c7140-64b4-4025-b58c-45a3b386324a';
+	}
+	if($srcData["owner"]=='BA837178-9ABD-4DD4-96A0-D2C21B756DC4'){
+		$srcData["owner"] = 'ba5463f3-72d1-4410-858e-eadd10884713';
+	}
+	$stmtUser->execute(array($srcData["owner"]));
+	$userId = $stmtUser->fetch(PDO::FETCH_ASSOC);
+	if(!$userId){
+		fwrite(STDERR,time()."error,no user id {$srcData["owner"]}".PHP_EOL);
+		continue;
+	}
+	if(strlen($srcData["owner"])>36){
+		fwrite(STDERR,time().",error,user id too long {$srcData["owner"]}".PHP_EOL);
+		continue;	
+	}
+
+    $srcData["status"] = 30;
+
+    if(empty($srcData["modify_time"])){
+        $srcData["modify_time"] = $srcData["create_time"];
+    }
+
+    if($srcData["create_time"] < 15987088320){
+        $srcData["create_time"] *= 1000;
+    }
+    if($srcData["modify_time"] < 15987088320){
+        $srcData["modify_time"] *= 1000;
+    }
+	//查询是否已经插入
+	$queryExsit = "SELECT id  FROM ".$dest_table." WHERE book = ? and paragraph = ? and word_start=? and word_end = ? ";
+	$getExist = $PDO_DEST->prepare($queryExsit);
+	$getExist->execute(array($srcData["book"],$srcData["paragraph"],$srcData["begin"],$srcData["end"]));
+	$exist = $getExist->fetch(PDO::FETCH_ASSOC);
+	if($exist){
+		continue;
+	}
+	#插入目标表
+	$created_at = date("Y-m-d H:i:s.",$srcData["create_time"]/1000).($srcData["create_time"]%1000)." UTC";
+	$updated_at = date("Y-m-d H:i:s.",$srcData["modify_time"]/1000).($srcData["modify_time"]%1000)." UTC";
+	$commitData = array(
+            $snowflake->id(),
+			$srcData["book"],
+			$srcData["paragraph"],
+			$srcData["begin"],
+			$srcData["end"],
+			$srcData["text"],
+			$srcData["length"],
+			$srcData["owner"],
+			$srcData["lang"],
+			$srcData["status"],
+			$srcData["create_time"],
+			$srcData["modify_time"],
+			$created_at,
+			$updated_at
+		);
+	$stmtDEST->execute($commitData);
+
+	$count++;	
+	$allInsertCount++;
+
+
+	if($count ==10000){
+		#10000行输出log 一次
+		echo "finished $count".PHP_EOL;
+		$count=0;
+	}	
+}
+
+fwrite(STDOUT,"insert done $allInsertCount in $allSrcCount ".PHP_EOL) ;
+fwrite(STDOUT, "all done in ".(time()-$start)."s".PHP_EOL);
+
+fclose($fpError);
+
+
+
+

+ 95 - 0
v1/scripts/migrations/20220214163000_custom_book_id_copy.php

@@ -0,0 +1,95 @@
+<?php
+/*
+迁移  article 库
+从旧数据表中提取数据插入到新的表
+插入时用uuid判断是否曾经插入
+曾经插入就不插入了
+*/
+require_once __DIR__."/../../../public/app/config.php";
+require_once __DIR__."/../../../public/app/public/snowflakeid.php";
+
+set_exception_handler(function($e){
+	fwrite(STDERR,"error-msg:".$e->getMessage().PHP_EOL);
+	fwrite(STDERR,"error-file:".$e->getFile().PHP_EOL);
+	fwrite(STDERR,"error-line:".$e->getLine().PHP_EOL);
+	exit;
+});
+$start = time();
+# 雪花id
+$snowflake = new SnowFlakeId();
+
+$fpError = fopen(__DIR__.'/log/'.basename($_SERVER['PHP_SELF'],'.php').".err.data.csv",'w');
+
+
+
+# 
+$src_db = _SQLITE_DB_HOSTSETTING_;#源数据库
+$src_table = _SQLITE_TABLE_HOSTSETTING_;#源表名
+
+$dest_db = _PG_DB_CUSTOM_BOOK_ID_;#目标数据库
+$dest_table = _PG_TABLE_CUSTOM_BOOK_ID_;#目标表名
+
+fwrite(STDOUT,"migarate custom book id".PHP_EOL);
+
+
+#打开源数据库
+$PDO_SRC = new PDO($src_db,_DB_USERNAME_,_DB_PASSWORD_,array(PDO::ATTR_PERSISTENT=>true));
+$PDO_SRC->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+fwrite(STDOUT,"open src table".PHP_EOL);
+
+#打开目标数据库
+$PDO_DEST = new PDO($dest_db,_DB_USERNAME_,_DB_PASSWORD_,array(PDO::ATTR_PERSISTENT=>true));
+$PDO_DEST->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+fwrite(STDOUT,"open dest table".PHP_EOL);
+
+$queryInsert = "INSERT INTO ".$dest_table." 
+								(
+									key,
+									value) 
+									VALUES (? , ?  )";
+$stmtDEST = $PDO_DEST->prepare($queryInsert);
+
+$commitData = [];
+$allInsertCount = 0;
+$allSrcCount = 0;
+$count = 0;
+
+
+#从源数据表中读取
+$query = "SELECT key,value  FROM ".$src_table. " where key = 'max_book_number' ";
+$stmtSrc = $PDO_SRC->prepare($query);
+$stmtSrc->execute();
+if($srcData = $stmtSrc->fetch(PDO::FETCH_ASSOC)){
+	$allSrcCount++;
+	//查询是否已经插入
+	$queryExsit = "SELECT id  FROM ".$dest_table." WHERE key = ? ";
+	$getExist = $PDO_DEST->prepare($queryExsit);
+	$getExist->execute(array($srcData["key"]));
+	$exist = $getExist->fetch(PDO::FETCH_ASSOC);
+	if($exist){
+        echo "key max_book_number exist value=".$getExist['value'];
+		exit;
+	}
+	#插入目标表
+
+	$commitData = array(
+			$srcData["key"],
+			$srcData["value"]
+		);
+	$stmtDEST->execute($commitData);
+
+	$count++;	
+	$allInsertCount++;
+
+}else{
+    echo "no row read".PHP_EOL;
+}
+
+fwrite(STDOUT,"insert done $allInsertCount in $allSrcCount ".PHP_EOL) ;
+fwrite(STDOUT, "all done in ".(time()-$start)."s".PHP_EOL);
+
+fclose($fpError);
+
+
+
+