visuddhinanda 1 год назад
Родитель
Сommit
ca25837618

+ 49 - 0
api-v8/app/Console/Commands/ExportAiPaliWordToken.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+use App\Http\Api\DictApi;
+
+class ExportAiPaliWordToken extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'export:ai.pali.word.token';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'export ai pali word token';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return int
+     */
+    public function handle()
+    {
+        $this->info('export ai pali word token');
+        $dict_id = DictApi::getSysDict('robot_compound');
+        if(!$dict_id){
+            $this->error('没有找到 robot_compound 字典');
+            return 1;
+        }
+        return 0;
+    }
+}

+ 96 - 0
api-v8/app/Console/Commands/ExportAiTrainingData.php

@@ -0,0 +1,96 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\Log;
+use App\Models\Sentence;
+use App\Models\PaliSentence;
+use Illuminate\Support\Str;
+use App\Http\Api\MdRender;
+
+class ExportAiTrainingData extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'export:ai.training.data {--format=gz  : zip file format 7z,lzma,gz }';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'export ai training data';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return int
+     */
+    public function handle()
+    {
+        Log::debug('task export offline sentence-table start');
+        $filename = 'wikipali-offline-ai-training-'.date("Y-m-d").'.tsv';
+        $exportFile = storage_path('app/public/export/offline/'.$filename);
+        $fp = fopen($exportFile, 'w');
+        if ($fp === false) {
+            die('无法创建文件');
+        }
+
+        $channels = [
+            '19f53a65-81db-4b7d-8144-ac33f1217d34',
+        ];
+        $start = time();
+        foreach ($channels as $key => $channel) {
+            $db = Sentence::where('channel_uid',$channel);
+            $bar = $this->output->createProgressBar($db->count());
+            $srcDb = $db->select(['book_id','paragraph',
+                                    'word_start','word_end',
+                                    'content','content_type'])->cursor();
+            foreach ($srcDb as $sent) {
+                $content = MdRender::render($sent->content,
+                                [$channel],
+                                null,
+                                'read',
+                                'translation',
+                                $sent->content_type,
+                                'text',
+                                );
+                $origin = PaliSentence::where('book',$sent->book_id)
+                                        ->where('paragraph',$sent->paragraph)
+                                        ->where('word_begin',$sent->word_start)
+                                        ->where('word_end',$sent->word_end)
+                                        ->value('text');
+                $currData = array(
+                    $origin,
+                    str_replace("\n", "", $content),
+                    );
+
+                fwrite($fp, implode("\t", $currData)."\n");
+
+                $bar->advance();
+            }
+        }
+        fclose($fp);
+        $this->info((time() - $start).' seconds');
+        $this->call('export:zip',[
+            'filename'=>$filename,
+            'title' => 'wikipali ai training data',
+            'format'=> $this->option('format'),
+        ]);
+        return 0;
+    }
+}

+ 118 - 0
api-v8/app/Console/Commands/UpgradeDictSysPreference.php

