Sfoglia il codice sorgente

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

bhikkhu-kosalla-china 3 anni fa
parent
commit
7b659d69cb

+ 1 - 1
app/Console/Commands/ExportOffline.php

@@ -48,7 +48,7 @@ class ExportOffline extends Command
         //导出译文
         $this->call('export:sentence');
         //导出原文
-        $this->call('export:sentence',['channel'=>'28f2e33a-794f-11ed-9481-1395f6ece2de']);
+        $this->call('export:sentence',['--type'=>'original']);
         shell_exec("XZ_OPT=-9 tar jcvf ".storage_path("app/public/export/offline.tar.xz")." ".storage_path("app/public/export/offline"));
         return 0;
     }

+ 14 - 5
app/Console/Commands/ExportSentence.php

@@ -6,6 +6,7 @@ use Illuminate\Console\Command;
 use Illuminate\Support\Facades\Storage;
 use App\Models\Sentence;
 use App\Models\Channel;
+use App\Http\Api\ChannelApi;
 
 class ExportSentence extends Command
 {
@@ -46,12 +47,20 @@ class ExportSentence extends Command
             $file_suf = $channel_id;
             $channels[] = $channel_id;
         }else{
-            $file_suf = $channel_type;
             $channel_type = $this->option('type');
-            $nissaya_channel = Channel::where('type',$channel_type)->where('status',30)->select('uid')->get();
-            foreach ($nissaya_channel as $key => $value) {
-                # code...
-                $channels[] = $value->uid;
+            $file_suf = $channel_type;
+            if($channel_type === "original"){
+                $pali_channel = ChannelApi::getSysChannel("_System_Pali_VRI_");
+                if($pali_channel === false){
+                    return 0;
+                }
+                $channels[] = $pali_channel;
+            }else{
+                $nissaya_channel = Channel::where('type',$channel_type)->where('status',30)->select('uid')->get();
+                foreach ($nissaya_channel as $key => $value) {
+                    # code...
+                    $channels[] = $value->uid;
+                }
             }
         }
         $db = Sentence::whereIn('channel_uid',$channels);

+ 1 - 1
app/Console/Commands/UpgradeCompound.php

@@ -107,7 +107,7 @@ class UpgradeCompound extends Command
 								->exists();
 
 			if($isExists){
-				$this->info("found:{$word->real}");
+				$this->info("Exists:{$word->real}");
 				continue;
 			}
 			# code...

+ 1 - 0
app/Console/Commands/UpgradeDictSysWbwExtract.php

@@ -8,6 +8,7 @@ namespace App\Console\Commands;
 
 use Illuminate\Console\Command;
 use App\Models\UserDict;
+use App\Http\Api\DictApi;
 
 class UpgradeDictSysWbwExtract extends Command
 {

+ 1 - 1
app/Console/Commands/UpgradeWbwTemplate.php

@@ -86,7 +86,7 @@ class UpgradeWbwTemplate extends Command
                 ];
 
             }
