StoragesController.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Jesús Macias <jmacias@solidgear.es>
  6. * @author Joas Schilling <coding@schilljs.com>
  7. * @author Juan Pablo Villafáñez <jvillafanez@solidgear.es>
  8. * @author Robin Appelman <robin@icewind.nl>
  9. * @author Robin McCorkell <robin@mccorkell.me.uk>
  10. * @author Vincent Petry <pvince81@owncloud.com>
  11. *
  12. * @license AGPL-3.0
  13. *
  14. * This code is free software: you can redistribute it and/or modify
  15. * it under the terms of the GNU Affero General Public License, version 3,
  16. * as published by the Free Software Foundation.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU Affero General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU Affero General Public License, version 3,
  24. * along with this program. If not, see <http://www.gnu.org/licenses/>
  25. *
  26. */
  27. namespace OCA\Files_External\Controller;
  28. use OCP\ILogger;
  29. use \OCP\IRequest;
  30. use \OCP\IL10N;
  31. use \OCP\AppFramework\Http\DataResponse;
  32. use \OCP\AppFramework\Controller;
  33. use \OCP\AppFramework\Http;
  34. use OCA\Files_External\Service\StoragesService;
  35. use OCA\Files_External\NotFoundException;
  36. use OCA\Files_External\Lib\StorageConfig;
  37. use \OCA\Files_External\Lib\Backend\Backend;
  38. use \OCA\Files_External\Lib\Auth\AuthMechanism;
  39. use \OCP\Files\StorageNotAvailableException;
  40. use \OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
  41. /**
  42. * Base class for storages controllers
  43. */
  44. abstract class StoragesController extends Controller {
  45. /**
  46. * L10N service
  47. *
  48. * @var IL10N
  49. */
  50. protected $l10n;
  51. /**
  52. * Storages service
  53. *
  54. * @var StoragesService
  55. */
  56. protected $service;
  57. /**
  58. * @var ILogger
  59. */
  60. protected $logger;
  61. /**
  62. * Creates a new storages controller.
  63. *
  64. * @param string $AppName application name
  65. * @param IRequest $request request object
  66. * @param IL10N $l10n l10n service
  67. * @param StoragesService $storagesService storage service
  68. * @param ILogger $logger
  69. */
  70. public function __construct(
  71. $AppName,
  72. IRequest $request,
  73. IL10N $l10n,
  74. StoragesService $storagesService,
  75. ILogger $logger
  76. ) {
  77. parent::__construct($AppName, $request);
  78. $this->l10n = $l10n;
  79. $this->service = $storagesService;
  80. $this->logger = $logger;
  81. }
  82. /**
  83. * Create a storage from its parameters
  84. *
  85. * @param string $mountPoint storage mount point
  86. * @param string $backend backend identifier
  87. * @param string $authMechanism authentication mechanism identifier
  88. * @param array $backendOptions backend-specific options
  89. * @param array|null $mountOptions mount-specific options
  90. * @param array|null $applicableUsers users for which to mount the storage
  91. * @param array|null $applicableGroups groups for which to mount the storage
  92. * @param int|null $priority priority
  93. *
  94. * @return StorageConfig|DataResponse
  95. */
  96. protected function createStorage(
  97. $mountPoint,
  98. $backend,
  99. $authMechanism,
  100. $backendOptions,
  101. $mountOptions = null,
  102. $applicableUsers = null,
  103. $applicableGroups = null,
  104. $priority = null
  105. ) {
  106. try {
  107. return $this->service->createStorage(
  108. $mountPoint,
  109. $backend,
  110. $authMechanism,
  111. $backendOptions,
  112. $mountOptions,
  113. $applicableUsers,
  114. $applicableGroups,
  115. $priority
  116. );
  117. } catch (\InvalidArgumentException $e) {
  118. $this->logger->logException($e);
  119. return new DataResponse(
  120. [
  121. 'message' => (string)$this->l10n->t('Invalid backend or authentication mechanism class')
  122. ],
  123. Http::STATUS_UNPROCESSABLE_ENTITY
  124. );
  125. }
  126. }
  127. /**
  128. * Validate storage config
  129. *
  130. * @param StorageConfig $storage storage config
  131. *1
  132. * @return DataResponse|null returns response in case of validation error
  133. */
  134. protected function validate(StorageConfig $storage) {
  135. $mountPoint = $storage->getMountPoint();
  136. if ($mountPoint === '') {
  137. return new DataResponse(
  138. array(
  139. 'message' => (string)$this->l10n->t('Invalid mount point')
  140. ),
  141. Http::STATUS_UNPROCESSABLE_ENTITY
  142. );
  143. }
  144. if ($storage->getBackendOption('objectstore')) {
  145. // objectstore must not be sent from client side
  146. return new DataResponse(
  147. array(
  148. 'message' => (string)$this->l10n->t('Objectstore forbidden')
  149. ),
  150. Http::STATUS_UNPROCESSABLE_ENTITY
  151. );
  152. }
  153. /** @var Backend */
  154. $backend = $storage->getBackend();
  155. /** @var AuthMechanism */
  156. $authMechanism = $storage->getAuthMechanism();
  157. if ($backend->checkDependencies()) {
  158. // invalid backend
  159. return new DataResponse(
  160. array(
  161. 'message' => (string)$this->l10n->t('Invalid storage backend "%s"', [
  162. $backend->getIdentifier()
  163. ])
  164. ),
  165. Http::STATUS_UNPROCESSABLE_ENTITY
  166. );
  167. }
  168. if (!$backend->isVisibleFor($this->service->getVisibilityType())) {
  169. // not permitted to use backend
  170. return new DataResponse(
  171. array(
  172. 'message' => (string)$this->l10n->t('Not permitted to use backend "%s"', [
  173. $backend->getIdentifier()
  174. ])
  175. ),
  176. Http::STATUS_UNPROCESSABLE_ENTITY
  177. );
  178. }
  179. if (!$authMechanism->isVisibleFor($this->service->getVisibilityType())) {
  180. // not permitted to use auth mechanism
  181. return new DataResponse(
  182. array(
  183. 'message' => (string)$this->l10n->t('Not permitted to use authentication mechanism "%s"', [
  184. $authMechanism->getIdentifier()
  185. ])
  186. ),
  187. Http::STATUS_UNPROCESSABLE_ENTITY
  188. );
  189. }
  190. if (!$backend->validateStorage($storage)) {
  191. // unsatisfied parameters
  192. return new DataResponse(
  193. array(
  194. 'message' => (string)$this->l10n->t('Unsatisfied backend parameters')
  195. ),
  196. Http::STATUS_UNPROCESSABLE_ENTITY
  197. );
  198. }
  199. if (!$authMechanism->validateStorage($storage)) {
  200. // unsatisfied parameters
  201. return new DataResponse(
  202. [
  203. 'message' => (string)$this->l10n->t('Unsatisfied authentication mechanism parameters')
  204. ],
  205. Http::STATUS_UNPROCESSABLE_ENTITY
  206. );
  207. }
  208. return null;
  209. }
  210. protected function manipulateStorageConfig(StorageConfig $storage) {
  211. /** @var AuthMechanism */
  212. $authMechanism = $storage->getAuthMechanism();
  213. $authMechanism->manipulateStorageConfig($storage);
  214. /** @var Backend */
  215. $backend = $storage->getBackend();
  216. $backend->manipulateStorageConfig($storage);
  217. }
  218. /**
  219. * Check whether the given storage is available / valid.
  220. *
  221. * Note that this operation can be time consuming depending
  222. * on whether the remote storage is available or not.
  223. *
  224. * @param StorageConfig $storage storage configuration
  225. * @param bool $testOnly whether to storage should only test the connection or do more things
  226. */
  227. protected function updateStorageStatus(StorageConfig &$storage, $testOnly = true) {
  228. try {
  229. $this->manipulateStorageConfig($storage);
  230. /** @var Backend */
  231. $backend = $storage->getBackend();
  232. // update status (can be time-consuming)
  233. $storage->setStatus(
  234. \OC_Mount_Config::getBackendStatus(
  235. $backend->getStorageClass(),
  236. $storage->getBackendOptions(),
  237. false,
  238. $testOnly
  239. )
  240. );
  241. } catch (InsufficientDataForMeaningfulAnswerException $e) {
  242. $status = $e->getCode() ? $e->getCode() : StorageNotAvailableException::STATUS_INDETERMINATE;
  243. $storage->setStatus(
  244. $status,
  245. $this->l10n->t('Insufficient data: %s', [$e->getMessage()])
  246. );
  247. } catch (StorageNotAvailableException $e) {
  248. $storage->setStatus(
  249. $e->getCode(),
  250. $this->l10n->t('%s', [$e->getMessage()])
  251. );
  252. } catch (\Exception $e) {
  253. // FIXME: convert storage exceptions to StorageNotAvailableException
  254. $storage->setStatus(
  255. StorageNotAvailableException::STATUS_ERROR,
  256. get_class($e).': '.$e->getMessage()
  257. );
  258. }
  259. }
  260. /**
  261. * Get all storage entries
  262. *
  263. * @return DataResponse
  264. */
  265. public function index() {
  266. $storages = $this->service->getStorages();
  267. return new DataResponse(
  268. $storages,
  269. Http::STATUS_OK
  270. );
  271. }
  272. /**
  273. * Get an external storage entry.
  274. *
  275. * @param int $id storage id
  276. * @param bool $testOnly whether to storage should only test the connection or do more things
  277. *
  278. * @return DataResponse
  279. */
  280. public function show($id, $testOnly = true) {
  281. try {
  282. $storage = $this->service->getStorage($id);
  283. $this->updateStorageStatus($storage, $testOnly);
  284. } catch (NotFoundException $e) {
  285. return new DataResponse(
  286. [
  287. 'message' => (string)$this->l10n->t('Storage with ID "%d" not found', array($id))
  288. ],
  289. Http::STATUS_NOT_FOUND
  290. );
  291. }
  292. return new DataResponse(
  293. $storage,
  294. Http::STATUS_OK
  295. );
  296. }
  297. /**
  298. * Deletes the storage with the given id.
  299. *
  300. * @param int $id storage id
  301. *
  302. * @return DataResponse
  303. */
  304. public function destroy($id) {
  305. try {
  306. $this->service->removeStorage($id);
  307. } catch (NotFoundException $e) {
  308. return new DataResponse(
  309. [
  310. 'message' => (string)$this->l10n->t('Storage with ID "%d" not found', array($id))
  311. ],
  312. Http::STATUS_NOT_FOUND
  313. );
  314. }
  315. return new DataResponse([], Http::STATUS_NO_CONTENT);
  316. }
  317. }