baseUrl = $baseUrl; // in case of ci deployment we take the server url from the environment $testServerUrl = getenv('TEST_SERVER_URL'); if ($testServerUrl !== false) { $this->baseUrl = substr($testServerUrl, 0, -5); } } /** * get a named entry from response instead of picking a random entry from values * * @param string $path * * @return array|string * @throws Exception */ private function getValueFromNamedEntries(string $path, array $response): mixed { $next = ''; if (str_contains($path, ' ')) { [$key, $next] = explode(' ', $path, 2); } else { $key = $path; } foreach ($response as $entry) { if ($entry['name'] === $key) { if ($next !== '') { return $this->getValueFromNamedEntries($next, $entry['value']); } else { return $entry['value']; } } } return null; } /** @AfterScenario */ public function teardownScenario() { $client = new \GuzzleHttp\Client(); try { $client->delete( $this->baseUrl . '/remote.php/webdav/myFileToComment.txt', [ 'auth' => [ 'user0', '123456', ], 'headers' => [ 'Content-Type' => 'application/json', ], ] ); } catch (\GuzzleHttp\Exception\ClientException $e) { $e->getResponse(); } } /** * @param string $path * @return int */ private function getFileIdForPath($path) { $url = $this->baseUrl . '/remote.php/webdav/' . $path; $context = stream_context_create([ 'http' => [ 'method' => 'PROPFIND', 'header' => "Authorization: Basic dXNlcjA6MTIzNDU2\r\nContent-Type: application/x-www-form-urlencoded", 'content' => ' ' ] ]); $response = file_get_contents($url, false, $context); preg_match_all('/\(.*)\<\/oc:fileid\>/', $response, $matches); return (int)$matches[1][0]; } /** * @When :user posts a comment with content :content on the file named :fileName it should return :statusCode * @param string $user * @param string $content * @param string $fileName * @param int $statusCode * @throws \Exception */ public function postsACommentWithContentOnTheFileNamedItShouldReturn($user, $content, $fileName, $statusCode) { $fileId = $this->getFileIdForPath($fileName); $this->fileId = (int)$fileId; $url = $this->baseUrl . '/remote.php/dav/comments/files/' . $fileId . '/'; $client = new \GuzzleHttp\Client(); try { $res = $client->post( $url, [ 'body' => '{"actorId":"user0","actorDisplayName":"user0","actorType":"users","verb":"comment","message":"' . $content . '","creationDateTime":"Thu, 18 Feb 2016 17:04:18 GMT","objectType":"files"}', 'auth' => [ $user, '123456', ], 'headers' => [ 'Content-Type' => 'application/json', ], ] ); } catch (\GuzzleHttp\Exception\ClientException $e) { $res = $e->getResponse(); } if ($res->getStatusCode() !== (int)$statusCode) { throw new \Exception("Response status code was not $statusCode (" . $res->getStatusCode() . ')'); } } /** * @Then As :user load all the comments of the file named :fileName it should return :statusCode * @param string $user * @param string $fileName * @param int $statusCode * @throws \Exception */ public function asLoadloadAllTheCommentsOfTheFileNamedItShouldReturn($user, $fileName, $statusCode) { $fileId = $this->getFileIdForPath($fileName); $url = $this->baseUrl . '/remote.php/dav/comments/files/' . $fileId . '/'; try { $client = new \GuzzleHttp\Client(); $res = $client->request( 'REPORT', $url, [ 'body' => ' 200 0 ', 'auth' => [ $user, '123456', ], 'headers' => [ 'Content-Type' => 'application/json', ], ] ); } catch (\GuzzleHttp\Exception\ClientException $e) { $res = $e->getResponse(); } if ($res->getStatusCode() !== (int)$statusCode) { throw new \Exception("Response status code was not $statusCode (" . $res->getStatusCode() . ')'); } if ($res->getStatusCode() === 207) { $service = new Sabre\Xml\Service(); $this->response = $service->parse($res->getBody()->getContents()); $this->commentId = (int)($this->getValueFromNamedEntries('{DAV:}response {DAV:}propstat {DAV:}prop {http://owncloud.org/ns}id', $this->response ?? []) ?? 0); } } /** * @Given As :user sending :verb to :url with * @param string $user * @param string $verb * @param string $url * @param \Behat\Gherkin\Node\TableNode $body * @throws \Exception */ public function asUserSendingToWith($user, $verb, $url, \Behat\Gherkin\Node\TableNode $body) { $client = new \GuzzleHttp\Client(); $options = []; $options['auth'] = [$user, '123456']; $fd = $body->getRowsHash(); $options['form_params'] = $fd; $options['headers'] = [ 'OCS-APIREQUEST' => 'true', ]; $client->request($verb, $this->baseUrl . '/ocs/v1.php/' . $url, $options); } /** * @Then As :user delete the created comment it should return :statusCode * @param string $user * @param int $statusCode * @throws \Exception */ public function asDeleteTheCreatedCommentItShouldReturn($user, $statusCode) { $url = $this->baseUrl . '/remote.php/dav/comments/files/' . $this->fileId . '/' . $this->commentId; $client = new \GuzzleHttp\Client(); try { $res = $client->delete( $url, [ 'auth' => [ $user, '123456', ], 'headers' => [ 'Content-Type' => 'application/json', ], ] ); } catch (\GuzzleHttp\Exception\ClientException $e) { $res = $e->getResponse(); } if ($res->getStatusCode() !== (int)$statusCode) { throw new \Exception("Response status code was not $statusCode (" . $res->getStatusCode() . ')'); } } /** * @Then the response should contain a property :key with value :value * @param string $key * @param string $value * @throws \Exception */ public function theResponseShouldContainAPropertyWithValue($key, $value) { // $keys = $this->response[0]['value'][1]['value'][0]['value']; $keys = $this->getValueFromNamedEntries('{DAV:}response {DAV:}propstat {DAV:}prop', $this->response); $found = false; foreach ($keys as $singleKey) { if ($singleKey['name'] === '{http://owncloud.org/ns}' . substr($key, 3)) { if ($singleKey['value'] === $value) { $found = true; } } } if ($found === false) { throw new \Exception("Cannot find property $key with $value"); } } /** * @Then the response should contain only :number comments * @param int $number * @throws \Exception */ public function theResponseShouldContainOnlyComments($number) { $count = 0; if ($this->response !== null) { $count = count($this->response); } if ($count !== (int)$number) { throw new \Exception("Found more comments than $number (" . $count . ')'); } } /** * @Then As :user edit the last created comment and set text to :text it should return :statusCode * @param string $user * @param string $text * @param int $statusCode * @throws \Exception */ public function asEditTheLastCreatedCommentAndSetTextToItShouldReturn($user, $text, $statusCode) { $client = new \GuzzleHttp\Client(); $options = []; $options['auth'] = [$user, '123456']; $options['body'] = ' ' . $text . ' '; try { $res = $client->request('PROPPATCH', $this->baseUrl . '/remote.php/dav/comments/files/' . $this->fileId . '/' . $this->commentId, $options); } catch (\GuzzleHttp\Exception\ClientException $e) { $res = $e->getResponse(); } if ($res->getStatusCode() !== (int)$statusCode) { throw new \Exception("Response status code was not $statusCode (" . $res->getStatusCode() . ')'); } } } Nextcloud server, a safe home for all your data: https://github.com/nextcloud/serverwww-data
aboutsummaryrefslogtreecommitdiffstats
path: root/core/Controller/CssController.php
blob: c8458eab29c6330fb54686caff58c5e7eee6bfa7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<?php
declare(strict_types=1);
/**
 * @copyright Copyright (c) 2016, John Molakvoæ (skjnldsv@protonmail.com)
 *
 * @author Joas Schilling <coding@schilljs.com>
 * @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
 * @author Morris Jobke <hey@morrisjobke.de>
 * @author Roeland Jago Douma <roeland@famdouma.nl>
 *
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * 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
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

namespace OC\Core\Controller;

use OC\Files\AppData\Factory;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\NotFoundResponse;
use OCP\AppFramework\Http\FileDisplayResponse;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Files\IAppData;
use OCP\Files\NotFoundException;
use OCP\Files\SimpleFS\ISimpleFile;
use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\IConfig;
use OCP\IRequest;

class CssController extends Controller {

	/** @var IAppData */
	protected $appData;

	/** @var ITimeFactory */
	protected $timeFactory;

	public function __construct(string $appName,
								IRequest $request,
								Factory $appDataFactory,
								ITimeFactory $timeFactory) {
		parent::__construct($appName, $request);

		$this->appData = $appDataFactory->get('css');
		$this->timeFactory = $timeFactory;
	}

	/**
	 * @PublicPage
	 * @NoCSRFRequired
	 *
	 * @param string $fileName css filename with extension
	 * @param string $appName css folder name
	 * @return FileDisplayResponse|NotFoundResponse
	 */
	public function getCss(string $fileName, string $appName): Response {
		try {
			$folder = $this->appData->getFolder($appName);
			$gzip = false;
			$file = $this->getFile($folder, $fileName, $gzip);
		} catch(NotFoundException $e) {
			return new NotFoundResponse();
		}

		$response = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'text/css']);
		if ($gzip) {
			$response->addHeader('Content-Encoding', 'gzip');
		}

		$ttl = 31536000;
		$response->addHeader('Cache-Control', 'max-age='.$ttl.', immutable');

		$expires = new \DateTime();
		$expires->setTimestamp($this->timeFactory->getTime());
		$expires->add(new \DateInterval('PT'.$ttl.'S'));
		$response->addHeader('Expires', $expires->format(\DateTime::RFC1123));
		$response->addHeader('Pragma', 'cache');
		return $response;
	}

	/**
	 * @param ISimpleFolder $folder
	 * @param string $fileName
	 * @param bool $gzip is set to true if we use the gzip file
	 * @return ISimpleFile
	 * @throws NotFoundException
	 */
	private function getFile(ISimpleFolder $folder, string $fileName, bool &$gzip): ISimpleFile {
		$encoding = $this->request->getHeader('Accept-Encoding');

		if (strpos($encoding, 'gzip') !== false) {
			try {
				$gzip = true;
				return $folder->getFile($fileName . '.gzip'); # Safari doesn't like .gz
			} catch (NotFoundException $e) {
				// continue
			}
		}

		$gzip = false;
		return $folder->getFile($fileName);
	}
}