@@ -0,0 +1,118 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+use App\Http\Api\DictApi;
+use App\Models\UserDict;
+use App\Models\WordIndex;
+
+class UpgradeDictSysPreference extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     * php artisan upgrade:dict.sys.preference
+     */
+    protected $signature = 'upgrade:dict.sys.preference';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'upgrade dict system preference';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return int
+     */
+    public function handle()
+    {
+        if(\App\Tools\Tools::isStop()){
+            return 0;
+        }
+        $this->info("start");
+        $dictList = [
+            'community_extract',
+            'robot_compound',
+            'system_regular',
+            'system_preference',
+        ];
+        $dict_id = array();
+        foreach ($dictList as $key => $value) {
+            $dict_id[$value] = DictApi::getSysDict($value);
+            if(!$dict_id[$value]){
+                $this->error("没有找到 {$value} 字典");
+                return 1;
+            }else{
+                $this->info("{$value} :{$dict_id[$value]}");
+            }
+        }
+
+        //搜索顺序
+        $order = [
+            '4d3a0d92-0adc-4052-80f5-512a2603d0e8',/* system irregular */
+            $dict_id['community_extract'],/* 社区字典*/
+            $dict_id['robot_compound'],
+            $dict_id['system_regular'],
+        ];
+        $words = WordIndex::orderBy('count', 'desc')->cursor();
+        $rows = 0;
+        $found = 0;
+        foreach ($words as $key => $word) {
+            if (preg_match('/\d/', $word->word)) {
+                continue;
+            }
+            $rows++;
+            $preference = null;
+            foreach ($order as $key => $dict) {
+                $preference = UserDict::where('word', $word->word)
+                                ->where('dict_id', $dict)
+                                ->whereNotNull('factors')
+                                ->where('factors','<>','')
+                                ->orderBy('confidence', 'desc')
+                                ->first();                # code...
+                if($preference){
+                    break;
+                }
+            }
+            if($preference){
+                $userDict = UserDict::firstOrNew([
+                    'word'=>$word->word,
+                    'dict_id'=>$dict_id['system_preference']
+                ],
+                [
+                    'id' => app('snowflake')->id(),
+                    'source' => '_ROBOT_',
+                    'create_time'=>(int)(microtime(true)*1000)
+                ]);
+                $userDict->factors = $preference->factors;
+                $userDict->parent = $preference->parent;
+                $userDict->confidence = $preference->confidence;
+                $userDict->language = 'cm';
+                $userDict->creator_id = 1;
+                $userDict->save();
+                $found++;
+            }
+            if($rows % 100 == 0){
+                $output = "[{$rows}] {$word->word} found:{$found}";
+                $this->info($output);
+                $found=0;
+            }
+        }
+        return 0;
+    }
+}

+ 47 - 0
api-v8/app/Http/Api/ProjectApi.php

@@ -0,0 +1,47 @@
+<?php
+namespace App\Http\Api;
+
+use App\Models\Project;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Facades\App;
+
+class ProjectApi{
+    public static function getById($id){
+        if(!$id){
+            return null;
+        };
+        $project = Project::where('id',$id)->first();
+        if($project){
+            return [
+                'id'=>$id,
+                'title'=>$project->title,
+                'type'=>$project->type,
+                'description'=>$project->description,
+            ];
+        }else{
+            return null;
+        }
+    }
+
+    public static function getListByIds($ids){
+        if(!$ids){
+            return null;
+        };
+        $projects = Project::whereIn('id',$ids)->get();
+        $output = array();
+        foreach ($ids as $key => $id) {
+            foreach ($projects as $project) {
+                if($project->id === $id){
+                    $output[] = [
+                        'id'=>$id,
+                        'title'=>$project->title,
+                        'type'=>$project->type,
+                        'description'=>$project->description,
+                    ];
+                    continue;
+                };
+            }
+        }
+        return $output;
+    }
+}

+ 45 - 0
api-v8/app/Http/Api/TaskApi.php

@@ -0,0 +1,45 @@
+<?php
+namespace App\Http\Api;
+
+use App\Models\Task;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Facades\App;
+
+class TaskApi{
+    public static function getById($id){
+        if(!$id){
+            return null;
+        };
+        $task = Task::where('id',$id)->first();
+        if($task){
+            return [
+                'id'=>$id,
+                'title'=>$task->title,
+                'description'=>$task->description,
+            ];
+        }else{
+            return null;
+        }
+    }
+
+    public static function getListByIds($ids){
+        if(!$ids){
+            return null;
+        };
+        $tasks = Task::whereIn('id',$ids)->get();
+        $output = array();
+        foreach ($ids as $key => $id) {
+            foreach ($tasks as $task) {
+                if($task->id === $id){
+                    $output[] = [
+                        'id'=>$id,
+                        'title'=>$task->title,
+                        'description'=>$task->description,
+                    ];
+                    continue;
+                };
+            }
+        }
+        return $output;
+    }
+}

+ 76 - 0
api-v8/app/Http/Controllers/CommandController.php