-            $sent = \json_encode($wbwContent);
+            $sent = \json_encode($wbwContent,JSON_UNESCAPED_UNICODE);
 
 			$newRow = Sentence::firstOrNew(
 				[

+ 1 - 136
app/Http/Api/MdRender.php

@@ -32,7 +32,7 @@ class MdRender{
 
         $html = str_replace("<p>","<div>",$html);
         $html = str_replace("</p>","</div>",$html);
-        $html = "<xml>".$html."</xml>";
+        $html = "<span>".$html."</span>";
         return $html;
     }
     public static function xmlQueryId(string $xml, string $id):string{
@@ -174,141 +174,6 @@ class MdRender{
      */
     public static function render($markdown,$channelId,$queryId=null,$mode='read'){
         return MdRender::render2($markdown,$channelId,$queryId,$mode);
-
-        $html = MdRender::markdown2wiki($markdown);
-
-        /**
-         * 转换为Mustache模版
-         */
-        $pattern = "/\{\{(.+?)\}\}/";
-        $replacement = "\n{{#function}}\n$1\n{{/function}}\n";
-        $html = preg_replace($pattern,$replacement,$html);
-
-        /**
-         * Mustache_Engine 处理Mustache模版
-         * 把Mustache模版内容转换为react组件
-         */
-        $m = new \Mustache_Engine(array('entity_flags' => ENT_QUOTES));
-        $html = $m->render($html, array(
-          'function' => function($text) use($m,$channelId) {
-            //1: 解析
-            $param = explode("|",$text);
-            //3: 处理业务逻辑
-            $tplName = trim($param[0]);
-            $innerString = "";
-            switch($tplName){
-                case 'term':
-                    //获取实际的参数
-                    $word = trim($param[1]);
-                    $props = Cache::remember("/term/{$channelId}/{$word}",
-                          60,
-                          function() use($word,$channelId){
-                            $tplParam = DhammaTerm::where("word",$word)->first();
-                            $output = [
-                                "word" => $word,
-                                "channel" => $channelId,
-                                ];
-                                $innerString = $output["word"];
-                            if($tplParam){
-                                $output["id"] = $tplParam->guid;
-                                $output["meaning"] = $tplParam->meaning;
-                                $innerString = $output["meaning"];
-                                if(!empty($tplParam->other_meaning)){
-                                    $output["meaning2"] = $tplParam->other_meaning;
-                                }
-                            }
-                            return $output;
-                          });
-                    break;
-                case 'note':
-                    if(isset($param[1])){
-                        $props = ["note"=>trim($param[1])];
-                    }
-                    if(isset($param[2])){
-                        $props["trigger"] = trim($param[2]);
-                        $innerString = $props["trigger"];
-                    }
-                    break;
-                case 'sent':
-                    $tplName = "sentedit";
-                    $innerString = "";
-                    $sentInfo = explode('@',trim($param[1]));
-                    $sentId = $sentInfo[0];
-                    $Sent = new CorpusController();
-                    if(empty($channelId)){
-                        $channels = [];
-                    }else{
-                        $channels = [$channelId];
-                    }
-                    if(isset($sentInfo[1])){
-                        $channels = [$sentInfo[1]];
-                    }
-                    $html = $Sent->getSentTpl($param[1],$channels);
-                    return $html;
-                    break;
-                case 'quote':
-                    $paraId = trim($param[1]);
-                    $props = Cache::remember("/quote/{$channelId}/{$paraId}",
-                          60,
-                          function() use($paraId,$channelId){
-                            $para = \explode('-',$paraId);
-                            $output = [
-                                "paraId" => $paraId,
-                                "channel" => $channelId,
-                                "innerString" => $paraId,
-                                ];
-                            if(count($para)<2){
-                                return $output;
-                            }
-                            $PaliText = PaliText::where("book",$para[0])
-                                                ->where("paragraph",$para[1])
-                                                ->select(['toc','path'])
-                                                ->first();
-
-                            if($PaliText){
-                                $output["pali"] = $PaliText->toc;
-                                $output["paliPath"] = \json_decode($PaliText->path);
-                                $innerString = $PaliText->toc;
-                            }
-                            return $output;
-                          });
-                    break;
-                case 'exercise':
-                    $exeId = trim($param[1]);
-                    $exeContent = trim($param[2]);
-                    $props = Cache::remember("/quote/{$channelId}/{$exeId}",
-                          60,
-                          function() use($exeId,$channelId){
-                            $output = [
-                                "id" => $exeId,
-                                "channel" => $channelId,
-                                ];
-                            return $output;
-                          });
-                    #替换句子
-                    $pattern = "/\(\((.+?)\)\)/";
-                    $replacement = '{{sent|$1}}';
-                    Log::info("content{$exeContent}");
-
-                    $exeContent = preg_replace($pattern,$replacement,$exeContent);
-                    Log::info("content{$exeContent}");
-                    $innerString = MdRender::render($exeContent,$channelId);
-                    break;
-                default:
-                    break;
-            }
-            //4: 返回拼好的字符串
-
-            $props = base64_encode(\json_encode($props));
-            $html = "<MdTpl tpl='{$tplName}' props='{$props}' >{$innerString}</MdTpl>";
-            return $html;
-          }
-        ));
-        if(substr_count($html,"<p>") === 1){
-            $html = \str_replace(['<p>','</p>'],'',$html);
-        }
-        //LOG::info($html);
-        return "<xml>{$html}</xml>";
     }
 
 }

+ 26 - 0
app/Http/Api/TemplateRender.php

@@ -42,6 +42,9 @@ class TemplateRender{
             case 'exercise':
                 $result = $this->render_exercise();
                 break;
+            case 'article':
+                $result = $this->render_article();
+                break;
             default:
                 # code...
                 $result = [
@@ -120,7 +123,30 @@ class TemplateRender{
             'tpl'=>'exercise',
             ];
     }
+    private  function render_article(){
 
+        $type = $this->get_param($this->param,"type",1);
+        $id = $this->get_param($this->param,"id",2);
+        $title = $this->get_param($this->param,"title",3);
+        $channel = $this->get_param($this->param,"channel",4);
+        $props = [
+                    "type" => $type,
+                    "id" => $id,
+                    "channel" => $channel,
+                ];
+        if(empty($channel)){
+            $props['channel'] = $this->channel_id;
+        }
+        if(!empty($title)){
+            $props['title'] = $title;
+        }
+        return [
+            'props'=>base64_encode(\json_encode($props)),
+            'html'=>"",
+            'tag'=>'span',
+            'tpl'=>'article',
+            ];
+    }
     private  function render_quote(){
         $paraId = $this->get_param($this->param,"para",1);
         $channelId = $this->channel_id;

+ 21 - 4
app/Http/Controllers/ArticleController.php

@@ -6,6 +6,8 @@ use App\Models\Article;
 use Illuminate\Http\Request;
 use Illuminate\Support\Str;
 use App\Http\Resources\ArticleResource;
+use App\Http\Api\AuthApi;
+use Illuminate\Support\Facades\DB;
 
 class ArticleController extends Controller
 {
@@ -35,8 +37,8 @@ class ArticleController extends Controller
 				break;
         }
         //处理搜索
-        if(isset($_GET["search"])){
-            $table = $table->where('title', 'like', $_GET["search"]."%");
+        if($request->has("search") && !empty($request->has("search"))){
+            $table = $table->where('title', 'like', "%".$request->get("search")."%");
         }
         //获取记录总条数
         $count = $table->count();
@@ -188,12 +190,27 @@ class ArticleController extends Controller
 
     /**
      * Remove the specified resource from storage.
-     *
+     * @param  \Illuminate\Http\Request  $request
      * @param  \App\Models\Article  $article
      * @return \Illuminate\Http\Response
      */
-    public function destroy(Article $article)
+    public function destroy(Request $request,Article $article)
     {
         //
+        $user = AuthApi::current($request);
+        if(!$user){
+            return $this->error(__('auth.failed'));
+        }
+        //判断当前用户是否有指定的studio的权限
+        if($user['user_uid'] !== $article->owner){
+            return $this->error(__('auth.failed'));
+        }
+        $delete = 0;
+        DB::transaction(function() use($article,$delete){
+            //TODO 删除文集中的文章
+            $delete = $article->delete();
+        });
+
+        return $this->ok($delete);
     }
 }

+ 57 - 2
app/Http/Controllers/ArticleMapController.php

@@ -3,6 +3,8 @@
 namespace App\Http\Controllers;
 
 use App\Models\ArticleCollection;
+use App\Models\Article;
+
 use Illuminate\Http\Request;
 use App\Http\Resources\ArticleMapResource;
 
@@ -37,6 +39,37 @@ class ArticleMapController extends Controller
     public function store(Request $request)
     {
         //
+        $validated = $request->validate([
+                'anthology_id' => 'required',
+                'operation' => 'required'
+            ]);
+        switch ($validated['operation']) {
+            case 'add':
+                # code...
+                $count=0;
+                foreach ($request->get('article_id') as $key => $article) {
+                    # code...
+
+                    if(!ArticleCollection::where('article_id',$article)
+                                        ->where('collect_id',$request->get('anthology_id'))
+                                        ->exists())
+                    {
+                        $new = new ArticleCollection;
+                        $new->id = app('snowflake')->id();
+                        $new->article_id = $article;
+                        $new->collect_id = $request->get('anthology_id');
+                        $new->title = Article::find($article)->title;
+                        $new->level = 1;
+                        $new->save();
+                        $count++;
+                    }
+                }
+                return $this->ok($count);
+                break;
+            default:
+                # code...
+                break;
+        }
     }
 
     /**
@@ -54,12 +87,34 @@ class ArticleMapController extends Controller
      * Update the specified resource in storage.
      *
      * @param  \Illuminate\Http\Request  $request
-     * @param  \App\Models\ArticleCollection  $articleCollection
+     * @param  string  $id
      * @return \Illuminate\Http\Response
      */
-    public function update(Request $request, ArticleCollection $articleCollection)
+    public function update(Request $request, string $id)
     {
         //
+        $validated = $request->validate([
+            'operation' => 'required'
+        ]);
+        switch ($validated['operation']) {
+            case 'anthology':
+                $delete = ArticleCollection::where('collect_id',$id)->delete();
+                $count=0;
+                foreach ($request->get('data') as $key => $row) {
+                    # code...
+                    $new = new ArticleCollection;
+                    $new->id = app('snowflake')->id();
+                    $new->article_id = $row["article_id"];
+                    $new->collect_id = $id;
+                    $new->title = $row["title"];
+                    $new->level = $row["level"];
+                    $new->children = $row["children"];
+                    $new->save();
+                    $count++;
+                }
+                return $this->ok($count);
+                break;
+        }
     }
 
     /**

+ 4 - 2
app/Http/Controllers/AuthController.php

@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
 use Firebase\JWT\JWT;
 use Firebase\JWT\Key;
 use App\Http\Api;
+use Illuminate\Support\Facades\Log;
 
 class AuthController extends Controller
 {
@@ -66,8 +67,8 @@ class AuthController extends Controller
         //
     }
     public function signIn(Request $request){
-        $userinfo = new \UserInfo();
-        $user = $userinfo->signIn($request->get('username'),$request->get('password'));
+        $userInfo = new \UserInfo();
+        $user = $userInfo->signIn($request->get('username'),$request->get('password'));
         if($user){
             $ExpTime = time() + 60 * 60 * 24 * 365;
             $key = env('APP_KEY');
@@ -80,6 +81,7 @@ class AuthController extends Controller
             $jwt = JWT::encode($payload,$key,'HS512');
             return $this->ok($jwt);
         }else{
+            Log::info($userInfo->getLog());
             return $this->error('invalid token');
         }
     }

+ 67 - 0
app/Http/Controllers/CaseController.php

@@ -0,0 +1,67 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Http\Request;
+use App\Tools\CaseMan;
+
+class CaseController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function index()
+    {
+        //
+    }
+
+    /**
+     * Store a newly created resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return \Illuminate\Http\Response
+     */
+    public function store(Request $request)
+    {
+        //
+    }
+
+    /**
+     * 输入一个单词,输出三藏中所有可能的变形
+     *
+     * @param  string  $word
+     * @return \Illuminate\Http\Response
+     */
+    public function show($word)
+    {
+        //
+        $case  = new CaseMan();
+        $result = $case->BaseToWord($word);
+        return $this->ok(['rows'=>$result,'count'=>count($result)]);
+    }
+
+    /**
+     * Update the specified resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  int  $id
+     * @return \Illuminate\Http\Response
+     */
+    public function update(Request $request, $id)
+    {
+        //
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     *
+     * @param  int  $id
+     * @return \Illuminate\Http\Response
+     */
+    public function destroy($id)
+    {
+        //
+    }
+}

+ 56 - 3
app/Http/Controllers/ChannelController.php

@@ -6,6 +6,8 @@ require_once __DIR__.'/../../../public/app/ucenter/function.php';
 
 use App\Models\Channel;
 use App\Models\Sentence;
+use App\Models\DhammaTerm;
+use App\Models\WbwBlock;
 use App\Models\PaliSentence;
 use App\Http\Controllers\AuthController;
 use Illuminate\Http\Request;
@@ -15,6 +17,7 @@ use App\Http\Api\StudioApi;
 use App\Http\Api\ShareApi;
 use App\Http\Api\PaliTextApi;
 use Illuminate\Support\Arr;
+use Illuminate\Support\Facades\DB;
 
 class ChannelController extends Controller
 {
@@ -44,9 +47,33 @@ class ChannelController extends Controller
                     return $this->error(__('auth.failed'));
                 }
 				break;
-            case 'user-in-chapter':
+            case 'user-edit':
+                /**
+                 * 某用户有编辑权限的
+                 */
                 #获取user所有有权限的channel列表
                 $user = AuthApi::current($request);
+                if(!$user){
+                    return $this->error(__('auth.failed'));
+                }
+                $channelById = [];
+                $channelId = [];
+                //获取共享channel
+                $allSharedChannels = ShareApi::getResList($user['user_uid'],2);
+                foreach ($allSharedChannels as $key => $value) {
+                    # code...
+                    if($value['power']>=20){
+                        $channelId[] = $value['res_id'];
+                        $channelById[$value['res_id']] = $value;
+                    }
+                }
+                $table = Channel::select($indexCol)
+                            ->whereIn('uid', $channelId)
+                            ->orWhere('owner_uid',$user['user_uid']);
+                break;
+            case 'user-in-chapter':
+                #获取user 在某章节 所有有权限的channel列表
+                $user = AuthApi::current($request);
                 if($user){
                     $channelById = [];
                     $channelId = [];
@@ -110,6 +137,7 @@ class ChannelController extends Controller
         }
         //获取数据
         $result = $table->get();
+//TODO 将下面代码转移到resource
         if($result){
             if($request->has('progress')){
                 //获取进度
@@ -285,12 +313,37 @@ class ChannelController extends Controller
 
     /**
      * Remove the specified resource from storage.
-     *
+     * @param  \Illuminate\Http\Request  $request
      * @param  \App\Models\Channel  $channel
      * @return \Illuminate\Http\Response
      */
-    public function destroy(Channel $channel)
+    public function destroy(Request $request,Channel $channel)
     {
         //
+        $user = AuthApi::current($request);
+        if(!$user){
+            return $this->error(__('auth.failed'));
+        }
+        //判断当前用户是否有指定的studio的权限
+        if($user['user_uid'] !== $channel->owner_uid){
+            return $this->error(__('auth.failed'));
+        }
+        //查询其他资源
+        if(Sentence::where("channel_uid",$channel->uid)->exists()){
+            return $this->error("译文有数据无法删除");
+        }
+        if(DhammaTerm::where("channal",$channel->uid)->exists()){
+            return $this->error("术语有数据无法删除");
+        }
+        if(WbwBlock::where("channel_uid",$channel->uid)->exists()){
+            return $this->error("逐词解析有数据无法删除");
+        }
+        $delete = 0;
+        DB::transaction(function() use($channel,$delete){
+            //TODO 删除相关资源
+            $delete = $channel->delete();
+        });
+
+        return $this->ok($delete);
     }
 }

+ 28 - 8
app/Http/Controllers/CollectionController.php

@@ -6,6 +6,8 @@ use App\Models\Collection;
 use Illuminate\Http\Request;
 use Illuminate\Support\Str;
 use Illuminate\Support\Facades\Log;
+use App\Http\Api\AuthApi;
+use Illuminate\Support\Facades\DB;
 
 require_once __DIR__.'/../../../public/app/ucenter/function.php';
 
@@ -57,8 +59,8 @@ class CollectionController extends Controller
 			    return $this->error("没有查询到数据");
 				break;
 		}
-        if(isset($_GET["search"])){
-            $table = $table->where('title', 'like', $_GET["search"]."%");
+        if($request->has("search") && !empty($request->has("search"))){
+            $table = $table->where('title', 'like', "%".$request->get("search")."%");
         }
         $count = $table->count();
         if(isset($_GET["order"]) && isset($_GET["dir"])){
@@ -195,10 +197,10 @@ class CollectionController extends Controller
      * @param  string  $id
      * @return \Illuminate\Http\Response
      */
-    public function update(Request $request, $id)
+    public function update(Request $request, string $id)
     {
         //
-        $collection  = Collection::where('uid', $id)->first();
+        $collection  = Collection::find($id);
         if($collection){
             //鉴权
             Log::info("找到文集");
@@ -207,7 +209,9 @@ class CollectionController extends Controller
                 $collection->title = $request->get('title');
                 $collection->subtitle = $request->get('subtitle');
                 $collection->summary = $request->get('summary');
-                $collection->article_list = \json_encode($request->get('aritcle_list')) ;
+                if($request->has('aritcle_list')){
+                    $collection->article_list = \json_encode($request->get('aritcle_list'));
+                } ;
                 $collection->lang = $request->get('lang');
                 $collection->status = $request->get('status');
                 $collection->modify_time = time()*1000;
@@ -228,12 +232,28 @@ class CollectionController extends Controller
 
     /**
      * Remove the specified resource from storage.
-     *
-     * @param  \App\Models\Collection  $collection
+     * @param  \Illuminate\Http\Request  $request
+     * @param  string  $id
      * @return \Illuminate\Http\Response
      */
-    public function destroy(Collection $collection)
+    public function destroy(Request $request,string $id)
     {
         //
+        $user = AuthApi::current($request);
+        if(!$user){
+            return $this->error(__('auth.failed'));
+        }
+        //判断当前用户是否有指定的studio的权限
+        $collection = Collection::find($id);
+        if($user['user_uid'] !== $collection['owner']){
+            return $this->error(__('auth.failed'));
+        }
+        $delete = 0;
+        DB::transaction(function() use($collection,$delete){
+            //TODO 删除文集中的文章
+            $delete = $collection->delete();
+        });
+
+        return $this->ok($delete);
     }
 }

+ 183 - 11
app/Http/Controllers/CorpusController.php

@@ -14,7 +14,9 @@ use Illuminate\Support\Facades\Cache;
 use App\Http\Api\MdRender;
 use App\Http\Api\SuggestionApi;
 use App\Http\Api\ChannelApi;
+use App\Http\Api\UserApi;
 use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Arr;
 
 class CorpusController extends Controller
 {
@@ -72,7 +74,12 @@ class CorpusController extends Controller
     public function getSentTpl($id,$channels,$mode='edit',$onlyProps=false){
         $sent = [];
         $sentId = \explode('-',$id);
-        $channelId = ChannelApi::getSysChannel('_System_Wbw_VRI_');
+        if($mode==='read'){
+            $channelId = ChannelApi::getSysChannel('_System_Pali_VRI_');
+        }else{
+            $channelId = ChannelApi::getSysChannel('_System_Wbw_VRI_');
+        }
+
         if($channelId !== false){
             array_push($channels,$channelId);
         }
@@ -161,6 +168,7 @@ class CorpusController extends Controller
         $this->result['content'] = $this->makeContent($record,$mode,$indexChannel);
         return $this->ok($this->result);
     }
+
     public function showChapter($id,$mode='read')
     {
         //
@@ -198,10 +206,10 @@ class CorpusController extends Controller
         $paraTo = $sentId[1]+$chapter->chapter_len-1;
         //获取标题
         $heading = PaliText::select(["book","paragraph","level"])
-        ->where('book',$sentId[0])
-        ->whereBetween('paragraph',[$paraFrom,$paraTo])
-        ->where('level','<',8)
-        ->get();
+                            ->where('book',$sentId[0])
+                            ->whereBetween('paragraph',[$paraFrom,$paraTo])
+                            ->where('level','<',8)
+                            ->get();
         //将标题段落转成索引数组 以便输出标题层级
         $indexedHeading = [];
         foreach ($heading as $key => $value) {
@@ -277,6 +285,100 @@ class CorpusController extends Controller
         $sent = [];
         $sent["origin"] = [];
         $sent["translation"] = [];
+        //获取句子编号列表
+
+        $sentList = [];
+        foreach ($record as $key => $value) {
+            $currSentId = "{$value->book_id}-{$value->paragraph}-{$value->word_start}-{$value->word_end}";
+            $sentList[$currSentId]=[$value->book_id ,$value->paragraph,$value->word_start,$value->word_end];
+            $value['sid'] = "{$currSentId}_{$value->channel_uid}";
+        }
+        //遍历列表查找每个句子的所有channel的数据,并填充
+        foreach ($sentList as $currSentId => $arrSentId) {
+            # code...
+            $sent = $this->newSent($arrSentId[0],$arrSentId[1],$arrSentId[2],$arrSentId[3]);
+            $sent["origin"] = [];
+            $sent["translation"] = [];
+            foreach ($indexChannel as $channelId => $info) {
+                # code...
+                $sid = "{$currSentId}_{$channelId}";
+                $newSent = [
+                    "content"=>"",
+                    "html"=> "",
+                    "book"=> $arrSentId[0],
+                    "para"=> $arrSentId[1],
+                    "wordStart"=> $arrSentId[2],
+                    "wordEnd"=> $arrSentId[3],
+                    "channel"=> [
+                        "name"=>$info->name,
+                        "type"=>$info->type,
+                        "id"=> $info->uid,
+                    ],
+                    "updateAt"=> "",
+                    "suggestionCount" => SuggestionApi::getCountBySent($arrSentId[0],$arrSentId[1],$arrSentId[2],$arrSentId[3],$channelId),
+                ];
+
+                $row = Arr::first($record,function($value,$key) use($sid){
+                    return $value['sid']===$sid;
+                });
+                if($row){
+                    $newSent['content'] = $row->content;
+                    $newSent['html'] = "";
+                    $newSent["editor"]=UserApi::getById($row->editor_uid);
+                    $newSent['updateAt'] = $row->updated_at;
+                    switch ($info->type) {
+                        case 'wbw':
+                        case 'original':
+                            //
+                                // 在编辑模式下。
+                                // 如果是原文,查看是否有逐词解析数据,
+                                // 有的话优先显示。
+                                // 阅读模式直接显示html原文
+                                // 传过来的数据一定有一个原文channel
+                                //
+                            if($mode !== "read"){
+                                $newSent['channel']['type'] = "wbw";
+                                if(isset($this->wbwChannels[0])){
+                                    //存在一个translation channel
+                                    //尝试查找逐词解析数据。找到,替换现有数据
+                                    $wbwData = $this->getWbw($arrSentId[0],$arrSentId[1],$arrSentId[2],$arrSentId[3],$channelId);
+                                    if($wbwData){
+                                        $newSent['content'] = $wbwData;
+                                        $newSent['html'] = "";
+                                    }
+                                }
+                            }else{
+                                $newSent['html'] = $row->content;
+                                $newSent['content'] = "";
+                            }
+
+                            break;
+                        default:
+                            //译文需要markdown渲染
+                            $newSent['html'] = Cache::remember("/sent/{$channelId}/{$currSentId}",10,
+                                                function() use($row){
+                                                    return MdRender::render($row->content,$row->channel_uid);
+                                                });
+                            break;
+                    }
+                }
+                switch ($info->type) {
+                    case 'wbw':
+                    case 'original':
+                        array_push($sent["origin"],$newSent);
+                        break;
+                    default:
+                        array_push($sent["translation"],$newSent);
+                        break;
+                }
+            }
+            if($onlyProps){
+                return $sent;
+            }
+            $content = $this->pushSent($content,$sent,0,$mode);
+        }
+
+/*
         foreach ($record as $key => $value) {
             # 遍历结果生成html文件
             $currSentId = $value->book_id.'-'.$value->paragraph.'-'.$value->word_start.'-'.$value->word_end;
@@ -354,10 +456,19 @@ class CorpusController extends Controller
                     }
                 }
 			}else{
-                $html = Cache::remember("/sent/{$value->channel_uid}/{$currSentId}",10,
-                function() use($value){
-                    return MdRender::render($value->content,$value->channel_uid);
-                });
+                if($indexChannel[$value->channel_uid]->type==="original"){
+                    //原文直接使用
+                    $html = Cache::remember("/sent/{$value->channel_uid}/{$currSentId}",10,
+                            function() use($value){
+                                return $value->content;
+                            });
+                }else{
+                    //译文需要markdown渲染
+                    $html = Cache::remember("/sent/{$value->channel_uid}/{$currSentId}",10,
+                            function() use($value){
+                                return MdRender::render($value->content,$value->channel_uid);
+                            });
+                }
             }
 
             $newSent = [
@@ -396,11 +507,72 @@ class CorpusController extends Controller
         if($onlyProps){
             return $sent;
         }
-		$content = $this->pushSent($content,$sent,0,$mode);
+        $content = $this->pushSent($content,$sent,0,$mode);
+*/
         $output = \implode("",$content);
-        return "<xml>{$output}</xml>";
+        return "<div>{$output}</div>";
     }
+    private function getWbw($book,$para,$start,$end,$channel){
+        /**
+         * 非阅读模式下。原文使用逐词解析数据。
+         * 优先加载第一个translation channel 如果没有。加载默认逐词解析。
+         */
+
+        //获取逐词解析数据
+        $wbwBlock = WbwBlock::where('channel_uid',$channel)
+                            ->where('book_id',$book)
+                            ->where('paragraph',$para)
+                            ->select('uid')
+                            ->first();
+        if(!$wbwBlock){
+            return false;
+        }
+        //找到逐词解析数据
+        $wbwData = Wbw::where('block_uid',$wbwBlock->uid)
+                      ->whereBetween('wid',[$start,$end])
+                      ->select(['data','uid'])
+                      ->orderBy('wid')
+                      ->get();
+        $wbwContent = [];
+        foreach ($wbwData as $wbwrow) {
+            $wbw = str_replace("&nbsp;",' ',$wbwrow->data);
+            $wbw = str_replace("<br>",' ',$wbw);
+
+            $xmlString = "<root>" . $wbw . "</root>";
+            try{
+                $xmlWord = simplexml_load_string($xmlString);
+            }catch(Exception $e){
+                continue;
+            }
+            $wordsList = $xmlWord->xpath('//word');
+            foreach ($wordsList as $word) {
+                $case = \str_replace(['#','.'],['$',''],$word->case->__toString());
+                $case = \str_replace('$$','$',$case);
+                $case = trim($case);
+                $case = trim($case,"$");
+                $wbwContent[] = [
+                    'uid'=>$wbwrow->uid,
+                    'word'=>['value'=>$word->pali->__toString(),'status'=>0],
+                    'real'=> ['value'=>$word->real->__toString(),'status'=>0],
+                    'meaning'=> ['value'=>\explode('$',$word->mean->__toString()) ,'status'=>0],
+                    'type'=> ['value'=>$word->type->__toString(),'status'=>0],
+                    'grammar'=> ['value'=>$word->gramma->__toString(),'status'=>0],
+                    'case'=> ['value'=>\explode('$',$case),'status'=>0],
+                    'parent'=> ['value'=>$word->parent->__toString(),'status'=>0],
+                    'style'=> ['value'=>$word->style->__toString(),'status'=>0],
+                    'factors'=> ['value'=>$word->org->__toString(),'status'=>0],
+                    'factorMeaning'=> ['value'=>$word->om->__toString(),'status'=>0],
+                    'confidence'=> 0.5,
+                    'hasComment'=>Discussion::where('res_id',$wbwrow->uid)->exists(),
+                ];
+            }
+        }
+        return \json_encode($wbwContent,JSON_UNESCAPED_UNICODE);
 
+    }
+    /**
+     * 将句子放进结果列表
+     */
 	private function pushSent($result,$sent,$level=0,$mode='read'){
 
 		$sentProps = base64_encode(\json_encode($sent)) ;

+ 6 - 5
app/Http/Controllers/CourseController.php

@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
 use App\Http\Api\AuthApi;
 use App\Http\Api\StudioApi;
 use App\Http\Resources\CourseResource;
+use Illuminate\Support\Facades\DB;
 
 class CourseController extends Controller
 {
@@ -227,11 +228,11 @@ class CourseController extends Controller
 
     /**
      * Remove the specified resource from storage.
-     *
+     * @param  \Illuminate\Http\Request  $request
      * @param  \App\Models\Course  $course
      * @return \Illuminate\Http\Response
      */
-    public function destroy(Course $course)
+    public function destroy(Request $request,Course $course)
     {
         //
         $user = AuthApi::current($request);
@@ -239,16 +240,16 @@ class CourseController extends Controller
             return $this->error(__('auth.failed'));
         }
         //判断当前用户是否有指定的studio的权限
-        if($user['user_uid'] !== StudioApi::getIdByName($request->get('studio'))){
+        if($user['user_uid'] !== $course->studio_id){
             return $this->error(__('auth.failed'));
         }
         $delete = 0;
-        DB::transaction(function() use($delete){
+        DB::transaction(function() use($delete,$course){
             //删除group member
             $memberDelete = CourseMember::where('course_id',$course->id)->delete();
             $delete = $course->delete();
         });
 
-        $this->ok($delete);
+        return $this->ok($delete);
     }
 }

+ 31 - 11
app/Http/Controllers/DhammaTermController.php

@@ -265,18 +265,38 @@ class DhammaTermController extends Controller
      */
     public function destroy(DhammaTerm $dhammaTerm,Request $request)
     {
-        //
-        $arrId = json_decode($request->get("id"),true) ;
-		$count = 0;
-		foreach ($arrId as $key => $id) {
-			# code...
-			$result = DhammaTerm::where('id', $id)
-							->where('owner', $_COOKIE["user_uid"])
-							->delete();
-            if($result){
-                $count++;
+        /**
+         * 一次删除多个单词
+         */
+        if(isset($_COOKIE["user_uid"])){
+            $user_uid = $_COOKIE["user_uid"];
+        }else{
+            $user = AuthApi::current($request);
+            if(!$user){
+                return $this->error(__('auth.failed'));
             }
-		}
+            $user_uid = $user['user_uid'];
+        }
+
+        if($request->has("uuid")){
+            $count = DhammaTerm::whereIn('guid', $request->get("id"))
+                            ->where('owner', $user_uid)
+                            ->delete();
+        }else{
+            $arrId = json_decode($request->get("id"),true) ;
+            $count = 0;
+
+            foreach ($arrId as $key => $id) {
+                # code...
+                $result = DhammaTerm::where('id', $id)
+                                ->where('owner', $user_uid)
+                                ->delete();
+                if($result){
+                    $count++;
+                }
+            }
+        }
+
 		return $this->ok($count);
     }
 }

+ 10 - 8
app/Http/Controllers/GroupController.php

@@ -102,7 +102,7 @@ class GroupController extends Controller
             return $this->error(__('auth.failed'));
         }
         //判断当前用户是否有指定的studio的权限
-        if($user['user_uid'] !== StudioApi::getIdByName($request->get('studio'))){
+        if($user['user_uid'] !== StudioApi::getIdByName($request->get('studio_name'))){
             return $this->error(__('auth.failed'));
         }
         //查询是否重复
@@ -112,6 +112,7 @@ class GroupController extends Controller
 
         $group = new GroupInfo;
         $group->id = app('snowflake')->id();
+        $group->uid = Str::uuid();
         $group->name = $request->get('name');
         $group->owner = $user['user_uid'];
         $group->create_time = time()*1000;
@@ -180,27 +181,28 @@ class GroupController extends Controller
 
     /**
      * Remove the specified resource from storage.
-     *
-     * @param  \App\Models\Group  $group
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \App\Models\GroupInfo  $group
      * @return \Illuminate\Http\Response
      */
-    public function destroy(Group $group)
+    public function destroy(Request $request,GroupInfo $group)
     {
         //
         $user = AuthApi::current($request);
         if(!$user){
             return $this->error(__('auth.failed'));
         }
-        //判断当前用户是否有指定的studio的权限
-        if($user['user_uid'] !== StudioApi::getIdByName($request->get('studio'))){
+        //判断当前用户是否有指定的 group 的删除权限
+        if($user['user_uid'] !== $group->owner){
             return $this->error(__('auth.failed'));
         }
-        DB::transaction(function(){
+        $delete = 0;
+        DB::transaction(function() use($group,$delete){
             //删除group member
             $memberDelete = GroupMember::where('group_id',$group->uid)->delete();
             $delete = $group->delete();
         });
 
-        $this->ok('ok');
+        return $this->ok($delete);
     }
 }

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

@@ -36,7 +36,11 @@ class ProgressChapterController extends Controller
         }else{
             $offset = 0;
         }
-
+        if($request->has('limit')){
+            $limit = (int)$request->get('limit');
+        }else{
+            $limit = 20;
+        }
         $channel_id = $request->get('channel');
 
         //
@@ -311,7 +315,7 @@ class ProgressChapterController extends Controller
 						left join channels as ch on pcd.channel_id = ch.uid
 						where ch.status >= 30 $channel_type
                         order by pcd.created_at desc
-                        limit 20 offset ?
+                        limit {$limit} offset ?
                     ) tpc
                     left join $pt as pt on tpc.book = pt.book and tpc.para = pt.paragraph;";
                 $chapters = DB::select($query,$param);

+ 86 - 78
app/Http/Controllers/SentenceController.php

@@ -32,95 +32,65 @@ class SentenceController extends Controller
                 $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;
+            case 'channel':
+                $sent = explode(',',$request->get('sentence')) ;
+                $query = [];
+                foreach ($sent as $value) {
+                    # code...
+                    $ids = explode('-',$value);
+                    $query[] = $ids;
+                }
+                $table = Sentence::select($indexCol)
+                                ->where('channel_uid', $request->get('channel'))
+                                ->whereIns(['book_id','paragraph','word_start','word_end'],$query);
                 break;
 			default:
 				# code...
 				break;
 		}
+        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();
 		if($result){
 			return $this->ok(["rows"=>$result,"count"=>$count]);
 		}else{
 			return $this->error("没有查询到数据");
 		}
     }
-
+    /**
+     * 用channel 和句子编号列表查询句子
+     */
+    public function sent_in_channel(Request $request){
+        $sent = $request->get('sentences') ;
+        $query = [];
+        foreach ($sent as $value) {
+            # code...
+            $ids = explode('-',$value);
+            $query[] = $ids;
+        }
+        $table = Sentence::select(['id','book_id','paragraph','word_start','word_end','content','channel_uid','updated_at'])
+                        ->where('channel_uid', $request->get('channel'))
+                        ->whereIns(['book_id','paragraph','word_start','word_end'],$query);
+        $result = $table->get();
+        if($result){
+            return $this->ok(["rows"=>$result,"count"=>count($result)]);
+        }else{
+            return $this->error("没有查询到数据");
+        }
+    }
     /**
      * Show the form for creating a new resource.
      *
@@ -139,7 +109,45 @@ class SentenceController extends Controller
      */
     public function store(Request $request)
     {
-        //
+        //鉴权
+        $user = \App\Http\Api\AuthApi::current($request);
+        if(!$user ){
+            //未登录用户
+            return $this->error(__('auth.failed'));
+        }
+        $channel = Channel::where('uid',$request->get('channel'))->first();
+        if(!$channel){
+            return $this->error(__('auth.failed'));
+        }
+        if($channel->owner_uid !== $user["user_uid"]){
+            //判断是否为协作
+            $power = ShareApi::getResPower($user["user_uid"],$channel->uid);
+            if($power<30){
+                return $this->error(__('auth.failed'));
+            }
+        }
+        foreach ($request->get('sentences') as $key => $sent) {
+            # code...
+            $row = Sentence::firstOrNew([
+                "book_id"=>$sent['book_id'],
+                "paragraph"=>$sent['paragraph'],
+                "word_start"=>$sent['word_start'],
+                "word_end"=>$sent['word_end'],
+                "channel_uid"=>$channel->uid,
+            ],[
+                "id"=>app('snowflake')->id(),
+                "uid"=>Str::orderedUuid(),
+            ]);
+            $row->content = $sent['content'];
+            $row->strlen = mb_strlen($sent['content'],"UTF-8");
+            $row->language = $channel->lang;
+            $row->status = $channel->status;
+            $row->editor_uid = $user["user_uid"];
+            $row->create_time = time()*1000;
+            $row->modify_time = time()*1000;
+            $row->save();
+        }
+        return $this->ok(count($request->get('sentences')));
     }
 
     /**

+ 38 - 15
app/Http/Controllers/UserDictController.php

@@ -7,6 +7,7 @@ use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Redis;
 use Illuminate\Support\Facades\Log;
 use App\Http\Api;
+use App\Http\Api\AuthApi;
 
 class UserDictController extends Controller
 {
@@ -179,21 +180,43 @@ class UserDictController extends Controller
         //
 		Log::info("userDictController->destroy start");
 		Log::info("userDictController->destroy id= {$id}");
-		$arrId = json_decode($request->get("id"),true) ;
-		$count = 0;
-		foreach ($arrId as $key => $id) {
-			# 找到对应数据
-			$data = UserDict::find($id);
-			//查看是否有权限删除
-			if($data->creator_id == $_COOKIE["user_id"]){
-				$result = UserDict::where('id', $id)
-								->delete();
-				$count += $result;
-				$updateOk = $this->update_sys_wbw($data);
-				$this->update_redis($data);
-			}
-		}
-		return $this->ok([$count,$updateOk]);
+
+        if(isset($_COOKIE["user_id"])){
+            $user_id = $_COOKIE["user_id"];
+        }else{
+            $user = AuthApi::current($request);
+            if(!$user){
+                return $this->error(__('auth.failed'));
+            }
+            $user_id = $user['user_id'];
+        }
+        if($request->has("id")){
+            $arrId = json_decode($request->get("id"),true) ;
+            $count = 0;
+            foreach ($arrId as $key => $id) {
+                # 找到对应数据
+                $data = UserDict::find($id);
+                //查看是否有权限删除
+                if($data->creator_id == $user_id){
+                    $result = UserDict::where('id', $id)
+                                    ->delete();
+                    $count += $result;
+                    $updateOk = $this->update_sys_wbw($data);
+                    $this->update_redis($data);
+                }
+            }
+            return $this->ok([$count,$updateOk]);
+        }else{
+            //删除单个单词
+            $userDict = UserDict::find($id);
+            //判断当前用户是否有指定的studio的权限
+            if((int)$user_id !== $userDict->creator_id){
+                return $this->error(__('auth.failed'));
+            }
+            $delete = $userDict->delete();
+            return $this->ok($delete);
+        }
+
     }
 	public function delete(Request $request){
 		Log::info("userDictController->delete start");

+ 1 - 0
app/Models/Collection.php

@@ -12,5 +12,6 @@ class Collection extends Model
     protected $casts = [
         'uid' => 'string'
     ];
+    protected $keyType = 'string';
     public  $incrementing = false;
 }

+ 9 - 3
app/Providers/AppServiceProvider.php

@@ -4,7 +4,10 @@ namespace App\Providers;
 
 use Godruoyi\Snowflake\Snowflake;
 use Godruoyi\Snowflake\LaravelSequenceResolver;
-
+use App\Tools\QueryBuilderMacro;
+use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
+use Illuminate\Database\Eloquent\Relations\Relation;
+use Illuminate\Database\Query\Builder as QueryBuilder;
 use Illuminate\Support\ServiceProvider;
 
 class AppServiceProvider extends ServiceProvider
@@ -17,7 +20,7 @@ class AppServiceProvider extends ServiceProvider
     public function register()
     {
         //雪花算法
-		
+
 		$this->app->singleton('snowflake', function () {
             return (new Snowflake(env('SNOWFLAKE_DATA_CENTER_ID'),env('SNOWFLAKE_WORKER_ID')))
                 ->setStartTimeStamp(strtotime(config('database.snowflake.start'))*1000)
@@ -25,7 +28,7 @@ class AppServiceProvider extends ServiceProvider
                     new LaravelSequenceResolver($this->app->get('cache')->store()
                 ));
         });
-		
+
     }
 
     /**
@@ -36,5 +39,8 @@ class AppServiceProvider extends ServiceProvider
     public function boot()
     {
         //
+        QueryBuilder::mixin($queryBuilderMacro = $this->app->make(QueryBuilderMacro::class));
+        EloquentBuilder::mixin($queryBuilderMacro);
+        Relation::mixin($queryBuilderMacro);
     }
 }

+ 32 - 5
app/Tools/CaseMan.php

@@ -4,6 +4,7 @@ namespace App\Tools;
 use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\Log;
 use App\Models\UserDict;
+use App\Models\WordIndex;
 
 
 class CaseMan
@@ -24,7 +25,33 @@ class CaseMan
      * @return void
      */
 	public function BaseToWord($base){
-
+        $newWord = array();
+        $case = new CaseEnding();
+        foreach ($case->ending as  $ending) {
+            # code...
+            $endingLen = mb_strlen($ending[0], "UTF-8");
+            $wordEnd = mb_substr($base, 0 - $endingLen, null, "UTF-8");
+            if ($wordEnd === $ending[0]) {
+                //匹配成功
+                $word = mb_substr($base, 0, mb_strlen($base, "UTF-8") - $endingLen, "UTF-8") . $ending[1];
+                if(!isset($newWord[$word])){
+                    $count = WordIndex::where('word',$word)->select(['count','bold'])->first();
+                    if($count){
+                        $newWord[$word] = ["count"=>$count->count,"bold"=>$count->bold];
+                    }else{
+                        $newWord[$word] = false;
+                    }
+                }
+            }
+        }
+        $result = [];
+        foreach ($newWord as $key => $value) {
+            # code...
+            if($value !== false){
+                $result[] = ['word'=>$key,"count"=>$value["count"],"bold"=>$value["bold"]];
+            }
+        }
+        return $result;
 	}
 
 	/**
@@ -47,7 +74,7 @@ class CaseMan
 						# code...
 						$endingLen = mb_strlen($ending[1], "UTF-8");
 						$wordEnd = mb_substr($currWord, 0 - $endingLen, null, "UTF-8");
-						if ($wordEnd == $ending[1]) {
+						if ($wordEnd === $ending[1]) {
 							//匹配成功
 							$base = mb_substr($currWord, 0, mb_strlen($currWord, "UTF-8") - $endingLen, "UTF-8") . $ending[0];
 							if(!isset($newBase[$base])){
@@ -3337,9 +3364,9 @@ class CaseEnding{
 		["eti","anīya",".ti:base.",".fpp.",0.99],
 		["oti","anīya",".ti:base.",".fpp.",0.99],
 		["ati","āpeti",".v:base.",".caus.",0.99],
-		["ati","yati",".v:base.",".caus.",0.99],
-		["oti","āpeti",".v:base.",".pp.",0.99],
-		["oti","yati",".v:base.",".pp.",0.99],
+		["ati","yati",".v:base.",".pass.",0.99],
+		["oti","āpeti",".v:base.",".caus.",0.99],
+		["oti","yati",".v:base.",".pass.",0.99],
 	];
 	public $union = [
 		["ssa","ssāpi"],

+ 76 - 0
app/Tools/QueryBuilderMacro.php

@@ -0,0 +1,76 @@
+<?php
+/**
+ * 作者:guanguans
+ * 链接:https://juejin.cn/post/7116779474783305735
+ * 来源:稀土掘金
+ * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
+ */
+namespace App\Tools;
+
+use Illuminate\Contracts\Support\Arrayable;
+
+class QueryBuilderMacro
+{
+    public function whereIns(): callable
+    {
+        /* @var Arrayable|array[] $values */
+        return function (array $columns, $values, string $boolean = 'and', bool $not = false) {
+            /** @var \Illuminate\Database\Eloquent\Builder $this */
+            $type = $not ? 'not in' : 'in';
+
+            $rawColumns = implode(',', $columns);
+
+            $values instanceof Arrayable and $values = $values->toArray();
+            $values = array_map(function ($value) use ($columns) {
+                if (array_is_list($value)) {
+                    return $value;
+                }
+
+                return array_reduce($columns, function ($sortedValue, $column) use ($value) {
+                    $sortedValue[$column] = $value[$column] ?? trigger_error(
+                        sprintf(
+                            '%s: %s',
+                            'The value of the column is not found in the array.',
+                            $column
+                        ),
+                        E_USER_ERROR
+                    );
+
+                    return $sortedValue;
+                }, []);
+            }, $values);
+
+            $rawValue = sprintf('(%s)', implode(',', array_fill(0, count($columns), '?')));
+            $rawValues = implode(',', array_fill(0, count($values), $rawValue));
+
+            $raw = "($rawColumns) $type ($rawValues)";
+
+            return $this->whereRaw($raw, $values, $boolean);
+        };
+    }
+
+    public function whereNotIns(): callable
+    {
+        return function (array $columns, $values) {
+            /** @var \Illuminate\Database\Eloquent\Builder $this */
+            return $this->whereIns($columns, $values, 'and', true);
+        };
+    }
+
+    public function orWhereIns(): callable
+    {
+        return function (array $columns, $values) {
+            /** @var \Illuminate\Database\Eloquent\Builder $this */
+            return $this->whereIns($columns, $values, 'or');
+        };
+    }
+
+    public function orWhereNotIns(): callable
+    {
+        return function (array $columns, $values) {
+            /** @var \Illuminate\Database\Eloquent\Builder $this */
+            return $this->whereIns($columns, $values, 'or', true);
+        };
+    }
+}
+

+ 36 - 0
database/migrations/2023_02_19_122318_add_index_created_at_in_sentences.php

@@ -0,0 +1,36 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddIndexCreatedAtInSentences extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('sentences', function (Blueprint $table) {
+            //
+            $table->index('created_at');
+            $table->index('updated_at');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('sentences', function (Blueprint $table) {
+            //
+            $table->dropIndex("sentences_created_at_index");
+            $table->dropIndex("sentences_updated_at_index");
+        });
+    }
+}

+ 29 - 9
public/app/ucenter/function.php

@@ -43,12 +43,15 @@ class UserInfo
 {
     private $dbh;
     private $buffer;
+    private $log;
+
     public function __construct()
     {
         $dns = _FILE_DB_USERINFO_;
         $this->dbh = new PDO($dns, "", "", array(PDO::ATTR_PERSISTENT => true));
         $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
-        $buffer = array();
+        $this->buffer = array();
+        $this->log = "";
     }
 
     public function getName($id)
@@ -56,8 +59,8 @@ class UserInfo
         if (empty($id)) {
             return array("nickname" => "", "username" => "");
         }
-        if (isset($buffer[$id])) {
-            return $buffer[$id];
+        if (isset($this->buffer[$id])) {
+            return $this->buffer[$id];
         }
         if ($this->dbh) {
             $query = "SELECT nickname,username FROM user WHERE id = ? or userid= ? ";
@@ -65,15 +68,15 @@ class UserInfo
             $stmt->execute(array($id,$id));
             $user = $stmt->fetchAll(PDO::FETCH_ASSOC);
             if (count($user) > 0) {
-                $buffer[$id] = array("nickname" => $user[0]["nickname"], "username" => $user[0]["username"]);
-                return $buffer[$id];
+                $this->buffer[$id] = array("nickname" => $user[0]["nickname"], "username" => $user[0]["username"]);
+                return $this->buffer[$id];
             } else {
-                $buffer[$id] = array("nickname" => "", "username" => "");
-                return $buffer[$id];
+                $this->buffer[$id] = array("nickname" => "", "username" => "");
+                return $this->buffer[$id];
             }
         } else {
-            $buffer[$id] = array("nickname" => "", "username" => "");
-            return $buffer[$id];
+            $this->buffer[$id] = array("nickname" => "", "username" => "");
+            return $this->buffer[$id];
         }
 	}
 	public function getId($uuid)
@@ -88,6 +91,8 @@ class UserInfo
             $user = $stmt->fetch(PDO::FETCH_ASSOC);
             if ($user) {
                 return $user["id"];
+            }else{
+                return 0;
             }
         } else {
             return 0;
@@ -105,6 +110,8 @@ class UserInfo
             $user = $stmt->fetch(PDO::FETCH_ASSOC);
             if ($user) {
                 return $user;
+            }else{
+                return false;
             }
         } else {
             return false;
@@ -148,10 +155,23 @@ class UserInfo
             if ($user) {
                 return $user;
             } else {
+                $query = "SELECT userid,id,password FROM user WHERE  username= ?";
+                $stmt = $this->dbh->prepare($query);
+                $stmt->execute(array($username));
+                $user = $stmt->fetch(PDO::FETCH_ASSOC);
+                if($user){
+                    $this->log .=  "username:{$username},pwd:{$user['password']}-".md5($password)."\n";
+                }else{
+                    $this->log .= "no user:{$username}\n";
+                }
                 return false;
             }
         } else {
             return false;
         }
 	}
+
+    public function getLog(){
+        return $this->log;
+    }
 }

+ 3 - 0
routes/api.php

@@ -34,6 +34,7 @@ use App\Http\Controllers\CourseMemberController;
 use App\Http\Controllers\ExerciseController;
 use App\Http\Controllers\ArticleMapController;
 use App\Http\Controllers\VocabularyController;
+use App\Http\Controllers\CaseController;
 
 /*
 |--------------------------------------------------------------------------
@@ -54,6 +55,7 @@ Route::group(['prefix' => 'v2'],function(){
 	Route::apiResource('wbw_templates',WbwTemplateController::class);
 	Route::apiResource('terms',DhammaTermController::class);
 	Route::apiResource('sentence',SentenceController::class);
+	Route::post('sent-in-channel',[SentenceController::class,"sent_in_channel"]);
 	Route::apiResource('sentpr',SentPrController::class);
 	Route::apiResource('progress',ProgressChapterController::class);
 	Route::apiResource('tag',TagController::class);
@@ -101,6 +103,7 @@ Route::group(['prefix' => 'v2'],function(){
     Route::apiResource('exercise',ExerciseController::class);
     Route::apiResource('article-map',ArticleMapController::class);
     Route::apiResource('vocabulary',VocabularyController::class);
+    Route::apiResource('case',CaseController::class);
 
     Route::get('guide/{lang}/{file}', function ($lang,$file) {
         $filename = public_path("app/users_guide/{$lang}/{$file}.md");