322 lines
7.7 KiB
PHP
Executable File
322 lines
7.7 KiB
PHP
Executable File
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Document;
|
|
use App\Models\Feed;
|
|
use App\Models\Folder;
|
|
use App\Models\Group;
|
|
use App\Models\Highlight;
|
|
use App\Models\IgnoredFeed;
|
|
use App\Models\User;
|
|
use Illuminate\Http\Request;
|
|
|
|
/**
|
|
* Imports data in Cyca.
|
|
*/
|
|
class Importer
|
|
{
|
|
/**
|
|
* Adapter used to import data.
|
|
*
|
|
* @var \App\Contracts\ImportAdapter
|
|
*/
|
|
protected $importAdapter;
|
|
|
|
/**
|
|
* User to import data for.
|
|
*
|
|
* @var \App\Models\User
|
|
*/
|
|
protected $forUser;
|
|
|
|
/**
|
|
* Folder to import bookmarks and feeds to.
|
|
*
|
|
* @var \App\Models\Folder
|
|
*/
|
|
protected $inFolder;
|
|
|
|
/**
|
|
* Should we import highlights as well ?
|
|
*
|
|
* @var bool
|
|
*/
|
|
protected $withHighlights = true;
|
|
|
|
/**
|
|
* Data to be imported as an array.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $dataArray = [];
|
|
|
|
/**
|
|
* Group to import data to.
|
|
*
|
|
* @var \App\Models\Group
|
|
*/
|
|
protected $inGroup;
|
|
|
|
/**
|
|
* Indicates which adapter to use for importation.
|
|
*
|
|
* @param string $adapterName
|
|
*
|
|
* @return self
|
|
*/
|
|
public function using($adapterName)
|
|
{
|
|
$className = config(sprintf('importers.adapters.%s.adapter', $adapterName));
|
|
|
|
if (empty($className)) {
|
|
abort(422, sprintf('Unknown import adapter %s', $className));
|
|
}
|
|
|
|
$this->importAdapter = new $className();
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Defines which user to import data for. If not defined, user will be
|
|
* extracted from request.
|
|
*
|
|
* @return self
|
|
*/
|
|
public function forUser(User $user)
|
|
{
|
|
$this->forUser = $user;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Defines the group to import data to.
|
|
*
|
|
* @return self
|
|
*/
|
|
public function inGroup(Group $group)
|
|
{
|
|
$this->inGroup = $group;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Defines in which folder data will be imported to. If not defined, root
|
|
* folder attached to specified user will be used.
|
|
*
|
|
* @return self
|
|
*/
|
|
public function inFolder(Folder $folder)
|
|
{
|
|
$this->inFolder = $folder;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Should we ignore highlights during import ? By default, highlights will
|
|
* be imported as well.
|
|
*
|
|
* @return self
|
|
*/
|
|
public function withoutHighlights()
|
|
{
|
|
$this->withHighlights = false;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Import data from specified file. Must be a valid json file, valid from
|
|
* Cyca's architecture point of view.
|
|
*
|
|
* @param string $path Full path to file to import
|
|
*
|
|
* @return self
|
|
*/
|
|
public function fromFile($path)
|
|
{
|
|
if (empty($this->forUser)) {
|
|
abort(422, 'Target user not specified');
|
|
}
|
|
|
|
$contents = file_get_contents($path);
|
|
|
|
if (empty($contents)) {
|
|
abort(422, 'File does not exists');
|
|
}
|
|
|
|
$this->dataArray = json_decode($contents, true);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Import data using current request informations.
|
|
*
|
|
* @return self
|
|
*/
|
|
public function fromRequest(Request $request)
|
|
{
|
|
if (empty($this->importAdapter)) {
|
|
$this->using($request->input('importer'));
|
|
}
|
|
|
|
if (empty($this->importAdapter)) {
|
|
abort(422, 'An import adapter must be specified');
|
|
}
|
|
|
|
if (empty($this->forUser)) {
|
|
$this->forUser = $request->user();
|
|
}
|
|
|
|
$this->dataArray = $this->importAdapter->importFromRequest($request);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Perform the import.
|
|
*/
|
|
public function import()
|
|
{
|
|
if (empty($this->inGroup)) {
|
|
$this->inGroup = $this->forUser->groups()->wherePivot('status', '=', 'own')->first();
|
|
}
|
|
|
|
if (empty($this->inFolder)) {
|
|
$this->inFolder = $this->inGroup->folders()->ofType('root')->first();
|
|
}
|
|
|
|
if ($this->withHighlights && !empty($this->dataArray['highlights'])) {
|
|
$this->importHighlights($this->dataArray['highlights']);
|
|
}
|
|
|
|
if (!empty($this->dataArray['bookmarks'])) {
|
|
$this->importBookmarks($this->dataArray['bookmarks']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Import highlights from specified array.
|
|
*
|
|
* @param array $highlights
|
|
*/
|
|
protected function importHighlights($highlights)
|
|
{
|
|
foreach ($highlights as $highlightData) {
|
|
$highlight = Highlight::where('user_id', $this->forUser->id)->where('expression', $highlightData['expression'])->first();
|
|
|
|
if (!$highlight) {
|
|
$highlight = new Highlight();
|
|
|
|
$highlight->user_id = $this->forUser->id;
|
|
$highlight->expression = $highlightData['expression'];
|
|
$highlight->color = $highlightData['color'];
|
|
|
|
$highlight->save();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Import bookmarks from specified array.
|
|
*
|
|
* @param array $bookmarks
|
|
*/
|
|
protected function importBookmarks($bookmarks)
|
|
{
|
|
$this->importDocuments($this->inFolder, $bookmarks['documents'] ?: []);
|
|
$this->importFolders($this->inFolder, $bookmarks['folders'] ?: []);
|
|
}
|
|
|
|
/**
|
|
* Import folders.
|
|
*
|
|
* @param \App\Models\Folder Destination folder
|
|
* @param array $foldersData Array of sub-folders definitions
|
|
* @param mixed $folder
|
|
*/
|
|
protected function importFolders($folder, $foldersData)
|
|
{
|
|
foreach ($foldersData as $folderData) {
|
|
$children = $this->inGroup->folders()->save(new Folder([
|
|
'title' => $folderData['title'],
|
|
'parent_id' => $folder->id,
|
|
'user_id' => $this->forUser->id,
|
|
]));
|
|
|
|
$this->importDocuments($children, $folderData['documents']);
|
|
$this->importFolders($children, $folderData['folders']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Import documents.
|
|
*
|
|
* @param \App\Models\Folder Destination folder
|
|
* @param array $documentsData Array of documents definitions
|
|
* @param mixed $folder
|
|
*/
|
|
protected function importDocuments($folder, $documentsData)
|
|
{
|
|
foreach ($documentsData as $docData) {
|
|
if (empty($docData['url'])) {
|
|
continue;
|
|
}
|
|
|
|
$url = urldecode($docData['url']);
|
|
$document = Document::firstOrCreate(['url' => $url]);
|
|
|
|
if (array_key_exists('feeds', $docData)) {
|
|
$this->importFeeds($document, $docData['feeds']);
|
|
}
|
|
|
|
$folder->documents()->save($document, [
|
|
'initial_url' => $url,
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Import feeds.
|
|
*
|
|
* @param \App\Models\Document $document Destination document
|
|
* @param array $feedsData Array of feeds definitions
|
|
*/
|
|
protected function importFeeds($document, $feedsData)
|
|
{
|
|
$feedsToAttach = $document->feeds()->get()->pluck('id')->all();
|
|
|
|
foreach ($feedsData as $feedData) {
|
|
if (empty($feedData['url'])) {
|
|
continue;
|
|
}
|
|
|
|
$feedUrl = urldecode($feedData['url']);
|
|
|
|
$feed = Feed::firstOrCreate(['url' => $feedUrl]);
|
|
|
|
$feedsToAttach[] = $feed->id;
|
|
|
|
if ($feedData['is_ignored']) {
|
|
$ignoredFeed = IgnoredFeed::where('user_id', $this->forUser->id)->where('feed_id', $feed->id)->first();
|
|
|
|
if (!$ignoredFeed) {
|
|
$ignoredFeed = new IgnoredFeed();
|
|
|
|
$ignoredFeed->user()->associate($this->forUser);
|
|
$ignoredFeed->feed()->associate($feed);
|
|
|
|
$ignoredFeed->save();
|
|
}
|
|
}
|
|
}
|
|
|
|
$document->feeds()->sync($feedsToAttach);
|
|
}
|
|
}
|