@@ -0,0 +1,76 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Http\Request;
+use App\Http\Api\AuthApi;
+use App\Http\Api\Mq;
+
+class CommandController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function index()
+    {
+        //
+        return $this->ok('ok');
+    }
+
+    /**
+     * Store a newly created resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return \Illuminate\Http\Response
+     */
+    public function store(Request $request)
+    {
+        //
+        $user = AuthApi::current($request);
+        if(!$user || $user['user_uid'] !== 'ba5463f3-72d1-4410-858e-eadd10884713'){
+            return $this->error(__('auth.failed'),403,403);
+        }
+
+        Mq::publish('task',[
+            'name'=>$request->get('name'),
+            'param'=>$request->get('param'),
+        ]);
+        return $this->ok('ok');
+    }
+
+    /**
+     * Display the specified resource.
+     *
+     * @param  int  $id
+     * @return \Illuminate\Http\Response
+     */
+    public function show($id)
+    {
+        //
+    }
+
+    /**
+     * 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)
+    {
+        //
+    }
+}

+ 111 - 0
api-v8/app/Http/Controllers/DictPreferenceController.php

@@ -0,0 +1,111 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Support\Facades\Log;
+use Illuminate\Http\Request;
+
+use App\Models\UserDict;
+use App\Models\WordIndex;
+use App\Http\Resources\DictPreferenceResource;
+use App\Http\Api\DictApi;
+
+class DictPreferenceController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function index(Request $request)
+    {
+        //
+        $dict_id = DictApi::getSysDict('system_preference');
+        if(!$dict_id){
+            return $this->error('没有找到 system_preference 字典',200,200);
+        }
+        $table = WordIndex::where('user_dicts.dict_id',$dict_id)
+                    ->leftJoin('user_dicts','word_indices.word','=','user_dicts.word')
+                    ->select([
+                        'user_dicts.id',
+                        'word_indices.word',
+                        'word_indices.count',
+                        'user_dicts.factors',
+                        'user_dicts.parent',
+                        'user_dicts.note',
+                        'user_dicts.confidence',
+                    ]);
+        //处理搜索
+        if(!empty($request->get("keyword"))){
+            $table = $table->where('word_indices.word', 'like', "%".$request->get("keyword")."%");
+        }
+
+        //获取记录总条数
+        $count = $table->count();
+        //处理排序
+        $table = $table->orderBy($request->get("order",'word_indices.count'),
+                                    $request->get("dir",'desc'));
+        //处理分页
+        $table = $table->skip($request->get("offset",0))
+                        ->take($request->get("limit",200));
+        //获取数据
+        $result = $table->get();
+        return $this->ok([
+            "rows"=>DictPreferenceResource::collection($result),
+            "count"=>$count
+        ]);
+    }
+
+    /**
+     * 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\UserDict  $userDict
+     * @return \Illuminate\Http\Response
+     */
+    public function show(UserDict $userDict)
+    {
+        //
+    }
+
+    /**
+     * Update the specified resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  string  $id
+     * @return \Illuminate\Http\Response
+     */
+    public function update(Request $request,  $id)
+    {
+        //
+		$newData = $request->all();
+		$result = UserDict::where('id', $id)
+				->update($newData);
+		if($result){
+			return $this->ok('ok');
+		}else{
+		    return $this->error("没有查询到数据");
+		}
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     *
+     * @param  \App\Models\UserDict  $userDict
+     * @return \Illuminate\Http\Response
+     */
+    public function destroy(UserDict $userDict)
+    {
+        //
+    }
+}

+ 162 - 0
api-v8/app/Http/Controllers/ProjectController.php

