visuddhinanda 2 سال پیش
والد
کامیت
02d9ba78fb

+ 139 - 0
app/Console/Commands/ExportArticle.php

@@ -0,0 +1,139 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\Http;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Str;
+use Illuminate\Support\Facades\Storage;
+
+use App\Tools\RedisClusters;
+use App\Tools\ExportDownload;
+use App\Http\Api\MdRender;
+
+
+class ExportArticle extends Command
+{
+    /**
+     * The name and signature of the console command.
+     * php artisan export:article 78c22ad3-58e2-4cf0-b979-67783ca3a375 123 --channel=7fea264d-7a26-40f8-bef7-bc95102760fb --format=html
+     * php artisan export:article 4732bcae-fb9d-4db4-b6b7-e8d0aa882f30 1234 --channel=7fea264d-7a26-40f8-bef7-bc95102760fb --anthology=eb9e3f7f-b942-4ca4-bd6f-b7876b59a523 --format=html
+     * @var string
+     */
+    protected $signature = 'export:article {id} {filename} {--anthology=} {--channel=}  {--origin=false} {--translation=true} {--format=tex} {--debug}';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'Command description';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return int
+     */
+    public function handle()
+    {
+        $this->info('task export chapter start');
+        Log::debug('task export chapter start');
+        if(\App\Tools\Tools::isStop()){
+            return 0;
+        }
+        $upload = new ExportDownload([
+            'filename'=>$this->argument('filename').'.zip',
+            'format'=>$this->option('format'),
+            'debug'=>$this->option('debug'),
+            'real_filename'=>'article',
+        ]);
+
+        MdRender::init();
+        $m = new \Mustache_Engine(array('entity_flags'=>ENT_QUOTES,
+                                        'delimiters' => '[[ ]]',
+                                        'escape'=>function ($value){
+                                            return $value;
+                                        }));
+
+        $api = 'http://127.0.0.1:8000/api';
+        $basicUrl = $api . '/v2/article/';
+        $sections = array();
+        $articles = array();
+
+        $url =  $basicUrl . $this->argument('id');
+        $this->info('http request url='.$url);
+        $response = Http::get($url,[
+                'mode' => 'read',
+                'format' => 'html',
+                'anthology'=> $this->option('anthology'),
+                'channel' => $this->option('channel'),
+            ]);
+        if($response->failed()){
+            $this->error('http request error');
+        }
+        if(!$response->json('ok')){
+            $this->error('http request error'.$response->json('message'));
+        }
+        $article = $response->json('data');
+        $bookMeta = array();
+        $bookMeta['book_author'] = "";
+        $bookMeta['book_title'] = $article['title_text'];
+
+        $articles[] = [
+            'level'=>1,
+            'title'=>$article['title_text'],
+            'content'=>isset($article['html'])?$article['html']:'',
+        ];
+        if(isset($article['toc'])){
+            $this->info('has sub article '. count($article['toc']));
+        }
+        foreach ($article['toc'] as $key => $value) {
+            $url =  $basicUrl . $value['key'];
+            $this->info('http request url='.$url);
+            $response = Http::get($url,[
+                    'mode' => 'read',
+                    'format' => 'html',
+                    'anthology'=> $this->option('anthology'),
+                    'channel' => $this->option('channel'),
+                ]);
+            if($response->failed()){
+                $this->error('http request error');
+                $this->error('http request error'.$response->json('message'));
+                continue;
+            }
+            if(!$response->json('ok')){
+                $this->error('http request error'.$response->json('message'));
+                continue;
+            }
+            $article = $response->json('data');
+            $this->info('sub article title='.$article['title_text']);
+            $articles[] = [
+                'level'=>$value['level'],
+                'title'=>$article['title_text'],
+                'content'=>isset($article['html'])?$article['html']:'',
+            ];
+        }
+        $sections[] = [
+            'name'=>'first',
+            'body'=>['articles'=>$articles],
+        ];
+        $this->info($upload->setStatus(0.9,'export content done'));
+        Log::debug('导出结束');
+
+
+        $upload->upload('article',$sections,$bookMeta);
+
+        return 0;
+    }
+}

