owncloud/core

View on GitHub
apps/dav/lib/DAV/LazyOpsPlugin.php

Summary

Maintainability
A
35 mins
Test Coverage
<?php
/**
 * @author Thomas Müller <thomas.mueller@tmit.eu>
 *
 * @copyright Copyright (c) 2018, ownCloud GmbH
 * @license AGPL-3.0
 *
 * This code is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License, version 3,
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 *
 */

namespace OCA\DAV\DAV;

use OCA\DAV\JobStatus\Entity\JobStatus;
use OCA\DAV\JobStatus\Entity\JobStatusMapper;
use OCP\ILogger;
use OCP\IURLGenerator;
use OCP\IUserSession;
use OCP\Shutdown\IShutdownManager;
use Sabre\DAV\Exception;
use Sabre\DAV\Server;
use Sabre\DAV\ServerPlugin;
use Sabre\DAV\UUIDUtil;
use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\Response;
use Sabre\HTTP\ResponseInterface;

/**
 * Class LazyOpsPlugin
 *
 * @package OCA\DAV\DAV
 */
class LazyOpsPlugin extends ServerPlugin {
    /** @var Server */
    private $server;
    /** @var string */
    private $jobId;
    /** @var JobStatus */
    private $entity;
    /** @var IUserSession */
    private $userSession;
    /** @var IURLGenerator */
    private $urlGenerator;
    /** @var IShutdownManager */
    private $shutdownManager;
    /** @var ILogger */
    private $logger;
    /** @var JobStatusMapper */
    private $mapper;

    public function __construct(
        IUserSession $userSession,
        IURLGenerator $urlGenerator,
        IShutdownManager $shutdownManager,
        JobStatusMapper $jobStatusMapper,
        ILogger $logger
    ) {
        $this->userSession = $userSession;
        $this->urlGenerator = $urlGenerator;
        $this->shutdownManager = $shutdownManager;
        $this->logger = $logger;
        $this->mapper = $jobStatusMapper;
    }

    /**
     * @param Server $server
     */
    public function initialize(Server $server) {
        $this->server = $server;
        $server->on('method:MOVE', [$this, 'httpMove'], 90);
    }

    /**
     * @param RequestInterface $request
     * @param ResponseInterface $response
     * @return bool
     * @throws Exception\NotAuthenticated
     */
    public function httpMove(RequestInterface $request, ResponseInterface $response) {
        if (!$request->getHeader('OC-LazyOps')) {
            return true;
        }

        $this->jobId = UUIDUtil::getUUID();
        $this->setJobStatus([
            'status' => 'init'
        ]);
        $userId = $this->getUserId();
        $location = $this->urlGenerator
                ->linkTo('', 'remote.php') . "/dav/job-status/{$userId}/{$this->jobId}";

        $response->setStatus(202);
        $response->setHeader('Connection', 'close');
        $response->setHeader('OC-JobStatus-Location', $location);

        $this->shutdownManager->register(function () use ($request, $response) {
            return $this->afterResponse($request, $response);
        }, IShutdownManager::HIGH);

        return false;
    }

    public function afterResponse(RequestInterface $request, ResponseInterface $response) {
        if (!$request->getHeader('OC-LazyOps')) {
            return true;
        }

        \flush();
        $request->removeHeader('OC-LazyOps');
        $responseDummy = new Response();
        try {
            $this->setJobStatus([
                'status' => 'started'
            ]);
            $this->server->emit('method:MOVE', [$request, $responseDummy]);

            $this->setJobStatus([
                'status' => 'finished',
                'fileId' => $response->getHeader('OC-FileId'),
                'ETag' => $response->getHeader('ETag')
            ]);
        } catch (\Exception $ex) {
            $this->logger->logException($ex);

            $this->setJobStatus([
                'status' => 'error',
                'errorCode' => $ex instanceof Exception ? $ex->getHTTPCode() : 500,
                'errorMessage' => $ex->getMessage()
            ]);
        }
        return false;
    }

    private function setJobStatus(array $status) {
        if ($this->entity === null) {
            $userId = $this->getUserId();

            $this->entity = new JobStatus();
            $this->entity->setStatusInfo(\json_encode($status));
            $this->entity->setUserId($userId);
            $this->entity->setUuid($this->jobId);
            $this->mapper->insert($this->entity);
        } else {
            $this->entity->setStatusInfo(\json_encode($status));
            $this->mapper->update($this->entity);
        }
    }

    /**
     * @return string
     * @throws Exception\NotAuthenticated
     */
    private function getUserId() {
        $user = $this->userSession->getUser();
        if ($user === null) {
            throw new Exception\NotAuthenticated();
        }
        return $user->getUID();
    }
}