@@ -0,0 +1,162 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Models\Project;
+use Illuminate\Http\Request;
+use App\Http\Api\AuthApi;
+use App\Http\Api\StudioApi;
+use App\Http\Resources\ProjectResource;
+use Illuminate\Support\Str;
+use Illuminate\Support\Facades\Log;
+
+class ProjectController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function index(Request $request)
+    {
+        $user = AuthApi::current($request);
+        if(!$user){
+            Log::error('notification auth failed {request}',['request'=>$request]);
+            return $this->error(__('auth.failed'),401,401);
+        }
+        switch ($request->get('view')) {
+            case 'studio':
+                $table = Project::where('owner_id',$user['user_uid'])
+                            ->whereNull('parent_id');
+                if($request->get('type','normal') !== 'all'){
+                    $table = $table->where('type',$request->get('type','normal'));
+                }
+                break;
+            case 'project-tree':
+                $table = Project::where('id',$request->get('project_id'))
+                                ->orWhereJsonContains('path',$request->get('project_id'));
+                break;
+            default:
+                # code...
+                break;
+        }
+
+        if($request->has('keyword')){
+            $table = $table->where('title','like','%'.$request->get('keyword').'%');
+        }
+        if($request->has('status')){
+            $table = $table->whereIn('status',explode(',',$request->get('status')) );
+        }
+        $count = $table->count();
+
+        $sql = $table->toSql();
+        Log::debug('sql',['sql'=>$sql]);
+
+        $table = $table->orderBy($request->get('order','created_at'),$request->get('dir','desc'));
+
+        $table = $table->skip($request->get("offset",0))
+                    ->take($request->get('limit',10000));
+
+        $result = $table->get();
+
+        return $this->ok(
+            [
+            "rows" => ProjectResource::collection($result),
+            "count" => $count,
+            ]);
+    }
+
+    public function canEdit($user_uid,$studio_uid){
+        return $user_uid == $studio_uid;
+    }
+
+    /**
+     * Store a newly created resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return \Illuminate\Http\Response
+     */
+    public function store(Request $request)
+    {
+        //
+        $user = AuthApi::current($request);
+        if(!$user){
+            return $this->error(__('auth.failed'),401,401);
+        }
+        $studioId = StudioApi::getIdByName($request->get('studio_name'));
+        if(!$this->canEdit($user['user_uid'],$studioId)){
+            return $this->error(__('auth.failed'),403,403);
+        }
+        $new = Project::firstOrNew(['id'=>$request->get('id')]);
+        if(Str::isUuid($request->get('id'))){
+            $new->id = $request->get('id');
+        }else{
+            $new->id =  Str::uuid();
+        }
+        $new->title = $request->get('title');
+        $new->description = $request->get('description');
+        $new->parent_id = $request->get('parent_id');
+        $new->editor_id = $user['user_uid'];
+        $new->owner_id = $studioId;
+        $new->type = $request->get('type','normal');
+
+        if(Str::isUuid($request->get('parent_id'))){
+            $parentPath = Project::where('id',$request->get('parent_id'))->value('path');
+            $parentPath = json_decode($parentPath);
+            if(!is_array($parentPath)){
+                $parentPath = array();
+            }
+            array_push($parentPath,$new->parent_id);
+            $new->path = json_encode($parentPath,JSON_UNESCAPED_UNICODE);
+        }
+        $new->save();
+
+        return $this->ok(new ProjectResource($new));
+    }
+
+    /**
+     * Display the specified resource.
+     *
+     * @param  \App\Models\Project  $project
+     * @return \Illuminate\Http\Response
+     */
+    public function show(Project $project)
+    {
+        //
+        return $this->ok(new ProjectResource($project));
+    }
+
+    /**
+     * Show the form for editing the specified resource.
+     *
+     * @param  \App\Models\Project  $project
+     * @return \Illuminate\Http\Response
+     */
+    public function edit(Project $project)
+    {
+        //
+    }
+
+    /**
+     * Update the specified resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \App\Models\Project  $project
+     * @return \Illuminate\Http\Response
+     */
+    public function update(Request $request, Project $project)
+    {
+        //
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     *
+     * @param  \App\Models\Project  $project
+     * @return \Illuminate\Http\Response
+     */
+    public function destroy(Project $project)
+    {
+        //
+    }
+}

+ 85 - 0
api-v8/app/Http/Controllers/TaskAssigneeController.php

@@ -0,0 +1,85 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Models\TaskAssignee;
+use Illuminate\Http\Request;
+
+class TaskAssigneeController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function index()
+    {
+        //
+    }
+
+    /**
+     * 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\TaskAssignee  $taskAssignee
+     * @return \Illuminate\Http\Response
+     */
+    public function show(TaskAssignee $taskAssignee)
+    {
+        //
+    }
+
+    /**
+     * Show the form for editing the specified resource.
+     *
+     * @param  \App\Models\TaskAssignee  $taskAssignee
+     * @return \Illuminate\Http\Response
+     */
+    public function edit(TaskAssignee $taskAssignee)
+    {
+        //
+    }
+
+    /**
+     * Update the specified resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \App\Models\TaskAssignee  $taskAssignee
+     * @return \Illuminate\Http\Response
+     */
+    public function update(Request $request, TaskAssignee $taskAssignee)
+    {
+        //
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     *
+     * @param  \App\Models\TaskAssignee  $taskAssignee
+     * @return \Illuminate\Http\Response
+     */
+    public function destroy(TaskAssignee $taskAssignee)
+    {
+        //
+    }
+}

