Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit cac1ecb

Browse files
feat: #66 import single html
1 parent 9c268e3 commit cac1ecb

File tree

4 files changed

+117
-67
lines changed

4 files changed

+117
-67
lines changed

‎app/Coding/Disk.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public function createFile(string $token, string $projectName, array $data): arr
5858
return $result['Response']['Data'];
5959
}
6060

61-
public function uploadAttachments(string $token, string $projectName, string $dataPath, array $attachments): array
61+
public function uploadAttachments(string $token, string $projectName, string $dataDir, array $attachments): array
6262
{
6363
if (empty($attachments)) {
6464
return [];
@@ -72,13 +72,14 @@ public function uploadAttachments(string $token, string $projectName, string $da
7272
$projectName,
7373
$filename
7474
);
75+
$filePath = $dataDir . DIRECTORY_SEPARATOR . $path;
7576
$result = [];
7677
try {
77-
$this->upload($uploadToken, $dataPath . $path);
78+
$this->upload($uploadToken, $filePath);
7879
$result = $this->createFile($token, $projectName, [
7980
"OriginalFileName" => $filename,
80-
"MimeType" => mime_content_type($dataPath . $path),
81-
"FileSize" => filesize($dataPath . $path),
81+
"MimeType" => mime_content_type($filePath),
82+
"FileSize" => filesize($filePath),
8283
"StorageKey" => $uploadToken['StorageKey'],
8384
"Time" => $uploadToken['Time'],
8485
"AuthToken" => $uploadToken['AuthToken'],

‎app/Commands/WikiImportCommand.php

Lines changed: 72 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,12 @@ private function handleConfluenceApi(): int
148148

149149
private function handleConfluenceHtml(): int
150150
{
151-
$htmlDir = $this->unzipConfluenceHtml();
152-
$filePath = $htmlDir . 'index.html';
151+
$path = $this->unzipConfluenceHtml();
152+
if (str_ends_with($path, '.html')) {
153+
return $this->uploadConfluencePage($path);
154+
}
155+
$htmlDir = $path;
156+
$filePath = $htmlDir . DIRECTORY_SEPARATOR . 'index.html';
153157
if (!file_exists($filePath)) {
154158
$message = "文件不存在:$filePath";
155159
$this->error($message);
@@ -188,55 +192,75 @@ private function handleConfluenceHtml(): int
188192
return 0;
189193
}
190194

191-
private function uploadConfluencePages(string $dataPath, array $tree, array $titles, int $parentId = 0): void
195+
private function uploadConfluencePages(string $htmlDir, array $tree, array $titles, int $parentId = 0): void
192196
{
193197
foreach ($tree as $page => $subPages) {
194198
$title = $titles[$page];
195-
$this->info('标题:' . $title);
196-
try {
197-
$markdown = $this->confluence->htmlFile2Markdown($dataPath . $page);
198-
} catch (FileNotFoundException $e) {
199-
$this->error('页面不存在:' . $dataPath . $page);
200-
continue;
199+
$wikiId = $this->uploadConfluencePage($htmlDir . DIRECTORY_SEPARATOR . $page, $title, $parentId);
200+
if ($wikiId && !empty($subPages)) {
201+
$this->info('发现 ' . count($subPages) . ' 个子页面');
202+
// TODO tests
203+
$this->uploadConfluencePages($htmlDir, $subPages, $titles, $wikiId);
201204
}
202-
$mdFilename = $this->dealAttachments($dataPath, $page, $markdown);
203-
$zipFilePath = $this->codingWiki->createMarkdownZip($markdown, $dataPath, $mdFilename, $title);
204-
$result = $this->codingWiki->createWikiByUploadZip(
205+
}
206+
}
207+
208+
private function uploadConfluencePage(string $filePath, string $title = '', int $parentId = 0): int
209+
{
210+
try {
211+
$markdown = $this->confluence->htmlFile2Markdown($filePath);
212+
} catch (FileNotFoundException $e) {
213+
$message = '页面不存在:' . $filePath;
214+
$this->error($message);
215+
$this->errors[] = $message;
216+
return false;
217+
}
218+
libxml_use_internal_errors(true);
219+
$this->document->loadHTMLFile($filePath);
220+
if (empty($title)) {
221+
$title = $this->document->getElementsByTagName('title')[0]->nodeValue;
222+
}
223+
$this->info('标题:' . $title);
224+
225+
$htmlDir = dirname($filePath);
226+
$page = basename($filePath);
227+
$markdown = $this->dealAttachments($filePath, $markdown);
228+
$mdFilename = substr($page, 0, -5) . '.md';
229+
if ($this->option('save-markdown')) {
230+
file_put_contents($htmlDir . DIRECTORY_SEPARATOR . $mdFilename, $markdown . "\n");
231+
}
232+
$zipFilePath = $this->codingWiki->createMarkdownZip($markdown, $htmlDir, $mdFilename, $title);
233+
$result = $this->codingWiki->createWikiByUploadZip(
234+
$this->codingToken,
235+
$this->codingProjectUri,
236+
$zipFilePath,
237+
$parentId,
238+
);
239+
$this->info('上传成功,正在处理,任务 ID:' . $result['JobId']);
240+
$wikiId = null;
241+
try {
242+
$jobStatus = $this->codingWiki->getImportJobStatusWithRetry(
205243
$this->codingToken,
206244
$this->codingProjectUri,
207-
$zipFilePath,
208-
$parentId,
245+
$result['JobId']
209246
);
210-
$this->info('上传成功,正在处理,任务 ID:' . $result['JobId']);
211-
$wikiId = null;
212-
try {
213-
$jobStatus = $this->codingWiki->getImportJobStatusWithRetry(
214-
$this->codingToken,
215-
$this->codingProjectUri,
216-
$result['JobId']
217-
);
218-
} catch (Exception $e) {
219-
$message = '错误:导入失败,跳过 ' . $title . '' . $page;
220-
$this->error($message);
221-
$this->errors[] = $message;
222-
continue;
223-
}
224-
if ($jobStatus['Status'] == 'success') {
225-
$wikiId = intval($jobStatus['Iids'][0]);
226-
}
227-
if (empty($wikiId)) {
228-
$message = '错误:导入失败,跳过 ' . $title . '' . $page;
229-
$this->error($message);
230-
$this->errors[] = $message;
231-
continue;
232-
}
233-
$this->codingWiki->updateTitle($this->codingToken, $this->codingProjectUri, $wikiId, $title);
234-
if (!empty($subPages)) {
235-
$this->info('发现 ' . count($subPages) . ' 个子页面');
236-
// TODO tests
237-
$this->uploadConfluencePages($dataPath, $subPages, $titles, $wikiId);
238-
}
247+
} catch (Exception $e) {
248+
$message = '错误:导入失败,跳过 ' . $title . '' . $page;
249+
$this->error($message);
250+
$this->errors[] = $message;
251+
return false;
252+
}
253+
if ($jobStatus['Status'] == 'success') {
254+
$wikiId = intval($jobStatus['Iids'][0]);
239255
}
256+
if (empty($wikiId)) {
257+
$message = '错误:导入失败,跳过 ' . $title . '' . $page;
258+
$this->error($message);
259+
$this->errors[] = $message;
260+
return false;
261+
}
262+
$this->codingWiki->updateTitle($this->codingToken, $this->codingProjectUri, $wikiId, $title);
263+
return $wikiId;
240264
}
241265

242266
private function unzipConfluenceHtml(): string
@@ -263,16 +287,16 @@ private function unzipConfluenceHtml(): string
263287
$zip->close();
264288
return $tmpDir . '/' . scandir($tmpDir, 1)[0] . '/';
265289
}
266-
return str_ends_with($dataPath, '/index.html') ? substr($dataPath, 0, -10) : Str::finish($dataPath, '/');
290+
return rtrim($dataPath, '/');
267291
}
268292

269-
private function dealAttachments(string $dataPath, string$page, string $markdown): string
293+
private function dealAttachments(string $filePath, string $markdown): string
270294
{
271-
$attachments = $this->confluence->parseAttachments($dataPath . $page, $markdown);
295+
$attachments = $this->confluence->parseAttachments($filePath, $markdown);
272296
$codingAttachments = $this->codingDisk->uploadAttachments(
273297
$this->codingToken,
274298
$this->codingProjectUri,
275-
$dataPath,
299+
dirname($filePath),
276300
$attachments
277301
);
278302
foreach ($codingAttachments as $attachmentPath => $codingAttachment) {
@@ -282,11 +306,6 @@ private function dealAttachments(string $dataPath, string $page, string $markdow
282306
$this->errors[] = $message;
283307
}
284308
}
285-
$markdown = $this->codingWiki->replaceAttachments($markdown, $codingAttachments);
286-
$mdFilename = substr($page, 0, -5) . '.md';
287-
if ($this->option('save-markdown')) {
288-
file_put_contents($dataPath . $mdFilename, $markdown . "\n");
289-
}
290-
return $mdFilename;
309+
return $this->codingWiki->replaceAttachments($markdown, $codingAttachments);
291310
}
292311
}

‎app/Commands/WikiUploadCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class WikiUploadCommand extends Command
3030
*
3131
* @var string
3232
*/
33-
protected $description = '上传 Zip 导入 Wiki';
33+
protected $description = '上传 Markdown 和图片的 Zip 导入 Wiki';
3434

3535
/**
3636
* Execute the console command.

‎tests/Feature/WikiImportCommandTest.php

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ public function testHandleConfluenceHtmlFileNotExist()
152152
->expectsQuestion('数据来源?', 'Confluence')
153153
->expectsQuestion('数据类型?', 'HTML')
154154
->expectsQuestion('空间导出的 HTML zip 文件路径', '/dev/null/index.html')
155-
->expectsOutput('文件不存在:/dev/null/index.html')
155+
->expectsOutput('页面不存在:/dev/null/index.html')
156156
->assertExitCode(1);
157157
}
158158

@@ -188,7 +188,6 @@ public function testHandleConfluenceHtmlSuccess()
188188
->expectsOutput('空间标识:space1')
189189
->expectsOutput('发现 3 个一级页面')
190190
->expectsOutput("开始导入 CODING:")
191-
->expectsOutput('标题:Not Found')
192191
->expectsOutput('页面不存在:' . $this->dataDir . 'confluence/space1/not-found.html')
193192
->expectsOutput('标题:Image Demo')
194193
->expectsOutput('上传成功,正在处理,任务 ID:a12353fa-f45b-4af2-83db-666bf9f66615')
@@ -199,13 +198,15 @@ public function testHandleConfluenceHtmlSuccess()
199198
->expectsOutput('上传成功,正在处理,任务 ID:a12353fa-f45b-4af2-83db-666bf9f66615')
200199
->expectsOutput('标题:Text Demo')
201200
->expectsOutput('上传成功,正在处理,任务 ID:a12353fa-f45b-4af2-83db-666bf9f66615')
202-
->assertExitCode(0);
203-
$this->assertFileExists($this->dataDir . 'confluence/space1/65591.md');
204-
$this->assertFileExists($this->dataDir . 'confluence/space1/attachment-demo_65615.md');
205-
$this->assertFileExists($this->dataDir . 'confluence/space1/text-demo_65601.md');
206-
unlink($this->dataDir . 'confluence/space1/65591.md');
207-
unlink($this->dataDir . 'confluence/space1/attachment-demo_65615.md');
208-
unlink($this->dataDir . 'confluence/space1/text-demo_65601.md');
201+
->expectsOutput('报错信息汇总:')
202+
->expectsOutput('页面不存在:' . $this->dataDir . 'confluence/space1/not-found.html')
203+
->assertExitCode(1);
204+
$this->assertFileExists($this->dataDir . '/confluence/space1/65591.md');
205+
$this->assertFileExists($this->dataDir . '/confluence/space1/attachment-demo_65615.md');
206+
$this->assertFileExists($this->dataDir . '/confluence/space1/text-demo_65601.md');
207+
unlink($this->dataDir . '/confluence/space1/65591.md');
208+
unlink($this->dataDir . '/confluence/space1/attachment-demo_65615.md');
209+
unlink($this->dataDir . '/confluence/space1/text-demo_65601.md');
209210
}
210211

211212
public function testAskNothing()
@@ -269,4 +270,33 @@ public function testHandleConfluenceHtmlZipSuccess()
269270
->expectsOutput('上传成功,正在处理,任务 ID:a12353fa-f45b-4af2-83db-666bf9f66615')
270271
->assertExitCode(0);
271272
}
273+
274+
public function testHandleConfluenceSingleHtmlSuccess()
275+
{
276+
$this->setConfig();
277+
278+
// 注意:不能使用 partialMock
279+
// https://laracasts.com/discuss/channels/testing/this-partialmock-doesnt-call-the-constructor
280+
$mock = \Mockery::mock(Wiki::class, [])->makePartial();
281+
$this->instance(Wiki::class, $mock);
282+
283+
$mock->shouldReceive('createWikiByUploadZip')->times(1)->andReturn(json_decode(
284+
file_get_contents($this->dataDir . 'coding/' . 'CreateWikiByZipResponse.json'),
285+
true
286+
)['Response']);
287+
$mock->shouldReceive('getImportJobStatus')->times(1)->andReturn(json_decode(
288+
file_get_contents($this->dataDir . 'coding/' . 'DescribeImportJobStatusResponse.json'),
289+
true
290+
)['Response']['Data']);
291+
$mock->shouldReceive('updateTitle')->times(1)->andReturn(true);
292+
293+
294+
$this->artisan('wiki:import')
295+
->expectsQuestion('数据来源?', 'Confluence')
296+
->expectsQuestion('数据类型?', 'HTML')
297+
->expectsQuestion('空间导出的 HTML zip 文件路径', $this->dataDir . 'confluence/space1/image-demo_65619.html')
298+
->expectsOutput('标题:空间 1 : Image Demo')
299+
->expectsOutput('上传成功,正在处理,任务 ID:a12353fa-f45b-4af2-83db-666bf9f66615')
300+
->assertExitCode(0);
301+
}
272302
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /