You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

355 lines
9.2 KiB

10 years ago
10 years ago
11 years ago
11 years ago
13 years ago
11 years ago
11 years ago
15 years ago
11 years ago
11 years ago
  1. <?php
  2. /**
  3. * @author Bart Visscher <bartv@thisnet.nl>
  4. * @author Brice Maron <brice@bmaron.net>
  5. * @author Felix Moeller <mail@felixmoeller.de>
  6. * @author Frank Karlitschek <frank@owncloud.org>
  7. * @author Joas Schilling <nickvergessen@owncloud.com>
  8. * @author Jörn Friedrich Dreyer <jfd@butonic.de>
  9. * @author Kamil Domanski <kdomanski@kdemail.net>
  10. * @author Lukas Reschke <lukas@owncloud.com>
  11. * @author Morris Jobke <hey@morrisjobke.de>
  12. * @author Robin McCorkell <robin@mccorkell.me.uk>
  13. * @author Sam Tuke <mail@samtuke.com>
  14. * @author Thomas Müller <thomas.mueller@tmit.eu>
  15. *
  16. * @copyright Copyright (c) 2016, ownCloud, Inc.
  17. * @license AGPL-3.0
  18. *
  19. * This code is free software: you can redistribute it and/or modify
  20. * it under the terms of the GNU Affero General Public License, version 3,
  21. * as published by the Free Software Foundation.
  22. *
  23. * This program is distributed in the hope that it will be useful,
  24. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  26. * GNU Affero General Public License for more details.
  27. *
  28. * You should have received a copy of the GNU Affero General Public License, version 3,
  29. * along with this program. If not, see <http://www.gnu.org/licenses/>
  30. *
  31. */
  32. namespace OC;
  33. use OCP\Http\Client\IClientService;
  34. use OCP\IConfig;
  35. use OCP\ILogger;
  36. /**
  37. * Class OCSClient is a class for communication with the ownCloud appstore
  38. *
  39. * @package OC
  40. */
  41. class OCSClient {
  42. /** @var IClientService */
  43. private $httpClientService;
  44. /** @var IConfig */
  45. private $config;
  46. /** @var ILogger */
  47. private $logger;
  48. /**
  49. * @param IClientService $httpClientService
  50. * @param IConfig $config
  51. * @param ILogger $logger
  52. */
  53. public function __construct(IClientService $httpClientService,
  54. IConfig $config,
  55. ILogger $logger) {
  56. $this->httpClientService = $httpClientService;
  57. $this->config = $config;
  58. $this->logger = $logger;
  59. }
  60. /**
  61. * Returns whether the AppStore is enabled (i.e. because the AppStore is disabled for EE)
  62. *
  63. * @return bool
  64. */
  65. public function isAppStoreEnabled() {
  66. // For a regular edition default to true, all others default to false
  67. $default = false;
  68. if (\OC_Util::getEditionString() === '') {
  69. $default = true;
  70. }
  71. return $this->config->getSystemValue('appstoreenabled', $default) === true;
  72. }
  73. /**
  74. * Get the url of the OCS AppStore server.
  75. *
  76. * @return string of the AppStore server
  77. */
  78. private function getAppStoreUrl() {
  79. return $this->config->getSystemValue('appstoreurl', 'https://api.owncloud.com/v1');
  80. }
  81. /**
  82. * @param string $body
  83. * @param string $action
  84. * @return null|\SimpleXMLElement
  85. */
  86. private function loadData($body, $action) {
  87. $loadEntities = libxml_disable_entity_loader(true);
  88. $data = @simplexml_load_string($body);
  89. libxml_disable_entity_loader($loadEntities);
  90. if($data === false) {
  91. libxml_clear_errors();
  92. $this->logger->error(
  93. sprintf('Could not get %s, content was no valid XML', $action),
  94. [
  95. 'app' => 'core',
  96. ]
  97. );
  98. return null;
  99. }
  100. return $data;
  101. }
  102. /**
  103. * Get all the categories from the OCS server
  104. *
  105. * @param array $targetVersion The target ownCloud version
  106. * @return array|null an array of category ids or null
  107. * @note returns NULL if config value appstoreenabled is set to false
  108. * This function returns a list of all the application categories on the OCS server
  109. */
  110. public function getCategories(array $targetVersion) {
  111. if (!$this->isAppStoreEnabled()) {
  112. return null;
  113. }
  114. $client = $this->httpClientService->newClient();
  115. try {
  116. $response = $client->get(
  117. $this->getAppStoreUrl() . '/content/categories',
  118. [
  119. 'timeout' => 20,
  120. 'query' => [
  121. 'version' => implode('x', $targetVersion),
  122. ],
  123. ]
  124. );
  125. } catch(\Exception $e) {
  126. $this->logger->error(
  127. sprintf('Could not get categories: %s', $e->getMessage()),
  128. [
  129. 'app' => 'core',
  130. ]
  131. );
  132. return null;
  133. }
  134. $data = $this->loadData($response->getBody(), 'categories');
  135. if($data === null) {
  136. return null;
  137. }
  138. $tmp = $data->data;
  139. $cats = [];
  140. foreach ($tmp->category as $value) {
  141. $id = (int)$value->id;
  142. $name = (string)$value->name;
  143. $cats[$id] = $name;
  144. }
  145. return $cats;
  146. }
  147. /**
  148. * Get all the applications from the OCS server
  149. * @param array $categories
  150. * @param int $page
  151. * @param string $filter
  152. * @param array $targetVersion The target ownCloud version
  153. * @return array An array of application data
  154. */
  155. public function getApplications(array $categories, $page, $filter, array $targetVersion) {
  156. if (!$this->isAppStoreEnabled()) {
  157. return [];
  158. }
  159. $client = $this->httpClientService->newClient();
  160. try {
  161. $response = $client->get(
  162. $this->getAppStoreUrl() . '/content/data',
  163. [
  164. 'timeout' => 20,
  165. 'query' => [
  166. 'version' => implode('x', $targetVersion),
  167. 'filter' => $filter,
  168. 'categories' => implode('x', $categories),
  169. 'sortmode' => 'new',
  170. 'page' => $page,
  171. 'pagesize' => 100,
  172. 'approved' => $filter
  173. ],
  174. ]
  175. );
  176. } catch(\Exception $e) {
  177. $this->logger->error(
  178. sprintf('Could not get applications: %s', $e->getMessage()),
  179. [
  180. 'app' => 'core',
  181. ]
  182. );
  183. return [];
  184. }
  185. $data = $this->loadData($response->getBody(), 'applications');
  186. if($data === null) {
  187. return [];
  188. }
  189. $tmp = $data->data->content;
  190. $tmpCount = count($tmp);
  191. $apps = [];
  192. for ($i = 0; $i < $tmpCount; $i++) {
  193. $app = [];
  194. $app['id'] = (string)$tmp[$i]->id;
  195. $app['name'] = (string)$tmp[$i]->name;
  196. $app['label'] = (string)$tmp[$i]->label;
  197. $app['version'] = (string)$tmp[$i]->version;
  198. $app['type'] = (string)$tmp[$i]->typeid;
  199. $app['typename'] = (string)$tmp[$i]->typename;
  200. $app['personid'] = (string)$tmp[$i]->personid;
  201. $app['profilepage'] = (string)$tmp[$i]->profilepage;
  202. $app['license'] = (string)$tmp[$i]->license;
  203. $app['detailpage'] = (string)$tmp[$i]->detailpage;
  204. $app['preview'] = (string)$tmp[$i]->smallpreviewpic1;
  205. $app['preview-full'] = (string)$tmp[$i]->previewpic1;
  206. $app['changed'] = strtotime($tmp[$i]->changed);
  207. $app['description'] = (string)$tmp[$i]->description;
  208. $app['score'] = (string)$tmp[$i]->score;
  209. $app['downloads'] = (int)$tmp[$i]->downloads;
  210. $app['level'] = (int)$tmp[$i]->approved;
  211. $apps[] = $app;
  212. }
  213. return $apps;
  214. }
  215. /**
  216. * Get an the applications from the OCS server
  217. *
  218. * @param string $id
  219. * @param array $targetVersion The target ownCloud version
  220. * @return array|null an array of application data or null
  221. *
  222. * This function returns an applications from the OCS server
  223. */
  224. public function getApplication($id, array $targetVersion) {
  225. if (!$this->isAppStoreEnabled()) {
  226. return null;
  227. }
  228. $client = $this->httpClientService->newClient();
  229. try {
  230. $response = $client->get(
  231. $this->getAppStoreUrl() . '/content/data/' . urlencode($id),
  232. [
  233. 'timeout' => 20,
  234. 'query' => [
  235. 'version' => implode('x', $targetVersion),
  236. ],
  237. ]
  238. );
  239. } catch(\Exception $e) {
  240. $this->logger->error(
  241. sprintf('Could not get application: %s', $e->getMessage()),
  242. [
  243. 'app' => 'core',
  244. ]
  245. );
  246. return null;
  247. }
  248. $data = $this->loadData($response->getBody(), 'application');
  249. if($data === null) {
  250. return null;
  251. }
  252. $tmp = $data->data->content;
  253. if (is_null($tmp)) {
  254. \OCP\Util::writeLog('core', 'No update found at the ownCloud appstore for app ' . $id, \OCP\Util::DEBUG);
  255. return null;
  256. }
  257. $app = [];
  258. $app['id'] = (int)$id;
  259. $app['name'] = (string)$tmp->name;
  260. $app['version'] = (string)$tmp->version;
  261. $app['type'] = (string)$tmp->typeid;
  262. $app['label'] = (string)$tmp->label;
  263. $app['typename'] = (string)$tmp->typename;
  264. $app['personid'] = (string)$tmp->personid;
  265. $app['profilepage'] = (string)$tmp->profilepage;
  266. $app['detailpage'] = (string)$tmp->detailpage;
  267. $app['preview1'] = (string)$tmp->smallpreviewpic1;
  268. $app['preview2'] = (string)$tmp->smallpreviewpic2;
  269. $app['preview3'] = (string)$tmp->smallpreviewpic3;
  270. $app['changed'] = strtotime($tmp->changed);
  271. $app['description'] = (string)$tmp->description;
  272. $app['detailpage'] = (string)$tmp->detailpage;
  273. $app['score'] = (int)$tmp->score;
  274. $app['level'] = (int)$tmp->approved;
  275. return $app;
  276. }
  277. /**
  278. * Get the download url for an application from the OCS server
  279. * @param string $id
  280. * @param array $targetVersion The target ownCloud version
  281. * @return array|null an array of application data or null
  282. */
  283. public function getApplicationDownload($id, array $targetVersion) {
  284. if (!$this->isAppStoreEnabled()) {
  285. return null;
  286. }
  287. $url = $this->getAppStoreUrl() . '/content/download/' . urlencode($id) . '/1';
  288. $client = $this->httpClientService->newClient();
  289. try {
  290. $response = $client->get(
  291. $url,
  292. [
  293. 'timeout' => 20,
  294. 'query' => [
  295. 'version' => implode('x', $targetVersion),
  296. ],
  297. ]
  298. );
  299. } catch(\Exception $e) {
  300. $this->logger->error(
  301. sprintf('Could not get application download URL: %s', $e->getMessage()),
  302. [
  303. 'app' => 'core',
  304. ]
  305. );
  306. return null;
  307. }
  308. $data = $this->loadData($response->getBody(), 'application download URL');
  309. if($data === null) {
  310. return null;
  311. }
  312. $tmp = $data->data->content;
  313. $app = [];
  314. if (isset($tmp->downloadlink)) {
  315. $app['downloadlink'] = (string)$tmp->downloadlink;
  316. } else {
  317. $app['downloadlink'] = '';
  318. }
  319. return $app;
  320. }
  321. }