+ 99 - 0
api-v8/app/Http/Controllers/UserMilestoneController.php

@@ -0,0 +1,99 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Http\Request;
+
+class UserMilestoneController 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)
+    {
+        //
+    }
+
+    /**
+     * Display the specified resource.
+     *
+     * @param  int  $id
+     * @return \Illuminate\Http\Response
+     */
+    public function show($studioName)
+    {
+        //
+        $user_uid = StudioApi::getIdByName($studioName);
+
+        $milestone = [];
+        $milestone[] = ['date'=>UserInfo::where('userid',$user_uid)->value('created_at'),'event'=>'sign-in'] ;
+        if(Wbw::where('creator_uid',$user_uid)->exists()){
+            $milestone[] = ['date'=>Wbw::where('creator_uid',$user_uid)
+                                       ->orderBy('created_at')
+                                       ->value('created_at'),
+                                       'event'=>'first-wbw'
+                           ] ;
+        }
+        if(Sentence::where('editor_uid',$user_uid)->exists()){
+            $milestone[] = ['date'=>Sentence::where('editor_uid',$user_uid)
+                                            ->orderBy('created_at')
+                                            ->value('created_at'),
+                                            'event'=>'first-translation'
+                            ] ;
+        }
+        if(DhammaTerm::where('owner',$user_uid)->exists()){
+            $milestone[] = ['date'=>DhammaTerm::where('owner',$user_uid)
+                                              ->orderBy('created_at')
+                                              ->value('created_at'),
+                                              'event'=>'first-term'
+                        ] ;
+
+        }
+        if(Course::where('studio_id',$user_uid)->exists()){
+            $milestone[] = ['date'=>Course::where('studio_id',$user_uid)
+                                           ->orderBy('created_at')
+                                           ->value('created_at'),
+                                           'event'=>'first-course'
+                                           ] ;
+        }
+
+
+        return $this->ok($milestone);
+    }
+
+    /**
+     * 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)
+    {
+        //
+    }
+}

+ 30 - 0
api-v8/app/Http/Resources/DictPreferenceResource.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class DictPreferenceResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
+     */
+    public function toArray($request)
+    {
+        $data = [
+            'id' => strval($this->id),
+            'word'=>$this->word,
+            'count'=>$this->count,
+            'parent'=>$this->parent,
+            'note'=>$this->note,
+            'factors'=>$this->factors,
+            'confidence'=>$this->confidence,
+            'updated_at'=>$this->updated_at,
+            'creator_id'=>$this->creator_id,
+           ];
+        return $data;
+    }
+}

+ 37 - 0
api-v8/app/Http/Resources/ProjectResource.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Resources\Json\JsonResource;
+use App\Http\Api\UserApi;
+use App\Http\Api\StudioApi;
+use App\Http\Api\ProjectApi;
+
+class ProjectResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
+     */
+    public function toArray($request)
+    {
+        $data = [
+            'id' => $this->id,
+            'title' => $this->title,
+            'type' => $this->type,
+            'description' => $this->description,
+            'executors_id' => json_decode($this->executors_id),
+            'parent_id' => $this->parent_id,
+            'parent' => ProjectApi::getById($this->parent_id),
+            'path' => ProjectApi::getListByIds(json_decode($this->path)),
+            'description' => $this->description,
+            "owner"=> StudioApi::getById($this->owner_id),
+            "editor"=> UserApi::getIdByUuid($this->editor_id),
+            'created_at' => $this->created_at,
+            'updated_at' => $this->updated_at,
+        ];
+        return $data;
+    }
+}

+ 106 - 0
api-v8/app/Http/Resources/TaskResource.php