+ 174 - 0
app/Tools/ExportDownload.php

@@ -0,0 +1,174 @@
+<?php
+namespace App\Tools;
+
+use Illuminate\Support\Str;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Facades\Storage;
+
+use App\Tools\RedisClusters;
+use App\Tools\Export;
+
+class ExportDownload
+{
+    protected $exportStatusKey = 'export/status';
+    protected $exportStatusExpiry = 3600;
+    protected $currExportStatusKey = '';
+    protected $realFilename = 'filename';
+    protected $format = 'tex';
+    protected $debug = false;
+    protected $zipFilename = 'file';
+
+        /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct($options)
+    {
+        if(isset($options['format'])){
+            $this->format = $options['format'];
+        }
+        if(isset($options['debug'])){
+            $this->debug = $options['debug'];
+        }
+        if(isset($options['filename'])){
+            $this->zipFilename = $options['filename'];
+        }
+        if(isset($options['real_filename'])){
+            $this->realFilename = $options['real_filename'];
+        }
+
+        $this->currExportStatusKey = $this->exportStatusKey . '/' . $this->zipFilename;
+    }
+
+    /**
+     * progress: 0-1, error -1
+     * message: string
+     */
+    public function setStatus($progress,$message=''){
+        $data = [
+                    'progress'=>$progress,
+                    'message'=>$message,
+                    'content-type'=>'application/zip',
+                ];
+        if($this->realFilename){
+            $data['filename'] = $this->realFilename;
+        }
+        RedisClusters::put($this->currExportStatusKey,
+                            $data,
+                            $this->exportStatusExpiry);
+        $percent = (int)($progress * 100);
+        return "[{$percent}%]".$message;
+    }
+
+
+    public function getStatus($filename){
+        return RedisClusters::get($this->exportStatusKey.'/'.$filename);
+    }
+
+    public function upload(string $type,$sections,$bookMeta){
+        $m = new \Mustache_Engine(array('entity_flags'=>ENT_QUOTES,
+                    'delimiters' => '[[ ]]',
+                    'escape'=>function ($value){
+                        return $value;
+                    }));
+
+        $tex = array();
+
+        $tplFile = resource_path("mustache/".$type.'/'.$this->format."/main.".$this->format);
+        $tpl = file_get_contents($tplFile);
+        $texContent = $m->render($tpl,$bookMeta);
+        $tex[] = ['name'=>'main.'.$this->format,
+                  'content'=>$texContent
+                 ];
+        foreach ($sections as $key => $section) {
+            $tplFile = resource_path("mustache/".$type.'/'.$this->format."/section.".$this->format);
+            $tpl = file_get_contents($tplFile);
+            $texContent = $m->render($tpl,$section['body']);
+            $tex[] = ['name'=>$section['name'],
+                  'content'=>$texContent
+                 ];
+        }
+
+        Log::debug('footnote start');
+        //footnote
+        $tplFile = resource_path("mustache/".$this->format."/footnote.".$this->format);
+        if(isset($GLOBALS['note']) &&
+            is_array($GLOBALS['note']) &&
+            count($GLOBALS['note'])>0 &&
+            file_exists($tplFile)){
+            $tpl = file_get_contents($tplFile);
+            $texContent = $m->render($tpl,['footnote'=>$GLOBALS['note']]);
+            $tex[] = ['name'=>'footnote.'.$this->format,
+                        'content'=>$texContent
+                        ];
+        }
+        if($this->debug){
+            $dir = "export/{$type}/".$this->format."/".$this->zipFilename."/";
+            foreach ($tex as $key => $section) {
+                Storage::disk('local')->put($dir.$section['name'], $section['content']);
+            }
+        }
+
+        Log::debug('footnote finished');
+        $this->setStatus(0.95,'export content done.');
+
+        //upload
+        $fileDate = '';
+        switch ($this->format) {
+            case 'tex':
+                $data = Export::ToPdf($tex);
+                if($data['ok']){
+                    $this->info($data['content-type']);
+                    $fileDate = $data['data'];
+                }else{
+                    $this->error($data['code'].'-'.$data['message']);
+                }
+                break;
+            case 'html':
+                $file = array();
+                foreach ($tex as $key => $section) {
+                    $file[] = $section['content'];
+                }
+                $fileDate = implode('',$file);
+                break;
+        }
+
+
+        $zipDir = storage_path('app/export/zip');
+        if(!is_dir($zipDir)){
+            $res = mkdir($zipDir,0755,true);
+            if(!$res){
+                Log::error('mkdir fail path='.$zipDir);
+                return 1;
+            }
+        }
+        $zipFile = $zipDir.'/'.Str::uuid().'.zip';
+
+        Log::debug('export chapter start zip  file='.$zipFile);
+        //zip压缩包里面的文件名
+        $realFilename = $this->realFilename.".".$this->format;
+
+        $zipOk = \App\Tools\Tools::zip($zipFile,[$realFilename=>$fileDate]);
+        if(!$zipOk){
+            Log::error('export chapter zip fail zip file='.$zipFile);
+            $this->setStatus(0.99,'export chapter zip fail');
+            $this->error('export chapter zip fail zip file='.$zipFile);
+            //TODO 给客户端返回错误状态
+            return 1;
+        }
+        $this->setStatus(0.96,'export chapter zip success');
+
+        $bucket = config('mint.attachments.bucket_name.temporary');
+        $tmpFile =  $bucket.'/'. $this->zipFilename ;
+        Log::debug('upload start filename='.$tmpFile);
+        $this->setStatus(0.97,'upload start ');
+        $zipData = file_get_contents($zipFile);
+        Storage::put($tmpFile, $zipData);
+        $this->setStatus(1,'export chapter done');
+        Log::debug('export chapter done, upload filename='.$tmpFile);
+
+        unlink($zipFile);
+        return true;
+    }
+}

