ThemingControllerTest.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
  4. *
  5. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  6. * @author Bjoern Schiessle <bjoern@schiessle.org>
  7. * @author Daniel Calviño Sánchez <danxuliu@gmail.com>
  8. * @author Jan-Christoph Borchardt <hey@jancborchardt.net>
  9. * @author Joas Schilling <coding@schilljs.com>
  10. * @author Julius Haertl <jus@bitgrid.net>
  11. * @author Julius Härtl <jus@bitgrid.net>
  12. * @author Lukas Reschke <lukas@statuscode.ch>
  13. * @author Roeland Jago Douma <roeland@famdouma.nl>
  14. *
  15. * @license GNU AGPL version 3 or any later version
  16. *
  17. * This program is free software: you can redistribute it and/or modify
  18. * it under the terms of the GNU Affero General Public License as
  19. * published by the Free Software Foundation, either version 3 of the
  20. * License, or (at your option) any later version.
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU Affero General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU Affero General Public License
  28. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  29. *
  30. */
  31. namespace OCA\Theming\Tests\Controller;
  32. use OC\Files\AppData\Factory;
  33. use OC\L10N\L10N;
  34. use OC\Template\SCSSCacher;
  35. use OCA\Theming\Controller\ThemingController;
  36. use OCA\Theming\Util;
  37. use OCP\App\IAppManager;
  38. use OCP\AppFramework\Http;
  39. use OCP\AppFramework\Http\DataResponse;
  40. use OCP\AppFramework\Utility\ITimeFactory;
  41. use OCP\Files\IAppData;
  42. use OCP\Files\IRootFolder;
  43. use OCP\Files\NotFoundException;
  44. use OCP\Files\SimpleFS\ISimpleFile;
  45. use OCP\Files\SimpleFS\ISimpleFolder;
  46. use OCP\IConfig;
  47. use OCP\IL10N;
  48. use OCP\ILogger;
  49. use OCP\IRequest;
  50. use OCP\ITempManager;
  51. use OCP\IURLGenerator;
  52. use Test\TestCase;
  53. use OCA\Theming\ThemingDefaults;
  54. class ThemingControllerTest extends TestCase {
  55. /** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */
  56. private $request;
  57. /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
  58. private $config;
  59. /** @var ThemingDefaults|\PHPUnit_Framework_MockObject_MockObject */
  60. private $themingDefaults;
  61. /** @var Util */
  62. private $util;
  63. /** @var \OCP\AppFramework\Utility\ITimeFactory */
  64. private $timeFactory;
  65. /** @var IL10N|\PHPUnit_Framework_MockObject_MockObject */
  66. private $l10n;
  67. /** @var ThemingController */
  68. private $themingController;
  69. /** @var ITempManager */
  70. private $tempManager;
  71. /** @var IAppManager|\PHPUnit_Framework_MockObject_MockObject */
  72. private $appManager;
  73. /** @var IAppData|\PHPUnit_Framework_MockObject_MockObject */
  74. private $appData;
  75. /** @var SCSSCacher */
  76. private $scssCacher;
  77. /** @var IURLGenerator */
  78. private $urlGenerator;
  79. public function setUp() {
  80. $this->request = $this->createMock(IRequest::class);
  81. $this->config = $this->createMock(IConfig::class);
  82. $this->themingDefaults = $this->createMock(ThemingDefaults::class);
  83. $this->timeFactory = $this->createMock(ITimeFactory::class);
  84. $this->l10n = $this->createMock(L10N::class);
  85. $this->appData = $this->createMock(IAppData::class);
  86. $this->appManager = $this->createMock(IAppManager::class);
  87. $this->util = new Util($this->config, $this->appManager, $this->appData);
  88. $this->timeFactory->expects($this->any())
  89. ->method('getTime')
  90. ->willReturn(123);
  91. $this->tempManager = \OC::$server->getTempManager();
  92. $this->scssCacher = $this->createMock(SCSSCacher::class);
  93. $this->urlGenerator = $this->createMock(IURLGenerator::class);
  94. $this->themingController = new ThemingController(
  95. 'theming',
  96. $this->request,
  97. $this->config,
  98. $this->themingDefaults,
  99. $this->util,
  100. $this->timeFactory,
  101. $this->l10n,
  102. $this->tempManager,
  103. $this->appData,
  104. $this->scssCacher,
  105. $this->urlGenerator,
  106. $this->appManager
  107. );
  108. return parent::setUp();
  109. }
  110. public function dataUpdateStylesheetSuccess() {
  111. return [
  112. ['name', str_repeat('a', 250), 'Saved'],
  113. ['url', str_repeat('a', 500), 'Saved'],
  114. ['slogan', str_repeat('a', 500), 'Saved'],
  115. ['color', '#0082c9', 'Saved'],
  116. ['color', '#0082C9', 'Saved'],
  117. ];
  118. }
  119. /**
  120. * @dataProvider dataUpdateStylesheetSuccess
  121. *
  122. * @param string $setting
  123. * @param string $value
  124. * @param string $message
  125. */
  126. public function testUpdateStylesheetSuccess($setting, $value, $message) {
  127. $this->themingDefaults
  128. ->expects($this->once())
  129. ->method('set')
  130. ->with($setting, $value);
  131. $this->l10n
  132. ->expects($this->once())
  133. ->method('t')
  134. ->will($this->returnCallback(function($str) {
  135. return $str;
  136. }));
  137. $this->scssCacher
  138. ->expects($this->once())
  139. ->method('getCachedSCSS')
  140. ->with('core', '/core/css/server.scss')
  141. ->willReturn('/core/css/someHash-server.scss');
  142. $this->urlGenerator
  143. ->expects($this->once())
  144. ->method('linkTo')
  145. ->with('', '/core/css/someHash-server.scss')
  146. ->willReturn('/nextcloudWebroot/core/css/someHash-server.scss');
  147. $expected = new DataResponse(
  148. [
  149. 'data' =>
  150. [
  151. 'message' => $message,
  152. 'serverCssUrl' => '/nextcloudWebroot/core/css/someHash-server.scss',
  153. ],
  154. 'status' => 'success',
  155. ]
  156. );
  157. $this->assertEquals($expected, $this->themingController->updateStylesheet($setting, $value));
  158. }
  159. public function dataUpdateStylesheetError() {
  160. return [
  161. ['name', str_repeat('a', 251), 'The given name is too long'],
  162. ['url', str_repeat('a', 501), 'The given web address is too long'],
  163. ['slogan', str_repeat('a', 501), 'The given slogan is too long'],
  164. ['color', '0082C9', 'The given color is invalid'],
  165. ['color', '#0082Z9', 'The given color is invalid'],
  166. ['color', 'Nextcloud', 'The given color is invalid'],
  167. ];
  168. }
  169. /**
  170. * @dataProvider dataUpdateStylesheetError
  171. *
  172. * @param string $setting
  173. * @param string $value
  174. * @param string $message
  175. */
  176. public function testUpdateStylesheetError($setting, $value, $message) {
  177. $this->themingDefaults
  178. ->expects($this->never())
  179. ->method('set')
  180. ->with($setting, $value);
  181. $this->l10n
  182. ->expects($this->once())
  183. ->method('t')
  184. ->will($this->returnCallback(function($str) {
  185. return $str;
  186. }));
  187. $expected = new DataResponse(
  188. [
  189. 'data' =>
  190. [
  191. 'message' => $message,
  192. ],
  193. 'status' => 'error',
  194. ]
  195. );
  196. $this->assertEquals($expected, $this->themingController->updateStylesheet($setting, $value));
  197. }
  198. public function testUpdateLogoNoData() {
  199. $this->request
  200. ->expects($this->at(0))
  201. ->method('getParam')
  202. ->with('backgroundColor')
  203. ->willReturn(false);
  204. $this->request
  205. ->expects($this->at(1))
  206. ->method('getUploadedFile')
  207. ->with('uploadlogo')
  208. ->willReturn(null);
  209. $this->request
  210. ->expects($this->at(2))
  211. ->method('getUploadedFile')
  212. ->with('upload-login-background')
  213. ->willReturn(null);
  214. $this->l10n
  215. ->expects($this->any())
  216. ->method('t')
  217. ->will($this->returnCallback(function($str) {
  218. return $str;
  219. }));
  220. $expected = new DataResponse(
  221. [
  222. 'data' =>
  223. [
  224. 'message' => 'No file uploaded',
  225. ],
  226. 'status' => 'failure',
  227. ],
  228. Http::STATUS_UNPROCESSABLE_ENTITY
  229. );
  230. $this->assertEquals($expected, $this->themingController->updateLogo());
  231. }
  232. public function testUpdateLogoInvalidMimeType() {
  233. $this->request
  234. ->expects($this->at(0))
  235. ->method('getParam')
  236. ->with('backgroundColor')
  237. ->willReturn(false);
  238. $this->request
  239. ->expects($this->at(1))
  240. ->method('getUploadedFile')
  241. ->with('uploadlogo')
  242. ->willReturn([
  243. 'tmp_name' => 'logo.pdf',
  244. 'type' => 'application/pdf',
  245. 'name' => 'logo.pdf',
  246. 'error' => 0,
  247. ]);
  248. $this->request
  249. ->expects($this->at(2))
  250. ->method('getUploadedFile')
  251. ->with('upload-login-background')
  252. ->willReturn(null);
  253. $this->l10n
  254. ->expects($this->any())
  255. ->method('t')
  256. ->will($this->returnCallback(function($str) {
  257. return $str;
  258. }));
  259. $folder = $this->createMock(ISimpleFolder::class);
  260. $this->appData
  261. ->expects($this->once())
  262. ->method('getFolder')
  263. ->with('images')
  264. ->willReturn($folder);
  265. $expected = new DataResponse(
  266. [
  267. 'data' =>
  268. [
  269. 'message' => 'Unsupported image type',
  270. ],
  271. 'status' => 'failure'
  272. ],
  273. Http::STATUS_UNPROCESSABLE_ENTITY
  274. );
  275. $this->assertEquals($expected, $this->themingController->updateLogo());
  276. }
  277. public function testUpdateBackgroundColor() {
  278. $this->request
  279. ->expects($this->at(0))
  280. ->method('getParam')
  281. ->with('backgroundColor')
  282. ->willReturn(true);
  283. $this->themingDefaults
  284. ->expects($this->once())
  285. ->method('set')
  286. ->with('backgroundMime', 'backgroundColor');
  287. $expected = new DataResponse(
  288. [
  289. 'data' =>
  290. [
  291. 'name' => 'backgroundColor',
  292. 'message' => $this->l10n->t('Saved')
  293. ],
  294. 'status' => 'success'
  295. ]
  296. );
  297. $this->assertEquals($expected, $this->themingController->updateLogo());
  298. }
  299. public function dataUpdateImages() {
  300. return [
  301. ['image/jpeg', false],
  302. ['image/jpeg', true],
  303. ['image/gif'],
  304. ['image/png'],
  305. ['image/svg+xml'],
  306. ['text/svg'],
  307. ];
  308. }
  309. /** @dataProvider dataUpdateImages */
  310. public function testUpdateLogoNormalLogoUpload($mimeType, $folderExists=true) {
  311. $tmpLogo = \OC::$server->getTempManager()->getTemporaryFolder() . '/logo.svg';
  312. $destination = \OC::$server->getTempManager()->getTemporaryFolder();
  313. touch($tmpLogo);
  314. $this->request
  315. ->expects($this->at(0))
  316. ->method('getParam')
  317. ->with('backgroundColor')
  318. ->willReturn(false);
  319. $this->request
  320. ->expects($this->at(1))
  321. ->method('getUploadedFile')
  322. ->with('uploadlogo')
  323. ->willReturn([
  324. 'tmp_name' => $tmpLogo,
  325. 'type' => $mimeType,
  326. 'name' => 'logo.svg',
  327. 'error' => 0,
  328. ]);
  329. $this->request
  330. ->expects($this->at(2))
  331. ->method('getUploadedFile')
  332. ->with('upload-login-background')
  333. ->willReturn(null);
  334. $this->l10n
  335. ->expects($this->any())
  336. ->method('t')
  337. ->will($this->returnCallback(function($str) {
  338. return $str;
  339. }));
  340. $file = $this->createMock(ISimpleFile::class);
  341. $folder = $this->createMock(ISimpleFolder::class);
  342. if($folderExists) {
  343. $this->appData
  344. ->expects($this->once())
  345. ->method('getFolder')
  346. ->with('images')
  347. ->willReturn($folder);
  348. } else {
  349. $this->appData
  350. ->expects($this->at(0))
  351. ->method('getFolder')
  352. ->with('images')
  353. ->willThrowException(new NotFoundException());
  354. $this->appData
  355. ->expects($this->at(1))
  356. ->method('newFolder')
  357. ->with('images')
  358. ->willReturn($folder);
  359. }
  360. $folder->expects($this->once())
  361. ->method('newFile')
  362. ->with('logo')
  363. ->willReturn($file);
  364. $expected = new DataResponse(
  365. [
  366. 'data' =>
  367. [
  368. 'name' => 'logo.svg',
  369. 'message' => 'Saved',
  370. ],
  371. 'status' => 'success'
  372. ]
  373. );
  374. $this->assertEquals($expected, $this->themingController->updateLogo());
  375. }
  376. /** @dataProvider dataUpdateImages */
  377. public function testUpdateLogoLoginScreenUpload($folderExists) {
  378. $tmpLogo = \OC::$server->getTempManager()->getTemporaryFolder() . '/logo.svg';
  379. touch($tmpLogo);
  380. file_put_contents($tmpLogo, file_get_contents(__DIR__ . '/../../../../tests/data/desktopapp.png'));
  381. $this->request
  382. ->expects($this->at(0))
  383. ->method('getParam')
  384. ->with('backgroundColor')
  385. ->willReturn(false);
  386. $this->request
  387. ->expects($this->at(1))
  388. ->method('getUploadedFile')
  389. ->with('uploadlogo')
  390. ->willReturn(null);
  391. $this->request
  392. ->expects($this->at(2))
  393. ->method('getUploadedFile')
  394. ->with('upload-login-background')
  395. ->willReturn([
  396. 'tmp_name' => $tmpLogo,
  397. 'type' => 'text/svg',
  398. 'name' => 'logo.svg',
  399. 'error' => 0,
  400. ]);
  401. $this->l10n
  402. ->expects($this->any())
  403. ->method('t')
  404. ->will($this->returnCallback(function($str) {
  405. return $str;
  406. }));
  407. $file = $this->createMock(ISimpleFile::class);
  408. $folder = $this->createMock(ISimpleFolder::class);
  409. if($folderExists) {
  410. $this->appData
  411. ->expects($this->once())
  412. ->method('getFolder')
  413. ->with('images')
  414. ->willReturn($folder);
  415. } else {
  416. $this->appData
  417. ->expects($this->at(0))
  418. ->method('getFolder')
  419. ->with('images')
  420. ->willThrowException(new NotFoundException());
  421. $this->appData
  422. ->expects($this->at(1))
  423. ->method('newFolder')
  424. ->with('images')
  425. ->willReturn($folder);
  426. }
  427. $folder->expects($this->once())
  428. ->method('newFile')
  429. ->with('background')
  430. ->willReturn($file);
  431. $expected = new DataResponse(
  432. [
  433. 'data' =>
  434. [
  435. 'name' => 'logo.svg',
  436. 'message' => 'Saved',
  437. ],
  438. 'status' => 'success'
  439. ]
  440. );
  441. $this->assertEquals($expected, $this->themingController->updateLogo());
  442. }
  443. public function testUpdateLogoLoginScreenUploadWithInvalidImage() {
  444. $tmpLogo = \OC::$server->getTempManager()->getTemporaryFolder() . '/logo.svg';
  445. touch($tmpLogo);
  446. file_put_contents($tmpLogo, file_get_contents(__DIR__ . '/../../../../tests/data/data.zip'));
  447. $this->request
  448. ->expects($this->at(0))
  449. ->method('getParam')
  450. ->with('backgroundColor')
  451. ->willReturn(false);
  452. $this->request
  453. ->expects($this->at(1))
  454. ->method('getUploadedFile')
  455. ->with('uploadlogo')
  456. ->willReturn(null);
  457. $this->request
  458. ->expects($this->at(2))
  459. ->method('getUploadedFile')
  460. ->with('upload-login-background')
  461. ->willReturn([
  462. 'tmp_name' => $tmpLogo,
  463. 'type' => 'text/svg',
  464. 'name' => 'logo.svg',
  465. 'error' => 0,
  466. ]);
  467. $this->l10n
  468. ->expects($this->any())
  469. ->method('t')
  470. ->will($this->returnCallback(function($str) {
  471. return $str;
  472. }));
  473. $folder = $this->createMock(ISimpleFolder::class);
  474. $this->appData
  475. ->expects($this->once())
  476. ->method('getFolder')
  477. ->with('images')
  478. ->willReturn($folder);
  479. $expected = new DataResponse(
  480. [
  481. 'data' =>
  482. [
  483. 'message' => 'Unsupported image type',
  484. ],
  485. 'status' => 'failure'
  486. ],
  487. Http::STATUS_UNPROCESSABLE_ENTITY
  488. );
  489. $this->assertEquals($expected, $this->themingController->updateLogo());
  490. }
  491. public function dataPhpUploadErrors() {
  492. return [
  493. [UPLOAD_ERR_INI_SIZE, 'The uploaded file exceeds the upload_max_filesize directive in php.ini'],
  494. [UPLOAD_ERR_FORM_SIZE, 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'],
  495. [UPLOAD_ERR_PARTIAL, 'The uploaded file was only partially uploaded'],
  496. [UPLOAD_ERR_NO_FILE, 'No file was uploaded'],
  497. [UPLOAD_ERR_NO_TMP_DIR, 'Missing a temporary folder'],
  498. [UPLOAD_ERR_CANT_WRITE, 'Failed to write file to disk.'],
  499. [UPLOAD_ERR_EXTENSION, 'A PHP extension stopped the file upload.'],
  500. ];
  501. }
  502. /**
  503. * @dataProvider dataPhpUploadErrors
  504. */
  505. public function testUpdateLogoLoginScreenUploadWithInvalidImageUpload($error, $expectedErrorMessage) {
  506. $this->request
  507. ->expects($this->at(0))
  508. ->method('getParam')
  509. ->with('backgroundColor')
  510. ->willReturn(false);
  511. $this->request
  512. ->expects($this->at(1))
  513. ->method('getUploadedFile')
  514. ->with('uploadlogo')
  515. ->willReturn(null);
  516. $this->request
  517. ->expects($this->at(2))
  518. ->method('getUploadedFile')
  519. ->with('upload-login-background')
  520. ->willReturn([
  521. 'tmp_name' => '',
  522. 'type' => 'text/svg',
  523. 'name' => 'logo.svg',
  524. 'error' => $error,
  525. ]);
  526. $this->l10n
  527. ->expects($this->any())
  528. ->method('t')
  529. ->will($this->returnCallback(function($str) {
  530. return $str;
  531. }));
  532. $expected = new DataResponse(
  533. [
  534. 'data' =>
  535. [
  536. 'message' => $expectedErrorMessage,
  537. ],
  538. 'status' => 'failure'
  539. ],
  540. Http::STATUS_UNPROCESSABLE_ENTITY
  541. );
  542. $this->assertEquals($expected, $this->themingController->updateLogo());
  543. }
  544. /**
  545. * @dataProvider dataPhpUploadErrors
  546. */
  547. public function testUpdateLogoUploadWithInvalidImageUpload($error, $expectedErrorMessage) {
  548. $this->request
  549. ->expects($this->at(0))
  550. ->method('getParam')
  551. ->with('backgroundColor')
  552. ->willReturn(false);
  553. $this->request
  554. ->expects($this->at(1))
  555. ->method('getUploadedFile')
  556. ->with('uploadlogo')
  557. ->willReturn([
  558. 'tmp_name' => '',
  559. 'type' => 'text/svg',
  560. 'name' => 'logo.svg',
  561. 'error' => $error,
  562. ]);
  563. $this->request
  564. ->expects($this->at(2))
  565. ->method('getUploadedFile')
  566. ->with('upload-login-background')
  567. ->willReturn(null);
  568. $this->l10n
  569. ->expects($this->any())
  570. ->method('t')
  571. ->will($this->returnCallback(function($str) {
  572. return $str;
  573. }));
  574. $expected = new DataResponse(
  575. [
  576. 'data' =>
  577. [
  578. 'message' => $expectedErrorMessage
  579. ],
  580. 'status' => 'failure'
  581. ],
  582. Http::STATUS_UNPROCESSABLE_ENTITY
  583. );
  584. $this->assertEquals($expected, $this->themingController->updateLogo());
  585. }
  586. public function testUndo() {
  587. $this->l10n
  588. ->expects($this->once())
  589. ->method('t')
  590. ->with('Saved')
  591. ->willReturn('Saved');
  592. $this->themingDefaults
  593. ->expects($this->once())
  594. ->method('undo')
  595. ->with('MySetting')
  596. ->willReturn('MyValue');
  597. $this->scssCacher
  598. ->expects($this->once())
  599. ->method('getCachedSCSS')
  600. ->with('core', '/core/css/server.scss')
  601. ->willReturn('/core/css/someHash-server.scss');
  602. $this->urlGenerator
  603. ->expects($this->once())
  604. ->method('linkTo')
  605. ->with('', '/core/css/someHash-server.scss')
  606. ->willReturn('/nextcloudWebroot/core/css/someHash-server.scss');
  607. $expected = new DataResponse(
  608. [
  609. 'data' =>
  610. [
  611. 'value' => 'MyValue',
  612. 'message' => 'Saved',
  613. 'serverCssUrl' => '/nextcloudWebroot/core/css/someHash-server.scss',
  614. ],
  615. 'status' => 'success'
  616. ]
  617. );
  618. $this->assertEquals($expected, $this->themingController->undo('MySetting'));
  619. }
  620. public function dataUndoDelete() {
  621. return [
  622. [ 'backgroundMime', 'background' ],
  623. [ 'logoMime', 'logo' ]
  624. ];
  625. }
  626. /** @dataProvider dataUndoDelete */
  627. public function testUndoDelete($value, $filename) {
  628. $this->l10n
  629. ->expects($this->once())
  630. ->method('t')
  631. ->with('Saved')
  632. ->willReturn('Saved');
  633. $this->themingDefaults
  634. ->expects($this->once())
  635. ->method('undo')
  636. ->with($value)
  637. ->willReturn($value);
  638. $this->scssCacher
  639. ->expects($this->once())
  640. ->method('getCachedSCSS')
  641. ->with('core', '/core/css/server.scss')
  642. ->willReturn('/core/css/someHash-server.scss');
  643. $this->urlGenerator
  644. ->expects($this->once())
  645. ->method('linkTo')
  646. ->with('', '/core/css/someHash-server.scss')
  647. ->willReturn('/nextcloudWebroot/core/css/someHash-server.scss');
  648. $folder = $this->createMock(ISimpleFolder::class);
  649. $file = $this->createMock(ISimpleFile::class);
  650. $this->appData
  651. ->expects($this->once())
  652. ->method('getFolder')
  653. ->with('images')
  654. ->willReturn($folder);
  655. $folder
  656. ->expects($this->once())
  657. ->method('getFile')
  658. ->with($filename)
  659. ->willReturn($file);
  660. $file
  661. ->expects($this->once())
  662. ->method('delete');
  663. $expected = new DataResponse(
  664. [
  665. 'data' =>
  666. [
  667. 'value' => $value,
  668. 'message' => 'Saved',
  669. 'serverCssUrl' => '/nextcloudWebroot/core/css/someHash-server.scss',
  670. ],
  671. 'status' => 'success'
  672. ]
  673. );
  674. $this->assertEquals($expected, $this->themingController->undo($value));
  675. }
  676. public function testGetLogoNotExistent() {
  677. $this->appData->method('getFolder')
  678. ->with($this->equalTo('images'))
  679. ->willThrowException(new NotFoundException());
  680. $expected = new Http\NotFoundResponse();
  681. $this->assertEquals($expected, $this->themingController->getLogo());
  682. }
  683. public function testGetLogo() {
  684. $file = $this->createMock(ISimpleFile::class);
  685. $folder = $this->createMock(ISimpleFolder::class);
  686. $this->appData
  687. ->expects($this->once())
  688. ->method('getFolder')
  689. ->with('images')
  690. ->willReturn($folder);
  691. $folder->expects($this->once())
  692. ->method('getFile')
  693. ->with('logo')
  694. ->willReturn($file);
  695. $this->config
  696. ->expects($this->once())
  697. ->method('getAppValue')
  698. ->with('theming', 'logoMime', '')
  699. ->willReturn('text/svg');
  700. @$expected = new Http\FileDisplayResponse($file);
  701. $expected->cacheFor(3600);
  702. $expires = new \DateTime();
  703. $expires->setTimestamp($this->timeFactory->getTime());
  704. $expires->add(new \DateInterval('PT24H'));
  705. $expected->addHeader('Expires', $expires->format(\DateTime::RFC2822));
  706. $expected->addHeader('Pragma', 'cache');
  707. $expected->addHeader('Content-Type', 'text/svg');
  708. @$this->assertEquals($expected, $this->themingController->getLogo());
  709. }
  710. public function testGetLoginBackgroundNotExistent() {
  711. $this->appData->method('getFolder')
  712. ->with($this->equalTo('images'))
  713. ->willThrowException(new NotFoundException());
  714. $expected = new Http\NotFoundResponse();
  715. $this->assertEquals($expected, $this->themingController->getLoginBackground());
  716. }
  717. public function testGetLoginBackground() {
  718. $file = $this->createMock(ISimpleFile::class);
  719. $folder = $this->createMock(ISimpleFolder::class);
  720. $this->appData
  721. ->expects($this->once())
  722. ->method('getFolder')
  723. ->with('images')
  724. ->willReturn($folder);
  725. $folder->expects($this->once())
  726. ->method('getFile')
  727. ->with('background')
  728. ->willReturn($file);
  729. $this->config
  730. ->expects($this->once())
  731. ->method('getAppValue')
  732. ->with('theming', 'backgroundMime', '')
  733. ->willReturn('image/png');
  734. @$expected = new Http\FileDisplayResponse($file);
  735. $expected->cacheFor(3600);
  736. $expires = new \DateTime();
  737. $expires->setTimestamp($this->timeFactory->getTime());
  738. $expires->add(new \DateInterval('PT24H'));
  739. $expected->addHeader('Expires', $expires->format(\DateTime::RFC2822));
  740. $expected->addHeader('Pragma', 'cache');
  741. $expected->addHeader('Content-Type', 'image/png');
  742. @$this->assertEquals($expected, $this->themingController->getLoginBackground());
  743. }
  744. public function testGetStylesheet() {
  745. $this->appManager->expects($this->once())->method('getAppPath')->with('theming')->willReturn(\OC::$SERVERROOT . '/theming');
  746. $file = $this->createMock(ISimpleFile::class);
  747. $file->expects($this->any())->method('getName')->willReturn('theming.css');
  748. $file->expects($this->any())->method('getContent')->willReturn('compiled');
  749. $this->scssCacher->expects($this->once())->method('process')->willReturn(true);
  750. $this->scssCacher->expects($this->once())->method('getCachedCSS')->willReturn($file);
  751. $response = new Http\FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'text/css']);
  752. $response->cacheFor(86400);
  753. $expires = new \DateTime();
  754. $expires->setTimestamp($this->timeFactory->getTime());
  755. $expires->add(new \DateInterval('PT24H'));
  756. $response->addHeader('Expires', $expires->format(\DateTime::RFC1123));
  757. $response->addHeader('Pragma', 'cache');
  758. $actual = $this->themingController->getStylesheet();
  759. $this->assertEquals($response, $actual);
  760. }
  761. public function testGetStylesheetFails() {
  762. $this->appManager->expects($this->once())->method('getAppPath')->with('theming')->willReturn(\OC::$SERVERROOT . '/theming');
  763. $file = $this->createMock(ISimpleFile::class);
  764. $file->expects($this->any())->method('getName')->willReturn('theming.css');
  765. $file->expects($this->any())->method('getContent')->willReturn('compiled');
  766. $this->scssCacher->expects($this->once())->method('process')->willReturn(true);
  767. $this->scssCacher->expects($this->once())->method('getCachedCSS')->willThrowException(new NotFoundException());
  768. $response = new Http\NotFoundResponse();
  769. $actual = $this->themingController->getStylesheet();
  770. $this->assertEquals($response, $actual);
  771. }
  772. public function testGetStylesheetOutsideServerroot() {
  773. $this->appManager->expects($this->once())->method('getAppPath')->with('theming')->willReturn('/outside/serverroot/theming');
  774. $file = $this->createMock(ISimpleFile::class);
  775. $file->expects($this->any())->method('getName')->willReturn('theming.css');
  776. $file->expects($this->any())->method('getContent')->willReturn('compiled');
  777. $this->scssCacher->expects($this->once())->method('process')->with('/outside/serverroot/theming', 'css/theming.scss', 'theming')->willReturn(true);
  778. $this->scssCacher->expects($this->once())->method('getCachedCSS')->willReturn($file);
  779. $response = new Http\FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'text/css']);
  780. $response->cacheFor(86400);
  781. $expires = new \DateTime();
  782. $expires->setTimestamp($this->timeFactory->getTime());
  783. $expires->add(new \DateInterval('PT24H'));
  784. $response->addHeader('Expires', $expires->format(\DateTime::RFC1123));
  785. $response->addHeader('Pragma', 'cache');
  786. $actual = $this->themingController->getStylesheet();
  787. $this->assertEquals($response, $actual);
  788. }
  789. public function testGetJavascript() {
  790. $this->themingDefaults
  791. ->expects($this->at(0))
  792. ->method('getName')
  793. ->willReturn("");
  794. $this->themingDefaults
  795. ->expects($this->at(1))
  796. ->method('getBaseUrl')
  797. ->willReturn("");
  798. $this->themingDefaults
  799. ->expects($this->at(2))
  800. ->method('getSlogan')
  801. ->willReturn("");
  802. $this->themingDefaults
  803. ->expects($this->at(3))
  804. ->method('getColorPrimary')
  805. ->willReturn("#000");
  806. $expectedResponse = '(function() {
  807. OCA.Theming = {
  808. name: "",
  809. url: "",
  810. slogan: "",
  811. color: "#000",
  812. imprintUrl: null,
  813. privacyUrl: null,
  814. inverted: false,
  815. cacheBuster: null
  816. };
  817. })();';
  818. $expected = new Http\DataDownloadResponse($expectedResponse, 'javascript', 'text/javascript');
  819. $expected->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime()));
  820. $expected->addHeader('Pragma', 'cache');
  821. $expected->cacheFor(3600);
  822. @$this->assertEquals($expected, $this->themingController->getJavascript());
  823. }
  824. public function testGetJavascriptInverted() {
  825. $this->themingDefaults
  826. ->expects($this->at(0))
  827. ->method('getName')
  828. ->willReturn("Nextcloud");
  829. $this->themingDefaults
  830. ->expects($this->at(1))
  831. ->method('getBaseUrl')
  832. ->willReturn("nextcloudurl");
  833. $this->themingDefaults
  834. ->expects($this->at(2))
  835. ->method('getSlogan')
  836. ->willReturn("awesome");
  837. $this->themingDefaults
  838. ->expects($this->any())
  839. ->method('getColorPrimary')
  840. ->willReturn("#ffffff");
  841. $expectedResponse = '(function() {
  842. OCA.Theming = {
  843. name: "Nextcloud",
  844. url: "nextcloudurl",
  845. slogan: "awesome",
  846. color: "#ffffff",
  847. imprintUrl: null,
  848. privacyUrl: null,
  849. inverted: true,
  850. cacheBuster: null
  851. };
  852. })();';
  853. $expected = new Http\DataDownloadResponse($expectedResponse, 'javascript', 'text/javascript');
  854. $expected->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime()));
  855. $expected->addHeader('Pragma', 'cache');
  856. $expected->cacheFor(3600);
  857. @$this->assertEquals($expected, $this->themingController->getJavascript());
  858. }
  859. public function testGetManifest() {
  860. $this->config
  861. ->expects($this->once())
  862. ->method('getAppValue')
  863. ->with('theming', 'cachebuster', '0')
  864. ->willReturn('0');
  865. $this->themingDefaults
  866. ->expects($this->any())
  867. ->method('getName')
  868. ->willReturn('Nextcloud');
  869. $this->urlGenerator
  870. ->expects($this->at(0))
  871. ->method('getBaseUrl')
  872. ->willReturn('localhost');
  873. $this->urlGenerator
  874. ->expects($this->at(1))
  875. ->method('linkToRoute')
  876. ->with('theming.Icon.getTouchIcon', ['app' => 'core'])
  877. ->willReturn('touchicon');
  878. $this->urlGenerator
  879. ->expects($this->at(2))
  880. ->method('linkToRoute')
  881. ->with('theming.Icon.getFavicon', ['app' => 'core'])
  882. ->willReturn('favicon');
  883. $response = new Http\JSONResponse([
  884. 'name' => 'Nextcloud',
  885. 'start_url' => 'localhost',
  886. 'icons' =>
  887. [
  888. [
  889. 'src' => 'touchicon?v=0',
  890. 'type'=> 'image/png',
  891. 'sizes'=> '128x128'
  892. ],
  893. [
  894. 'src' => 'favicon?v=0',
  895. 'type' => 'image/svg+xml',
  896. 'sizes' => '16x16'
  897. ]
  898. ],
  899. 'display' => 'standalone'
  900. ]);
  901. $response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime()));
  902. $response->addHeader('Pragma', 'cache');
  903. $response->cacheFor(3600);
  904. $this->assertEquals($response, $this->themingController->getManifest('core'));
  905. }
  906. }