@@ -0,0 +1,106 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Resources\Json\JsonResource;
+use App\Http\Api\UserApi;
+use App\Http\Api\StudioApi;
+use App\Http\Api\TaskApi;
+use App\Http\Api\ProjectApi;
+use App\Http\Api\MdRender;
+use App\Models\TaskAssignee;
+
+use Illuminate\Support\Str;
+
+class TaskResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
+     */
+    public function toArray($request)
+    {
+        /*
+  id: string;
+  title: string;
+  description?: string | null;
+  assignees?: IUser[] | null;
+  assignees_id?: string[] | null;
+  parent?: ITaskData | null;
+  parent_id?: string | null;
+  roles?: string[] | null;
+  executor?: IUser | null;
+  executor_id?: string | null;
+  executor_relation_task?: ITaskData | null;
+  executor_relation_task_id?: string | null;
+  pre_task?: ITaskData | null;
+  pre_task_id?: string | null;
+  is_milestone: boolean;
+  project?: IProject|null;
+  project_id?: string | null;
+  owner?: IStudio;
+  owner_id?: string | null;
+  editor?: IUser;
+  editor_id?: string | null;
+  status?: TTaskStatus;
+  created_at?: string;
+  updated_at?: string;
+  started_at?: string | null;
+  finished_at?: string | null;
+         */
+        $htmlRender = new MdRender([
+            'mode' => 'read',
+            'format'=> 'react',
+            'footnote' => true,
+            'origin' => $request->get('origin',true),
+            'paragraph' => $request->get('paragraph',false),
+        ]);
+        $data = [
+            'id' => $this->id,
+            'title' => $this->title,
+            'description' => $this->description,
+            'parent_id' => $this->parent_id,
+            'parent' => TaskApi::getById($this->parent_id),
+            'roles' => $this->roles,
+            'executor_id' => $this->executor_id,
+            'executor_relation_task_id' => $this->executor_relation_task_id,
+            'executor_relation_task' => TaskApi::getById($this->executor_relation_task_id),
+            'pre_task_id' => $this->pre_task_id,
+            'pre_task' => TaskApi::getById($this->pre_task_id),
+            'next_task_id' => $this->next_task_id,
+            'next_task' => TaskApi::getById($this->next_task_id),
+            'is_milestone' => $this->is_milestone,
+            'project_id' => $this->project_id,
+            'project' => ProjectApi::getById($this->project_id),
+            'owner_id' => $this->owner_id,
+            "owner"=> StudioApi::getById($this->owner_id),
+            'editor_id' => $this->editor_id,
+            "editor"=> UserApi::getByUuid($this->editor_id),
+            'order' => $this->order,
+            'status' => $this->status,
+            'created_at' => $this->created_at,
+            'updated_at' => $this->updated_at,
+            'started_at' => $this->started_at,
+            'finished_at' => $this->finished_at,
+        ];
+        $assignees = TaskAssignee::where('task_id',$this->id)->select('assignee_id')->get();
+        if(count($assignees)>0){
+            $assignees_id = [];
+            foreach ($assignees as $key => $value) {
+                $assignees_id[] = $value->assignee_id;
+            }
+            $data['assignees_id'] = $assignees_id;
+            $data['assignees'] = UserApi::getListByUuid($assignees_id);
+        }
+        if(!empty($this->description)){
+            $data["html"] = $htmlRender->convert($this->description,[]);
+        }
+
+        if(Str::isUuid($this->executor_id)){
+            $data["executor"] = UserApi::getByUuid($this->executor_id);
+        }
+        return $data;
+    }
+}

+ 11 - 0
api-v8/app/Models/Milestone.php

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

+ 16 - 0
api-v8/app/Models/Project.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class Project extends Model
+{
+    use HasFactory;
+    protected $primaryKey = 'id';
+    protected $casts = [
+        'id' => 'string'
+    ];
+    protected $fillable = ['id'];
+}

+ 23 - 0
api-v8/app/Models/Task.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class Task extends Model
+{
+    use HasFactory;
+    protected $primaryKey = 'id';
+    protected $casts = [
+        'id' => 'string'
+    ];
+    protected $fillable = ['id','owner_id','project_id'];
+
+    protected $dates = [
+        'created_at',
+        'updated_at',
+        'started_at',
+        'finished_at',
+    ];
+}

+ 17 - 0
api-v8/app/Models/TaskAssignee.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class TaskAssignee extends Model
+{
+    use HasFactory;
+
+    protected $primaryKey = 'id';
+    protected $casts = [
+        'id' => 'string'
+    ];
+    protected $fillable = ['id','task_id','assignee_id','editor_id'];
+}