+ 6 - 0
resources/mustache/article/html/footnote.html

@@ -0,0 +1,6 @@
+<h2 id="footnote">脚注</h2>
+<div class="footnote">
+[[#footnote]]
+<div class="item" id="footnote-[[sn]]"><a href="#note-[[sn]]" name="footnote-[[sn]]">[[sn]]</a>[[trigger]]:[[content]]</div>
+[[/footnote]]
+</div>

+ 9 - 0
resources/mustache/article/html/glossary.html

@@ -0,0 +1,9 @@
+<h2>glossary</h2>
+<div class="glossary">
+[[#pali]]
+<div class="item pali"><span class="head">[[pali]]</span><span class="content">[[meaning]]</span></div>
+[[/pali]]
+[[#meaning]]
+<div class="item meaning"><span class="head">[[meaning]]</span><span  class="content">[[pali]]</span></div>
+[[/meaning]]
+</div>

+ 48 - 0
resources/mustache/article/html/main.html

@@ -0,0 +1,48 @@
+<html lang="en-us">
+  <head>
+    <meta charset="utf-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+    <title>[[book_title]]</title>
+    <style>
+        p {
+            text-indent: 2em;
+            line-height: 1.7em;
+        }
+        a {
+            text-decoration: none;
+        }
+        .paragraph {
+            margin-bottom: 1em;
+        }
+
+        .row {
+            display: flex;
+        }
+        @media screen and (max-width: 960px){
+            .row {
+                flex-direction: column;
+            }
+        }
+        .col {
+            flex: 5;
+        }
+        code {
+            background-color: #ffe4c478;
+            padding: 2px 6px;
+            border-radius: 4px;
+        }
+        .origin {
+            font-family: times;
+        }
+    </style>
+</head>
+<body>
+<h1>[[book_title]]</h1>
+
+<h2>目录</h2>
+<ul>
+    [[#sections]]
+    <li><a href="#[[filename]]">[[filename]]</a></li>
+    [[/sections]]
+</ul>
+

+ 5 - 0
resources/mustache/article/html/section.html

@@ -0,0 +1,5 @@
+[[#articles]]
+<h[[level]]>[[title]]</h[[level]]>
+[[#subtitle]]<div class="subtitle">[[subtitle]]</div>[[/subtitle]]
+<div class="content">[[content]]</div>
+[[/articles]]